Mulai Android 17 (level API 37) dan diupdate melalui Update Sistem Google Play (modul APEX Mainline), Android memperkenalkan dekoder audio software dalam proses untuk format audio terkompresi, termasuk Opus dan AAC.
Dengan menjalankan dekoder audio langsung dalam proses aplikasi, bukan dalam proses sistem sandbox terpisah, aplikasi dapat mengurangi latensi decoding audio hingga sekitar 40%, mengurangi penggunaan CPU, dan memperpanjang masa pakai baterai selama pemutaran media berkelanjutan, pesan suara, dan bermain game.
Dekode di luar proses versus dalam proses
Sebelumnya, Android menjalankan semua dekoder media software platform di dalam daemon sistem khusus yang di-sandbox (mediaswcodec) untuk melindungi aplikasi dan OS dari bitstream media yang tidak valid. Namun, sandbox di luar proses
memperkenalkan overhead performa yang terukur:
- Latensi komunikasi antarproses (IPC): Setiap frame input audio yang diantrekan ke dekoder dan setiap buffer audio PCM yang didekodekan yang ditampilkan memerlukan serialisasi IPC Binder lintas proses dan pengalihan konteks.
- Overhead memori bersama: Penyerahan buffer antar-proses memerlukan sinkronisasi
memori bersama (
C2Buffer) dan pengelolaan cache. - Persaingan penjadwalan: Dalam beban CPU yang berat, persaingan penjadwalan thread antara proses aplikasi dan
mediaswcodecdapat menyebabkan kekurangan buffer dan audio tersendat dalam pipeline audio latensi rendah (seperti DAW, komunikasi VoIP, dan game interaktif).
Menjalankan decoder media dalam proses secara langsung mengatasi hambatan performa ini:
- Menghilangkan latensi IPC: Melewati transaksi IPC Binder dan pengalihan konteks, sehingga mengurangi latensi decoding end-to-end sekitar 40%.
- Meminimalkan overhead buffer: Meneruskan buffer audio secara langsung dalam ruang memori aplikasi lokal tanpa memerlukan pemetaan memori bersama lintas proses.
- Mencegah jitter penjadwalan: Menjalankan decoding pada thread prioritas aplikasi sendiri (seperti thread AAudio atau Oboe real-time), mencegah gangguan audio dan kekurangan buffer saat beban sistem berat.
Keamanan memori dengan Rust
Sebelumnya, Android mengisolasi software decoder dalam proses terpisah (mediaswcodec) karena decoder memproses bitstream yang tidak tepercaya dari file media eksternal, sehingga eksploitasi kerusakan memori (seperti luapan buffer) menjadi masalah keamanan utama.
Android dapat memindahkan dekoder software secara aman langsung ke proses aplikasi yang memanggilnya dengan mengimplementasikannya dalam bahasa yang aman untuk memori seperti Rust atau mengisolasinya dengan Isolasi Kesalahan Ringan (LFI).
Untuk menghilangkan overhead sandbox di luar proses secara aman untuk AAC
(c2.android.inproc.aac.decoder), Android menyediakan decoder yang diimplementasikan dalam
Rust murni atau dilindungi oleh rangkaian antarmuka fungsi asing (FFI) Rust yang aman.
Rust dianggap aman untuk decoding dalam proses karena alasan berikut:
- Keamanan memori waktu kompilasi: Pemeriksaan kepemilikan, peminjaman, dan masa pakai yang ketat di Rust memastikan bahwa memori tidak dapat diakses setelah dibebaskan atau diubah saat dibagikan.
- Penghapusan kerentanan umum: Rust sepenuhnya mencegah luapan buffer heap, stack smash, pembacaan dan penulisan array di luar batas, error penggunaan setelah tersedia, dan kerentanan double-free pada waktu kompilasi.
- Pajak sandbox runtime nol: Karena keamanan memori terbukti secara matematis pada waktu kompilasi dan diverifikasi melalui pemeriksaan batas, dekoder Rust dieksekusi dengan kecepatan native di dalam proses aplikasi tanpa memerlukan transisi tabel halaman atau konteks sandbox hardware.
Keamanan memori dengan Isolasi Kesalahan Ringan (LFI)
Untuk decoder audio C/C++ lama yang kompleks yang belum ditulis ulang di Rust—khususnya decoder Opus (c2.android.inproc.opus.decoderdidukung oleh libopus)—Android menyediakan keamanan dalam proses menggunakan Isolasi Kesalahan Ringan (LFI).
LFI dianggap aman untuk dekoder C/C++ karena alasan berikut:
- Sandbox memori linear yang dilindungi hardware: LFI mengompilasi library codec C/C++ ke dalam kode mesin linear turunan WebAssembly yang dibatasi ke slot memori linear 4 GB yang dilindungi hardware.
- Kunci Perlindungan Memori Linux (
pku): LFI menggunakan Kunci Perlindungan Memori Linux (pku/pkey_mprotect) untuk mempartisi izin ruang alamat. Library terisolasi tidak dapat membaca atau menulis memori di luar slot sandbox 4 GB yang ditetapkan. - Penyadapan panggilan sistem: Panggilan sistem OS host nol (seperti I/O file, akses jaringan, atau kontrol proses) diizinkan di dalam sandbox. Panggilan library yang tidak didukung akan dirutekan ke stub dummy minimal (
lfi_stubs.c). - Pemulihan kesalahan yang aman: Jika bitstream Opus yang salah bentuk atau berbahaya mencoba membaca atau menulis di luar batas dalam sandbox linear, runtime LFI akan menjebak kesalahan dengan aman di ruang pengguna dan menampilkan error decoding
C2_CORRUPTEDyang bersih tanpa membuat aplikasi host mengalami error.
Arsitektur dan perangkat yang didukung untuk LFI
LFI tidak memerlukan petunjuk hardware CPU kustom dan didukung di arsitektur prosesor ARM64 (aarch64) dan x86_64:
- Perangkat ARM64 (
aarch64): Sebagian besar perangkat seluler konsumen—termasuk ponsel (seperti perangkat Pixel dengan SoC Google Tensor, SoC Qualcomm Snapdragon, dan SoC MediaTek), perangkat foldable, tablet, dan unit infotainment otomotif—berjalan di prosesor ARM64 dan mendukung dekoder dalam proses LFI. - Perangkat x86_64: Emulator Android yang berjalan di workstation developer dengan CPU Intel atau AMD, serta Chromebook ChromeOS yang menjalankan aplikasi Android menggunakan ARC (Android Runtime for ChromeOS), dieksekusi di arsitektur x86_64 dan mendukung sandbox LFI.
Decoder audio dalam proses yang tersedia
| Format audio | Jenis MIME | Nama komponen dalam proses | Penerapan |
|---|---|---|---|
| Opus | audio/opus |
c2.android.inproc.opus.decoder |
C/C++ libopus dengan LFI |
| AAC | audio/mp4a-latm |
c2.android.inproc.aac.decoder |
Rust yang aman untuk memori (C2ApexAacDec) |
- AAC (
c2.android.inproc.aac.decoder): Menangani streaming ADTS (dengan penguraian header ADTS dinamis) dan Unit Akses (AU) mentah dengan pelacakan stempel waktu presentasi yang akurat (hanya pemrosesan AU satu frame dalam kasusAAC_PACKAGING_RAW). - Opus (
c2.android.inproc.opus.decoder): Mendekode paket container Ogg Opus atau Matroska standar dengan pengambilan sampel ulang internal ke PCM 48 kHz.
Mengaktifkan decoder dalam proses
Saat ini, decoder dalam proses bukan default sistem saat memanggil
MediaCodec.createDecoderByType().
Platform ini mempertahankan prioritas pemilihan Codec 2.0 yang lebih tinggi untuk decoder di luar proses lama selama verifikasi ekosistem.
Untuk mengaktifkan decoder dalam proses hari ini untuk pemutaran atau pengujian latensi rendah, buat instance codec secara eksplisit berdasarkan nama komponen menggunakan MediaCodec.createByCodecName().
Buat instance berdasarkan nama komponen
Contoh berikut menunjukkan cara membuat instance dekoder AAC dalam proses secara eksplisit, yang akan kembali ke dekoder default jika komponen dalam proses tidak tersedia di perangkat:
Kotlin
val INPROC_AAC_CODEC = "c2.android.inproc.aac.decoder" fun createAudioDecoder(): MediaCodec { return try { // Attempt to opt in to the low-latency in-process AAC decoder MediaCodec.createByCodecName(INPROC_AAC_CODEC) } catch (e: IllegalArgumentException) { // Fall back to the default platform AAC decoder MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AAC) } }
Java
private static final String INPROC_AAC_CODEC = "c2.android.inproc.aac.decoder"; public MediaCodec createAudioDecoder() throws IOException { try { // Attempt to opt in to the low-latency in-process AAC decoder return MediaCodec.createByCodecName(INPROC_AAC_CODEC); } catch (IllegalArgumentException e) { // Fall back to the default platform AAC decoder return MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AAC); } }
Mengonfigurasi Jetpack Media3 atau ExoPlayer
Jika aplikasi Anda menggunakan Jetpack Media3 atau ExoPlayer, Anda dapat membuat MediaCodecSelector kustom untuk memprioritaskan dekoder dalam proses saat tersedia di perangkat:
Kotlin
class InprocPreferredMediaCodecSelector : MediaCodecSelector { override fun getDecoderInfos( mimeType: String, requiresSecureDecoder: Boolean, requiresTunnelingDecoder: Boolean ): List<MediaCodecInfo> { val defaultInfos = MediaCodecUtil.getDecoderInfos( mimeType, requiresSecureDecoder, requiresTunnelingDecoder ) val inprocNames = setOf( "c2.android.inproc.opus.decoder", "c2.android.inproc.aac.decoder" ) // Sort in-process decoders to the top of the selection list return defaultInfos.sortedByDescending { it.name in inprocNames } } }
Java
public class InprocPreferredMediaCodecSelector implements MediaCodecSelector { private static final Set<String> INPROC_NAMES = new HashSet<>(Arrays.asList( "c2.android.inproc.opus.decoder", "c2.android.inproc.aac.decoder" )); @Override public List<MediaCodecInfo> getDecoderInfos( String mimeType, boolean requiresSecureDecoder, boolean requiresTunnelingDecoder) throws MediaCodecUtil.DecoderQueryException { List<MediaCodecInfo> defaultInfos = new ArrayList<>( MediaCodecUtil.getDecoderInfos(mimeType, requiresSecureDecoder, requiresTunnelingDecoder) ); // Sort in-process decoders to the top of the selection list defaultInfos.sort((a, b) -> { boolean aInproc = INPROC_NAMES.contains(a.name); boolean bInproc = INPROC_NAMES.contains(b.name); return Boolean.compare(bInproc, aInproc); }); return defaultInfos; } }
Rencana untuk decoder sistem default
Android secara aktif bersiap untuk mentransisikan dekoder dalam proses yang aman untuk memori ini menjadi dekoder default sistem untuk jenis MIME audio masing-masing dalam rilis platform mendatang (dimulai dengan Opus LFI dan AAC Rust di Android 18 atau update modul Mainline mendatang).
Setelah decoder dalam proses menjadi komponen Codec 2.0 default untuk jenis MIME-nya, panggilan standar ke MediaCodec.createDecoderByType(...) akan otomatis dirutekan melalui penerapan dalam proses, sehingga memberikan latensi decoding yang sekitar 40% lebih rendah tanpa memerlukan perubahan kode aplikasi.