Proses debug audio

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

  1. cd frameworks/av/services/audioflinger
  2. Sunting Configuration.h .
  3. Batalkan komentar #define TEE_SINK .
  4. Bangun kembali libaudioflinger.so .
  5. adb root
  6. adb remount
  7. Dorong atau sinkronkan libaudioflinger.so baru ke /system/lib perangkat.

Pengaturan waktu proses

  1. adb shell getprop | grep ro.debuggable
    Konfirmasikan bahwa outputnya adalah: [ro.debuggable]: [1]
  2. adb shell
  3. 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
    
  4. echo af.tee=# > /data/local.prop
    Dimana nilai af.tee adalah angka yang dijelaskan di bawah ini.
  5. chmod 644 /data/local.prop
  6. 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

  1. Jalankan tes audio Anda.
  2. adb shell dumpsys media.audio_flinger
  3. Carilah baris pada keluaran dumpsys seperti ini:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Ini adalah file .wav PCM.
  4. Kemudian adb pull file /data/misc/audioserver/*.wav apa pun yang menarik; perhatikan bahwa nama file dump khusus track tidak muncul di output dumpsys , tetapi masih disimpan ke /data/misc/audioserver setelah track ditutup.
  5. 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:

  1. Kembalikan perubahan kode sumber ke Configuration.h .
  2. Bangun kembali libaudioflinger.so .
  3. Dorong atau sinkronkan libaudioflinger.so yang dipulihkan ke /system/lib perangkat.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. 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 dan FastCapture .
  • 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:

Arsitektur sebelum media.log

Gambar 1. Arsitektur sebelum media.log

Poin penting:

  • init fork dan execs mediaserver .
  • init mendeteksi kematian mediaserver , dan melakukan fork ulang jika diperlukan.
  • Pencatatan log ALOGx tidak ditampilkan.

Diagram di bawah menunjukkan hubungan baru komponen, setelah media.log ditambahkan ke arsitektur:

Arsitektur setelah media.log

Gambar 2. Arsitektur setelah media.log

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 shell
Perintah 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