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 carattere 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à dell'ABI: a differenza di ION, l'interfaccia IOCTL del framework dei segmenti DMA-BUF è stabile a livello di ABI perché viene gestita nel kernel Linux upstream.
- Standardizzazione: il framework degli heap DMA-BUF offre un'API U ben definita. ION consentiva flag personalizzati e ID heap che impedivano lo sviluppo di un framework di test comune perché l'implementazione di ION di ogni dispositivo poteva comportarsi in modo diverso.
Il ramo android12-5.10
del kernel comune Android è stato disattivato
CONFIG_ION
il giorno 1° marzo 2021.
Sfondo
Di seguito è riportato un breve confronto tra gli heap ION e DMA-BUF.
Somiglianze tra il framework ION e DMA-BUF heaps
- I framework ION e DMA-BUF heaps sono entrambi esportatori DMA-BUF basati sull'heap.
- Entrambi consentono a ogni heap di definire le proprie operazioni di allocatore e DMA-BUF.
- Il rendimento dell'allocazione è simile perché entrambi gli schemi richiedono un singolo IOCTL per l'allocazione.
Differenze tra il framework di heap ION e DMA-BUF
ION heaps | Heap DMA-BUF |
---|---|
Tutte le allocazioni ION vengono eseguite con /dev/ion .
|
Ogni heap DMA-BUF è un dispositivo carattere 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 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 separati che si trovano in /dev/dma_heap/system e /dev/dma_heap/system_uncached .
|
Per l'allocazione devono essere specificati la maschera e i flag dell'heap. | 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.
Eseguire la transizione dei driver del kernel da ION a heap DMA-BUF
Driver del kernel che implementano heap ION
Gli heap ION e DMA-BUF consentono a ciascun heap di implementare allocatori e operazioni DMA-BUF personalizzati. In questo modo, puoi passare da un'implementazione dell'heap ION a un'implementazione dell'heap DMA-BUF utilizzando un diverso insieme di API per registrare l'heap. Questa tabella mostra le API di registrazione dell'heap ION e le API di heap DMA-BUF equivalenti.
ION heaps | 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 all'interno dello stesso driver.
Questo esempio di dma-buf: system_heap
mostra l'implementazione delle varianti memorizzate nella cache e non memorizzate nella cache dell'heap di sistema.
Utilizza questo template di esempio dma-buf: heaps per creare un heap DMA-BUF da zero.
Driver del kernel che allocano direttamente dagli heap ION
Il framework heap DMA-BUF offre anche un'interfaccia di allocazione per i client in-kernel. Invece di specificare la maschera e i flag dell'heap per selezionare il tipo di allocazione, l'interfaccia offerta dagli heap DMA-BUF accetta un nome heap come input.
Di seguito sono riportate l'API di allocazione ION in-kernel e le API di allocazione dell'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 passata come argomento all'API
dma_heap_buffer_alloc()
.
ION heaps | 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 dello spazio utente di ION agli heap DMA-BUF
Per semplificare la transizione per i client user-space di ION, è disponibile una libreria di astrazione chiamata libdmabufheap
. libdmabufheap
supporta l'allocazione negli heap DMA-BUF
e negli heap ION. Controlla innanzitutto se esiste un heap DMA-BUF con il nome specificato
e, in caso contrario, esegue il fallback 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 perché i descrittori di file creati aprendo
/dev/ion
e /dev/dma_heap/<heap_name>
vengono 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, anziché dell'ID/maschera dell'intestazione e del flag dell'heap.
- Sostituisci l'API
ion_alloc_fd()
, che accetta un argomento di maschera heap e 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 senza memorizzazione 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 senza cache
è in attesa di approvazione upstream, 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 heap ION (nome o maschera e flag dell'heap) 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.
Aggiunte obbligatorie a ueventd
Per ogni nuovo heap DMA-BUF specifico del dispositivo creato, aggiungi una nuova voce al file
ueventd.rc
del dispositivo.
Questo esempio di configurazione di ueventd per supportare gli heap DMA-BUF
mostra come viene eseguita questa operazione per l'heap di sistema DMA-BUF.
Aggiunte obbligatorie a sepolicy
Aggiungi le autorizzazioni sepolicy per consentire a un client userspace 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 dei fornitori dal codice del framework
Per garantire la conformità a Treble, il codice del framework può allocare solo da categorie preapprovate di heap del fornitore.
In base al feedback ricevuto dai partner, Google ha identificato due categorie di heap del fornitore a cui è necessario accedere dal codice del framework:
- Heap basati sull'heap di sistema con ottimizzazioni delle prestazioni 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 il dispositivo o il SoC
Per supportare questo caso d'uso, è possibile sostituire l'implementazione dell'heap del sistema DMA-BUF predefinito.
CONFIG_DMABUF_HEAPS_SYSTEM
è disattivato ingki_defconfig
per consentire che sia 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 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 comune di Android 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.
- I componenti del framework hanno accesso a questi heap, in modo da poter attivare l'utilizzo degli heap tramite le HAL Codec2/non binderizzate e le HAL nello stesso processo. Tuttavia, le funzionalità generiche del framework Android non possono dipendere da loro a causa della variabilità dei dettagli di implementazione. Se in futuro verrà aggiunta un'implementazione generica dell'heap sicuro al kernel comune Android, dovrà utilizzare un'ABI diversa per evitare conflitti con l'upgrade dei dispositivi.
Allocatore Codec 2 per heap DMA-BUF
In AOSP è disponibile un allocatore codec2 per l'interfaccia heap DMA-BUF.
L'interfaccia dell'archivio dei componenti che consente di specificare i parametri dell'heap da C2 HAL è disponibile con l'allocatore dell'heap C2 DMA-BUF.
Flusso di transizione di esempio per un heap ION
Per semplificare la transizione dagli heap ION a DMA-BUF, libdmabufheap
consente
di passare da un heap all'altro. I seguenti passaggi 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 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
attivato.
Passaggio 2: crea le modifiche di ueventd per i nuovi heap my_heap
e
my_heap_special
DMA-BUF. 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 allocano da my_heap
, modifica i makefile
per collegarli a libdmabufheap
. Durante l'inizializzazione del client, crea un'istanza di un oggetto BufferAllocator
e utilizza l'API MapNameToIonHeap()
per mappare la combinazione <ION heap name/mask, flag>
ai nomi 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 la mappatura da
<ION heap mask, flag>
a nomi di heap DMA-BUF equivalenti
impostando il parametro del nome dell'heap ION su vuoto.
Passaggio 4: sostituisci le chiamate ion_alloc_fd()
con BufferAllocator::Alloc()
utilizzando il nome dell'heap appropriato.
Tipo di allocazione | libion | 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 è funzionale, ma continua ad allocare dalla heap ION perché non dispone delle autorizzazioni sepolicy richieste per aprire la 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 attrezzato per allocare dall'heap DMA-BUF.
Passaggio 6: verifica che le allocazioni avvengano 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 heap ION), puoi anche rimuovere le invocazioni MapNameToIonHeap()
.