Transisi dari heap ION ke DMA-BUF

Di Android 12, GKI 2.0 menggantikan alokator ION dengan heap DMA-BUF karena alasan berikut:

  • Keamanan: Karena setiap heap DMA-BUF adalah perangkat karakter terpisah, akses ke setiap heap dapat dikontrol secara terpisah dengan sepolicy. Hal ini tidak mungkin dengan ION karena alokasi dari heap mana pun hanya memerlukan akses ke perangkat /dev/ion.
  • Stabilitas ABI: Tidak seperti ION, antarmuka IOCTL framework heap DMA-BUF stabil ABI karena dipertahankan di kernel Linux upstream.
  • Standarisasi: Framework heap DMA-BUF menawarkan UAPI yang ditentukan dengan baik. ION mengizinkan flag kustom dan ID heap yang mencegah pengembangan framework pengujian umum karena implementasi ION setiap perangkat dapat berperilaku secara berbeda.

Cabang android12-5.10 dari Android Common Kernel menonaktifkan CONFIG_ION pada 1 Maret 2021.

Latar belakang

Berikut adalah perbandingan singkat antara heap ION dan DMA-BUF.

Kesamaan antara framework heap ION dan DMA-BUF

  • Framework heap ION dan DMA-BUF adalah eksportir DMA-BUF berbasis heap.
  • Keduanya memungkinkan setiap heap menentukan alokator dan operasi DMA-BUF-nya sendiri.
  • Performa alokasi serupa karena kedua skema memerlukan satu IOCTL untuk alokasi.

Perbedaan antara framework heap ION dan DMA-BUF

Heap ION Heap DMA-BUF
Semua alokasi ION dilakukan dengan /dev/ion. Setiap heap DMA-BUF adalah perangkat karakter yang ada di /dev/dma_heap/<heap_name>.
ION mendukung flag pribadi heap. Heap DMA-BUF tidak mendukung flag pribadi heap. Setiap jenis alokasi yang berbeda dilakukan dari heap yang berbeda. Misalnya, varian heap sistem yang di-cache dan tidak di-cache adalah heap terpisah yang terletak di /dev/dma_heap/system dan /dev/dma_heap/system_uncached.
ID/mask heap dan flag harus ditentukan untuk alokasi. Nama heap digunakan untuk alokasi.

Bagian berikut mencantumkan komponen yang menangani ION dan menjelaskan cara beralih ke framework heap DMA-BUF.

Mentransisikan driver kernel dari heap ION ke DMA-BUF

Driver kernel yang menerapkan heap ION

Heap ION dan DMA-BUF memungkinkan setiap heap menerapkan alokator dan DMA-BUF op-nya sendiri. Jadi, Anda dapat beralih dari implementasi heap ION ke implementasi heap DMA-BUF menggunakan kumpulan API yang berbeda untuk mendaftarkan heap. Tabel ini menunjukkan API pendaftaran heap ION dan API heap DMA-BUF yang setara.

Heap ION Heap DMA-BUF
void ion_device_add_heap(struct ion_heap *heap) struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info);
void ion_device_remove_heap(struct ion_heap *heap) void dma_heap_put(struct dma_heap *heap);

Heap DMA-BUF tidak mendukung flag pribadi heap. Jadi, setiap varian heap harus didaftarkan satu per satu menggunakan API dma_heap_add(). Untuk memudahkan berbagi kode, sebaiknya daftarkan semua varian heap yang sama dalam driver yang sama. Contoh dma-buf: system_heap ini menunjukkan penerapan varian heap sistem yang di-cache dan tidak di-cache.

Gunakan dma-buf: heaps: example template ini untuk membuat heap DMA-BUF dari awal.

Driver kernel mengalokasikan langsung dari heap ION

Framework heap DMA-BUF juga menawarkan antarmuka alokasi untuk klien dalam kernel. Alih-alih menentukan mask dan flag heap untuk memilih jenis alokasi, antarmuka yang ditawarkan oleh heap DMA-BUF menggunakan nama heap sebagai input.

Berikut adalah API alokasi ION dalam kernel dan API alokasi heap DMA-BUF yang setara. Driver kernel dapat menggunakan dma_heap_find() API untuk membuat kueri adanya heap. API menampilkan pointer ke instance struct dma_heap, yang kemudian dapat diteruskan sebagai argumen ke dma_heap_buffer_alloc() API.

Heap ION Heap DMA-BUF
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)

struct dma_heap *dma_heap_find(const char *name)

struct dma_buf *struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, unsigned int fd_flags, unsigned int heap_flags)

Driver kernel yang menggunakan DMA-BUF

Tidak ada perubahan yang diperlukan untuk driver yang hanya mengimpor DMA-BUF, karena buffering yang dialokasikan dari heap ION berperilaku sama persis dengan buffering yang dialokasikan dari heap DMA-BUF yang setara.

Mentransisikan klien ruang pengguna ION ke heap DMA-BUF

Untuk mempermudah transisi bagi klien ruang pengguna ION, library abstraksi yang disebut libdmabufheap tersedia. libdmabufheap mendukung alokasi di heap DMA-BUF dan heap ION. Pertama-tama, fungsi ini memeriksa apakah heap DMA-BUF dengan nama yang ditentukan ada dan jika tidak, kembali ke heap ION yang setara, jika ada.

Klien harus melakukan inisialisasi objek BufferAllocator selama inisialisasi, bukan membuka /dev/ion using ion_open(). Hal ini karena deskriptor file yang dibuat dengan membuka /dev/ion dan /dev/dma_heap/<heap_name> dikelola secara internal oleh objek BufferAllocator.

Untuk beralih dari libion ke libdmabufheap, ubah perilaku klien sebagai berikut:

  • Lacak nama heap yang akan digunakan untuk alokasi, bukan ID/mask kepala dan flag heap.
  • Ganti ion_alloc_fd() API, yang menggunakan mask heap dan argumen flag, dengan BufferAllocator::Alloc() API, yang menggunakan nama heap sebagai gantinya.

Tabel berikut mengilustrasikan perubahan ini dengan menunjukkan cara libion dan libdmabufheap melakukan alokasi heap sistem yang tidak di-cache.

Jenis alokasi libion libdmabufheap
Alokasi yang di-cache dari heap sistem ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
Alokasi yang tidak disimpan dalam cache dari heap sistem ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

Varian heap sistem yang tidak di-cache menunggu persetujuan upstream, tetapi sudah menjadi bagian dari cabang android12-5.10.

Untuk mendukung upgrade perangkat, MapNameToIonHeap() API memungkinkan pemetaan nama heap ke parameter heap ION (nama heap atau mask dan flag) untuk memungkinkan antarmuka tersebut menggunakan alokasi berbasis nama. Berikut adalah contoh alokasi berbasis nama.

Dokumentasi untuk setiap API yang diekspos oleh libdmabufheap tersedia. Library juga mengekspos file header untuk digunakan oleh klien C.

Referensi penerapan Gralloc

Penerapan gralloc Hikey960 menggunakan libdmabufheap, sehingga Anda dapat menggunakannya sebagai penerapan referensi.

Penambahan ueventd yang diperlukan

Untuk heap DMA-BUF khusus perangkat baru yang dibuat, tambahkan entri baru ke file ueventd.rc perangkat. Contoh Penyiapan ueventd untuk mendukung heap DMA-BUF ini menunjukkan cara melakukannya untuk heap sistem DMA-BUF.

Penambahan sepolicy yang diperlukan

Menambahkan izin sepolicy untuk memungkinkan klien ruang pengguna mengakses heap DMA-BUF baru. Contoh menambahkan izin yang diperlukan ini menunjukkan izin sepolicy yang dibuat untuk berbagai klien agar dapat mengakses heap sistem DMA-BUF.

Mengakses heap vendor dari kode framework

Untuk memastikan kepatuhan Treble, kode framework hanya dapat dialokasikan dari kategori heap vendor yang telah disetujui sebelumnya.

Berdasarkan masukan yang diterima dari partner, Google mengidentifikasi dua kategori heap vendor yang harus diakses dari kode framework:

  1. Heap yang didasarkan pada heap sistem dengan pengoptimalan performa khusus perangkat atau SoC.
  2. Heap untuk dialokasikan dari memori yang dilindungi.

Heap berdasarkan heap sistem dengan pengoptimalan performa khusus perangkat atau SoC

Untuk mendukung kasus penggunaan ini, implementasi heap dari sistem heap DMA-BUF default dapat diganti.

  • CONFIG_DMABUF_HEAPS_SYSTEM dinonaktifkan di gki_defconfig agar menjadi modul vendor.
  • Pengujian kepatuhan VTS memastikan bahwa heap ada di /dev/dma_heap/system. Pengujian juga memverifikasi bahwa heap dapat dialokasikan dari, dan bahwa deskriptor file yang ditampilkan (fd) dapat dipetakan memori (mmapped) dari ruang pengguna.

Poin sebelumnya juga berlaku untuk varian heap sistem yang tidak di-cache, meskipun keberadaannya tidak wajib untuk perangkat yang sepenuhnya koheren dengan IO.

Heap yang akan dialokasikan dari memori yang dilindungi

Implementasi heap aman harus khusus vendor karena Android Common Kernel tidak mendukung implementasi heap aman generik.

  • Daftarkan implementasi khusus vendor Anda sebagai /dev/dma_heap/system-secure<vendor-suffix>.
  • Implementasi heap ini bersifat opsional.
  • Jika heap ada, pengujian VTS akan memastikan bahwa alokasi dapat dilakukan dari heap tersebut.
  • Komponen framework diberikan akses ke heap ini sehingga dapat mengaktifkan penggunaan heap melalui HAL Codec2/HAL non-binderized, proses yang sama. Namun, fitur framework Android generik tidak dapat bergantung pada fitur tersebut karena variabilitas dalam detail penerapannya. Jika implementasi heap aman umum ditambahkan ke Android Common Kernel pada masa mendatang, implementasi tersebut harus menggunakan ABI yang berbeda untuk menghindari konflik dengan perangkat yang diupgrade.

Alokator Codec 2 untuk heap DMA-BUF

Alokator codec2 untuk antarmuka heap DMA-BUF tersedia di AOSP.

Antarmuka penyimpanan komponen yang memungkinkan parameter heap ditentukan dari C2 HAL tersedia dengan alokator heap DMA-BUF C2.

Contoh alur transisi untuk heap ION

Untuk memperlancar transisi dari heap ION ke DMA-BUF, libdmabufheap memungkinkan pengalihan satu heap pada satu waktu. Langkah-langkah berikut menunjukkan alur kerja yang disarankan untuk mentransisikan heap ION non-lama bernama my_heap yang mendukung satu tanda, ION_FLAG_MY_FLAG.

Langkah 1: Buat setara dengan heap ION dalam framework DMA-BUF. Dalam contoh ini, karena heap ION my_heap mendukung flag ION_FLAG_MY_FLAG, kita mendaftarkan dua heap DMA-BUF:

  • Perilaku my_heap sama persis dengan perilaku heap ION dengan tanda ION_FLAG_MY_FLAG dinonaktifkan.
  • Perilaku my_heap_special sama persis dengan perilaku heap ION dengan flag ION_FLAG_MY_FLAG yang diaktifkan.

Langkah 2: Buat perubahan ueventd untuk heap DMA-BUF my_heap dan my_heap_special baru. Pada tahap ini, heap terlihat sebagai /dev/dma_heap/my_heap dan /dev/dma_heap/my_heap_special, dengan izin yang diinginkan.

Langkah 3: Untuk klien yang mengalokasikan dari my_heap, ubah makefile mereka agar ditautkan ke libdmabufheap. Selama inisialisasi klien, buat instance objek BufferAllocator dan gunakan MapNameToIonHeap() API untuk memetakan kombinasi <ION heap name/mask, flag> ke nama heap DMA-BUF yang setara.

Contoh:

allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )

Daripada menggunakan MapNameToIonHeap() API dengan parameter nama dan flag, Anda dapat membuat pemetaan dari <ION heap mask, flag> ke nama heap DMA-BUF yang setara dengan menetapkan parameter nama heap ION ke kosong.

Langkah 4: Ganti pemanggilan ion_alloc_fd() dengan BufferAllocator::Alloc() menggunakan nama heap yang sesuai.

Jenis alokasi libion libdmabufheap
Alokasi dari my_heap dengan flag ION_FLAG_MY_FLAG tidak ditetapkan ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size)
Alokasi dari my_heap dengan flag ION_FLAG_MY_FLAG ditetapkan ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

Pada tahap ini, klien berfungsi tetapi masih mengalokasikan dari heap ION karena tidak memiliki izin sepolicy yang diperlukan untuk membuka heap DMA-BUF.

Langkah 5: Buat izin sepolicy yang diperlukan agar klien dapat mengakses heap DMA-BUF baru. Klien kini sepenuhnya dapat mengalokasikan dari heap DMA-BUF baru.

Langkah 6: Pastikan alokasi terjadi dari heap DMA-BUF baru dengan memeriksa logcat.

Langkah 7: Nonaktifkan heap ION my_heap di kernel. Jika kode klien tidak perlu mendukung perangkat upgrade (yang kernelnya mungkin hanya mendukung heap ION), Anda juga dapat menghapus pemanggilan MapNameToIonHeap().