Debug audio

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

  1. cd frameworks/av/services/audioflinger
  2. Modifica Configuration.h.
  3. Rimuovi il commento da #define TEE_SINK.
  4. Esegui nuovamente la build di libaudioflinger.so.
  5. adb root
  6. adb remount
  7. Esegui il push o la sincronizzazione del nuovo libaudioflinger.so con il /system/lib del dispositivo.

Configurazione di runtime

  1. adb shell getprop | grep ro.debuggable
    Verifica che l'output sia: [ro.debuggable]: [1]
  2. adb shell
  3. 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
    
  4. echo af.tee=# > /data/local.prop
    dove il valore af.tee è un numero descritto di seguito.
  5. chmod 644 /data/local.prop
  6. 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

  1. Esegui il test audio.
  2. adb shell dumpsys media.audio_flinger
  3. Cerca una riga nell'output di dumpsys come questa:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Questo è un file .wav PCM.
  4. 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 di dumpsys, ma vengono comunque salvati in /data/misc/audioserver al termine del canale.
  5. 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:

  1. Ripristina le modifiche al codice sorgente in Configuration.h.
  2. Esegui nuovamente la build di libaudioflinger.so.
  3. Esegui il push o la sincronizzazione del libaudioflinger.so ripristinato con il /system/lib del dispositivo.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. 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 e FastCapture.
  • 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:

Architettura prima di media.log

Figura 1. Architettura precedente a media.log

Punti salienti:

  • init fork ed exec mediaserver.
  • init rileva il ritiro di mediaserver 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:

Architettura dopo media.log

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
Ora il comando 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