Cet article décrit quelques trucs et astuces pour déboguer l'audio Android.
Évier en T
Le "tee sink" est une fonctionnalité de débogage AudioFlinger, disponible uniquement dans les versions personnalisées, pour conserver un court fragment d'audio récent pour une analyse ultérieure. Cela permet de comparer ce qui a été réellement joué ou enregistré par rapport à ce qui était attendu.
Pour des raisons de confidentialité, le puits de tee est désactivé par défaut, à la fois à la compilation et à l'exécution. Pour utiliser l'évier en té, vous devrez l'activer en recompilant, ainsi qu'en définissant une propriété. Assurez-vous de désactiver cette fonctionnalité après avoir terminé le débogage ; l'évier en T ne doit pas rester activé dans les versions de production.
Les instructions de cette section concernent Android 7.x et supérieur. Pour Android 5.x et 6.x, remplacez /data/misc/audioserver
par /data/misc/media
. De plus, vous devez utiliser une build userdebug ou eng. Si vous utilisez une version userdebug, désactivez verity avec :
adb root && adb disable-verity && adb reboot
Configuration au moment de la compilation
-
cd frameworks/av/services/audioflinger
- Modifier
Configuration.h
. - Décommentez
#define TEE_SINK
. -
libaudioflinger.so
. -
adb root
-
adb remount
- Poussez ou synchronisez le nouveau
libaudioflinger.so
avec le/system/lib
de l'appareil.
Configuration de l'exécution
-
adb shell getprop | grep ro.debuggable
Confirmez que la sortie est :[ro.debuggable]: [1]
-
adb shell
-
ls -ld /data/misc/audioserver
Vérifiez que la sortie est :
drwx------ media media ... media
Si le répertoire n'existe pas, créez-le comme suit :
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
-
echo af.tee=# > /data/local.prop
Où la valeuraf.tee
est un nombre décrit ci-dessous. -
chmod 644 /data/local.prop
-
reboot
Valeurs de la propriété af.tee
La valeur de af.tee
est un nombre compris entre 0 et 7, exprimant la somme de plusieurs bits, un par caractéristique. Voir le code sur AudioFlinger::AudioFlinger()
dans AudioFlinger.cpp
pour une explication de chaque bit, mais brièvement :
- 1 = entrée
- 2 = Sortie FastMixer
- 4 = AudioRecord et AudioTrack par piste
Il n'y a pas encore de bit pour le tampon profond ou le mélangeur normal, mais vous pouvez obtenir des résultats similaires en utilisant "4".
Tester et acquérir des données
- Exécutez votre test audio.
-
adb shell dumpsys media.audio_flinger
- Recherchez une ligne dans la sortie de
dumpsys
telle que celle-ci :
tee copied to /data/misc/audioserver/20131010101147_2.wav
Il s'agit d'un fichier PCM .wav. - Ensuite,
adb pull
tous les fichiers/data/misc/audioserver/*.wav
intéressent ; notez que les noms de fichier de vidage spécifiques à la piste n'apparaissent pas dans la sortie dedumpsys
, mais sont toujours enregistrés dans/data/misc/audioserver
lors de la fermeture de la piste. - Examinez les fichiers de vidage pour les problèmes de confidentialité avant de les partager avec d'autres.
Suggestions
Essayez ces idées pour des résultats plus utiles :
- Désactivez les sons tactiles et les clics de touche pour réduire les interruptions de la sortie de test.
- Maximisez tous les volumes.
- Désactivez les applications qui émettent du son ou enregistrent à partir du microphone, si elles ne présentent aucun intérêt pour votre test.
- Les vidages spécifiques à la piste ne sont enregistrés que lorsque la piste est fermée ; vous devrez peut-être forcer la fermeture d'une application afin de vider ses données spécifiques à la piste
- Faites les
dumpsys
immédiatement après le test ; l'espace d'enregistrement disponible est limité. - Pour vous assurer de ne pas perdre vos fichiers de vidage, téléchargez-les régulièrement sur votre hébergeur. Seul un nombre limité de fichiers de vidage est conservé ; les anciens vidages sont supprimés une fois cette limite atteinte.
Restaurer
Comme indiqué ci-dessus, la fonction d'évier en T ne doit pas rester activée. Restaurez votre build et votre appareil comme suit :
- Annulez les modifications du code source dans
Configuration.h
. -
libaudioflinger.so
. - Poussez ou synchronisez le
libaudioflinger.so
restauré avec le/system/lib
de l'appareil. -
adb shell
-
rm /data/local.prop
-
rm /data/misc/audioserver/*.wav
-
reboot
media.log
Macros ALOGx
L'API standard de journalisation du langage Java dans le SDK Android est android.util.Log .
L'API de langage C correspondante dans Android NDK est __android_log_print
déclaré dans <android/log.h>
.
Dans la partie native du framework Android, nous préférons les macros nommées ALOGE
, ALOGW
, ALOGI
, ALOGV
, etc. Elles sont déclarées dans <utils/Log.h>
, et pour les besoins de cet article nous les appellerons collectivement ALOGx
.
Toutes ces API sont faciles à utiliser et bien comprises, elles sont donc omniprésentes sur toute la plate-forme Android. En particulier, le processus mediaserver
, qui inclut le serveur audio AudioFlinger, utilise largement ALOGx
.
Néanmoins, il existe certaines limitations à ALOGx
et ses amis :
- Ils sont sensibles au "spam du journal": le tampon du journal est une ressource partagée, il peut donc facilement déborder en raison d'entrées de journal non liées, ce qui entraîne des informations manquées. La variante
ALOGV
est désactivée au moment de la compilation par défaut. Mais bien sûr, même cela peut entraîner un spam de journal s'il est activé. - Les appels système sous-jacents du noyau pourraient se bloquer, entraînant éventuellement une inversion de priorité et, par conséquent, des perturbations et des inexactitudes de mesure. Ceci est particulièrement préoccupant pour les threads critiques tels que
FastMixer
etFastCapture
. - Si un journal particulier est désactivé pour réduire le spam du journal, toutes les informations qui auraient été capturées par ce journal sont perdues. Il n'est pas possible d'activer un journal spécifique rétroactivement, après qu'il devient clair que le journal aurait été intéressant.
NBLOG, media.log et MediaLogService
Les API NBLOG
et le processus media.log
associé et le service MediaLogService
forment ensemble un nouveau système de journalisation pour les médias et sont spécifiquement conçus pour résoudre les problèmes ci-dessus. Nous utiliserons vaguement le terme "media.log" pour désigner les trois, mais à proprement parler, NBLOG
est l'API de journalisation C++, media.log
est un nom de processus Linux et MediaLogService
est un service de classeur Android permettant d'examiner les journaux.
Une "chronologie" media.log
est une série d'entrées de journal dont l'ordre relatif est préservé. Par convention, chaque thread doit utiliser sa propre chronologie.
Avantages
Les avantages du système media.log
sont qu'il :
- Ne spamme pas le journal principal à moins que et jusqu'à ce que cela soit nécessaire.
- Peut être examiné même lorsque
mediaserver
tombe en panne ou se bloque. - Est non bloquant par chronologie.
- Offre moins de perturbations aux performances. (Bien sûr, aucune forme de journalisation n'est complètement non intrusive.)
Architecture
Le schéma ci-dessous montre la relation entre le processus mediaserver
et le processus init
, avant l'introduction de media.log
:

Figure 1. Architecture avant media.log
Points notables :
-
init
forks et execsmediaserver
. -
init
détecte la mort demediaserver
et re-fork si nécessaire. - La journalisation
ALOGx
n'est pas affichée.
Le schéma ci-dessous montre la nouvelle relation des composants, après l'ajout de media.log
à l'architecture :

Figure 2. Architecture après media.log
Modifications importantes :
- Les clients utilisent l'API
NBLOG
pour créer des entrées de journal et les ajouter à un tampon circulaire dans la mémoire partagée. -
MediaLogService
peut vider le contenu du tampon circulaire à tout moment. - Le tampon circulaire est conçu de telle manière que toute corruption de la mémoire partagée ne plantera pas
MediaLogService
, et il pourra toujours vider autant de tampon qui n'est pas affecté par la corruption. - Le tampon circulaire est non bloquant et sans verrou pour l'écriture de nouvelles entrées et la lecture d'entrées existantes.
- Aucun appel système du noyau n'est requis pour écrire ou lire dans le tampon circulaire (autre que les horodatages facultatifs).
Où utiliser
Depuis Android 4.4, seuls quelques points de journalisation dans AudioFlinger utilisent le système media.log
. Bien que les nouvelles API ne soient pas aussi faciles à utiliser ALOGx
, elles ne sont pas non plus extrêmement difficiles. Nous vous encourageons à apprendre le nouveau système de journalisation pour les occasions où il est indispensable. En particulier, il est recommandé pour les threads AudioFlinger qui doivent s'exécuter fréquemment, périodiquement et sans blocage tels que les FastMixer
et FastCapture
.
Comment utiliser
Ajouter des journaux
Tout d'abord, vous devez ajouter des journaux à votre code.
Dans FastMixer
et FastCapture
, utilisez un code tel que celui-ci :
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Comme cette chronologie NBLog
est utilisée uniquement par les FastMixer
et FastCapture
, il n'y a pas besoin d'exclusion mutuelle.
Dans d'autres threads AudioFlinger, utilisez mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Pour les threads autres que FastMixer
et FastCapture
, la chronologie NBLog
du thread peut être utilisée à la fois par le thread lui-même et par les opérations de classeur. NBLog::Writer
ne fournit aucune exclusion mutuelle implicite par chronologie, assurez-vous donc que tous les journaux se produisent dans un contexte où le mutex mLock
du thread est conservé.
Après avoir ajouté les journaux, reconstruisez AudioFlinger.
Attention : une chronologie NBLog::Writer
distincte est requise par thread, pour garantir la sécurité des threads, car les chronologies omettent les mutex par conception. Si vous souhaitez que plusieurs threads utilisent le même scénario, vous pouvez protéger avec un mutex existant (comme décrit ci-dessus pour mLock
). Ou vous pouvez utiliser le wrapper NBLog::LockedWriter
au lieu de NBLog::Writer
. Cependant, cela annule un avantage principal de cette API : son comportement non bloquant.
L'API NBLog
complète se trouve dans frameworks/av/include/media/nbaio/NBLog.h
.
Activer media.log
media.log
est désactivé par défaut. Il n'est actif que lorsque la propriété ro.test_harness
vaut 1
. Vous pouvez l'activer en :
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
La connexion est perdue lors du redémarrage, donc :
adb shellLa commande
ps media
affichera maintenant deux processus :- media.log
- Serveur multimédia
Notez l'ID de processus de mediaserver
pour plus tard.
Affichage des chronologies
Vous pouvez demander manuellement un vidage de journal à tout moment. Cette commande affiche les journaux de toutes les chronologies actives et récentes, puis les efface :
dumpsys media.log
Notez que de par leur conception, les chronologies sont indépendantes et qu'il n'y a aucune possibilité de fusionner les chronologies.
Récupération des journaux après la mort du serveur multimédia
Maintenant, essayez de tuer le processus mediaserver
: kill -9 #
, où # est l'ID de processus que vous avez noté précédemment. Vous devriez voir un vidage de media.log
dans le logcat
principal, montrant tous les journaux menant au crash.
dumpsys media.log