In Android 12 ersetzt GKI 2.0 den ION-Allocator aus folgenden Gründen durch DMA-BUF-Haufen:
- 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 gut 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-Stapel |
---|---|
Alle ION-Zuweisungen erfolgen über /dev/ion .
|
Jeder DMA-BUF-Heap ist ein Zeichengerät, das unter /dev/dma_heap/<heap_name> vorhanden ist.
|
ION unterstützt Flags für den privaten Heap. | DMA-BUF-Haufen unterstützen keine Flags für private Haufen. Jede Art der Zuweisung erfolgt stattdessen aus einem anderen Heap. Beispielsweise sind die Varianten des System-Heaps mit und ohne Cache 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
Kernel-Treiber, die ION-Stapel implementieren
Sowohl ION- als auch DMA-BUF-Stapel ermöglichen es jedem Stapel, eigene Allocatoren und DMA-BUF-Vorgänge zu implementieren. So können Sie von einer ION-Heap-Implementierung zu einer DMA-BUF-Heap-Implementierung wechseln, indem Sie zum Registrieren des Heaps eine andere Gruppe von APIs verwenden. In dieser Tabelle sind die ION-Heap-Registrierungs-APIs und ihre entsprechenden DMA-BUF-Heap-APIs aufgeführt.
ION-Haufen | 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 Flags für private Haufen. Daher muss jede Variante des Heaps einzeln über die dma_heap_add()
API registriert werden. Um die Codefreigabe zu erleichtern, wird empfohlen, alle Varianten desselben Heaps im selben Treiber zu registrieren.
Dieses Beispiel dma-buf: system_heap zeigt die Implementierung der mit und ohne Cache verfügbaren Varianten des Systemheaps.
Verwenden Sie diese dma-buf: heaps: Beispielvorlage, um einen DMA-BUF-Haufen von Grund auf neu zu erstellen.
Kernel-Treiber, 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 Flags anzugeben, um die Art der Zuweisung auszuwählen, nimmt die von DMA-BUF-Heaps angebotene Schnittstelle einen Heap-Namen als Eingabe entgegen.
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 Verweis auf eine Instanz von struct dma_heap zurück, der dann als Argument an die dma_heap_buffer_alloc()
API ü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.
Nutzerbereichs-Clients von ION auf DMA-BUF-Haufen umstellen
Um den Übergang für User-Space-Clients von ION zu erleichtern, steht eine Abstraktionsbibliothek namens libdmabufheap
zur Verfügung. libdmabufheap
unterstützt die Zuweisung in DMA-BUF- und ION-Heaps. Es wird zuerst geprüft, ob ein DMA-BUF-Heap mit dem angegebenen Namen vorhanden ist. Andernfalls wird auf einen entsprechenden ION-Heap zurückgegriffen, falls 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 Kunden 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 |
---|---|---|
Aus dem System-Heap im Cache zugewiesene Speicherbereiche | 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 ist ein Beispiel für eine namenbasierte Zuweisung.
Die Dokumentation für alle APIs, die von libdmabufheap
freigegeben werden, ist verfügbar. Die Bibliothek stellt auch eine Headerdatei für die Verwendung durch C-Clients bereit.
Referenzimplementierung von Gralloc
Die Hikey960-Gralloc-Implementierung verwendet libdmabufheap
. Sie können sie also 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. In diesem Beispiel zum Hinzufügen erforderlicher Berechtigungen sind die Sepolicy-Berechtigungen zu sehen, die für verschiedene Clients zum 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.- Bei VTS-Compliance-Tests wird sichergestellt, dass 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.
Heaps, die aus geschütztem Arbeitsspeicher zugewiesen werden sollen
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 für Zuordnungen verwendet 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. Generische Android-Framework-Funktionen können jedoch aufgrund der Variabilität ihrer Implementierungsdetails nicht davon 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-Haufen
In AOSP ist ein Codec2-Allocator für die DMA-BUF-Stapelschnittstelle 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 älteren ION-Haufens mit dem Namen my_heap
, der ein Flag namens 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
entspricht genau dem des ION-Heaps mit aktiviertem FlagION_FLAG_MY_FLAG
.
Schritt 2:Erstellen Sie die ueventd-Änderungen für die neuen my_heap
- und my_heap_special
-DMA-BUF-Haufen. Zu diesem Zeitpunkt sind die Heaps als /dev/dma_heap/my_heap
und /dev/dma_heap/my_heap_special
mit den gewünschten Berechtigungen zu sehen.
Schritt 3:Ändern Sie die Makefiles für Clients, die von my_heap
aus zuweisen, sodass sie mit libdmabufheap
verknüpft werden. Instanziere während der Clientinitialisierung ein BufferAllocator
-Objekt und ordne mithilfe der MapNameToIonHeap()
API die <ION heap name/mask, flag>
-Kombination den entsprechenden DMA-BUF-Heapnamen zu.
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“ auf „leer“ setzen.
Schritt 4:Ersetzen Sie ion_alloc_fd()
-Aufrufe durch BufferAllocator::Alloc()
mit dem entsprechenden Heap-Namen.
Zuweisungstyp | libion | 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)
|
Der Client funktioniert zwar, weist aber weiterhin Speicherplatz aus dem ION-Heap zu, da er nicht über die erforderlichen SEPolicy-Berechtigungen zum Öffnen des DMA-BUF-Heaps verfügt.
Schritt 5:Erstellen Sie die Sepolicy-Berechtigungen, die der Client zum Zugriff auf die neuen DMA-BUF-Haufen benötigt. 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.