In Android 12, GKI 2.0 sostituisce l'allocatore ION con gli heap DMA-BUF per i seguenti motivi:
- Sicurezza: poiché ogni heap DMA-BUF è un dispositivo carattere separato, l'accesso
a ogni heap può essere controllato separatamente con sepolicy. Con ION non era possibile perché l'allocazione da qualsiasi heap richiedeva solo l'accesso al dispositivo
/dev/ion
. - Stabilità ABI: a differenza di ION, l'interfaccia IOCTL del framework di heap DMA-BUF è stabile in ABI perché viene mantenuta nel kernel Linux upstream.
- Standardizzazione: il framework degli heap DMA-BUF offre un'UAPI ben definita. ION consentiva flag e ID heap personalizzati che impedivano lo sviluppo di un framework di test comune perché l'implementazione di ION di ciascun dispositivo poteva comportarsi in modo diverso.
Il ramo android12-5.10
dell'Android Common Kernel è stato disattivato
CONFIG_ION
il 1° marzo 2021.
Background
Di seguito è riportato un breve confronto tra gli heap ION e DMA-BUF.
Somiglianze tra il framework degli heap ION e DMA-BUF
- I framework degli heap ION e DMA-BUF sono entrambi esportatori DMA-BUF basati su heap.
- Entrambi consentono a ogni heap di definire il proprio allocatore e le proprie operazioni DMA-BUF.
- Le prestazioni di allocazione sono simili perché entrambi gli schemi richiedono un singolo IOCTL per l'allocazione.
Differenze tra il framework heap ION e DMA-BUF
Heap ION | Heap DMA-BUF |
---|---|
Tutte le allocazioni ION vengono eseguite con /dev/ion .
|
Ogni heap DMA-BUF è un dispositivo a caratteri presente in /dev/dma_heap/<heap_name> .
|
ION supporta i flag privati dell'heap. | Gli heap DMA-BUF non supportano i flag privati heap. Ogni tipo diverso di allocazione viene invece eseguito da un heap diverso. Ad esempio, le varianti dell'heap di sistema memorizzate nella cache e non memorizzate nella cache sono heap distinti situati in /dev/dma_heap/system e /dev/dma_heap/system_uncached .
|
Per l'allocazione è necessario specificare l'ID/la maschera dell'heap e i flag. | Il nome dell'heap viene utilizzato per l'allocazione. |
Le sezioni seguenti elencano i componenti che gestiscono ION e descrivono come passare al framework degli heap DMA-BUF.
Eseguire la transizione dei driver del kernel dagli heap ION a DMA-BUF
Driver del kernel che implementano gli heap ION
Entrambi gli heap ION e DMA-BUF consentono a ogni heap di implementare i propri allocatori e operazioni DMA-BUF. Pertanto, puoi passare da un'implementazione dell'heap ION a un'implementazione dell'heap DMA-BUF utilizzando un insieme diverso di API per registrare l'heap. Questa tabella mostra le API di registrazione dell'heap ION e le API di heap DMA-BUF equivalenti.
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);
|
Gli heap DMA-BUF non supportano i flag privati dell'heap. Pertanto, ogni variante dell'heap deve essere registrata singolarmente utilizzando l'API dma_heap_add()
. Per facilitare la condivisione del codice, è consigliabile registrare tutte le varianti dello stesso heap nello stesso driver.
Questo esempio dma-buf: system_heap mostra l'implementazione delle varianti dell'heap di sistema memorizzate e non memorizzate nella cache.
Utilizza questo modello dma-buf: heaps: example per creare un heap DMA-BUF da zero.
Driver del kernel che allocano direttamente dagli heap ION
Il framework degli heap DMA-BUF offre anche un'interfaccia di allocazione per i client in-kernel. Anziché specificare la maschera e i flag dell'heap per selezionare il tipo di allocazione, l'interfaccia offerta dagli heap DMA-BUF accetta come input un nome dell'heap.
Di seguito è riportata l'API di allocazione ION in-kernel e le API di allocazione heap DMA-BUF equivalenti. I driver del kernel possono utilizzare l'API dma_heap_find()
per eseguire query sull'esistenza di un heap. L'API restituisce un puntatore a un'istanza di
struct dma_heap, che può essere passato come argomento all'API
dma_heap_buffer_alloc()
.
Heap ION | heap DMA-BUF |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
|
|
Driver del kernel che utilizzano DMA-BUF
Non sono necessarie modifiche per i driver che importano solo DMA-BUF, perché un buffer allocato da un heap ION si comporta esattamente come un buffer allocato da un heap DMA-BUF equivalente.
Eseguire la transizione dei client nello spazio utente di ION agli heap DMA-BUF
Per semplificare la transizione per i client nello spazio utente di ION, è disponibile una libreria di astrazione chiamata libdmabufheap
. libdmabufheap
supporta l'allocazione negli heap DMA-BUF
e negli heap ION. Innanzitutto, controlla se esiste un heap DMA-BUF del nome specificato
e, in caso contrario, passa a un heap ION equivalente, se esistente.
I client devono inizializzare un oggetto
BufferAllocator
durante l'inizializzazione anziché aprire /dev/ion using
ion_open()
. Questo accade perché i descrittori file creati aprendo /dev/ion
e /dev/dma_heap/<heap_name>
sono gestiti internamente dall'oggetto BufferAllocator
.
Per passare da libion
a libdmabufheap
, modifica il comportamento dei client come segue:
- Tieni traccia del nome dell'heap da utilizzare per l'allocazione, al posto dell'ID/mask head e del flag dell'heap.
- Sostituisci l'API
ion_alloc_fd()
, che richiede una maschera heap e un argomento flag, con l'APIBufferAllocator::Alloc()
, che utilizza invece un nome heap.
Questa tabella illustra queste modifiche mostrando come libion
e libdmabufheap
effettuano un'allocazione dell'heap di sistema non memorizzata nella cache.
Tipo di allocazione | libion | libdmabufheap |
---|---|---|
Allocazione memorizzata nella cache dall'heap di sistema | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd)
|
allocator->Alloc("system", size)
|
Allocazione non memorizzata nella cache dall'heap di sistema | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd)
|
allocator->Alloc("system-uncached", size)
|
La variante dell'heap di sistema non memorizzata nella cache è in attesa di approvazione a monte, ma fa già parte del ramo android12-5.10
.
Per supportare l'upgrade dei dispositivi, l'API MapNameToIonHeap()
consente di mappare un nome heap ai parametri dell'heap ION (nome dell'heap o maschera e flag) per consentire a queste interfacce di utilizzare allocazioni basate sul nome. Ecco un esempio di allocazione basata sul nome.
È disponibile la documentazione per ogni API esposta da
libdmabufheap
. La libreria espone anche un file di intestazione per l'utilizzo da parte dei client C.
Implementazione di riferimento di Gralloc
L'implementazione di gralloc di Hikey960 utilizza libdmabufheap
, quindi puoi utilizzarla come
implementazione di riferimento.
Aggiunta di ueventd obbligatoria
Per ogni nuovo heap DMA-BUF specifico del dispositivo creato, aggiungi una nuova voce al
file ueventd.rc
del dispositivo.
L'esempio di configurazione per supportare gli heap DMA-BUF mostra come questa operazione viene eseguita per l'heap del sistema DMA-BUF.
Aggiunta di sepolicy obbligatoria
Aggiungi autorizzazioni sepolicy per consentire a un client dello spazio utente di accedere a un nuovo heap DMA-BUF. Questo esempio di aggiunta delle autorizzazioni obbligatorie mostra le autorizzazioni sepolicy create per vari client per accedere all'heap di sistema DMA-BUF.
Accedere agli heap del fornitore dal codice del framework
Per garantire la conformità a Treble, il codice del framework può eseguire l'allocazione solo da categorie di heap del fornitore preapprovate.
In base al feedback ricevuto dai partner, Google ha identificato due categorie di heap di fornitori a cui è necessario accedere dal codice del framework:
- Heap basate sull'heap di sistema con ottimizzazioni del rendimento specifiche per il dispositivo o il SoC.
- Heap da allocare dalla memoria protetta.
Heap basati sull'heap di sistema con ottimizzazioni delle prestazioni specifiche per dispositivo o SoC
Per supportare questo caso d'uso, l'implementazione dell'heap del sistema di heap DMA-BUF predefinito può essere sostituita.
CONFIG_DMABUF_HEAPS_SYSTEM
è disattivato ingki_defconfig
per consentirgli di essere un modulo del fornitore.- I test di conformità VTS assicurano che l'heap esista in
/dev/dma_heap/system
. I test verificano inoltre che l'heap possa essere allocato e che il descrittore file restituito (fd
) possa essere mappato in memoria (mmapped) dallo spazio utente.
I punti precedenti valgono anche per la variante non memorizzata nella cache dell'heap di sistema, anche se la sua esistenza non è obbligatoria per i dispositivi completamente coerenti con l'I/O.
Heap da allocare dalla memoria protetta
Le implementazioni dell'heap sicuro devono essere specifiche del fornitore, poiché il kernel Android Common non supporta un'implementazione generica dell'heap sicuro.
- Registra le implementazioni specifiche del fornitore come
/dev/dma_heap/system-secure<vendor-suffix>
. - Queste implementazioni dell'heap sono facoltative.
- Se gli heap esistono, i test VTS assicurano che sia possibile effettuare allocazioni da essi.
- Ai componenti del framework viene fornito l'accesso a questi heap in modo che possano consentire l'utilizzo degli heap tramite gli HAL Codec2 HAL/lo stesso processo non binderizzati. Tuttavia, le funzionalità generiche del framework Android non possono dipendere da queste librerie a causa della variabilità dei dettagli di implementazione. Se in futuro verrà aggiunta al kernel comune di Android un'implementazione generica dell'heap sicuro, dovrà utilizzare un ABI diverso per evitare conflitti con i dispositivi in fase di upgrade.
Allocator codec 2 per gli heap DMA-BUF
In AOSP è disponibile un allocatore codec2 per l'interfaccia degli heap DMA-BUF.
L'interfaccia del repository dei componenti che consente di specificare i parametri dell'heap dall'HAL C2 è disponibile con l'allocatore dell'heap DMA-BUF C2.
Esempio di flusso di transizione per un heap ION
Per rendere più agevole la transizione dagli heap ION a quelli DMA-BUF, libdmabufheap
consente di cambiare un heap alla volta. I passaggi che seguono mostrano un flusso di lavoro suggerito per la transizione di un heap ION non legacy denominato my_heap
che supporta un flag, ION_FLAG_MY_FLAG
.
Passaggio 1: crea gli equivalenti dell'heap ION nel framework DMA-BUF. In questo esempio, poiché l'heap ION my_heap
supporta un flag ION_FLAG_MY_FLAG
, registriamo due heap DMA-BUF:
- Il comportamento di
my_heap
corrisponde esattamente a quello dell'heap ION con il flagION_FLAG_MY_FLAG
disattivato. - Il comportamento di
my_heap_special
corrisponde esattamente a quello dell'heap ION con il flagION_FLAG_MY_FLAG
abilitato.
Passaggio 2: crea le modifiche a ueventd per i nuovi heap DMA-BUF my_heap
e
my_heap_special
. A questo punto, gli heap sono visibili come
/dev/dma_heap/my_heap
e /dev/dma_heap/my_heap_special
, con
le autorizzazioni previste.
Passaggio 3: per i client che eseguono l'allocazione da my_heap
, modifica i file make per collegarli a libdmabufheap
. Durante l'inizializzazione del client, crea un oggetto
BufferAllocator
e utilizza l'API MapNameToIonHeap()
per mappare la combinazione
<ION heap name/mask, flag>
ai nomi dell'heap DMA-BUF equivalenti.
Ad esempio:
allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )
Anziché utilizzare l'API MapNameToIonHeap()
con i parametri name e flag, puoi creare il mapping da <ION heap mask, flag>
ai nomi heap DMA-BUF equivalenti impostando il parametro del nome heap ION su vuoto.
Passaggio 4: sostituisci le chiamate ion_alloc_fd()
con
BufferAllocator::Alloc()
utilizzando il nome dell'heap appropriato.
Tipo di allocazione | leone | libdmabufheap |
---|---|---|
Allokazione da my_heap con flag
ION_FLAG_MY_FLAG non impostato
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd)
|
allocator->Alloc("my_heap", size)
|
Allokazione da my_heap con flag impostato su ION_FLAG_MY_FLAG
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP,
ION_FLAG_MY_FLAG, &fd)
|
allocator->Alloc("my_heap_special", size)
|
A questo punto, il client è funzionale, ma esegue ancora l'allocazione dall'heap ION perché non dispone delle autorizzazioni sepolicy necessarie per aprire l'heap DMA-BUF.
Passaggio 5: crea le autorizzazioni sepolicy necessarie per consentire al client di accedere ai nuovi heap DMA-BUF. Il client è ora completamente equipaggiato per l'allocazione dal nuovo heap DMA-BUF.
Passaggio 6: verifica che le allocazioni vengano eseguite dal nuovo heap DMA-BUF esaminando logcat.
Passaggio 7: disattiva l'heap ION my_heap
nel kernel. Se il codice client
non deve supportare l'upgrade dei dispositivi (i cui kernel potrebbero supportare solo gli heap
ION), puoi anche rimuovere le chiamate MapNameToIonHeap()
.