Questo articolo descrive alcuni suggerimenti e trucchi per il debug dell'audio di Android.
Lavello a T
"Tee sink" è una funzionalità di debug di AudioFlinger, disponibile solo nelle build personalizzate, per conservare un breve frammento di audio recente per analisi successive. In questo modo è possibile confrontare ciò che è stato effettivamente riprodotto o registrato con ciò che era previsto.
Per motivi di privacy, l'output tee è disabilitato per impostazione predefinita sia in fase di compilazione sia in fase di esecuzione. Per utilizzare l'output tee, devi attivarlo ricompilando e impostando una proprietà. Assicurati di disattivare questa funzionalità al termine del debug. L'output tee non deve essere lasciato attivo 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, sostituisci /data/misc/audioserver
con /data/misc/media
. Inoltre, devi utilizzare una build userdebug o
eng. Se utilizzi una build userdebug, disattiva Verity con:
adb root && adb disable-verity && adb reboot
Configurazione in fase di compilazione
cd frameworks/av/services/audioflinger
- Modifica
Configuration.h
. - Rimuovi il commento da
#define TEE_SINK
. - Esegui nuovamente la build di
libaudioflinger.so
. adb root
adb remount
- Esegui il push o la sincronizzazione del nuovo
libaudioflinger.so
con il/system/lib
del dispositivo.
Configurazione di runtime
adb shell getprop | grep ro.debuggable
Verifica che l'output sia:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
Verifica che l'output sia:
drwx------ media media ... media
Se la directory non esiste, creane una 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 diversi bit, uno per caratteristica.
Consulta il codice in AudioFlinger::AudioFlinger()
in AudioFlinger.cpp
per una spiegazione di ciascun bit, ma brevemente:
- 1 = input
- 2 = uscita FastMixer
- 4 = AudioRecord e AudioTrack per traccia
Non è ancora disponibile un bit per il buffer profondo o il mixer normale, ma puoi ottenere risultati simili utilizzando "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 .wav PCM. - Quindi
adb pull
tutti i file/data/misc/audioserver/*.wav
di tuo interesse. Tieni presente che i nomi dei file dump specifici del canale non vengono visualizzati nell'output didumpsys
, ma vengono comunque salvati in/data/misc/audioserver
al termine del canale. - Esamina i file dump per verificare la presenza di problemi di privacy prima di condividerli con altri.
Suggerimenti
Prova queste idee per ottenere risultati più utili:
- Disattiva i suoni dei tocchi e i clic dei tasti per ridurre le interruzioni nell'output del test.
- Massimizza tutti i volumi.
- Disattiva le app che riproducono audio o registrano dal microfono se non sono di interesse per il test.
- I dump specifici del canale vengono salvati solo quando il canale è chiuso. potrebbe essere necessario chiudere forzatamente un'app per eseguire il dump dei relativi dati specifici del canale
- Esegui la
dumpsys
subito dopo il test. È disponibile uno spazio di registrazione limitato. - Per assicurarti di non perdere i file dump, caricali periodicamente sul tuo host. Viene conservato solo un numero limitato di file dump. I dump precedenti vengono rimossi una volta raggiunto questo limite.
Ripristina
Come indicato sopra, la funzionalità di scarico a T non deve essere lasciata attiva. Ripristina la build e il dispositivo nel seguente modo:
- Ripristina le modifiche al codice sorgente in
Configuration.h
. - Esegui nuovamente la build di
libaudioflinger.so
. - Esegui il push o la sincronizzazione del
libaudioflinger.so
ripristinato con il/system/lib
del dispositivo. adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
Macro ALOGx
L'API di logging del linguaggio Java standard nell'SDK Android è android.util.Log.
L'API in linguaggio C corrispondente in Android NDK è
__android_log_print
dichiarata in <android/log.h>
.
All'interno della parte nativa del framework Android, preferiamo le macro denominate ALOGE
, ALOGW
,
ALOGI
, ALOGV
e così via. Sono dichiarate in
<utils/Log.h>
e, ai fini di questo articolo, le chiameremo collettivamente ALOGx
.
Tutte queste API sono facili da usare e ben conosciute, quindi sono presenti su tutta la piattaforma Android. In particolare, il processo mediaserver
, che include il server audio AudioFlinger, utilizza molto ALOGx
.
Tuttavia, ALOGx
e i suoi amici presentano alcune limitazioni:
-
Sono suscettibili di "spam di log": il buffer dei log è una risorsa condivisa, pertanto può facilmente verificarsi un overflow a causa di voci di log non correlate, con conseguente perdita di informazioni. La variante
ALOGV
è disattivata al compilatore per impostazione predefinita. Tuttavia, anche se è attivato, può generare spam nei log. -
Le chiamate di sistema del kernel sottostanti potrebbero bloccarsi, con possibile inversione della priorità e conseguente disturbo e imprecisione della misurazione. Questo è di particolare interesse per i thread che richiedono tempi rapidi, come
FastMixer
eFastCapture
. - Se un determinato log viene disattivato per ridurre lo spam dei log, tutte le informazioni che sarebbero state acquisite dal log andranno perse. Non è possibile attivare un log specifico in modo retroattivo, dopo che è diventato chiaro che il log sarebbe stato interessante.
NBLOG, media.log e MediaLogService
Le API NBLOG
e il processo e il servizio media.log
associati formano insieme un sistema di registrazione più recente per i contenuti multimediali e sono progettate appositamente per risolvere i problemi sopra indicati.MediaLogService
Useremo in modo approssimativo il termine "media.log" per riferirci a tutti e tre, ma, in senso stretto, NBLOG
è l'API di registrazione C++, media.log
è il nome di un processo Linux e MediaLogService
è un servizio di binder Android per esaminare i log.
Una "sequenza temporale" media.log
è una serie di voci di log il cui ordine relativo viene mantenuto.
Per convenzione, ogni thread deve utilizzare la propria sequenza temporale.
Vantaggi
I vantaggi del sistema media.log
sono:
- Non invia spam al log principale, a meno che non sia necessario.
- Può essere esaminato anche quando
mediaserver
si arresta in modo anomalo o si blocca. - Non blocca la sequenza temporale.
- Offre meno disturbi alle prestazioni. Ovviamente, nessuna forma di logging è completamente non invasiva.
Architettura
Il seguente diagramma mostra la relazione tra la procedura mediaserver
e la procedura init
, prima dell'introduzione di media.log
:

Figura 1. Architettura precedente a media.log
Punti salienti:
init
fork ed execmediaserver
.init
rileva il ritiro dimediaserver
e esegue nuovamente il fork in base alle necessità.- La registrazione
ALOGx
non viene mostrata.
Il seguente diagramma mostra la nuova relazione tra i componenti,
dopo l'aggiunta di media.log
all'architettura:

Figura 2. Architettura dopo media.log
Modifiche importanti:
-
I client utilizzano l'API
NBLOG
per creare voci di log e aggiungerle a un buffer circolare nella memoria condivisa. -
MediaLogService
può scaricare i contenuti dell'area buffer circolare in qualsiasi momento. -
Il buffer circolare è progettato in modo che qualsiasi danneggiamento della memoria condivisa non causi un arresto anomalo
MediaLogService
e sia comunque in grado di scaricare la maggior parte del buffer non interessata dal danneggiamento. - Il buffer circolare è non bloccante e senza blocco sia per la scrittura delle nuove voci sia per la lettura di quelle esistenti.
- Non sono necessarie chiamate di sistema del kernel per scrivere o leggere dal buffer circolare (diversi dai timestamp facoltativi).
Paesi in cui è disponibile Android Auto
A partire da Android 4.4, in AudioFlinger esistono solo alcuni punti di log che utilizzano il sistema media.log
. Sebbene le nuove API non siano
tanto facili da usare quanto ALOGx
, non sono nemmeno estremamente difficili.
Ti invitiamo a conoscere il nuovo sistema di registrazione per le occasioni in cui è indispensabile.
In particolare, è consigliato per i thread AudioFlinger che devono essere eseguiti frequentemente, periodicamente e senza blocco, come i thread FastMixer
e FastCapture
.
Modalità di utilizzo
Aggiungi log
Innanzitutto, devi aggiungere i log al codice.
Nei thread FastMixer
e FastCapture
, utilizza un 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 l'esclusione reciproca.
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 di binder. NBLog::Writer
non fornisce alcuna esclusione mutua implicita per ogni sequenza temporale, quindi assicurati che tutti i log si verifichino in un contesto in cui viene mantenuto il mutex mLock
del thread.
Dopo aver aggiunto i log, ricostruisci AudioFlinger.
Attenzione:
è necessaria una sequenza temporale NBLog::Writer
separata per thread per garantire la sicurezza del thread, poiché le sequenze temporali omettono i mutex per progettazione. Se vuoi che più thread utilizzino la stessa sequenza temporale, puoi proteggerla con un mutex esistente (come descritto sopra per mLock
). In alternativa, puoi utilizzare il wrapper NBLog::LockedWriter
anziché NBLog::Writer
.
Tuttavia, questo annulla uno dei principali vantaggi di questa API: il suo comportamento non bloccante.
L'API NBLog
completa è disponibile all'indirizzo frameworks/av/include/media/nbaio/NBLog.h
.
Attivare media.log
media.log
è disattivato per impostazione predefinita. È attiva solo quando la proprietà
ro.test_harness
è 1
. Per attivarla:
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
La connessione si interrompe durante il riavvio, quindi:
adb shell
ps media
mostrerà due processi:
- media.log
- mediaserver
Prendi nota dell'ID processo mediaserver
per riferimento futuro.
Visualizzare le sequenze temporali
Puoi richiedere manualmente un dump dei log in qualsiasi momento. Questo comando mostra i log di tutte le sequenze temporali attive e recenti, quindi li cancella:
dumpsys media.log
Tieni presente che, per impostazione predefinita, le sequenze temporali sono indipendenti e non è possibile unire le sequenze temporali.
Recuperare i log dopo l'arresto anomalo del mediaserver
Ora prova a terminare il processo mediaserver
: kill -9 #
, dove # è
l'ID processo che hai annotato in precedenza. Dovresti vedere un dump da media.log
nel file logcat
principale, che mostra tutti i log che hanno portato all'arresto anomalo.
dumpsys media.log