In Android 12, GKI 2.0 sostituisce l'allocatore ION con heap DMA-BUF per i seguenti motivi:
- Sicurezza: poiché ogni heap DMA-BUF è un dispositivo a caratteri separato, l'accesso a ogni heap può essere controllato separatamente con sepolicy. Ciò non era possibile con ION 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 heap DMA-BUF è garantita come stabile ABI perché è mantenuta nel kernel Linux upstream.
- Standardizzazione: il framework degli heap DMA-BUF offre una UAPI ben definita. ION consentiva flag personalizzati e ID heap che impedivano lo sviluppo di un framework di test comune perché l'implementazione ION di ciascun dispositivo poteva comportarsi in modo diverso.
Il ramo android12-5.10
del kernel comune Android ha disabilitato CONFIG_ION
il 1° marzo 2021 .
Sfondo
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 heap ION e DMA-BUF sono entrambi esportatori DMA-BUF basati su heap.
- Entrambi consentono a ciascun heap di definire il proprio allocatore e le operazioni DMA-BUF.
- Le prestazioni di allocazione sono simili perché entrambi gli schemi necessitano di un singolo IOCTL per l'allocazione.
Differenze tra il framework degli heap ION e DMA-BUF
Cumuli di IONI | Cumuli 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 dell'heap. Ogni diverso tipo di allocazione viene invece eseguito da un heap diverso. Ad esempio, le varianti dell'heap di sistema memorizzato nella cache e non memorizzato nella cache sono heap separati situati in /dev/dma_heap/system e /dev/dma_heap/system_uncached . |
È necessario specificare l'ID/maschera e i flag dell'heap per l'allocazione. | Il nome dell'heap viene utilizzato per l'allocazione. |
Le sezioni seguenti elencano i componenti che gestiscono ION e descrivono come passarli al framework di heap DMA-BUF.
Transizione dei driver del kernel dagli heap ION agli heap DMA-BUF
Driver del kernel che implementano gli heap ION
Sia gli heap ION che quelli DMA-BUF consentono a ciascun heap di implementare i propri allocatori e le operazioni DMA-BUF. Quindi puoi passare da un'implementazione dell'heap ION a un'implementazione dell'heap DMA-BUF utilizzando un diverso set di API per registrare l'heap. Questa tabella mostra le API di registrazione dell'heap ION e le relative API dell'heap DMA-BUF equivalenti.
Cumuli di IONI | Cumuli 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. Quindi ogni variante dell'heap deve essere registrata individualmente utilizzando l'API dma_heap_add()
. Per facilitare la condivisione del codice, si consiglia di registrare tutte le varianti dello stesso heap all'interno dello stesso driver. Questo esempio dma-buf: system_heap mostra l'implementazione delle varianti memorizzate nella cache e non memorizzate nella cache dell'heap di sistema.
Utilizza questo dma-buf: heaps: modello di esempio per creare un heap DMA-BUF da zero.
Driver del kernel che eseguono l'allocazione diretta dagli heap ION
Il framework degli heap DMA-BUF offre anche un'interfaccia di allocazione per i client in-kernel. Invece di specificare la maschera dell'heap e i flag per selezionare il tipo di allocazione, l'interfaccia offerta dagli heap DMA-BUF accetta un nome di heap come input.
Di seguito viene mostrata l'API di allocazione ION nel kernel e le relative API di allocazione heap DMA-BUF equivalenti. I driver del kernel possono utilizzare l'API dma_heap_find()
per interrogare l'esistenza di un heap. L'API restituisce un puntatore a un'istanza della struttura dma_heap , che può quindi essere passata come argomento all'API dma_heap_buffer_alloc()
.
Cumuli di IONI | Cumuli 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 richieste modifiche per i driver che importano solo DMA-BUF, poiché un buffer allocato da un heap ION si comporta esattamente come un buffer allocato da un heap DMA-BUF equivalente.
Transizione dei client dello spazio utente di ION agli heap DMA-BUF
Per facilitare la transizione per i client dello 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 con il nome specificato e, in caso contrario, ritorna a un heap ION equivalente, se ne esiste uno.
I client dovrebbero inizializzare un oggetto BufferAllocator
durante l'inizializzazione invece di aprire /dev/ion using ion_open()
. Questo perché i descrittori di file creati aprendo /dev/ion
e /dev/dma_heap/<heap_name>
sono gestiti internamente dall'oggetto BufferAllocator
.
Per passare da libion
a libdmabufheap
, modificare il comportamento dei client come segue:
- Tieni traccia del nome dell'heap da utilizzare per l'allocazione, anziché dell'ID/maschera dell'intestazione e del flag dell'heap.
- Sostituisci l'API
ion_alloc_fd()
, che accetta una maschera heap e un argomento flag, con l'APIBufferAllocator::Alloc()
, che accetta invece un nome heap.
Questa tabella illustra queste modifiche mostrando come libion
e libdmabufheap
eseguono un'allocazione dell'heap di sistema non memorizzato nella cache.
Tipo di assegnazione | libico | 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 memorizzato nella cache è in attesa di approvazione a monte, ma fa già parte del ramo android12-5.10
.
Per supportare l'aggiornamento dei dispositivi, l'API MapNameToIonHeap()
consente di mappare un nome heap sui parametri heap ION (nome/maschera heap e flag) per consentire a tali interfacce di utilizzare anche allocazioni basate sul nome. Di seguito è riportato un esempio di allocazione basata sul nome .
È disponibile la documentazione per ogni API esposta da libdmabufheap
. La libreria espone anche un file di intestazione utilizzabile dai client C.
Implementazione di Galloc di riferimento
L'implementazione gralloc di Hikey960 utilizza libdmabufheap
, quindi puoi usarla come implementazione di riferimento .
Aggiunte uventd richieste
Per ogni nuovo heap DMA-BUF specifico del dispositivo creato, aggiungere una nuova voce al file ueventd.rc
del dispositivo. Questo esempio di installazione di eventi per supportare gli heap DMA-BUF illustra come eseguire questa operazione per l'heap di sistema DMA-BUF.
Aggiunte sepolicy richieste
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 richieste mostra le autorizzazioni sepolicy create per vari client per accedere all'heap di sistema DMA-BUF.
Accesso agli heap dei fornitori dal codice del framework
Per garantire la conformità Treble, il codice framework può allocare solo da categorie pre-approvate di heap del fornitore.
Sulla base del feedback ricevuto dai partner, Google ha identificato due categorie di heap dei fornitori a cui è necessario accedere dal codice del framework:
- Heap basati sull'heap di sistema con ottimizzazioni delle prestazioni specifiche del dispositivo o del SoC.
- Heap da allocare dalla memoria protetta.
Heap basati sull'heap del sistema con ottimizzazioni delle prestazioni specifiche del dispositivo o del SoC
Per supportare questo caso d'uso, è possibile sovrascrivere l'implementazione heap del sistema heap DMA-BUF predefinito.
-
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 anche che l'heap possa essere allocato e che il descrittore di file restituito (fd
) possa essere mappato in memoria (mmapped) dallo spazio utente.
I punti precedenti valgono anche per la variante senza cache dell'heap di sistema, sebbene la sua esistenza non sia obbligatoria per i dispositivi con coerenza I/O completa.
Heap da allocare dalla memoria protetta
Le implementazioni dell'heap sicuro devono essere specifiche del fornitore poiché Android Common Kernel non supporta un'implementazione generica dell'heap sicuro.
- Registra le implementazioni specifiche del tuo fornitore come
/dev/dma_heap/system-secure<vendor-suffix>
. - Queste implementazioni dell'heap sono facoltative.
- Se gli heap esistono, i test VTS assicurano che da essi possano essere effettuate le allocazioni.
- Ai componenti del framework viene fornito l'accesso a questi heap in modo che possano abilitare l'utilizzo degli heap tramite HAL Codec2/HAL non binderizzati e con lo stesso processo. Tuttavia, le funzionalità generiche del framework Android non possono dipendere da loro a causa della variabilità nei dettagli di implementazione. Se in futuro un'implementazione generica dell'heap sicuro viene aggiunta al kernel comune di Android, dovrà utilizzare un'ABI diversa per evitare conflitti con i dispositivi di aggiornamento.
Allocatore Codec 2 per heap DMA-BUF
Un allocatore codec2 per l'interfaccia heap DMA-BUF è disponibile in AOSP.
L'interfaccia dell'archivio componenti che consente di specificare i parametri heap dall'HAL C2 è disponibile con l'allocatore heap C2 DMA-BUF.
Flusso di transizione di esempio per un heap ION
Per facilitare la transizione dagli heap ION agli heap DMA-BUF, libdmabufheap
consente di passare da un heap alla volta. I passaggi seguenti dimostrano 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: creare 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
my_heap
corrisponde esattamente al comportamento dell'heap ION con il flagION_FLAG_MY_FLAG
disabilitato. - Il comportamento di
my_heap_special
corrisponde esattamente al comportamento dell'heap ION con il flagION_FLAG_MY_FLAG
abilitato.
Passaggio 2: creare le modifiche ueventd per i nuovi my_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 effettuano l'allocazione da my_heap
, modificare i propri makefile per collegarsi a libdmabufheap
. Durante l'inizializzazione del client, creare un'istanza di un oggetto BufferAllocator
e utilizzare l'API MapNameToIonHeap()
per mappare la combinazione <ION heap name/mask, flag>
ai nomi heap DMA-BUF equivalenti.
Per esempio:
allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )
Invece di utilizzare l'API MapNameToIonHeap()
con i parametri name e flag, è possibile creare la mappatura da <ION heap mask, flag>
ai nomi heap DMA-BUF equivalenti impostando il parametro del nome heap ION su vuoto.
Passaggio 4: sostituire le invocazioni ion_alloc_fd()
con BufferAllocator::Alloc()
utilizzando il nome heap appropriato.
Tipo di allocazione | libico | libdmabufheap |
---|---|---|
Allocazione 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 |
Allocazione da my_heap con flag ION_FLAG_MY_FLAG impostato | 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 è funzionante ma sta ancora effettuando l'allocazione dall'heap ION perché non dispone delle autorizzazioni sepolicy necessarie per aprire l'heap DMA-BUF.
Passaggio 5: creare le autorizzazioni sepolicy richieste affinché il client possa accedere ai nuovi heap DMA-BUF. Il client è ora completamente attrezzato per allocare dal nuovo heap DMA-BUF.
Passaggio 6: verificare che le allocazioni avvengano dal nuovo heap DMA-BUF esaminando logcat .
Passaggio 7: disabilitare l'heap ION my_heap
nel kernel. Se il codice client non deve supportare l'aggiornamento dei dispositivi (i cui kernel potrebbero supportare solo heap ION), puoi anche rimuovere le invocazioni MapNameToIonHeap()
.