Questo articolo descrive alcuni suggerimenti e trucchi per il debug dell'audio Android.
Lavandino a T
Il "tee sink" è una funzionalità di debug di AudioFlinger, disponibile solo nelle build personalizzate, per conservare un breve frammento di audio recente per un'analisi successiva. Ciò consente il confronto tra ciò che è stato effettivamente riprodotto o registrato e ciò che ci si aspettava.
Per motivi di privacy il tee sink è disabilitato per impostazione predefinita, sia in fase di compilazione che in fase di esecuzione. Per utilizzare il tee sink, dovrai abilitarlo ricompilando e anche impostando una proprietà. Assicurati di disabilitare questa funzione una volta terminato il debug; il lavandino a T non deve essere lasciato abilitato nelle build di produzione.
Le istruzioni in questa sezione si riferiscono ad Android 7.x e versioni successive. Per Android 5.x e 6.x, sostituire /data/misc/audioserver
con /data/misc/media
. Inoltre, è necessario utilizzare un userdebug o un build eng. Se usi una build userdebug, disabilita verity con:
adb root && adb disable-verity && adb reboot
Configurazione in fase di compilazione
-
cd frameworks/av/services/audioflinger
- Modifica
Configuration.h
. - Decommenta
#define TEE_SINK
. - Ricostruire
libaudioflinger.so
. -
adb root
-
adb remount
- Invia o sincronizza il nuovo
libaudioflinger.so
nel/system/lib
del dispositivo.
Configurazione in fase di esecuzione
-
adb shell getprop | grep ro.debuggable
Confermare che l'output sia:[ro.debuggable]: [1]
-
adb shell
-
ls -ld /data/misc/audioserver
Confermare che l'output sia:
drwx------ media media ... media
Se la directory non esiste, creala come segue:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
-
echo af.tee=# > /data/local.prop
Dove il valoreaf.tee
è un numero descritto di seguito. -
chmod 644 /data/local.prop
-
reboot
Valori per la proprietà af.tee
Il valore di af.tee
è un numero compreso tra 0 e 7, che esprime la somma di più bit, uno per caratteristica. Vedi il codice in AudioFlinger::AudioFlinger()
in AudioFlinger.cpp
per una spiegazione di ogni bit, ma brevemente:
- 1 = ingresso
- 2 = uscita FastMixer
- 4 = AudioRecord e AudioTrack per traccia
Non esiste ancora un bit per il buffer profondo o il mixer normale, ma puoi ottenere risultati simili usando "4".
Testare e acquisire dati
- Esegui il test audio.
-
adb shell dumpsys media.audio_flinger
- Cerca una riga nell'output di
dumpsys
come questa:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Questo è un file PCM .wav. - Quindi
adb pull
tutti i file/data/misc/audioserver/*.wav
di interesse; tieni presente che i nomi dei file dump specifici della traccia non appaiono nell'outputdumpsys
, ma vengono comunque salvati in/data/misc/audioserver
alla chiusura della traccia. - Esamina i file di dump per problemi di privacy prima di condividerli con altri.
Suggerimenti
Prova queste idee per risultati più utili:
- Disattiva i suoni tattili e i clic dei tasti per ridurre le interruzioni nell'output del test.
- Massimizza tutti i volumi.
- Disattiva le app che emettono suoni o registrano dal microfono, se non interessano al tuo test.
- I dump specifici della traccia vengono salvati solo quando la traccia è chiusa; potrebbe essere necessario forzare la chiusura di un'app per scaricare i dati specifici della traccia
- Esegui i
dumpsys
immediatamente dopo il test; lo spazio di registrazione disponibile è limitato. - Per assicurarti di non perdere i file dump, caricali periodicamente sul tuo host. Viene conservato solo un numero limitato di file di dump; i dump più vecchi vengono rimossi una volta raggiunto tale limite.
Ristabilire
Come notato sopra, la funzionalità del tee sink non deve essere lasciata abilitata. Ripristina la build e il dispositivo come segue:
- Ripristina le modifiche del codice sorgente a
Configuration.h
. - Ricostruire
libaudioflinger.so
. - Invia o sincronizza il
libaudioflinger.so
ripristinato sul/system/lib
del dispositivo. -
adb shell
-
rm /data/local.prop
-
rm /data/misc/audioserver/*.wav
-
reboot
media.log
Macro ALOGx
L'API di registrazione del linguaggio Java standard nell'SDK di Android è android.util.Log .
L'API del linguaggio C corrispondente in Android NDK è __android_log_print
dichiarata in <android/log.h>
.
All'interno della porzione nativa del framework Android, preferiamo le macro denominate ALOGE
, ALOGW
, ALOGI
, ALOGV
, ecc. Sono dichiarate in <utils/Log.h>
e per gli scopi di questo articolo ci riferiremo collettivamente a loro come ALOGx
.
Tutte queste API sono facili da usare e ben comprensibili, quindi sono pervasive in tutta la piattaforma Android. In particolare il processo mediaserver
, che include il server audio AudioFlinger, utilizza ampiamente ALOGx
.
Tuttavia, ci sono alcune limitazioni per ALOGx
e compagni:
- Sono soggetti allo "spam dei log": il buffer dei log è una risorsa condivisa, quindi può facilmente traboccare a causa di voci di log non correlate, con conseguente perdita di informazioni. La variante
ALOGV
è disabilitata in fase di compilazione per impostazione predefinita. Ma ovviamente anche questo può provocare spam nei log se è abilitato. - Le chiamate di sistema del kernel sottostante potrebbero bloccarsi, con il rischio di inversione di priorità e di conseguenza disturbi e imprecisioni di misurazione. Ciò è di particolare interesse per i thread critici in termini di tempo come
FastMixer
eFastCapture
. - Se un particolare registro viene disabilitato per ridurre lo spam nel registro, tutte le informazioni che sarebbero state acquisite da quel registro andranno perse. Non è possibile abilitare retroattivamente un registro specifico, dopo che risulta chiaro che il registro sarebbe stato interessante.
NBLOG, media.log e MediaLogService
Le API NBLOG
, il processo media.log
associato e il servizio MediaLogService
insieme formano un nuovo sistema di registrazione per i media e sono progettati specificamente per risolvere i problemi di cui sopra. Utilizzeremo liberamente il termine "media.log" per fare riferimento a tutti e tre, ma in senso stretto NBLOG
è l'API di registrazione C++, media.log
è un nome di processo Linux e MediaLogService
è un servizio di associazione Android per l'esame dei log.
Una "timeline" media.log
è una serie di voci di log il cui ordinamento relativo viene preservato. Per convenzione, ogni thread dovrebbe utilizzare la propria sequenza temporale.
Benefici
I vantaggi del sistema media.log
sono che:
- Non invia spam al registro principale a meno che e finché non sia necessario.
- Può essere esaminato anche quando
mediaserver
si blocca o si blocca. - Non è bloccante per sequenza temporale.
- Offre meno disturbi alle prestazioni. (Ovviamente nessuna forma di registrazione è completamente non intrusiva.)
Architettura
Il diagramma seguente mostra la relazione tra il processo mediaserver
e il processo init
, prima che venga introdotto media.log
:
Punti notevoli:
-
init
fork ed execsmediaserver
. -
init
rileva la morte dimediaserver
e, se necessario, esegue nuovamente il fork. - La registrazione
ALOGx
non viene visualizzata.
Il diagramma seguente mostra la nuova relazione dei componenti, dopo che media.log
è stato aggiunto all'architettura:
Cambiamenti importanti:
- I client utilizzano l'API
NBLOG
per creare voci di registro e aggiungerle a un buffer circolare nella memoria condivisa. -
MediaLogService
può eseguire il dump del contenuto del buffer circolare in qualsiasi momento. - Il buffer circolare è progettato in modo tale che qualsiasi corruzione della memoria condivisa non provochi l'arresto anomalo
MediaLogService
e sarà comunque in grado di scaricare la maggior parte del buffer che non è interessata dalla corruzione. - Il buffer circolare non è bloccante ed è privo di blocchi sia per la scrittura di nuove voci che per la lettura delle voci esistenti.
- Non sono necessarie chiamate di sistema del kernel per scrivere o leggere dal buffer circolare (a parte i timestamp opzionali).
Dove usarlo
A partire da Android 4.4, ci sono solo pochi punti di registro in AudioFlinger che utilizzano il sistema media.log
. Sebbene le nuove API non siano facili da usare come ALOGx
, non sono nemmeno estremamente difficili. Ti invitiamo a imparare il nuovo sistema di registrazione per quelle occasioni in cui è indispensabile. In particolare, è consigliato per i thread AudioFlinger che devono essere eseguiti frequentemente, periodicamente e senza blocchi come i thread FastMixer
e FastCapture
.
Come usare
Aggiungi log
Innanzitutto, devi aggiungere i log al tuo codice.
Nei thread FastMixer
e FastCapture
, utilizza codice come questo:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Poiché questa sequenza temporale NBLog
viene utilizzata solo dai thread FastMixer
e FastCapture
, non è necessaria la mutua esclusione.
In altri thread AudioFlinger, utilizza mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Per thread diversi da FastMixer
e FastCapture
, la sequenza temporale NBLog
del thread può essere utilizzata sia dal thread stesso sia dalle operazioni del raccoglitore. NBLog::Writer
non fornisce alcuna esclusione reciproca implicita per sequenza temporale, quindi assicurati che tutti i log si verifichino all'interno di un contesto in cui viene mantenuto il mutex mLock
del thread.
Dopo aver aggiunto i registri, ricostruisci AudioFlinger.
Attenzione: è necessaria una sequenza temporale NBLog::Writer
separata per thread, per garantire la sicurezza del thread, poiché le sequenze temporali omettono mutex per impostazione predefinita. Se desideri che più di un thread utilizzi la stessa sequenza temporale, puoi proteggerla con un mutex esistente (come descritto sopra per mLock
). Oppure puoi utilizzare il wrapper NBLog::LockedWriter
invece di NBLog::Writer
. Tuttavia, ciò annulla uno dei vantaggi principali di questa API: il suo comportamento non bloccante.
L'API NBLog
completa si trova in frameworks/av/include/media/nbaio/NBLog.h
.
Abilita media.log
media.log
è disabilitato per impostazione predefinita. È attivo solo quando la proprietà ro.test_harness
è 1
. Puoi abilitarlo:
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
La connessione viene persa durante il riavvio, quindi:
adb shellIl comando
ps media
ora mostrerà due processi:- media.log
- mediaserver
Annotare l'ID del processo del mediaserver
per dopo.
Visualizza le sequenze temporali
Puoi richiedere manualmente un dump del registro in qualsiasi momento. Questo comando mostra i registri di tutte le sequenze temporali attive e recenti, quindi li cancella:
dumpsys media.log
Tieni presente che, in base alla progettazione, le sequenze temporali sono indipendenti e non è possibile unirle.
Recupera i log dopo la morte del mediaserver
Ora prova a uccidere il processo mediaserver
: kill -9 #
, dove # è l'ID del processo che hai annotato in precedenza. Dovresti vedere un dump da media.log
nel logcat
principale, che mostra tutti i log che hanno portato all'arresto anomalo.
dumpsys media.log