In Android 12 ersetzt GKI 2.0 den ION-Allocator aus folgenden Gründen durch DMA-BUF-Heaps:
- Sicherheit: Da jeder DMA-BUF-Heap ein separates Zeichengerät ist, kann der Zugriff auf jeden Heap mit sepolicy separat gesteuert werden. Das war mit ION nicht möglich, da die Zuordnung aus einem beliebigen Heap nur Zugriff auf das
/dev/ion
-Gerät erforderte. - ABI-Stabilität: Im Gegensatz zu ION ist die IOCTL-Schnittstelle des DMA-BUF-Haufen-Frameworks ABI-stabil, da sie im Upstream-Linux-Kernel gepflegt wird.
- Standardisierung: Das DMA-BUF-Heap-Framework bietet eine klar definierte UAPI. ION erlaubte benutzerdefinierte Flags und Heap-IDs, die die Entwicklung eines gemeinsamen Testframeworks verhinderten, da sich die ION-Implementierung jedes Geräts unterschiedlich verhalten konnte.
Der android12-5.10
-Zweig des Android Common Kernel wurde am 1. März 2021CONFIG_ION
deaktiviert.
Hintergrund
Im Folgenden wird ION mit DMA-BUF-Haufen verglichen.
Ähnlichkeiten zwischen dem ION- und dem DMA-BUF-Heap-Framework
- Die ION- und DMA-BUF-Heap-Frameworks sind beide heapbasierte DMA-BUF-Exporteure.
- Bei beiden kann jeder Heap seinen eigenen Allocator und DMA-BUF-Vorgänge definieren.
- Die Allokationsleistung ist ähnlich, da beide Schemata für die Allokation eine einzelne IOCTL benötigen.
Unterschiede zwischen dem ION- und dem DMA-BUF-Heap-Framework
ION-Haufen | DMA-BUF-Heaps |
---|---|
Alle ION-Zuweisungen werden mit /dev/ion abgeschlossen.
|
Jeder DMA-BUF-Haufen ist ein Zeichengerät, das unter /dev/dma_heap/<heap_name> vorhanden ist.
|
ION unterstützt Flags für den privaten Heap. | DMA-BUF-Heaps unterstützen keine privaten Heap-Flags. Jede Art der Zuordnung erfolgt stattdessen über einen anderen Heap. Die im Cache gespeicherten und nicht zwischengespeicherten System-Heap-Varianten sind beispielsweise separate Heaps, die sich unter /dev/dma_heap/system und /dev/dma_heap/system_uncached befinden.
|
Für die Zuordnung müssen Heap-ID/-Maske und Flags angegeben werden. | Der Heap-Name wird für die Zuordnung verwendet. |
In den folgenden Abschnitten werden die Komponenten aufgeführt, die mit ION zu tun haben, und beschrieben, wie sie auf das DMA-BUF-Heap-Framework umgestellt werden.
Kerneltreiber von ION- zu DMA-BUF-Haufen migrieren
Kerneltreiber, die ION-Heaps implementieren
Sowohl ION- als auch DMA-BUF-Stapel ermöglichen es jedem Stapel, eigene Allocatoren und DMA-BUF-Vorgänge zu implementieren. Sie können also von einer ION-Heap-Implementierung zu einer DMA-BUF-Heap-Implementierung wechseln, indem Sie einen anderen Satz von APIs zum Registrieren des Heaps verwenden. In dieser Tabelle sind die ION-Heap-Registrierungs-APIs und ihre entsprechenden DMA-BUF-Heap-APIs aufgeführt.
ION-Heaps | DMA-BUF-Stapel |
---|---|
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);
|
DMA-BUF-Haufen unterstützen keine privaten Flags für Haufen. Daher muss jede Variante des Heaps einzeln über die dma_heap_add()
API registriert werden. Wir empfehlen, alle Varianten desselben Heaps innerhalb desselben Treibers zu registrieren, um die Codefreigabe zu erleichtern.
Dieses Beispiel dma-buf: system_heap zeigt die Implementierung der Varianten mit und ohne Cache des Systemheaps.
Verwenden Sie diese dma-buf: heaps: Beispielvorlage, um einen DMA-BUF-Haufen von Grund auf neu zu erstellen.
Kerneltreiber, die direkt aus ION-Haufen zuweisen
Das DMA-BUF-Heap-Framework bietet außerdem eine Allokationsschnittstelle für In-Kernel-Clients. Anstatt die Heap-Maske und die Flags anzugeben, um den Zuweisungstyp auszuwählen, verwendet die von DMA-BUF-Heaps angebotene Schnittstelle einen Heap-Namen als Eingabe.
Im Folgenden sind die ION-Allokations-API im Kernel und die entsprechenden DMA-BUF-Heap-Allokations-APIs zu sehen. Kerneltreiber können die dma_heap_find()
API verwenden, um die Existenz eines Heaps abzufragen. Die API gibt einen Zeiger auf eine Instanz von struct dma_heap zurück, der dann als Argument an die API dma_heap_buffer_alloc()
übergeben werden kann.
ION-Haufen | DMA-BUF-Stapel |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
|
|
Kerneltreiber, die DMA-BUFs verwenden
Für Treiber, die nur DMA-BUFs importieren, sind keine Änderungen erforderlich, da sich ein aus einem ION-Heap zugewiesener Puffer genau so verhält wie ein aus einem entsprechenden DMA-BUF-Heap zugewiesener Puffer.
User-Space-Clients von ION auf DMA-BUF-Haufen umstellen
Um den Übergang für User-Space-Clients von ION zu erleichtern, ist eine Abstraktionsbibliothek namens libdmabufheap
verfügbar. libdmabufheap
unterstützt die Zuweisung in DMA-BUF- und ION-Heaps. Zuerst wird geprüft, ob ein DMA-BUF-Heap des angegebenen Namens existiert. Falls nicht, wird auf einen entsprechenden ION-Heap zurückgegriffen, sofern vorhanden.
Clients sollten während der Initialisierung ein BufferAllocator
-Objekt initialisieren, anstatt /dev/ion using
ion_open()
zu öffnen. Das liegt daran, dass Dateideskriptoren, die durch das Öffnen von /dev/ion
und /dev/dma_heap/<heap_name>
erstellt werden, intern vom BufferAllocator
-Objekt verwaltet werden.
Wenn Sie von libion
zu libdmabufheap
wechseln möchten, ändern Sie das Verhalten der Clients so:
- Behalten Sie den Heap-Namen im Auge, der für die Zuordnung verwendet werden soll, anstelle der Kopf-ID/-Maske und des Heap-Flags.
- Ersetzen Sie die
ion_alloc_fd()
API, die eine Heapmaske und ein Flag-Argument annimmt, durch dieBufferAllocator::Alloc()
API, die stattdessen einen Heapnamen annimmt.
In dieser Tabelle werden diese Änderungen veranschaulicht, indem gezeigt wird, wie libion
und libdmabufheap
eine nicht im Cache gespeicherte Systemheap-Zuweisung vornehmen.
Art der Zuweisung | libion | libdmabufheap |
---|---|---|
Im Cache gespeicherte Zuordnung aus System-Heap | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd)
|
allocator->Alloc("system", size)
|
Nicht zwischengespeicherte Zuweisung aus dem System-Heap | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd)
|
allocator->Alloc("system-uncached", size)
|
Die Variante des nicht im Cache befindlichen System-Heaps wartet noch auf die Genehmigung, ist aber bereits Teil des android12-5.10
-Branches.
Zur Unterstützung des Upgrades von Geräten können Sie mit der MapNameToIonHeap()
API einen Heap-Namen auf ION-Heap-Parameter (Heap-Name oder Maske und Flags) abbilden, damit diese Schnittstellen namenbasierte Zuordnungen verwenden können. Hier ein Beispiel für eine namensbasierte Zuweisung.
Die Dokumentation für alle von libdmabufheap
freigegebenen APIs ist verfügbar. Die Bibliothek stellt auch eine Headerdatei für die Verwendung durch C-Clients bereit.
Referenzimplementierung von Gralloc
Die gralloc-Implementierung von Hikey960 verwendet libdmabufheap
. Sie können sie als Referenzimplementierung verwenden.
Erforderliche ueventd-Ergänzungen
Fügen Sie für alle neu erstellten gerätespezifischen DMA-BUF-Haufen einen neuen Eintrag in die ueventd.rc
-Datei des Geräts ein.
In diesem Beispiel für die Einrichtung von ueventd zur Unterstützung von DMA-BUF-Haufen wird gezeigt, wie dies für den DMA-BUF-System-Haufen geschieht.
Erforderliche Sepolicy-Ergänzungen
Fügen Sie Sepolicy-Berechtigungen hinzu, damit ein Userspace-Client auf einen neuen DMA-BUF-Haufen zugreifen kann. Dieses Beispiel zum Hinzufügen erforderlicher Berechtigungen zeigt die sepolicy-Berechtigungen, die für verschiedene Clients für den Zugriff auf den DMA-BUF-System-Heap erstellt wurden.
Über Framework-Code auf Anbieter-Heaps zugreifen
Zur Einhaltung der Treble-Compliance kann Framework-Code nur aus vorab genehmigten Kategorien von Anbieter-Haufen zugewiesen werden.
Auf Grundlage des Feedbacks von Partnern hat Google zwei Kategorien von Anbieter-Heaps identifiziert, auf die über Framework-Code zugegriffen werden muss:
- Heaps, die auf dem System-Heap basieren, mit geräte- oder SoC-spezifischen Leistungsoptimierungen.
- Heaps, die aus geschütztem Arbeitsspeicher zugewiesen werden sollen.
Heaps basierend auf dem System-Heap mit geräte- oder SoC-spezifischen Leistungsoptimierungen
Zur Unterstützung dieses Anwendungsfalls kann die Heap-Implementierung des standardmäßigen DMA-BUF-Heap-Systems überschrieben werden.
CONFIG_DMABUF_HEAPS_SYSTEM
ist ingki_defconfig
deaktiviert, damit es als Anbietermodul verwendet werden kann.- VTS-Compliance-Tests prüfen, ob der Heap unter
/dev/dma_heap/system
vorhanden ist. Außerdem wird geprüft, ob der Heap aus dem Nutzerbereich zugewiesen werden kann und ob der zurückgegebene Dateideskriptor (fd
) aus dem Nutzerbereich in den Arbeitsspeicher (mmapped) kopiert werden kann.
Die oben genannten Punkte gelten auch für die nicht im Cache gespeicherte Variante des System-Heaps, obwohl ihre Existenz für vollständig IO-kohärente Geräte nicht obligatorisch ist.
Zugewiesene Heaps aus dem geschützten Arbeitsspeicher
Implementierungen des sicheren Heaps müssen anbieterspezifisch sein, da der Android Common Kernel keine generische Implementierung des sicheren Heaps unterstützt.
- Registrieren Sie Ihre anbieterspezifischen Implementierungen als
/dev/dma_heap/system-secure<vendor-suffix>
. - Diese Heap-Implementierungen sind optional.
- Wenn die Heaps vorhanden sind, sorgen VTS-Tests dafür, dass sie zugewiesen werden können.
- Framework-Komponenten erhalten Zugriff auf diese Heaps, damit sie die Heap-Nutzung über die Codec2 HAL/nicht gebundene HALs im selben Prozess aktivieren können. Die allgemeinen Android-Framework-Funktionen können aufgrund der Abweichungen in ihren Implementierungsdetails jedoch nicht von ihnen abhängig sein. Wenn dem Android Common Kernel in Zukunft eine generische sichere Heap-Implementierung hinzugefügt wird, muss eine andere ABI verwendet werden, um Konflikte beim Upgraden von Geräten zu vermeiden.
Codec-2-Allocator für DMA-BUF-Heaps
In AOSP ist ein Codec2-Allocator für die DMA-BUF-Heap-Schnittstelle verfügbar.
Die Component Store-Oberfläche, mit der Heap-Parameter über die C2 HAL angegeben werden können, ist mit dem C2 DMA-BUF-Heap-Allocator verfügbar.
Beispiel für einen Übergangsablauf für einen ION-Heap
Um den Übergang von ION- zu DMA-BUF-Haufen reibungslos zu gestalten, ermöglicht libdmabufheap
das Umschalten jeweils eines Haufens. Die folgenden Schritte veranschaulichen einen vorgeschlagenen Workflow für die Umstellung eines nicht veralteten ION-Heaps mit dem Namen my_heap
, der ein Flag (ION_FLAG_MY_FLAG
) unterstützt.
Schritt 1:Erstellen Sie Entsprechungen des ION-Heaps im DMA-BUF-Framework. In diesem Beispiel registrieren wir zwei DMA-BUF-Haufen, da der ION-Haufen my_heap
ein Flag ION_FLAG_MY_FLAG
unterstützt:
- Das Verhalten von
my_heap
entspricht genau dem des ION-Heaps, wenn das FlagION_FLAG_MY_FLAG
deaktiviert ist. - Das Verhalten von
my_heap_special
stimmt genau mit dem Verhalten des ION-Heaps mit aktiviertem FlagION_FLAG_MY_FLAG
überein.
Schritt 2: Erstellen Sie die ueventd-Änderungen für die neuen DMA-BUF-Heaps my_heap
und my_heap_special
. An dieser Stelle werden die Heaps als /dev/dma_heap/my_heap
und /dev/dma_heap/my_heap_special
mit den vorgesehenen Berechtigungen angezeigt.
Schritt 3:Ändern Sie bei Clients, die eine Zuordnung aus my_heap
vornehmen, ihre Makefiles so, dass sie mit libdmabufheap
verknüpft werden. Instanziieren Sie während der Clientinitialisierung ein BufferAllocator
-Objekt und verwenden Sie die MapNameToIonHeap()
API, um die <ION heap name/mask, flag>
-Kombination äquivalenten DMA-BUF-Heap-Namen zuzuordnen.
Beispiel:
allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )
Anstatt die MapNameToIonHeap()
API mit den Parametern „Name“ und „Flag“ zu verwenden, können Sie die Zuordnung von <ION heap mask, flag>
zu entsprechenden DMA-BUF-Heap-Namen erstellen, indem Sie den Parameter „ION-Heap-Name“ leer setzen.
Schritt 4:Ersetzen Sie ion_alloc_fd()
-Aufrufe durch BufferAllocator::Alloc()
mit dem entsprechenden Heap-Namen.
Zuweisungstyp | Librion | Libdmabufheap |
---|---|---|
Zuweisung von my_heap ohne Flag ION_FLAG_MY_FLAG
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd)
|
allocator->Alloc("my_heap", size)
|
Zuweisung von my_heap mit gesetztem Flag 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)
|
An diesem Punkt funktioniert der Client, weist aber noch eine Zuordnung aus dem ION-Heap zu, da er nicht die erforderlichen sepolicy-Berechtigungen zum Öffnen des DMA-BUF-Heaps hat.
Schritt 5: Erstellen Sie die sepolicy-Berechtigungen, die für den Client für den Zugriff auf die neuen DMA-BUF-Heaps erforderlich sind. Der Client ist jetzt vollständig für die Zuweisung aus dem neuen DMA-BUF-Heap gerüstet.
Schritt 6:Prüfen Sie anhand von logcat, ob die Zuordnungen aus dem neuen DMA-BUF-Heap erfolgen.
Schritt 7:Deaktivieren Sie den ION-Heap my_heap
im Kernel. Wenn der Clientcode keine Aktualisierung von Geräten unterstützen muss, deren Kernel möglicherweise nur ION-Haufen unterstützen, können Sie auch die MapNameToIonHeap()
-Aufrufe entfernen.