Transisi dari Tumpukan ION ke DMA-BUF

Di Android 12, GKI 2.0 menggantikan pengalokasi 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 dilakukan dengan ION karena alokasi dari heap mana pun hanya memerlukan akses ke perangkat /dev/ion .
  • Stabilitas ABI: Tidak seperti ION, antarmuka IOCTL kerangka tumpukan DMA-BUF dijamin stabil ABI karena dipertahankan di kernel Linux hulu.
  • Standardisasi: Kerangka kerja tumpukan DMA-BUF menawarkan UAPI yang terdefinisi dengan baik. ION mengizinkan tanda khusus dan ID heap yang mencegah pengembangan kerangka pengujian umum karena penerapan ION setiap perangkat dapat berperilaku berbeda.

Cabang android12-5.10 dari Kernel Umum Android dinonaktifkan CONFIG_ION pada 1 Maret 2021 .

Latar belakang

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

Kesamaan antara kerangka tumpukan ION dan DMA-BUF

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

Perbedaan antara kerangka 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 tumpukan bendera pribadi. Tumpukan DMA-BUF tidak mendukung tanda tumpukan pribadi. Setiap jenis alokasi yang berbeda dilakukan dari tumpukan 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 tumpukan/mask dan bendera perlu ditentukan untuk alokasi. Nama heap digunakan untuk alokasi.

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

Transisi driver kernel dari tumpukan ION ke DMA-BUF

Driver kernel yang mengimplementasikan tumpukan ION

Baik heap ION maupun DMA-BUF memungkinkan setiap heap mengimplementasikan pengalokasi dan operasi DMA-BUFnya sendiri. Jadi, Anda dapat beralih dari implementasi heap ION ke implementasi heap DMA-BUF dengan menggunakan serangkaian API yang berbeda untuk mendaftarkan heap. Tabel ini menunjukkan API registrasi 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);

Tumpukan DMA-BUF tidak mendukung tanda tumpukan pribadi. Jadi setiap varian heap harus didaftarkan satu per satu menggunakan API dma_heap_add() . Untuk memfasilitasi berbagi kode, disarankan untuk mendaftarkan semua varian heap yang sama dalam driver yang sama. Contoh dma-buf: system_heap ini menunjukkan implementasi varian heap sistem yang di-cache dan tidak di-cache.

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

Driver kernel dialokasikan langsung dari tumpukan ION

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

Berikut ini menunjukkan API alokasi ION dalam kernel dan API alokasi heap DMA-BUF yang setara. Driver kernel dapat menggunakan API dma_heap_find() 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-BUF

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 memudahkan transisi bagi klien ruang pengguna ION, tersedia perpustakaan abstraksi yang disebut libdmabufheap . libdmabufheap mendukung alokasi di tumpukan DMA-BUF dan tumpukan ION. Pertama-tama ia memeriksa apakah tumpukan DMA-BUF dengan nama yang ditentukan ada dan jika tidak, akan dikembalikan ke tumpukan ION yang setara, jika ada.

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

Tabel ini mengilustrasikan perubahan ini dengan menunjukkan bagaimana libion ​​dan libdmabufheap melakukan alokasi heap 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 heap sistem yang tidak di-cache sedang menunggu persetujuan upstream tetapi sudah menjadi bagian dari cabang android12-5.10 .

Untuk mendukung peningkatan 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 berbasis nama .

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

Referensi implementasi Gralloc

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

Penambahan uevend yang diperlukan

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

Penambahan sepolicy yang diperlukan

Tambahkan izin sepolicy untuk memungkinkan klien ruang pengguna mengakses tumpukan DMA-BUF baru. Contoh penambahan izin yang diperlukan ini menunjukkan izin sepolicy 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 mengalokasikan dari kategori tumpukan vendor yang telah disetujui sebelumnya.

Berdasarkan masukan 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 pengoptimalan kinerja khusus perangkat atau SoC

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

  • CONFIG_DMABUF_HEAPS_SYSTEM dimatikan di gki_defconfig agar dapat menjadi modul vendor.
  • Uji kepatuhan VTS memastikan bahwa heap ada di /dev/dma_heap/system . Pengujian juga memverifikasi bahwa heap dapat dialokasikan, dan bahwa deskriptor file yang dikembalikan ( fd ) dapat dipetakan ke 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 secure heap harus spesifik vendor karena Android Common Kernel tidak mendukung implementasi secure heap umum.

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

Pengalokasi Codec 2 untuk tumpukan DMA-BUF

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

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

Contoh aliran transisi untuk heap 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 nonlegasi bernama my_heap yang mendukung satu tanda, ION_FLAG_MY_FLAG .

Langkah 1: Buat tumpukan ION yang setara dalam kerangka 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 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 uevend untuk tumpukan DMA-BUF my_heap dan my_heap_special yang baru. Pada titik ini, tumpukan 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 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.

Misalnya:

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 API MapNameToIonHeap() dengan parameter nama dan bendera, Anda dapat membuat pemetaan dari <ION heap mask, flag> ke nama heap DMA-BUF yang setara dengan mengatur 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 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 disetel 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 sepolicy yang diperlukan untuk membuka tumpukan DMA-BUF.

Langkah 5: Buat izin sepolicy yang diperlukan klien untuk mengakses tumpukan DMA-BUF baru. Klien sekarang telah dilengkapi sepenuhnya untuk mengalokasikan dari heap DMA-BUF baru.

Langkah 6: Verifikasi bahwa alokasi dilakukan dari tumpukan DMA-BUF baru dengan memeriksa logcat .

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