Artikel ini menjelaskan beberapa tips dan trik untuk men-debug audio Android.
Wastafel Tee
"Tee sink" bernilai fitur debug AudioFlinger, yang hanya tersedia di build 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, {i>tee sink<i} dinonaktifkan secara {i>default<i}, pada waktu kompilasi dan waktu proses. Untuk menggunakan {i>tee sink<i}, Anda harus mengaktifkannya dengan mengompilasi ulang, dan juga dengan menetapkan properti. Pastikan untuk menonaktifkan fitur ini setelah Anda melakukan {i>debugging<i}; {i>tee sink<i} tidak boleh dibiarkan diaktifkan di build produksi.
Petunjuk di bagian ini ditujukan untuk Android 7.x dan yang lebih baru. Untuk Android
5.x dan 6.x, ganti /data/misc/audioserver
dengan
/data/misc/media
. Selain itu, Anda harus menggunakan userdebug atau
ing. 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
. - Membuat ulang
libaudioflinger.so
. adb root
adb remount
- Kirim atau sinkronkan
libaudioflinger.so
baru ke/system/lib
perangkat.
Penyiapan run-time
adb shell getprop | grep ro.debuggable
Konfirmasi bahwa output-nya adalah:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
Pastikan output-nya:
drwx------ media media ... media
Jika direktori tidak ada, buat direktori seperti 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
adalah jumlah dari beberapa bit, satu per fitur.
Lihat kode di AudioFlinger::AudioFlinger()
di AudioFlinger.cpp
untuk penjelasan setiap bit, secara singkat:
- 1 = masukan
- 2 = Output FastMixer
- 4 = AudioRecord dan AudioTrack per trek
Belum ada bit untuk {i>deep buffer <i} atau mixer normal, tapi Anda bisa mendapatkan hasil yang serupa dengan 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
File ini adalah file .wav PCM. - Lalu
adb pull
file/data/misc/audioserver/*.wav
apa pun yang diinginkan; perhatikan bahwa nama file dump khusus jalur tidak muncul dalam outputdumpsys
, tetapi masih disimpan ke/data/misc/audioserver
setelah jalur ditutup. - Tinjau file dump untuk mengetahui masalah privasi sebelum membagikannya kepada orang lain.
Saran
Coba ide ini untuk hasil yang lebih bermanfaat:
- Nonaktifkan suara sentuhan dan klik tombol untuk mengurangi gangguan pada output pengujian.
- Maksimalkan semua volume.
- Menonaktifkan aplikasi yang mengeluarkan suara atau merekam dari mikrofon, jika tidak tertarik untuk pengujian Anda.
- Dump khusus jalur hanya disimpan saat trek ditutup; Anda mungkin perlu menutup aplikasi secara paksa untuk membuang data khusus jalur
- Lakukan
dumpsys
segera setelah pengujian; ruang perekaman yang tersedia terbatas. - Untuk memastikan Anda tidak kehilangan file {i>dump<i} Anda, mengunggahnya ke {i> host<i} secara berkala. Hanya sejumlah kecil file dump yang dipertahankan; dump yang lebih lama akan dihapus setelah batas tersebut tercapai.
Pulihkan
Seperti disebutkan di atas, fitur {i>tee sink<i} tidak boleh dibiarkan diaktifkan. Pulihkan build dan perangkat Anda sebagai berikut:
- Kembalikan perubahan kode sumber ke
Configuration.h
. - Membuat 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
__android_log_print
yang dideklarasikan di <android/log.h>
.
Dalam bagian native framework Android, kita
lebih suka makro bernama ALOGE
, ALOGW
,
ALOGI
, ALOGV
, dll. Dideklarasikan di
<utils/Log.h>
, dan untuk tujuan artikel ini
secara kolektif kita akan menyebutnya sebagai ALOGx
.
Semua API ini mudah digunakan dan dipahami dengan baik, sehingga mudah digunakan
di seluruh platform Android. Khususnya mediaserver
yang mencakup server suara AudioFlinger, menggunakan
ALOGx
secara ekstensif.
Meskipun demikian, ada beberapa batasan untuk ALOGx
dan teman:
-
Mereka rentan terhadap "spam log": {i>buffer<i} log adalah sumber daya bersama
sehingga mudah meluap karena
entri log yang tidak terkait, yang mengakibatkan
informasi yang terlewat. Varian
ALOGV
dinonaktifkan pada waktu kompilasi secara default. Namun tentu saja hal ini dapat menghasilkan spam log jika sudah diaktifkan. -
Panggilan sistem {i>kernel<i} yang mendasarinya bisa diblokir, dan mungkin mengakibatkan
inversi prioritas dan akibatnya gangguan pengukuran dan
dan ketidakakuratan data. Ini dari
perhatian khusus untuk thread yang mendesak seperti
FastMixer
danFastCapture
. - Jika log tertentu dinonaktifkan untuk mengurangi spam log, maka informasi apa pun yang akan ditangkap oleh log tersebut akan hilang. Log tertentu tidak dapat diaktifkan secara surut, setelah menjadi jelas bahwa log tersebut akan menarik.
NBLOG, media.log, dan MediaLogService
NBLOG
API dan media.log
terkait
dan MediaLogService
bersama-sama membentuk sistem {i>logging<i}
yang lebih baru untuk media, dan secara
dirancang untuk mengatasi masalah di atas. Kita akan menggunakan istilah
"media.log" untuk merujuk pada ketiganya, namun NBLOG
adalah
API logging C++, media.log
adalah nama proses Linux, dan MediaLogService
adalah layanan binder Android untuk memeriksa log.
"Linimasa" media.log
adalah seri
entri log yang urutan relatifnya dipertahankan.
Berdasarkan konvensi, setiap thread harus menggunakan linimasanya sendiri.
Manfaat
Manfaat sistem media.log
adalah:
- Tidak mengirim spam ke log utama kecuali dan hingga diperlukan.
- Dapat diperiksa bahkan saat
mediaserver
mengalami error atau hang. - Tidak memblokir per linimasa.
- Menawarkan lebih sedikit gangguan terhadap performa. (Tentu saja tidak ada pencatatan log yang benar-benar tidak mengganggu.)
Arsitektur
Diagram di bawah menunjukkan hubungan proses mediaserver
dan proses init
, sebelum media.log
diperkenalkan:
Poin penting:
init
fork dan execmediaserver
.init
mendeteksi kematianmediaserver
, dan melakukan fork ulang sesuai kebutuhan.- Logging
ALOGx
tidak ditampilkan.
Diagram di bawah ini menunjukkan hubungan baru dari komponen-komponen,
setelah media.log
ditambahkan ke arsitektur:
Perubahan penting:
-
Klien menggunakan
NBLOG
API untuk membuat entri log dan menambahkannya ke {i>buffer<i} sirkular dalam memori bersama. -
MediaLogService
dapat membuang konten buffer sirkular kapan saja. -
{i>Buffer<i} sirkular dirancang sedemikian rupa sehingga setiap kerusakan
memori bersama tidak akan membuat error
MediaLogService
, dan masih dapat digunakan untuk membuang sebanyak mungkin {i>buffer<i} yang tidak terpengaruh oleh kerusakan itu. - Buffer sirkular tidak memblokir dan bebas kunci untuk kedua penulisan 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 ini tidak
mudah digunakan sebagai ALOGx
, tetapi tidak terlalu sulit.
Sebaiknya Anda mempelajari sistem
pencatatan log baru untuk mereka
peristiwa ketika hal itu sangat diperlukan.
Secara khusus, direkomendasikan untuk thread AudioFlinger yang harus
sering berjalan, secara berkala, dan tanpa pemblokiran seperti
FastMixer
dan FastCapture
thread.
Cara menggunakan
Tambahkan log
Pertama, Anda harus menambahkan log ke kode Anda.
Dalam thread FastMixer
dan FastCapture
, gunakan kode seperti ini:
logWriter->log("string"); logWriter->logf("format", parameters); logWriter->logTimestamp();
Karena linimasa NBLog
ini hanya digunakan oleh FastMixer
dan
FastCapture
rangkaian pesan,
tidak perlu pengecualian bersama.
Di thread AudioFlinger lainnya, gunakan mNBLogWriter
:
mNBLogWriter->log("string"); mNBLogWriter->logf("format", parameters); mNBLogWriter->logTimestamp();
Untuk rangkaian pesan selain FastMixer
dan FastCapture
,
linimasa NBLog
thread dapat digunakan oleh thread itu sendiri, dan
oleh operasi binder. NBLog::Writer
tidak menyediakan
pengecualian timbal balik implisit per linimasa, jadi pastikan bahwa semua log terjadi
dalam konteks tempat mLock
mutex thread ditahan.
Setelah Anda 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 melindunginya dengan
mutex yang ada (seperti yang dijelaskan di atas untuk mLock
). Atau Anda bisa
gunakan wrapper NBLog::LockedWriter
, bukan NBLog::Writer
.
Namun, hal ini meniadakan manfaat utama dari API ini: fungsi non-pemblokirannya
perilaku model.
API NBLog
lengkap 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 selama reboot, jadi:
adb shell
ps media
sekarang akan menampilkan dua proses:
- media.log
- server media
Catat ID proses mediaserver
untuk 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 sesuai dengan desain, lini masa bersifat independen, dan tidak ada fasilitas untuk menggabungkan linimasa.
Memulihkan log setelah server media dihentikan
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 tersebut.
dumpsys media.log