Artikel ini menjelaskan beberapa tips dan trik untuk men-debug audio Android.
Tee tenggelam
"tee sink" adalah fitur debugging AudioFlinger, hanya tersedia dalam versi kustom, untuk menyimpan fragmen pendek audio terbaru untuk analisis nanti. Hal ini memungkinkan perbandingan antara apa yang sebenarnya diputar atau direkam vs. apa yang diharapkan.
Untuk privasi, tee sink dinonaktifkan secara default, baik pada waktu kompilasi maupun waktu proses. Untuk menggunakan tee sink, Anda harus mengaktifkannya dengan mengkompilasi ulang, dan juga dengan mengatur properti. Pastikan untuk menonaktifkan fitur ini setelah Anda selesai melakukan debug; tee sink tidak boleh dibiarkan diaktifkan di build produksi.
Petunjuk di bagian ini ditujukan untuk Android 7.x dan lebih tinggi. Untuk Android 5.x dan 6.x, ganti /data/misc/audioserver
dengan /data/misc/media
. Selain itu, Anda harus menggunakan userdebug atau eng build. Jika Anda menggunakan build userdebug, nonaktifkan verity dengan:
adb root && adb disable-verity && adb reboot
Pengaturan waktu kompilasi
-
cd frameworks/av/services/audioflinger
- Sunting
Configuration.h
. - Batalkan komentar
#define TEE_SINK
. - Bangun kembali
libaudioflinger.so
. -
adb root
-
adb remount
- Dorong atau sinkronkan
libaudioflinger.so
baru ke/system/lib
perangkat.
Pengaturan waktu proses
-
adb shell getprop | grep ro.debuggable
Konfirmasikan bahwa outputnya adalah:[ro.debuggable]: [1]
-
adb shell
-
ls -ld /data/misc/audioserver
Konfirmasikan bahwa outputnya adalah:
drwx------ media media ... media
Jika direktori tidak ada, buatlah sebagai berikut:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
-
echo af.tee=# > /data/local.prop
Dimana nilaiaf.tee
adalah angka yang dijelaskan di bawah ini. -
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 bit per fitur. Lihat kode di AudioFlinger::AudioFlinger()
di AudioFlinger.cpp
untuk penjelasan setiap bit, namun secara singkat:
- 1 = masukan
- 2 = Keluaran FastMixer
- 4 = AudioRecord dan AudioTrack per trek
Belum ada bit untuk buffer dalam atau mixer normal, tetapi Anda bisa mendapatkan hasil serupa menggunakan "4".
Uji dan peroleh data
- Jalankan tes audio Anda.
-
adb shell dumpsys media.audio_flinger
- Carilah baris pada keluaran
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
apa pun yang menarik; perhatikan bahwa nama file dump khusus track tidak muncul di outputdumpsys
, tetapi masih disimpan ke/data/misc/audioserver
setelah track ditutup. - Tinjau file dump untuk mengetahui masalah privasi sebelum berbagi dengan orang lain.
Saran
Cobalah ide berikut untuk hasil yang lebih bermanfaat:
- Nonaktifkan suara sentuhan dan klik tombol untuk mengurangi interupsi pada hasil pengujian.
- Maksimalkan semua volume.
- Nonaktifkan aplikasi yang mengeluarkan suara atau rekaman dari mikrofon, jika aplikasi tersebut tidak menarik untuk pengujian Anda.
- Pembuangan khusus trek hanya disimpan saat trek ditutup; Anda mungkin perlu menutup paksa aplikasi untuk membuang data spesifik treknya
- Lakukan
dumpsys
segera setelah tes; ada jumlah ruang perekaman yang tersedia terbatas. - Untuk memastikan Anda tidak kehilangan file dump, unggah file tersebut ke host Anda secara berkala. Hanya sejumlah file dump yang disimpan; dump lama akan dihapus setelah batas tersebut tercapai.
Memulihkan
Seperti disebutkan di atas, fitur tee sink tidak boleh dibiarkan aktif. Pulihkan build dan perangkat Anda sebagai berikut:
- Kembalikan perubahan kode sumber ke
Configuration.h
. - Bangun kembali
libaudioflinger.so
. - Dorong 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 asli kerangka Android, kami lebih memilih makro bernama ALOGE
, ALOGW
, ALOGI
, ALOGV
, dll. Makro tersebut dideklarasikan dalam <utils/Log.h>
, dan untuk keperluan artikel ini kami secara kolektif akan menyebutnya sebagai ALOGx
.
Semua API ini mudah digunakan dan dipahami dengan baik, sehingga dapat digunakan di seluruh platform Android. Khususnya proses mediaserver
, yang mencakup server suara AudioFlinger, menggunakan ALOGx
secara ekstensif.
Meski demikian, ada beberapa keterbatasan pada ALOGx
dan kawan-kawan:
- Mereka rentan terhadap "spam log": buffer log adalah sumber daya bersama sehingga dapat dengan mudah meluap karena entri log yang tidak terkait, sehingga mengakibatkan informasi yang terlewat. Varian
ALOGV
dinonaktifkan pada waktu kompilasi secara default. Namun tentu saja hal ini dapat mengakibatkan log spam jika diaktifkan. - Panggilan sistem kernel yang mendasarinya dapat diblokir, kemungkinan mengakibatkan inversi prioritas dan akibatnya gangguan dan ketidakakuratan pengukuran. Hal ini menjadi perhatian khusus pada thread yang kritis terhadap waktu seperti
FastMixer
danFastCapture
. - Jika log tertentu dinonaktifkan untuk mengurangi spam log, maka informasi apa pun yang seharusnya diambil oleh log tersebut akan hilang. Tidak mungkin untuk mengaktifkan log tertentu secara surut, setelah menjadi jelas bahwa log tersebut menarik.
NBLOG, media.log, dan MediaLogService
API NBLOG
dan proses media.log
terkait serta layanan MediaLogService
bersama-sama membentuk sistem pencatatan yang lebih baru untuk media, dan dirancang khusus untuk mengatasi masalah di atas. Kita akan menggunakan istilah "media.log" untuk merujuk pada ketiganya, namun sebenarnya NBLOG
adalah API logging C++, media.log
adalah nama proses Linux, dan MediaLogService
adalah layanan pengikat Android untuk memeriksa log.
"Garis waktu" media.log
adalah serangkaian entri log yang urutan relatifnya dipertahankan. Berdasarkan konvensi, setiap thread harus menggunakan timeline-nya sendiri.
Manfaat
Manfaat sistem media.log
adalah:
- Tidak mengirim spam ke log utama kecuali dan sampai diperlukan.
- Dapat diperiksa bahkan ketika
mediaserver
mengalami crash atau hang. - Non-pemblokiran per timeline.
- Menawarkan lebih sedikit gangguan terhadap kinerja. (Tentu saja tidak ada bentuk penebangan yang sepenuhnya tidak mengganggu.)
Arsitektur
Diagram di bawah menunjukkan hubungan proses mediaserver
dan proses init
, sebelum media.log
diperkenalkan:
Poin penting:
-
init
fork dan execsmediaserver
. -
init
mendeteksi kematianmediaserver
, dan melakukan fork ulang jika diperlukan. - Pencatatan log
ALOGx
tidak ditampilkan.
Diagram di bawah menunjukkan hubungan baru komponen, setelah media.log
ditambahkan ke arsitektur:
Perubahan penting:
- Klien menggunakan
NBLOG
API untuk membuat entri log dan menambahkannya ke buffer melingkar di memori bersama. -
MediaLogService
dapat membuang konten buffer melingkar kapan saja. - Buffer melingkar dirancang sedemikian rupa sehingga kerusakan apa pun pada memori bersama tidak akan membuat
MediaLogService
mogok, dan buffer tersebut masih dapat membuang sebanyak mungkin buffer yang tidak terpengaruh oleh kerusakan tersebut. - Buffer melingkar tidak memblokir dan bebas kunci untuk menulis entri baru dan membaca entri yang sudah ada.
- Tidak diperlukan panggilan sistem kernel untuk menulis atau membaca dari buffer melingkar (selain cap waktu opsional).
Dimana untuk digunakan
Pada Android 4.4, hanya ada beberapa titik log di AudioFlinger yang menggunakan sistem media.log
. Meskipun penggunaan API baru ini tidak semudah ALOGx
, namun juga tidak terlalu sulit. Kami mendorong Anda untuk mempelajari sistem logging baru pada saat-saat ketika sistem tersebut sangat diperlukan. Secara khusus, direkomendasikan untuk thread AudioFlinger yang harus dijalankan secara sering, berkala, dan tanpa pemblokiran seperti thread FastMixer
dan FastCapture
.
Cara Penggunaan
Tambahkan log
Pertama, Anda perlu menambahkan log ke kode Anda.
Di thread FastMixer
dan FastCapture
, gunakan kode seperti ini:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Karena garis waktu NBLog
ini hanya digunakan oleh thread FastMixer
dan FastCapture
, tidak diperlukan saling pengecualian.
Di thread AudioFlinger lainnya, gunakan mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Untuk thread selain FastMixer
dan FastCapture
, garis waktu NBLog
thread dapat digunakan oleh thread itu sendiri, dan oleh operasi pengikat. NBLog::Writer
tidak memberikan pengecualian timbal balik apa pun secara implisit per garis waktu, jadi pastikan semua log terjadi dalam konteks di mana mutex mLock
thread disimpan.
Setelah Anda menambahkan log, buat ulang AudioFlinger.
Perhatian: Garis waktu NBLog::Writer
terpisah diperlukan per thread, untuk memastikan keamanan thread, karena garis waktu sengaja menghilangkan mutex. Jika Anda ingin lebih dari satu thread menggunakan timeline yang sama, Anda dapat memproteksi dengan mutex yang ada (seperti dijelaskan di atas untuk mLock
). Atau Anda dapat menggunakan pembungkus NBLog::LockedWriter
alih-alih NBLog::Writer
. Namun, hal ini meniadakan manfaat utama API ini: perilaku non-pemblokirannya.
NBLog
API selengkapnya ada di frameworks/av/include/media/nbaio/NBLog.h
.
Aktifkan media.log
media.log
dinonaktifkan secara default. Ini hanya aktif ketika 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 saat reboot, jadi:
adb shellPerintah
ps media
sekarang akan menampilkan dua proses:- media.log
- server media
Catat ID proses mediaserver
untuk nanti.
Tampilkan garis waktu
Anda dapat meminta dump log secara manual kapan saja. Perintah ini menampilkan log dari semua linimasa aktif dan terkini, lalu menghapusnya:
dumpsys media.log
Perhatikan bahwa menurut desain, garis waktu bersifat independen, dan tidak ada fasilitas untuk menggabungkan garis waktu.
Pulihkan log setelah kematian server media
Sekarang coba matikan proses mediaserver
: kill -9 #
, di mana # adalah ID proses yang Anda catat sebelumnya. Anda akan melihat dump dari media.log
di logcat
utama, yang menampilkan semua log yang menyebabkan kerusakan.
dumpsys media.log