Je suis en train de développer une application pour ma thèse finale sur l'informatique et j'ai besoin de collecter et d'enregistrer des données d'accéléromètre. Je dois l'acquérir pendant toute une journée, il y a donc de sérieuses contraintes de batterie (par exemple, je ne peux pas laisser l'écran allumé). En outre, ce n'est pas une application ciblée sur le marché, il est donc assez acceptable de faire un piratage sérieux, même un codage C/C++ de bas niveau, si nécessaire.
Il est bien connu que sur de nombreux appareils, les écouteurs des événements de l'accéléromètre cessent de générer des événements lorsque l'écran s'éteint (certains liens concernant ce problème: http://code.google.com/p/Android/issues/detail?id = 3708 , l'accéléromètre arrête de fournir des échantillons lorsque l'écran est éteint sur Droid/Nexus One même avec un WakeLock ). J'ai soigneusement recherché quelques alternatives, certaines d'entre elles incluent des solutions de contournement qui ne fonctionnent pas pour mon appareil (LG P990, ROM stock).
Ainsi, ce qui se passe est le suivant: lorsque vous enregistrez un écouteur d'événements pour Android d'accéléromètre Android dans un service, cela fonctionne bien jusqu'à ce que l'écran soit éteint. J'ai déjà essayé d'enregistrer le eventListener sur un service , sur un IntentService, a tenté d'acquérir WakeLocks. En ce qui concerne les wakelocks, je peux vérifier que le service fonctionne toujours en regardant la sortie LOGcat, mais il semble que l'accéléromètre soit mis en mode veille. L'une des solutions de contournement présentées dans certains des liens est de annuler l'enregistrement et réenregistrer périodiquement l'écouteur d'événements en utilisant le thread d'un IntentService comme dans cet extrait de code ci-dessous
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (lockStatic==null) {
PowerManager mgr=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,NAME);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
@Override
protected void onHandleIntent(Intent intent) {
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.unregisterListener(this);
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
synchronized (this) {
boolean run = true;
while (run){
try {
wait(1000);
getLock(AccelerometerService.this).acquire();
sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.unregisterListener(this);
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
Log.d("Accelerometer service", "tick!");
} catch (Exception e) {
run = false;
Log.d("Accelerometer service", "interrupted; cause: " + e.getMessage());
}
}
}
}
@Override
public void onSensorChanged(SensorEvent event) {
Log.d("accelerometer event received", "xyz: "+ event.values[0] + "," + event.values[1] + "," + event.values[2]);
}
ce qui fait que l'onSensorChange est appelé à chaque fois que nous désinscrivons/enregistrons l'auditeur. Le problème est que l'événement reçu contient toujours les mêmes valeurs, que je secoue ou non l'appareil.
Donc, fondamentalement, mes questions sont les suivantes: (restez avec moi, je termine presque: P)
est-il possible d'avoir un accès de bas niveau (approche C/C++) au matériel de l'accéléromètre SANS s'inscrire à un écouteur d'événement?
existe-t-il une autre solution de contournement ou un hack?
est-ce que n'importe qui avec un téléphone plus à jour pourrait bien tester si le problème persiste dans le firmware 3.0 et supérieur?
[MISE À JOUR]
Malheureusement, cela semble être un bug avec certains téléphones portables. Plus de détails dans ma réponse.
Fondamentalement, c'est un problème avec mon téléphone. D'autres utilisateurs ont signalé que cela se produit également avec leurs téléphones, de différentes marques mais identiques Android. Les autres personnes n'ont aucun problème - indiquant fortement que ce n'est pas un problème avec la version stock de = Android mais à partir des implémentations de chaque entreprise pour leurs pilotes matériels.
J'ai besoin de données d'accéléromètre constantes fournies et je ne peux pas avoir un dongle mesurant ces données pour moi - j'ai un Arduino avec Bluetooth et un accéléromètre, donc j'aurais pu implémenter cette solution. J'ai donc décidé que la solution temporaire pour mon téléphone portable était de laisser l'écran allumé (grisé) et d'ignorer la consommation de la batterie. Plus tard, j'effectuerai les tests d'utilisation de la batterie en utilisant un autre Android qui fonctionne avec l'écran éteint.
Plus d'informations sur le bug
J'ai fait des recherches et trouvé des rapports d'autres Android et je pense que je comprends peut-être ce qui se passe. La bibliothèque libsensors.so qui contient les pilotes pour les capteurs du téléphone n'est pas développée par Google mais par chaque fournisseur de téléphone portable - bien sûr, parce que chaque téléphone portable a son propre matériel spécifique. Google ne fournit qu'un fichier d'en-tête C pour que les développeurs sachent ce qu'ils doivent implémenter. Sur certaines implémentations de ces pilotes, les développeurs désactivent simplement l'accéléromètre lorsque l'écran s'éteint, empêchant ainsi l'écouteur d'événements du capteur de recevoir de nouveaux événements.
J'ai également testé cela avec CyanogenMod RC7.2 mais cela n'a pas fonctionné non plus, car les pilotes d'accéléromètre sont d'origine LG.
E-mails échangés avec le service RH de LG
J'ai envoyé un e-mail aux développeurs du LG P990 et j'ai finalement obtenu des réponses concrètes! Cela peut être d'une grande aide pour certaines personnes comme moi qui rencontrent ces problèmes avec Android. J'ai écrit la question suivante
Salut! Je suis en train de développer ma thèse en informatique et actuellement je récupère des données depuis un accéléromètre. À partir de maintenant, j'ai découvert que les accéléromètres n'envoient pas d'événements lorsque l'écran est éteint, donc même lorsque j'attrape un verrou de réveil dans l'un de mes programmes, je peux vérifier que mon programme fonctionne toujours (via la sortie LOGcat) mais pas l'événement accéléromètre sort. Je dois éteindre mon écran (ce que je ne peux pas me permettre, la batterie se décharge trop rapidement) pour recommencer à recevoir les événements de l'accéléromètre. J'ai également essayé d'y accéder via du code C natif, en m'inscrivant sur les événements de l'accéléromètre, mais le résultat était le même, l'accéléromètre n'a émis aucune valeur, même si je faisais tourner mon appareil. Je me demandais donc si je pouvais avoir un accès direct au matériel, avec du code natif, sans avoir à m'inscrire à un auditeur. Est-ce possible? Dans l'affirmative, pourriez-vous nous donner quelques conseils supplémentaires? J'apprécierais beaucoup toute aide! Martin
Pour ce que j'ai reçu cette réponse:
Cher Martin, Nous avons reçu la réponse de Dev. Équipe. Ils ont dit que vous ne pouvez pas obtenir d'événement accéléromètre lorsque l'écran de votre téléphone est éteint. Parce que la couche HAL n'a pas implémenté le chemin sysFS pour obtenir un événement H/W tel qu'un accéléromètre et il n'y a pas d'API publique pour obtenir l'événement. Je vous remercie. Meilleures salutations. (Sean Kim)
J'ai ensuite renvoyé un e-mail, disant entre autres choses que je considérais cela comme un bug, car il fallait avoir accès à tout le matériel lors de l'acquisition d'un verrou de réveil:
[...] J'ai posé cette question car j'ai des amis qui ont aussi des téléphones Android avec la même version Gingerbread mais d'autres marques de téléphones portables, et certains d'entre eux ont signalé qu'ils recevaient des événements des accéléromètres lorsque l'écran est éteint. J'ai lu sur certains forums que ce bogue - je le considère comme un bogue, car lorsque j'achète un Wakelock, je m'attends à ce qu'un traitement soit en cours - dépend des pilotes de capteur que les fournisseurs implémentent pour leurs téléphones portables. Est-il possible que ces pilotes puissent être mis à jour ou ce bug sera-t-il corrigé à un moment donné? Cela m'aiderait énormément dans mon travail en cours [...]
Et puis j'ai reçu cette réponse:
À ma connaissance de Dev. Équipe, ce n'est pas un bug. C'est une limite de ce téléphone en raison de l'architecture H/W. Nous devons repenser l'architecture HAL et le pilote de périphérique pour prendre en charge votre demande. Mais, comme vous le savez, c'est trop difficile à cause du manque de ressources. Nous essayons de vous aider dans tous nos efforts mais nous ne pouvons pas soutenir votre demande comme je l'ai mentionné. (Sean Kim)
Donc, apparemment, ils le savent mais n'essaient pas de le corriger parce qu'ils ne pensent pas que c'est un bogue - que je crois toujours fermement être un défaut logique - ou ils n'ont pas le temps/les ressources pour le corriger.
Conclusion Si vous avez un téléphone portable qui n'envoie pas d'accéléromètre avec l'écran éteint, essayez de mettre à jour votre firmware. Si cela ne résout pas et que vous voulez vraiment faire un piratage sérieux, réimplémentez votre couche matérielle - indice: c'est probablement quelque chose à voir avec libsensors.so.
Je ne sais pas si cela vous aidera réellement, mais j'ai trouvé un moyen de contourner le problème (je ne sais pas si cela aidera à économiser la batterie).
En utilisant bash, j'ai une boucle while cat-ing /sys/devices/virtual/accelerometer/accelerometer/acc_file
, et lorsque j'éteins l'écran via le bouton d'alimentation, la sortie continue, mais est figée. (J'ai eu sshd en cours d'exécution dans un chroot d'où la possibilité de le voir.)
Cependant, en faisant écho à 0 > /sys/devices/platform/msm_fb.196609/leds/lcd-backlight/brightness
. L'écran s'éteint et la sortie est continue.
Il s'agit d'un SGH-T589W, exécutant Android version 2.3.6.
J'ai appliqué le PARTIAL_WAKE_LOCK et cela a fonctionné comme un charme pour moi. Testé sur OS 5.0, 6.0 et 7.0. Voici mon code pour acquérir et libérer le verrouillage de réveil. Attention, cela augmente le drainage de la batterie, alors acquérez-le et relâchez-le intelligemment.
public void acquireWakeLock() {
final PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
releaseWakeLock();
//Acquire new wake lock
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK");
mWakeLock.acquire();
}
public void releaseWakeLock() {
if (mWakeLock != null && mWakeLock.isHeld()) {
mWakeLock.release();
mWakeLock = null;
}
}
Réf: https://developer.Android.com/training/scheduling/wakelock.html#cp
Je travaille sur un sdk de prédiction, qui utilise les données des capteurs de l'appareil (accéléromètre/gyroscope) et prédit les événements utilisateurs. J'ai rencontré le même problème.
J'ai rencontré des problèmes similaires avec le Samsung Nexus fonctionnant Android 4.0.2 en utilisant d'autres services système qui s'arrêtent/s'arrêtent lorsque l'écran est éteint même si un PARTIAL_WAKE_LOCK
est acquis. Ma solution était d'utiliser un SCREEN_DIM_WAKE_LOCK
un péché:
lockStatic = mgr.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,NAME);
Il serait beaucoup mieux d'avoir l'écran complètement éteint, mais au moins cette solution fonctionne bien qu'il serait encore mieux si je pouvais limiter l'utilisation d'un SCREEN_DIM_WAKE_LOCK
uniquement aux périphériques/OS qui en ont besoin.
Je déteste vous décevoir, mais certains appareils ne permettent tout simplement pas d'accélérométrie lorsqu'ils sont en mode veille. Certains le font, d'autres non. Vous pouvez vérifier n'importe quelle application de perte de poids de podomètre en magasin, la plupart d'entre elles indiquent explicitement que cela ne fonctionnera pas sur certains appareils.
Si l'option de verrouillage de réveil partiel n'est pas disponible pour votre téléphone, cela signifie que le pilote du capteur a early_suspend
activée.
Il y a deux options.
1: désactiver EARLY_SUSPEND
dans le pilote
2: Ajoutez un indicateur d'exécution qui peut enable
/disable early_suspend
fonctionnalité au niveau du pilote.
ex. cat/sys/module/earlysuspend/sensor 1/0
OMI, la deuxième option aurait dû être là depuis le début.