Proses debug audio

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

  1. cd frameworks/av/services/audioflinger
  2. Edit Configuration.h.
  3. Hapus tanda komentar #define TEE_SINK.
  4. Build ulang libaudioflinger.so.
  5. adb root
  6. adb remount
  7. Kirim atau sinkronkan libaudioflinger.so baru ke /system/lib perangkat.

Penyiapan runtime

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

  1. Jalankan pengujian audio.
  2. adb shell dumpsys media.audio_flinger
  3. Cari baris dalam output 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 yang diinginkan; perhatikan bahwa nama file dump khusus jalur tidak muncul dalam output dumpsys, tetapi masih disimpan ke /data/misc/audioserver setelah penutupan jalur.
  5. 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:

  1. Kembalikan perubahan kode sumber ke Configuration.h.
  2. Build ulang libaudioflinger.so.
  3. Kirim 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 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 dan FastCapture.
  • 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:

Arsitektur sebelum media.log

Gambar 1. Arsitektur sebelum media.log

Poin penting:

  • init fork dan exec mediaserver.
  • init mendeteksi penghentian mediaserver, dan melakukan fork ulang sesuai kebutuhan.
  • Logging 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 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
Perintah 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