adb en script : les pièges qui font mentir un test
💡 Sujet
Utilisé à la main, adb sert à installer un APK et à lire les logs. Dès qu'on s'en sert pour
piloter un parc de téléphones depuis un script, il se comporte autrement qu'on ne l'attend : des
comparaisons qui échouent sans raison, des stimuli refusés en silence, des logs filtrés sur la
mauvaise horloge. Chacun de ces cas produit un test qui échoue — ou pire, qui passe — pour une
raison étrangère à ce qu'il vérifie.
🎯 Toujours désigner l'appareil
Avec plus d'un téléphone branché, toute commande sans -s échoue. Autant en faire un raccourci une
fois pour toutes, et vérifier la joignabilité avant de commencer :
A() { adb -s "$S" "$@"; }
A get-state >/dev/null 2>&1 || { echo "adb injoignable"; exit 2; }get-state est le test le moins cher : pas de shell distant, pas d'effet de bord.
🩸 Le piège n°1 : les \r en fin de ligne
La sortie de adb shell revient avec un retour chariot en fin de chaque ligne. Invisible à
l'écran, fatal en comparaison :
[ "$(A shell getprop sys.boot_completed)" = "1" ] # faux : la valeur est "1\r"
[ "$(A shell getprop sys.boot_completed | tr -d '\r')" = "1" ] # vraiLe symptôme est une condition qui ne se déclenche jamais, sans message d'erreur. Le réflexe : tr -d '\r' sur toute valeur capturée depuis adb shell, systématiquement.
🚀 Lancer une app sans connaître son activité
Inutile de chercher le nom complet de l'activité de lancement : monkey la résout via la catégorie
LAUNCHER.
A shell monkey -p com.example.monapp -c android.intent.category.LAUNCHER 1Pour cibler un composant précis en revanche, il faut son nom complet. Un raccourci relatif
(.background.services.MonService) se résout contre l'applicationId, donc il casse dès qu'une
variante ajoute un suffixe (.staging, .preprod) alors que la classe, elle, n'a pas bougé de
package.
📡 Les radios avec svc
A shell svc bluetooth disable
A shell svc wifi enable
A shell svc data disable
A shell svc power stayon trueLe mode avion n'est volontairement pas dans la liste : il demande le root ou des permissions
secure sur la plupart des surcouches constructeur. Couper le réseau se fait donc en coupant wifi
et data.
🤫 Un stimulus peut être refusé en silence
Lire un réglage marche toujours ; l'écrire peut être bloqué. Sur MIUI, WRITE_SECURE_SETTINGS
est refusé au shell tant que « Débogage USB (réglages de sécurité) » n'est pas activé — et la
commande sort sans erreur exploitable.
A shell settings put secure location_mode 0 # peut ne rien faire
A shell settings get secure location_mode | tr -d '\r' # relire pour en avoir le cœur netRègle : après chaque stimulus, relire l'état et abandonner le scénario s'il n'a pas pris. Sinon on teste le comportement de l'app dans des conditions qu'on croit avoir créées.
⏱️ logcat -T : l'horodatage se prend sur le téléphone
Pour ne lire que les logs postérieurs à une action, logcat -T <timestamp>. Mais la référence doit
venir de l'appareil, pas du poste — les deux horloges ne sont pas les mêmes :
since_now() { A shell 'date "+%m-%d %H:%M:%S.000"' | tr -d '\r'; }
SINCE=$(since_now)
# … action …
A logcat -d -T "$SINCE" | grep -cE "mon marqueur"Les quotes simples comptent : la chaîne de format doit être interprétée sur le téléphone.
🔁 Attendre un redémarrage
adb reboot rend la main immédiatement. La suite du script parlerait dans le vide : il faut
attendre que le système annonce lui-même sa disponibilité.
A reboot
until [ "$(A shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" = "1" ]; do sleep 5; done🔬 Savoir sur quel type de build on tourne
Les marqueurs de log d'une app n'existent souvent qu'en build debug. Autant le détecter et adapter les vérifications plutôt que d'échouer :
A shell dumpsys package "$PKG" | grep -q DEBUGGABLE🧩 Résumé
- 🎯
adb -s <serial>dès qu'il y a plus d'un appareil ;adb get-statepour la joignabilité. - 🩸
tr -d '\r'sur toute valeur capturée deadb shell— sans ça, les comparaisons échouent en silence. - 🚀
monkey -p <pkg> -c android.intent.category.LAUNCHER 1lance une app sans connaître son activité ; à l'inverse, un composant se désigne par son nom complet. - 📡
svc bluetooth|wifi|data|powerpour les radios ; le mode avion demande des droits qu'un shell n'a pas. - 🤫 Écrire un réglage
securepeut être refusé sans erreur : relire pour vérifier. - ⏱️ L'horodatage de
logcat -Tse prend avecadb shell date, pas sur le poste. - 🔁 Après
adb reboot, attendregetprop sys.boot_completed=1.