In Android 12 ersetzt GKI 2.0 den ION-Allokator 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 für die Zuweisung von einem beliebigen Heap nur Zugriff auf das
/dev/ion
-Gerät erforderlich war. - 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 genau definierte UAPI. ION erlaubte benutzerdefinierte Flags und Heap-IDs, die die Entwicklung eines gemeinsamen Test-Frameworks verhinderten, da sich die ION-Implementierung jedes Geräts unterschiedlich verhalten konnte.
Der android12-5.10
Zweig des Android Common Kernel hat CONFIG_ION
am 1. März 2021 deaktiviert.
Hintergrund
Im Folgenden finden Sie einen kurzen 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-Exporteure.
- Beide lassen jeden Heap seinen eigenen Allokator und seine eigenen DMA-BUF-Operationen definieren.
- Die Zuteilungsleistung ist ähnlich, da beide Schemata einen einzigen IOCTL für die Zuteilung benötigen.
Unterschiede zwischen dem ION- und dem DMA-BUF-Heaps-Framework
ION-Haufen | DMA-BUF-Heaps |
---|---|
Alle ION-Zuweisungen erfolgen mit /dev/ion . | Jeder DMA-BUF-Heap ist ein Zeichengerät, das unter /dev/dma_heap/<heap_name> vorhanden ist. |
ION unterstützt private Heap-Flags. | DMA-BUF-Heaps unterstützen keine privaten Heap-Flags. Jede unterschiedliche Art der Zuweisung erfolgt stattdessen von einem anderen Heap aus. 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 befinden. |
Für die Zuweisung 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 sich mit ION befassen, und beschrieben, wie sie auf das DMA-BUF-Heaps-Framework umgestellt werden.
Umstellung der Kernel-Treiber von ION auf DMA-BUF-Heaps
Kernel-Treiber, die ION-Heaps implementieren
Sowohl ION- als auch DMA-BUF-Heaps ermöglichen es jedem Heap, seine eigenen Allokatoren 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 zum Registrieren des Heaps verwenden. Diese Tabelle zeigt die ION-Heap-Registrierungs-APIs und ihre entsprechenden DMA-BUF-Heap-APIs.
ION-Haufen | DMA-BUF-Heaps |
---|---|
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 privaten Heap-Flags. Daher muss jede Variante des Heaps einzeln mit der API dma_heap_add()
registriert werden. Um die Codefreigabe 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 zu erstellen.
Kernel-Treiber, die direkt von ION-Heaps zuweisen
Das DMA-BUF-Heaps-Framework bietet auch eine Zuweisungsschnittstelle für In-Kernel-Clients. Anstatt die Heap-Maske und Flags anzugeben, um die Art der Zuweisung auszuwählen, verwendet die von DMA-BUF-Heaps angebotene Schnittstelle einen Heap-Namen als Eingabe.
Im Folgenden werden die kerninterne ION-Zuteilungs-API und die entsprechenden DMA-BUF-Heap-Zuteilungs-APIs gezeigt. Kernel-Treiber können die API dma_heap_find()
verwenden, um das Vorhandensein 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-Heaps |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags) | |
Kernel-Treiber, die DMA-BUFs verwenden
Für Treiber, die nur DMA-BUFs importieren, sind keine Änderungen erforderlich, da sich ein von einem ION-Heap zugewiesener Puffer genauso verhält wie ein von einem entsprechenden DMA-BUF-Heap zugewiesener Puffer.
Umstellung der User-Space-Clients von ION auf DMA-BUF-Heaps
Um User-Space-Clients von ION den Übergang zu erleichtern, steht eine Abstraktionsbibliothek namens libdmabufheap
zur Verfügung. libdmabufheap
unterstützt die Zuordnung in DMA-BUF-Heaps und ION-Heaps. Es prüft zunächst, ob ein DMA-BUF-Heap mit dem angegebenen Namen existiert, und falls nicht, greift es auf einen entsprechenden ION-Heap zurück, sofern einer vorhanden ist.
Clients sollten während ihrer Initialisierung ein BufferAllocator
Objekt initialisieren, anstatt /dev/ion using ion_open()
zu öffnen. Dies liegt daran, dass durch Öffnen von /dev/ion
und /dev/dma_heap/<heap_name>
erstellte Dateideskriptoren intern vom BufferAllocator
Objekt verwaltet werden.
Um von libion
zu libdmabufheap
zu wechseln, ändern Sie das Verhalten der Clients wie folgt:
- Behalten Sie den Heap-Namen im Auge, der für die Zuweisung verwendet werden soll, anstelle der Kopf-ID/Maske und des Heap-Flags.
- Ersetzen Sie die API
ion_alloc_fd()
, die eine Heap-Maske und ein Flag-Argument annimmt, durch die APIBufferAllocator::Alloc()
, die stattdessen einen Heap-Namen annimmt.
Diese Tabelle veranschaulicht diese Änderungen, indem sie zeigt, wie libion
und libdmabufheap
eine nicht zwischengespeicherte System-Heap-Zuweisung durchführen.
Art der Zuteilung | libion | libdmabufheap |
---|---|---|
Zwischengespeicherte Zuordnung 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 nicht zwischengespeicherte System-Heap-Variante wartet auf die Genehmigung durch den Upstream, ist aber bereits Teil des android12-5.10
Zweigs.
Um die Aktualisierung von Geräten zu unterstützen, ermöglicht die MapNameToIonHeap()
-API 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 außerdem eine Header-Datei zur Verwendung durch C-Clients bereit.
Referenzieren Sie die Gralloc-Implementierung
Die Hikey960-Gralloc-Implementierung verwendet libdmabufheap
, sodass Sie es als Referenzimplementierung verwenden können.
Erforderliche ueventd-Ergänzungen
Fügen Sie für alle neu erstellten gerätespezifischen DMA-BUF-Heaps einen neuen Eintrag zur Datei ueventd.rc
des Geräts hinzu. Dieses Setup-Ueventd-Beispiel zur Unterstützung von DMA-BUF-Heaps zeigt, wie dies für den DMA-BUF-System-Heap durchgeführt wird.
Erforderliche seperate 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 über den Framework-Code
Um die Treble-Konformität sicherzustellen, kann der Framework-Code nur Zuweisungen aus vorab genehmigten Kategorien von Anbieter-Heaps vornehmen.
Basierend auf dem Feedback von Partnern hat Google zwei Kategorien von Anbieter-Heaps identifiziert, auf die über den Framework-Code zugegriffen werden muss:
- Heaps, die auf System-Heaps mit geräte- oder SoC-spezifischen Leistungsoptimierungen basieren.
- Heaps, die aus dem geschützten Speicher zugewiesen werden sollen.
Heaps basierend auf System-Heap 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 ingki_defconfig
deaktiviert, damit es ein Anbietermodul sein kann. - VTS-Konformitätstests stellen sicher, dass der Heap unter
/dev/dma_heap/system
vorhanden ist. Die Tests überprüfen auch, ob der Heap zugewiesen werden kann und ob der zurückgegebene Dateideskriptor (fd
) vom Benutzerbereich aus dem Speicher zugeordnet (mmapped) werden kann.
Die vorstehenden Punkte gelten auch für die nicht zwischengespeicherte Variante des System-Heaps, obwohl dessen Existenz für vollständig IO-kohärente Geräte nicht zwingend erforderlich ist.
Heaps, die aus dem geschützten Speicher zugewiesen werden sollen
Secure-Heap-Implementierungen müssen herstellerspezifisch sein, da der Android Common Kernel keine generische Secure-Heap-Implementierung unterstützt.
- Registrieren Sie Ihre herstellerspezifischen Implementierungen als
/dev/dma_heap/system-secure<vendor-suffix>
. - Diese Heap-Implementierungen sind optional.
- Wenn die Heaps vorhanden sind, stellen VTS-Tests sicher, dass daraus Allokationen vorgenommen werden können.
- Framework-Komponenten erhalten Zugriff auf diese Heaps, sodass sie die Heap-Nutzung über die Codec2-HALs/nicht gebundene HALs mit demselben Prozess ermöglichen können. Generische Android-Framework-Funktionen können jedoch aufgrund der Variabilität ihrer Implementierungsdetails nicht von ihnen 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 mit der Aktualisierung 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 die Angabe von Heap-Parametern aus der C2-HAL ermöglicht, ist mit dem C2-DMA-BUF-Heap-Allokator verfügbar.
Beispielübergangsfluss für einen ION-Heap
Um den Übergang von ION- zu DMA-BUF-Heaps zu erleichtern, ermöglicht libdmabufheap
den Wechsel eines Heaps nach dem anderen. Die folgenden Schritte veranschaulichen einen vorgeschlagenen Workflow für den Übergang eines nicht veralteten 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 in diesem Beispiel der ION-Heap my_heap
ein Flag ION_FLAG_MY_FLAG
unterstützt, registrieren wir zwei DMA-BUF-Heaps:
- Das Verhalten
my_heap
entspricht genau dem Verhalten des ION-Heaps mit deaktiviertem FlagION_FLAG_MY_FLAG
. - Das Verhalten
my_heap_special
entspricht genau dem Verhalten des ION-Heaps mit aktiviertem FlagION_FLAG_MY_FLAG
.
Schritt 2: Erstellen Sie die ueventd-Änderungen für die neuen DMA-BUF-Heaps my_heap
und my_heap_special
. Zu diesem Zeitpunkt sind die Heaps als /dev/dma_heap/my_heap
und /dev/dma_heap/my_heap_special
mit den vorgesehenen Berechtigungen sichtbar.
Schritt 3: Für Clients, die von my_heap
zuweisen, ändern Sie ihre Makefiles, um eine Verknüpfung zu libdmabufheap
herzustellen. Instanziieren Sie während der Client-Initialisierung ein BufferAllocator
Objekt und verwenden Sie die MapNameToIonHeap()
-API, um die Kombination <ION heap name/mask, flag>
entsprechenden DMA-BUF-Heap-Namen zuzuordnen.
Zum 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 API MapNameToIonHeap()
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()
unter Verwendung des entsprechenden Heap-Namens.
Zuordnungstyp | libion | libdmabufheap |
---|---|---|
Zuordnung von my_heap mit nicht gesetztem 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) |
Zu diesem Zeitpunkt ist der Client funktionsfähig, weist jedoch weiterhin vom ION-Heap zu, da er nicht über die erforderlichen Sepolicy-Berechtigungen zum Öffnen des DMA-BUF-Heaps verfügt.
Schritt 5: Erstellen Sie die erforderlichen Sepolicy-Berechtigungen, damit der Client auf die neuen DMA-BUF-Heaps zugreifen kann. Der Client ist nun vollständig für die Zuweisung aus dem neuen DMA-BUF-Heap gerüstet.
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 Clientcode die Aktualisierung von Geräten nicht unterstützen muss (deren Kernel möglicherweise nur ION-Heaps unterstützt), können Sie auch die MapNameToIonHeap()
Aufrufe entfernen.