Übergang von ION zu DMA-BUF Heaps

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

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 separat mit sepolicy gesteuert werden. Dies war mit ION nicht möglich, da die Zuweisung von jedem Heap nur den Zugriff auf das /dev/ion Gerät erforderte.
  • ABI-Stabilität: Im Gegensatz zu ION ist die IOCTL-Schnittstelle des DMA-BUF-Heaps-Frameworks garantiert ABI-stabil, da sie im Upstream-Linux-Kernel verwaltet wird.
  • Standardisierung: Das DMA-BUF-Heaps-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 könnte.

Der Zweig android12-5.10 des Android Common Kernel CONFIG_ION am 1. März 2021 deaktiviert.

Hintergrund

Das Folgende ist ein kurzer Vergleich zwischen ION- und DMA-BUF-Heaps.

Ähnlichkeiten zwischen dem ION- und dem DMA-BUF-Heaps-Framework

  • Die ION- und DMA-BUF-Heaps-Frameworks sind beide Heap-basierte DMA-BUF-Exporter.
  • Beide lassen jeden Heap seinen eigenen Zuordner und seine eigenen DMA-BUF-Operationen definieren.
  • Die Zuweisungsleistung ist ähnlich, da beide Schemata eine einzige IOCTL für die Zuweisung benötigen.

Unterschiede zwischen dem ION- und dem DMA-BUF-Heaps-Framework

ION-Haufen DMA-BUF-Haufen
Alle ION-Zuweisungen erfolgen mit /dev/ion . Jeder DMA-BUF-Heap ist ein Zeichengerät, das unter /dev/dma_heap/<heap_name> .
ION unterstützt Heap-Private-Flags. DMA-BUF-Heaps unterstützen keine Heap-Private-Flags. Jede unterschiedliche Art der Zuweisung erfolgt stattdessen von einem anderen Heap. Beispielsweise sind die zwischengespeicherten und nicht zwischengespeicherten System-Heap-Varianten separate Heaps, die sich unter /dev/dma_heap/system und /dev/dma_heap/system_uncached .
Heap-ID/Maske und Flags müssen für die Zuordnung angegeben werden. Der Heap-Name wird für die Zuordnung verwendet.

Die folgenden Abschnitte listen die Komponenten auf, die sich mit ION befassen, und beschreiben, wie sie auf das DMA-BUF-Heaps-Framework umgestellt werden.

Übergang von Kernel-Treibern von ION zu DMA-BUF-Heaps

Kerneltreiber, die ION-Heaps implementieren

Sowohl ION- als auch DMA-BUF-Heaps ermöglichen jedem Heap, seine eigenen Zuordner und DMA-BUF-Operationen 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 verwenden, um den Heap zu registrieren. Diese Tabelle zeigt die ION-Heap-Registrierungs-APIs und ihre äquivalenten DMA-BUF-Heap-APIs.

ION-Haufen DMA-BUF-Haufen
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-Heaps unterstützen keine Heap-Private-Flags. Daher muss jede Variante des Heaps einzeln mit der API dma_heap_add() registriert werden. Um die gemeinsame Nutzung von Code zu erleichtern, wird empfohlen, alle Varianten desselben Heaps innerhalb desselben Treibers zu registrieren. Dieses dma-buf: system_heap- Beispiel zeigt die Implementierung der zwischengespeicherten und nicht zwischengespeicherten Varianten des Systemheaps.

Verwenden Sie diese dma-buf: heaps: Beispielvorlage , um einen DMA-BUF-Heap von Grund auf neu zu erstellen.

Kernel-Treiber, die direkt von ION-Heaps zuordnen

Das DMA-BUF-Heaps-Framework bietet auch eine Zuordnungsschnittstelle für In-Kernel-Clients. Anstatt die Heap-Maske und Flags anzugeben, um den Zuordnungstyp auszuwählen, nimmt die von DMA-BUF-Heaps angebotene Schnittstelle einen Heap-Namen als Eingabe.

Das Folgende zeigt die ION-Zuweisungs-API im Kernel und ihre äquivalenten DMA-BUF-Heap-Zuweisungs-APIs. Kerneltreiber können die API dma_heap_find() 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() werden kann.

ION-Haufen DMA-BUF-Haufen
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)

struct dma_heap *dma_heap_find(const char *name)

struct dma_buf *struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, unsigned int fd_flags, unsigned int heap_flags)

Kerneltreiber, die DMA-BUFs verwenden

Für Treiber, die nur DMA-BUFs importieren, sind keine Änderungen erforderlich, da sich ein Puffer, der von einem ION-Heap zugewiesen wird, genauso verhält wie ein Puffer, der von einem äquivalenten DMA-BUF-Heap zugewiesen wird.

Übergang der User-Space-Clients von ION zu DMA-BUF-Heaps

Um den Übergang für User-Space-Clients von ION zu erleichtern, ist eine Abstraktionsbibliothek namens libdmabufheap verfügbar. libdmabufheap unterstützt die Zuordnung in DMA-BUF-Heaps und ION-Heaps. Es prüft zuerst, ob ein DMA-BUF-Heap des angegebenen Namens existiert, und wenn nicht, greift es auf einen äquivalenten ION-Heap zurück, falls einer existiert.

Clients sollten während ihrer Initialisierung ein BufferAllocator Objekt initialisieren, anstatt /dev/ion using ion_open() . Dies liegt daran, dass Dateideskriptoren, die durch Öffnen von /dev/ion und /dev/dma_heap/<heap_name> wurden, intern vom BufferAllocator Objekt verwaltet werden.

Um von libion zu libdmabufheap zu wechseln, ändern Sie das Verhalten der Clients wie folgt:

  • Verfolgen Sie den für die Zuordnung zu verwendenden Heap-Namen anstelle der Kopf-ID/Maske und des Heap-Flags.
  • Ersetzen Sie die API ion_alloc_fd() , die eine Heap-Maske und ein Flag-Argument akzeptiert, durch die API BufferAllocator::Alloc() , die stattdessen einen Heap-Namen akzeptiert.

Diese Tabelle veranschaulicht diese Änderungen, indem sie zeigt, wie libion und libdmabufheap eine ungecachte System-Heap-Zuordnung vornehmen.

Art der Zuordnung Libion libdmabufheap
Zwischengespeicherte Zuweisung vom Systemheap ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
Nicht zwischengespeicherte Zuordnung vom Systemheap ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

Die ungecachte System-Heap-Variante wartet auf die Genehmigung der Upstream-Seite, ist aber bereits Teil des android12-5.10 Zweigs.

Um das Upgrade von Geräten zu unterstützen, ermöglicht die API MapNameToIonHeap() die Zuordnung eines Heap-Namens zu ION-Heap-Parametern (Heap-Name/Maske und Flags), damit diese Schnittstellen auch namensbasierte Zuordnungen verwenden können. Hier ist ein Beispiel für eine namensbasierte Zuordnung .

Die Dokumentation für jede von libdmabufheap bereitgestellte API ist verfügbar. Die Bibliothek stellt auch eine Header-Datei zur Verwendung durch C-Clients zur Verfügung.

Referenz Gralloc-Implementierung

Die gralloc - Implementierung von Hikey960 verwendet libdmabufheap , sodass Sie sie als Referenzimplementierung verwenden können .

Erforderliche ueventd-Zusätze

Fügen Sie für alle neu erstellten gerätespezifischen DMA-BUF-Heaps einen neuen Eintrag zur ueventd.rc -Datei des Geräts hinzu. Dieses Beispiel zur Einrichtung von ueventd zur Unterstützung von DMA-BUF-Heaps zeigt, wie dies für den DMA-BUF-System-Heap erfolgt.

Erforderliche sepolicy-Ergänzungen

Fügen Sie sepolicy-Berechtigungen hinzu, um einem Userspace-Client den Zugriff auf einen neuen DMA-BUF-Heap zu ermöglichen. Dieses Beispiel zum Hinzufügen erforderlicher Berechtigungen zeigt die sepolicy-Berechtigungen, die für verschiedene Clients erstellt wurden, um auf den DMA-BUF-Systemheap zuzugreifen.

Zugriff auf Anbieter-Heaps aus Framework-Code

Um die Einhaltung von Treble sicherzustellen, kann Framework-Code nur aus vorab genehmigten Kategorien von Anbieter-Heaps zugewiesen werden.

Basierend auf dem Feedback von Partnern hat Google zwei Kategorien von Anbieter-Heaps identifiziert, auf die über Framework-Code zugegriffen werden muss:

  1. Heaps, die auf Systemheap mit geräte- oder SoC-spezifischen Leistungsoptimierungen basieren.
  2. Aus dem geschützten Speicher zuzuweisende Heaps.

Heaps basierend auf Systemheap mit geräte- oder SoC-spezifischen Leistungsoptimierungen

Um diesen Anwendungsfall zu unterstützen, kann die Heap-Implementierung des standardmäßigen DMA-BUF-Heap-Systems überschrieben werden.

  • CONFIG_DMABUF_HEAPS_SYSTEM ist in gki_defconfig , damit es ein Anbietermodul sein kann.
  • VTS-Compliance-Tests stellen sicher, dass der Heap unter /dev/dma_heap/system . Die Tests verifizieren auch, dass der Heap zugewiesen werden kann und dass der zurückgegebene Dateideskriptor ( fd ) aus dem Benutzerbereich speicherabgebildet (mmapped) werden kann.

Die vorstehenden Punkte gelten auch für die ungecachte Variante des Systemheaps, obwohl seine Existenz für vollständig IO-kohärente Geräte nicht zwingend erforderlich ist.

Aus dem geschützten Speicher zuzuweisende Heaps

Sichere Heap-Implementierungen müssen herstellerspezifisch sein, da der Android Common Kernel keine generische sichere Heap-Implementierung 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, stellen VTS-Tests sicher, dass Zuordnungen von ihnen vorgenommen werden können.
  • Framework-Komponenten erhalten Zugriff auf diese Heaps, so dass sie die Heap-Nutzung durch die Codec2-HAL/nicht gebundenen, prozessgleichen HALs ermöglichen können. Generische Android-Frameworkfunktionen können jedoch aufgrund der Variabilität ihrer Implementierungsdetails nicht davon abhängig sein. Wenn dem Android Common Kernel in Zukunft eine generische Secure Heap-Implementierung hinzugefügt wird, muss diese eine andere ABI verwenden, um Konflikte beim Aktualisieren von Geräten zu vermeiden.

Codec 2-Zuweisung für DMA-BUF-Heaps

Ein Codec2-Zuordner für die DMA-BUF-Heaps-Schnittstelle ist in AOSP verfügbar.

Die Komponentenspeicherschnittstelle, die es ermöglicht, Heap-Parameter von der C2-HAL anzugeben, ist mit dem C2-DMA-BUF-Heap-Zuordner verfügbar.

Beispielübergangsfluss für einen ION-Heap

Um den Übergang von ION- zu DMA-BUF-Heaps zu glätten, ermöglicht libdmabufheap das Umschalten jeweils eines Heaps. Die folgenden Schritte veranschaulichen einen vorgeschlagenen Arbeitsablauf für die Umstellung eines Nicht-Legacy-ION-Heaps namens my_heap , der ein Flag unterstützt, ION_FLAG_MY_FLAG .

Schritt 1: Erstellen Sie Äquivalente des ION-Heaps im DMA-BUF-Framework. Da der ION-Heap my_heap in diesem Beispiel ein Flag ION_FLAG_MY_FLAG unterstützt, registrieren wir zwei DMA-BUF-Heaps:

  • Das Verhalten von my_heap genau dem Verhalten des ION-Heaps mit deaktiviertem Flag ION_FLAG_MY_FLAG .
  • Das Verhalten von my_heap_special genau mit dem Verhalten des ION-Heaps überein, wenn das Flag ION_FLAG_MY_FLAG aktiviert ist.

Schritt 2: Erstellen Sie die ueventd-Änderungen für die neuen DMA-BUF-Heaps my_heap und my_heap_special . An diesem Punkt sind die Heaps als /dev/dma_heap/my_heap und /dev/dma_heap/my_heap_special mit den beabsichtigten Berechtigungen sichtbar.

Schritt 3: Für Clients, die von my_heap , ändern Sie ihre Makefiles, um auf libdmabufheap zu verlinken. Instanziieren Sie während der Client-Initialisierung ein BufferAllocator Objekt und verwenden Sie die MapNameToIonHeap() API, um die <ION heap name/mask, flag> -Kombination entsprechenden DMA-BUF-Heap-Namen zuzuordnen.

Beispielsweise:

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 Namens- und Flag-Parametern zu verwenden, können Sie die Zuordnung von <ION heap mask, flag> zu entsprechenden DMA-BUF-Heap-Namen erstellen, indem Sie den ION-Heap-Namensparameter auf leer setzen.

Schritt 4: Ersetzen Sie ion_alloc_fd() -Aufrufe durch BufferAllocator::Alloc() unter Verwendung des entsprechenden Heap-Namens.

Zuordnungstyp Libion libdmabufheap
Zuordnung von my_heap mit Flag ION_FLAG_MY_FLAG nicht gesetzt ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size
Zuordnung 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 ist der Client funktionsfähig, weist aber immer noch vom ION-Heap zu, da er nicht über die erforderlichen sepolicy-Berechtigungen zum Öffnen des DMA-BUF-Heap verfügt.

Schritt 5: Erstellen Sie die sepolicy-Berechtigungen, die der Client benötigt, um auf die neuen DMA-BUF-Heaps zuzugreifen. Der Client ist nun voll ausgestattet, um von dem neuen DMA-BUF-Heap zuzuweisen.

Schritt 6: Überprüfen Sie, ob die Zuweisungen vom neuen DMA-BUF-Heap erfolgen, indem Sie logcat untersuchen.

Schritt 7: Deaktivieren Sie den ION-Heap my_heap im Kernel. Wenn der Client-Code keine Aktualisierung von Geräten unterstützen muss (deren Kernel möglicherweise nur ION-Heaps unterstützen), können Sie auch die MapNameToIonHeap() -Aufrufe entfernen.