Transisi dari ION ke DMA-BUF Heap

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

  • Keamanan: Karena setiap heap DMA-BUF adalah perangkat karakter yang terpisah, akses ke setiap heap dapat dikontrol secara terpisah dengan kebijakan. Ini tidak mungkin dilakukan dengan ION karena alokasi dari heap mana pun hanya memerlukan akses ke perangkat /dev/ion .
  • Stabilitas ABI: Tidak seperti ION, antarmuka IOCTL kerangka kerja tumpukan DMA-BUF dijamin stabil ABI karena dipertahankan di kernel Linux upstream.
  • Standardisasi: Kerangka tumpukan DMA-BUF menawarkan UAPI yang terdefinisi dengan baik. ION mengizinkan tanda khusus dan ID tumpukan yang mencegah pengembangan kerangka kerja pengujian umum karena implementasi ION setiap perangkat dapat berperilaku berbeda.

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

Latar belakang

Berikut ini adalah perbandingan singkat antara tumpukan ION dan DMA-BUF.

Kesamaan antara kerangka tumpukan ION dan DMA-BUF

  • Kerangka kerja heap ION dan DMA-BUF keduanya adalah eksportir DMA-BUF berbasis heap.
  • Keduanya membiarkan setiap heap menentukan pengalokasinya sendiri dan operasi DMA-BUF.
  • Kinerja alokasi serupa karena kedua skema membutuhkan IOCTL tunggal untuk alokasi.

Perbedaan antara kerangka kerja tumpukan ION dan DMA-BUF

tumpukan ION tumpukan 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 heap private flag. Heap DMA-BUF tidak mendukung heap private flags. Setiap jenis alokasi yang berbeda malah dilakukan dari tumpukan yang berbeda. Misalnya, varian tumpukan sistem yang di-cache dan tidak di-cache adalah tumpukan terpisah yang terletak di /dev/dma_heap/system dan /dev/dma_heap/system_uncached .
Heap ID/masker dan flag harus ditentukan untuk alokasi. Nama tumpukan digunakan untuk alokasi.

Bagian berikut mencantumkan komponen yang berhubungan dengan ION dan menjelaskan cara mengalihkannya ke kerangka kerja heap DMA-BUF.

Transisi driver kernel dari tumpukan ION ke DMA-BUF

Driver kernel mengimplementasikan tumpukan ION

Heap ION dan DMA-BUF memungkinkan setiap heap untuk mengimplementasikan pengalokasi dan operasi DMA-BUF-nya sendiri. Jadi, Anda dapat beralih dari implementasi heap ION ke implementasi heap DMA-BUF dengan menggunakan set API yang berbeda untuk mendaftarkan heap. Tabel ini menunjukkan API pendaftaran heap ION dan API heap DMA-BUF yang setara.

tumpukan ION tumpukan 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 heap private flags. Jadi setiap varian heap harus didaftarkan satu per satu menggunakan dma_heap_add() API. Untuk memfasilitasi berbagi kode, disarankan untuk mendaftarkan semua varian dari tumpukan yang sama dalam driver yang sama. Contoh dma-buf: system_heap ini menunjukkan implementasi varian yang di-cache dan tidak di-cache dari tumpukan sistem.

Gunakan templat contoh dma-buf: heaps: ini untuk membuat heap DMA-BUF dari awal.

Driver kernel mengalokasikan langsung dari tumpukan ION

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

Berikut ini menunjukkan API alokasi ION dalam kernel dan API alokasi heap DMA-BUF yang setara. Driver kernel dapat menggunakan dma_heap_find() API untuk menanyakan keberadaan heap. API mengembalikan pointer ke instance struct dma_heap , yang kemudian dapat diteruskan sebagai argumen ke dma_heap_buffer_alloc() API.

tumpukan ION tumpukan 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-BUFs

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

Transisi klien ruang pengguna ION ke tumpukan DMA-BUF

Untuk mempermudah transisi bagi klien ruang pengguna ION, tersedia perpustakaan abstraksi yang disebut libdmabufheap . libdmabufheap mendukung alokasi di tumpukan DMA-BUF dan tumpukan ION. Ini pertama-tama memeriksa apakah tumpukan DMA-BUF dari nama yang ditentukan ada dan jika tidak, jatuh kembali ke tumpukan ION yang setara, jika ada.

Klien harus menginisialisasi objek BufferAllocator selama inisialisasi alih-alih membuka /dev/ion using ion_open() . 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, alih-alih head ID/mask dan heap flag.
  • Ganti ion_alloc_fd() API, yang menggunakan heap mask dan argumen flag, dengan BufferAllocator::Alloc() API, yang mengambil nama heap.

Tabel ini mengilustrasikan perubahan ini dengan menunjukkan bagaimana libion dan libdmabufheap melakukan alokasi tumpukan sistem yang tidak di-cache.

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

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

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

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

Referensi implementasi Gralloc

Implementasi gralloc Hikey960 menggunakan libdmabufheap , sehingga Anda dapat menggunakannya sebagai implementasi referensi .

Tambahan uevent yang diperlukan

Untuk setiap heap DMA-BUF khusus perangkat baru yang dibuat, tambahkan entri baru ke file ueventd.rc perangkat. Contoh Pengaturan ini dibuat untuk mendukung tumpukan DMA-BUF menunjukkan bagaimana hal ini dilakukan untuk tumpukan sistem DMA-BUF.

Tambahan kebijakan yang diperlukan

Tambahkan izin kebijakan untuk memungkinkan klien ruang pengguna mengakses tumpukan DMA-BUF baru. Contoh penambahan izin yang diperlukan ini menunjukkan izin kebijakan yang dibuat untuk berbagai klien untuk mengakses tumpukan sistem DMA-BUF.

Mengakses tumpukan vendor dari kode kerangka kerja

Untuk memastikan kepatuhan Treble, kode kerangka kerja hanya dapat dialokasikan dari kategori tumpukan vendor yang telah disetujui sebelumnya.

Berdasarkan umpan balik yang diterima dari mitra, Google mengidentifikasi dua kategori tumpukan vendor yang harus diakses dari kode kerangka kerja:

  1. Tumpukan yang didasarkan pada tumpukan sistem dengan pengoptimalan kinerja khusus perangkat atau SoC.
  2. Tumpukan untuk dialokasikan dari memori yang dilindungi.

Tumpukan berdasarkan tumpukan sistem dengan perangkat atau pengoptimalan kinerja khusus SoC

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

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

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

Tumpukan untuk dialokasikan dari memori yang dilindungi

Implementasi heap aman harus spesifik 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 tumpukan ada, tes VTS memastikan bahwa alokasi dapat dibuat darinya.
  • Komponen kerangka diberikan akses ke tumpukan ini sehingga mereka dapat mengaktifkan penggunaan tumpukan melalui HAL Codec2/non-binderized, proses yang sama. Namun, fitur kerangka kerja Android generik tidak dapat bergantung padanya karena variabilitas dalam detail implementasinya. Jika implementasi heap aman generik ditambahkan ke Android Common Kernel di masa mendatang, implementasi tersebut harus menggunakan ABI yang berbeda untuk menghindari konflik dengan peningkatan perangkat.

Codec 2 pengalokasi untuk tumpukan DMA-BUF

Pengalokasi codec2 untuk antarmuka tumpukan DMA-BUF tersedia di AOSP.

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

Contoh aliran transisi untuk tumpukan ION

Untuk memperlancar transisi dari tumpukan ION ke DMA-BUF, libdmabufheap memungkinkan peralihan satu tumpukan pada satu waktu. Langkah-langkah berikut menunjukkan alur kerja yang disarankan untuk mentransisikan heap ION nonlegacy bernama my_heap yang mendukung satu flag, ION_FLAG_MY_FLAG .

Langkah1: Buat yang setara dengan tumpukan ION dalam kerangka kerja DMA-BUF. Dalam contoh ini, karena heap ION my_heap mendukung flag ION_FLAG_MY_FLAG , kami mendaftarkan dua heap DMA-BUF:

  • perilaku my_heap sama persis dengan perilaku tumpukan ION dengan tanda ION_FLAG_MY_FLAG dinonaktifkan.
  • perilaku my_heap_special sama persis dengan perilaku tumpukan ION dengan tanda ION_FLAG_MY_FLAG diaktifkan.

Langkah 2: Buat perubahan uevent untuk my_heap dan my_heap_special DMA-BUF baru. Pada titik ini, tumpukan terlihat sebagai /dev/dma_heap/my_heap dan /dev/dma_heap/my_heap_special , dengan izin yang dimaksud.

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

Sebagai 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 menyetel parameter nama heap ION ke kosong.

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

Jenis alokasi libion libdmabufheap
Alokasi dari my_heap dengan tanda ION_FLAG_MY_FLAG tidak disetel 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 set ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

Pada titik ini, klien berfungsi tetapi masih mengalokasikan dari tumpukan ION karena tidak memiliki izin kebijakan yang diperlukan untuk membuka tumpukan DMA-BUF.

Langkah 5: Buat izin kebijakan yang diperlukan klien untuk mengakses tumpukan DMA-BUF baru. Klien sekarang sepenuhnya siap untuk mengalokasikan dari tumpukan DMA-BUF baru.

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

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