Artikel ini menjelaskan beberapa tips dan trik untuk men-debug audio Android.
Tee sink
"tee sink" adalah fitur proses debug AudioFlinger, yang hanya tersedia dalam build kustom, untuk mempertahankan fragmen singkat audio terbaru untuk analisis di lain waktu. Hal ini memungkinkan perbandingan antara apa yang sebenarnya diputar atau direkam dengan apa yang diharapkan.
Untuk privasi, sink tee dinonaktifkan secara default, baik pada waktu kompilasi maupun waktu proses. Untuk menggunakan sink tee, Anda harus mengaktifkannya dengan mengompilasi ulang, dan juga dengan menetapkan properti. Pastikan untuk menonaktifkan fitur ini setelah Anda selesai melakukan proses debug; sink tee tidak boleh dibiarkan diaktifkan dalam build produksi.
Petunjuk di bagian ini ditujukan untuk Android 7.x dan yang lebih tinggi. Untuk Android
5.x dan 6.x, ganti /data/misc/audioserver
dengan
/data/misc/media
. Selain itu, Anda harus menggunakan build userdebug atau
eng. Jika Anda menggunakan build userdebug, nonaktifkan verity dengan:
adb root && adb disable-verity && adb reboot
Penyiapan waktu kompilasi
cd frameworks/av/services/audioflinger
- Edit
Configuration.h
. - Hapus tanda komentar
#define TEE_SINK
. - Build ulang
libaudioflinger.so
. adb root
adb remount
- Kirim atau sinkronkan
libaudioflinger.so
baru ke/system/lib
perangkat.
Penyiapan runtime
adb shell getprop | grep ro.debuggable
Konfirmasi bahwa outputnya adalah:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
Pastikan outputnya:
drwx------ media media ... media
Jika direktori tidak ada, buat direktori tersebut sebagai berikut:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
Dengan nilaiaf.tee
adalah angka yang dijelaskan di bawah.chmod 644 /data/local.prop
reboot
Nilai untuk properti af.tee
Nilai af.tee
adalah angka antara 0 dan 7, yang menyatakan jumlah beberapa bit, satu per fitur.
Lihat kode di AudioFlinger::AudioFlinger()
di AudioFlinger.cpp
untuk mengetahui penjelasan setiap bit, tetapi secara singkat:
- 1 = input
- 2 = Output FastMixer
- 4 = AudioRecord dan AudioTrack per trek
Belum ada bit untuk buffering dalam atau mixer normal, tetapi Anda bisa mendapatkan hasil yang serupa menggunakan "4".
Menguji dan memperoleh data
- Jalankan pengujian audio.
adb shell dumpsys media.audio_flinger
- Cari baris dalam output
dumpsys
seperti ini:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Ini adalah file .wav PCM. - Kemudian,
adb pull
file/data/misc/audioserver/*.wav
yang diinginkan; perhatikan bahwa nama file dump khusus jalur tidak muncul dalam outputdumpsys
, tetapi masih disimpan ke/data/misc/audioserver
setelah penutupan jalur. - Tinjau file dump untuk mengetahui masalah privasi sebelum membagikannya kepada orang lain.
Saran
Coba ide-ide berikut untuk mendapatkan hasil yang lebih bermanfaat:
- Nonaktifkan suara sentuh dan klik tombol untuk mengurangi gangguan pada output pengujian.
- Maksimalkan semua volume.
- Nonaktifkan aplikasi yang membuat suara atau merekam dari mikrofon, jika tidak relevan dengan pengujian Anda.
- Dump khusus jalur hanya disimpan saat jalur ditutup; Anda mungkin perlu menutup paksa aplikasi untuk membuang data khusus jalurnya
- Lakukan
dumpsys
segera setelah pengujian; ruang perekaman yang tersedia terbatas. - Untuk memastikan Anda tidak kehilangan file dump, upload file tersebut ke host secara berkala. Hanya file dump dalam jumlah terbatas yang disimpan; dump yang lebih lama akan dihapus setelah batas tersebut tercapai.
Pulihkan
Seperti yang telah disebutkan di atas, fitur tee sink tidak boleh dibiarkan diaktifkan. Pulihkan build dan perangkat Anda sebagai berikut:
- Kembalikan perubahan kode sumber ke
Configuration.h
. - Build ulang
libaudioflinger.so
. - Kirim atau sinkronkan
libaudioflinger.so
yang dipulihkan ke/system/lib
perangkat. adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
Makro ALOGx
API logging bahasa Java standar di Android SDK adalah android.util.Log.
API bahasa C yang sesuai di Android NDK adalah
__android_log_print
yang dideklarasikan di <android/log.h>
.
Dalam bagian native framework Android, kita
lebih memilih makro bernama ALOGE
, ALOGW
,
ALOGI
, ALOGV
, dll. Makro tersebut dideklarasikan di
<utils/Log.h>
, dan untuk tujuan artikel ini
kita akan secara kolektif menyebutnya sebagai ALOGx
.
Semua API ini mudah digunakan dan dipahami dengan baik, sehingga API ini tersebar
di seluruh platform Android. Secara khusus, proses
mediaserver
, yang mencakup server suara AudioFlinger, menggunakan
ALOGx
secara ekstensif.
Namun, ada beberapa batasan untuk ALOGx
dan teman-temannya:
-
Buffer log rentan terhadap "spam log": buffer log adalah resource bersama
sehingga dapat dengan mudah meluap karena entri log yang tidak terkait, sehingga
informasi terlewat. Varian
ALOGV
dinonaktifkan pada waktu kompilasi secara default. Namun, tentu saja, log tersebut dapat menghasilkan spam log jika diaktifkan. -
Panggilan sistem kernel yang mendasarinya dapat diblokir, yang mungkin mengakibatkan
inversi prioritas dan akibatnya gangguan pengukuran dan
ketidakakuratan. Hal ini
merupakan perhatian khusus untuk thread yang sangat penting waktunya seperti
FastMixer
danFastCapture
. - Jika log tertentu dinonaktifkan untuk mengurangi spam log, informasi apa pun yang akan direkam oleh log tersebut akan hilang. Anda tidak dapat mengaktifkan log tertentu secara retroaktif, setelah menjadi jelas bahwa log tersebut akan menarik.
NBLOG, media.log, dan MediaLogService
API NBLOG
dan proses media.log
terkait serta layanan
MediaLogService
bersama-sama membentuk sistem logging yang lebih baru untuk media, dan secara khusus
dirancang untuk mengatasi masalah di atas. Kami akan menggunakan istilah
"media.log" secara longgar untuk merujuk ke ketiganya, tetapi secara ketat NBLOG
adalah
API logging C++, media.log
adalah nama proses Linux, dan MediaLogService
adalah layanan binder Android untuk memeriksa log.
"Linimasa" media.log
adalah serangkaian
entri log yang urutan relatifnya dipertahankan.
Secara umum, setiap thread harus menggunakan linimasanya sendiri.
Manfaat
Manfaat sistem media.log
adalah:
- Tidak mengirim spam ke log utama kecuali dan sampai diperlukan.
- Dapat diperiksa meskipun
mediaserver
mengalami error atau hang. - Tidak memblokir per linimasa.
- Memberikan gangguan yang lebih sedikit pada performa. (Tentu saja tidak ada bentuk logging yang sepenuhnya tidak mengganggu.)
Arsitektur
Diagram di bawah menunjukkan hubungan proses mediaserver
dan proses init
, sebelum media.log
diperkenalkan:

Gambar 1. Arsitektur sebelum media.log
Poin penting:
init
fork dan execmediaserver
.init
mendeteksi penghentianmediaserver
, dan melakukan fork ulang sesuai kebutuhan.- Logging
ALOGx
tidak ditampilkan.
Diagram di bawah menunjukkan hubungan baru komponen,
setelah media.log
ditambahkan ke arsitektur:

Gambar 2. Arsitektur setelah media.log
Perubahan penting:
-
Klien menggunakan
NBLOG
API untuk membuat entri log dan menambahkannya ke buffer melingkar dalam memori bersama. -
MediaLogService
dapat membuang konten buffer melingkar kapan saja. -
Buffer sirkular dirancang sedemikian rupa sehingga kerusakan
memori bersama tidak akan membuat
MediaLogService
error, dan buffer tersebut masih dapat membuang sebanyak mungkin buffer yang tidak terpengaruh oleh kerusakan. - Buffer melingkar bersifat non-blocking dan bebas kunci untuk menulis entri baru dan membaca entri yang ada.
- Tidak ada panggilan sistem kernel yang diperlukan untuk menulis ke atau membaca dari buffer sirkular (selain stempel waktu opsional).
Lokasi penggunaan
Mulai Android 4.4, hanya ada beberapa titik log di AudioFlinger
yang menggunakan sistem media.log
. Meskipun API baru tidak
semudah digunakan seperti ALOGx
, API ini juga tidak terlalu sulit.
Sebaiknya pelajari sistem logging baru untuk situasi
yang mengharuskannya.
Secara khusus, ini direkomendasikan untuk thread AudioFlinger yang harus
berjalan secara rutin, berkala, dan tanpa pemblokiran seperti
thread FastMixer
dan FastCapture
.
Cara menggunakan
Menambahkan log
Pertama, Anda perlu menambahkan log ke kode.
Di thread FastMixer
dan FastCapture
, gunakan kode seperti ini:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Karena linimasa NBLog
ini hanya digunakan oleh thread FastMixer
dan
FastCapture
,
tidak perlu saling mengecualikan.
Di thread AudioFlinger lainnya, gunakan mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Untuk thread selain FastMixer
dan FastCapture
,
linimasa NBLog
thread dapat digunakan oleh thread itu sendiri, dan
oleh operasi binder. NBLog::Writer
tidak menyediakan
mutual exclusion implisit per linimasa, jadi pastikan semua log terjadi
dalam konteks tempat mutex mLock
thread ditahan.
Setelah menambahkan log, build ulang AudioFlinger.
Perhatian:
Linimasa NBLog::Writer
terpisah diperlukan per thread,
untuk memastikan keamanan thread, karena linimasa menghilangkan mutex secara desain. Jika Anda
ingin lebih dari satu thread menggunakan linimasa yang sama, Anda dapat melindungi dengan
mutex yang ada (seperti yang dijelaskan di atas untuk mLock
). Atau, Anda dapat
menggunakan wrapper NBLog::LockedWriter
, bukan NBLog::Writer
.
Namun, hal ini akan menghilangkan manfaat utama API ini: perilaku
non-pemblokirannya.
NBLog
API lengkap ada di frameworks/av/include/media/nbaio/NBLog.h
.
Mengaktifkan media.log
media.log
dinonaktifkan secara default. Properti ini hanya aktif jika properti
ro.test_harness
adalah 1
. Anda dapat mengaktifkannya dengan:
adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot
Koneksi terputus selama mulai ulang, jadi:
adb shell
ps media
kini akan menampilkan dua proses:
- media.log
- mediaserver
Catat ID proses mediaserver
untuk digunakan nanti.
Menampilkan linimasa
Anda dapat meminta dump log secara manual kapan saja. Perintah ini menampilkan log dari semua linimasa yang aktif dan terbaru, lalu menghapusnya:
dumpsys media.log
Perhatikan bahwa berdasarkan desain, linimasa bersifat independen, dan tidak ada fasilitas untuk menggabungkan linimasa.
Memulihkan log setelah mediaserver berhenti berfungsi
Sekarang, coba hentikan proses mediaserver
: kill -9 #
, dengan # adalah
ID proses yang Anda catat sebelumnya. Anda akan melihat dump dari media.log
di logcat
utama, yang menampilkan semua log yang mengarah ke error.
dumpsys media.log