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 rootadb remount- Kirim atau sinkronkan
libaudioflinger.sobaru ke/system/libperangkat.
Penyiapan runtime
adb shell getprop | grep ro.debuggable
Konfirmasi bahwa outputnya adalah:[ro.debuggable]: [1]adb shellls -ld /data/misc/audioserver
Pastikan outputnya:
drwx------ media media ... media
Jika direktori tidak ada, buat direktori tersebut sebagai berikut:
mkdir /data/misc/audioserverchown media:media /data/misc/audioserverecho af.tee=# > /data/local.prop
Dengan nilaiaf.teeadalah angka yang dijelaskan di bawah.chmod 644 /data/local.propreboot
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
dumpsysseperti ini:
tee copied to /data/misc/audioserver/20131010101147_2.wav
Ini adalah file .wav PCM. - Kemudian,
adb pullfile/data/misc/audioserver/*.wavyang diinginkan; perhatikan bahwa nama file dump khusus jalur tidak muncul dalam outputdumpsys, tetapi masih disimpan ke/data/misc/audioserversetelah 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
dumpsyssegera 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.soyang dipulihkan ke/system/libperangkat. adb shellrm /data/local.proprm /data/misc/audioserver/*.wavreboot
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
ALOGVdinonaktifkan 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
FastMixerdanFastCapture. - 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
mediaservermengalami 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:
initfork dan execmediaserver.initmendeteksi penghentianmediaserver, dan melakukan fork ulang sesuai kebutuhan.- Logging
ALOGxtidak ditampilkan.
Diagram di bawah menunjukkan hubungan baru komponen,
setelah media.log ditambahkan ke arsitektur:
Gambar 2. Arsitektur setelah media.log
Perubahan penting:
-
Klien menggunakan
NBLOGAPI untuk membuat entri log dan menambahkannya ke buffer melingkar dalam memori bersama. -
MediaLogServicedapat membuang konten buffer melingkar kapan saja. -
Buffer sirkular dirancang sedemikian rupa sehingga kerusakan
memori bersama tidak akan membuat
MediaLogServiceerror, 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 rootadb shellecho ro.test_harness=1 > /data/local.propchmod 644 /data/local.propreboot
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