In diesem Artikel finden Sie einige Tipps und Tricks zur Fehlerbehebung bei Android-Audio.
T-Senke
„Tee sink“ ist eine AudioFlinger-Debugging-Funktion, die nur in benutzerdefinierten Builds verfügbar ist. Damit wird ein kurzes Fragment der letzten Audioaufnahme für eine spätere Analyse beibehalten. So können Sie vergleichen, was tatsächlich abgespielt oder aufgezeichnet wurde, und was erwartet wurde.
Aus Gründen des Datenschutzes ist der Tee-Sink sowohl zur Kompilierungs- als auch zur Laufzeit standardmäßig deaktiviert. Wenn Sie die Tee-Senke verwenden möchten, müssen Sie sie aktivieren, indem Sie sie neu kompilieren und ein Attribut festlegen. Deaktivieren Sie diese Funktion, nachdem Sie mit der Fehlerbehebung fertig sind. Der Tee-Sink sollte in Produktionsbuilds nicht aktiviert bleiben.
Die Anleitung in diesem Abschnitt gilt für Android 7.x und höher. Ersetzen Sie unter Android 5.x und 6.x /data/misc/audioserver
durch /data/misc/media
. Außerdem müssen Sie eine userdebug- oder eng-Build verwenden. Wenn Sie einen Userdebug-Build verwenden, deaktivieren Sie die Verity-Funktion mit:
adb root && adb disable-verity && adb reboot
Einrichtung zur Kompilierungszeit
cd frameworks/av/services/audioflinger
Configuration.h
bearbeiten- Entfernen Sie den Kommentar zu
#define TEE_SINK
. - Erstellen Sie
libaudioflinger.so
neu. adb root
adb remount
- Übertragen oder synchronisieren Sie die neue
libaudioflinger.so
mit der/system/lib
des Geräts.
Laufzeiteinrichtung
adb shell getprop | grep ro.debuggable
Prüfen Sie, ob die Ausgabe so aussieht:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
Prüfen Sie, ob die Ausgabe:
drwx------ media media ... media
Wenn das Verzeichnis nicht vorhanden ist, erstellen Sie es so:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
Der Wertaf.tee
ist eine Zahl, die unten beschrieben wird.chmod 644 /data/local.prop
reboot
Werte für das Attribut „af.tee“
Der Wert von af.tee
ist eine Zahl zwischen 0 und 7, die die Summe mehrerer Bits ausdrückt, jeweils eines pro Merkmal.
Eine Erklärung der einzelnen Bits findest du im Code bei AudioFlinger::AudioFlinger()
in AudioFlinger.cpp
. Hier eine kurze Zusammenfassung:
- 1 = Eingabe
- 2 = FastMixer-Ausgabe
- 4 = AudioRecord und AudioTrack pro Spur
Es gibt noch kein Bit für Deep Buffer oder Normal Mixer, aber du kannst ähnliche Ergebnisse mit „4“ erzielen.
Daten testen und erfassen
- Führen Sie den Audiotest aus.
adb shell dumpsys media.audio_flinger
- Suchen Sie in der
dumpsys
-Ausgabe nach einer Zeile wie dieser:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Dies ist eine PCM-WAV-Datei. - Anschließend
adb pull
alle gewünschten/data/misc/audioserver/*.wav
-Dateien. Beachte, dass trackspezifische Dumpdateinamen nicht in derdumpsys
-Ausgabe erscheinen, aber beim Schließen des Tracks trotzdem in/data/misc/audioserver
gespeichert werden. - Prüfen Sie die Dumpdateien auf Datenschutzrisiken, bevor Sie sie für andere freigeben.
Vorschläge
Mit diesen Ideen erhalten Sie nützlichere Ergebnisse:
- Deaktivieren Sie Berührungsgeräusche und Tastenklicks, um Unterbrechungen in der Testausgabe zu reduzieren.
- Maximieren Sie alle Lautstärken.
- Deaktivieren Sie Apps, die Töne ausgeben oder über das Mikrofon aufzeichnen, wenn sie für Ihren Test nicht relevant sind.
- Daten zu einzelnen Tracks werden nur gespeichert, wenn der Track geschlossen ist. Möglicherweise müssen Sie eine App zum Dumpen der trackspezifischen Daten erzwingen.
- Führen Sie die
dumpsys
unmittelbar nach dem Test durch. Es ist nur begrenzter Aufnahmespeicher verfügbar. - Damit Sie Ihre Dumpdateien nicht verlieren, sollten Sie sie regelmäßig auf Ihren Host hochladen. Es wird nur eine begrenzte Anzahl von Dumpdateien aufbewahrt. Ältere Dumps werden entfernt, sobald dieses Limit erreicht ist.
Wiederherstellen
Wie bereits erwähnt, sollte die Funktion „Tee-Senke“ nicht aktiviert bleiben. So stellen Sie die Build-Version und das Gerät wieder her:
- Nehmen Sie die Änderungen am Quellcode auf
Configuration.h
zurück. - Erstellen Sie
libaudioflinger.so
neu. - Pushen oder synchronisieren Sie die wiederhergestellte
libaudioflinger.so
mit der/system/lib
des Geräts. adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
ALOGx-Makros
Die standardmäßige Java-Logging API im Android SDK ist android.util.Log.
Die entsprechende C-Sprach-API in Android NDK ist __android_log_print
und wird in <android/log.h>
deklariert.
Im nativen Teil des Android-Frameworks bevorzugen wir Makros mit den Namen ALOGE
, ALOGW
, ALOGI
, ALOGV
usw. Sie werden in <utils/Log.h>
deklariert und in diesem Artikel werden sie gemeinsam als ALOGx
bezeichnet.
Alle diese APIs sind einfach zu verwenden und gut bekannt, daher werden sie auf der gesamten Android-Plattform eingesetzt. Insbesondere der Prozess mediaserver
, der den AudioFlinger-Soundserver enthält, nutzt ALOGx
intensiv.
Es gibt jedoch einige Einschränkungen für ALOGx
und Freunde:
-
Sie sind anfällig für „Log-Spam“: Der Log-Puffer ist eine freigegebene Ressource und kann daher leicht aufgrund nicht verwandter Logeinträge überlaufen, was zu fehlenden Informationen führt. Die
ALOGV
-Variante ist standardmäßig zur Kompilierungszeit deaktiviert. Aber natürlich kann es auch zu Log-Spam kommen, wenn diese Option aktiviert ist. -
Die zugrunde liegenden Kernelsystemaufrufe können blockieren, was zu einer Prioritätsumkehrung und infolgedessen zu Messstörungen und Ungenauigkeiten führen kann. Das ist besonders wichtig für zeitkritische Threads wie
FastMixer
undFastCapture
. - Wenn ein bestimmtes Protokoll deaktiviert wird, um Protokollspam zu reduzieren, gehen alle Informationen verloren, die in diesem Protokoll erfasst worden wären. Es ist nicht möglich, ein bestimmtes Protokoll rückwirkend zu aktivieren, nachdem klar geworden ist, dass es interessant gewesen wäre.
NBLOG, media.log und MediaLogService
Die NBLOG
APIs und der zugehörige media.log
-Prozess und MediaLogService
-Dienst bilden zusammen ein neueres Logging-System für Medien und wurden speziell entwickelt, um die oben genannten Probleme zu beheben. Wir verwenden den Begriff „media.log“ im weiteren Sinne für alle drei. Streng genommen ist NBLOG
die C++-Logging-API, media.log
ein Linux-Prozessname und MediaLogService
ein Android-Binderdienst zum Prüfen der Protokolle.
Eine media.log
-Zeitachse besteht aus einer Reihe von Logeinträgen, deren relative Reihenfolge beibehalten wird.
Normalerweise sollte jeder Thread eine eigene Zeitachse haben.
Vorteile
Das media.log
-System bietet folgende Vorteile:
- Das Hauptprotokoll wird nur dann mit Informationen geflutet, wenn es erforderlich ist.
- Kann auch dann geprüft werden, wenn
mediaserver
abstürzt oder hängt. - Ist nicht blockierend pro Zeitachse.
- Sie beeinträchtigen die Leistung weniger. Natürlich ist keine Logging-Methode völlig unaufdringlich.
Architektur
Das folgende Diagramm zeigt die Beziehung zwischen dem mediaserver
-Prozess und dem init
-Prozess, bevor media.log
eingeführt wird:

Abbildung 1: Architektur vor media.log
Wichtige Punkte:
init
forks und execsmediaserver
.init
erkennt den Tod vonmediaserver
und führt bei Bedarf eine neue Fork durch.ALOGx
Protokollierung wird nicht angezeigt.
Das folgende Diagramm zeigt die neue Beziehung der Komponenten, nachdem media.log
der Architektur hinzugefügt wurde:

Abbildung 2: Architektur nach media.log
Wichtige Änderungen:
-
Clients verwenden die
NBLOG
API, um Protokolleinträge zu erstellen und an einen zyklischen Puffer im gemeinsamen Speicher anzuhängen. -
MediaLogService
kann den Inhalt des zyklischen Puffers jederzeit ausgeben. -
Der zyklische Puffer ist so konzipiert, dass eine Beschädigung des gemeinsamen Speichers nicht zu einem Absturz von
MediaLogService
führt. Außerdem kann so viel wie möglich des Puffers, der nicht von der Beschädigung betroffen ist, gedumpt werden. - Der zyklische Puffer ist sowohl für das Schreiben neuer Einträge als auch für das Lesen vorhandener Einträge nicht blockierend und frei von Sperren.
- Zum Schreiben in den zyklischen Puffer oder zum Lesen daraus sind keine Kernel-Systemaufrufe erforderlich (außer optionale Zeitstempel).
Verfügbarkeit
Ab Android 4.4 gibt es in AudioFlinger nur noch wenige Protokollpunkte, die das media.log
-System verwenden. Die neuen APIs sind zwar nicht so einfach zu verwenden wie ALOGx
, aber auch nicht extrem schwierig.
Wir empfehlen Ihnen, sich mit dem neuen Logging-System vertraut zu machen, für den Fall, dass es unverzichtbar ist.
Dies wird insbesondere für AudioFlinger-Threads empfohlen, die häufig, regelmäßig und ohne Blockierung ausgeführt werden müssen, z. B. die FastMixer
- und FastCapture
-Threads.
Verwendung
Protokolle hinzufügen
Dazu müssen Sie Ihrem Code Protokolle hinzufügen.
Verwenden Sie in FastMixer
- und FastCapture
-Threads Code wie diesen:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Da diese NBLog
-Zeitachse nur von den Threads FastMixer
und FastCapture
verwendet wird, ist keine gegenseitige Ausschließung erforderlich.
In anderen AudioFlinger-Threads verwenden Sie mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Bei anderen Threads als FastMixer
und FastCapture
kann die NBLog
-Zeitachse des Threads sowohl vom Thread selbst als auch von Binder-Vorgängen verwendet werden. NBLog::Writer
bietet keinen impliziten gegenseitigen Ausschluss pro Zeitachse. Achten Sie daher darauf, dass alle Protokolle in einem Kontext auftreten, in dem der Mutex mLock
des Threads gehalten wird.
Nachdem Sie die Protokolle hinzugefügt haben, bauen Sie AudioFlinger neu.
Achtung:Pro Thread ist eine separate NBLog::Writer
-Zeitachse erforderlich, um die Threadsicherheit zu gewährleisten, da Zeitachsen standardmäßig keine Mutexe enthalten. Wenn mehrere Threads dieselbe Zeitachse verwenden sollen, können Sie sie mit einem vorhandenen Mutex schützen (wie oben für mLock
beschrieben). Sie können auch den NBLog::LockedWriter
-Wrapper anstelle von NBLog::Writer
verwenden.
Dadurch wird jedoch ein Hauptvorteil dieser API aufgehoben: ihr nicht blockierendes Verhalten.
Die vollständige NBLog
API findest du unter frameworks/av/include/media/nbaio/NBLog.h
.
media.log aktivieren
media.log
ist standardmäßig deaktiviert. Sie ist nur aktiv, wenn das Attribut ro.test_harness
den Wert 1
hat. So aktivieren Sie die Funktion:
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
Die Verbindung wird während des Neustarts unterbrochen. Gehen Sie so vor:
adb shell
ps media
zeigt jetzt zwei Prozesse an:
- media.log
- mediaserver
Notieren Sie sich die Prozess-ID von mediaserver
für später.
Zeitleisten anzeigen
Sie können jederzeit manuell einen Log-Dump anfordern. Mit diesem Befehl werden Protokolle aus allen aktiven und letzten Zeitachsen angezeigt und dann gelöscht:
dumpsys media.log
Zeitleisten sind unabhängig und können nicht zusammengeführt werden.
Protokolle nach einem Ausfall des Mediaservers wiederherstellen
Versuchen Sie jetzt, den Prozess mediaserver
: kill -9 #
zu beenden, wobei # die zuvor notierte Prozess-ID ist. Im Haupt-logcat
sollte ein Dump von media.log
angezeigt werden, der alle Logs enthält, die zum Absturz geführt haben.
dumpsys media.log