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 Zeichenspezialgerät ist, kann der Zugriff auf jeden Heap mit sepolicy separat gesteuert werden. Das war mit ION nicht möglich, da für die Zuweisung aus einem beliebigen Heap nur der Zugriff auf das Gerät
/dev/ionerforderlich war. - ABI-Stabilität: Im Gegensatz zu ION ist die IOCTL-Schnittstelle des DMA-BUF-Heaps-Frameworks ABI-stabil, da sie im Upstream-Linux-Kernel verwaltet wird.
- Standardisierung: Das DMA-BUF-Heaps-Framework bietet eine klar definierte UAPI. ION ermöglichte benutzerdefinierte Flags und Heap-IDs, die die Entwicklung eines gemeinsamen Test-Frameworks verhinderten, da sich die ION-Implementierung jedes Geräts unterschiedlich verhalten konnte.
Im Branch android12-5.10 des Android Common Kernel wurde 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
- Das ION- und das DMA-BUF-Heaps-Framework sind beide heapbasierte DMA-BUF-Exporter.
- Beide ermöglichen es, dass jeder Heap seinen eigenen Allokator und seine eigenen DMA-BUF-Vorgänge definiert.
- Die Zuweisungsleistung ist ähnlich, da für die Zuweisung in beiden Schemas ein einzelner IOCTL erforderlich ist.
Unterschiede zwischen dem ION- und dem DMA-BUF-Heaps-Framework
| ION-Heaps | DMA-BUF-Heaps |
|---|---|
Alle ION-Zuweisungen erfolgen mit /dev/ion.
|
Jeder DMA-BUF-Heap ist ein Zeichenspezialgerä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. Stattdessen erfolgt jede Art von
Zuweisung aus einem anderen Heap. Beispielsweise sind die Varianten des System-Heaps mit und ohne Cache separate Heaps unter /dev/dma_heap/system und /dev/dma_heap/system_uncached.
|
| Für die Zuweisung müssen Heap-ID/Maske und Flags angegeben werden. | Für die Zuweisung wird der Heap-Name verwendet. |
In den folgenden Abschnitten sind die Komponenten aufgeführt, die mit ION arbeiten, und es wird beschrieben, wie Sie sie auf das DMA-BUF-Heaps-Framework umstellen.
Kernel-Treiber von ION auf DMA-BUF-Heaps umstellen
Kernel-Treiber, die ION-Heaps implementieren
Sowohl ION als auch DMA-BUF-Heaps ermöglichen es, dass jeder Heap seine eigenen Allokatoren und DMA-BUF-Vorgänge implementiert. 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. In dieser Tabelle sind die ION-Heap-Registrierungs-APIs und die entsprechenden DMA-BUF-Heap-APIs aufgeführt.
| ION-Heaps | 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 dma_heap_add()
API registriert werden. Um die gemeinsame Nutzung von Code zu erleichtern, empfiehlt es sich, alle Varianten desselben Heaps im selben Treiber zu registrieren.
In diesem Beispiel für dma-buf: system_heap wird die Implementierung der Varianten des System
Heaps mit und ohne Cache gezeigt.
Verwenden Sie diese Beispielvorlage für dma-buf: heaps: um einen DMA-BUF-Heap von Grund auf neu zu erstellen.
Kernel-Treiber, die direkt aus ION-Heaps zuweisen
Das DMA-BUF-Heaps-Framework bietet auch eine Zuweisungsschnittstelle für In-Kernel-Clients. Anstatt die Heap-Maske und die Flags anzugeben, um den Zuweisungstyp auszuwählen, wird für die Schnittstelle, die von DMA-BUF-Heaps angeboten wird, ein Heap-Name als Eingabe verwendet.
Im Folgenden sind die In-Kernel-ION-Zuweisungs-API und die entsprechenden DMA-BUF-Heap-Zuweisungs-APIs aufgeführt. Kernel-Treiber können mit der API dma_heap_find() prüfen, ob ein Heap vorhanden ist. Die API gibt einen Zeiger auf eine Instanz von
struct dma_heap zurück, die dann als Argument an die
dma_heap_buffer_alloc() API übergeben werden kann.
| ION-Heaps | 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 aus einem ION-Heap zugewiesener Puffer genau wie ein aus einem entsprechenden DMA-BUF-Heap zugewiesener Puffer verhält.
Userspace-Clients von ION auf DMA-BUF-Heaps umstellen
Um die Umstellung für Userspace-Clients von ION zu erleichtern, ist eine Abstraktion
Bibliothek namens
libdmabufheap
verfügbar. libdmabufheap unterstützt die Zuweisung in DMA-BUF-Heaps und ION-Heaps. Zuerst wird geprüft, ob ein DMA-BUF-Heap mit dem angegebenen Namen vorhanden ist. Wenn nicht, 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 die Dateideskriptoren, die durch das Öffnen von
/dev/ion und /dev/dma_heap/<heap_name> erstellt wurden, intern vom BufferAllocator Objekt verwaltet werden.
So stellen Sie von libion auf libdmabufheap um:
- Verfolgen Sie den Heap-Namen, der für die Zuweisung verwendet werden soll, anstelle der Heap-ID/Maske und des Heap-Flags.
- Ersetzen Sie die API
ion_alloc_fd(), die ein Heap-Masken- und ein Flag-Argument verwendet, durch die APIBufferAllocator::Alloc(), die stattdessen einen Heap-Namen verwendet.
In dieser Tabelle werden diese Änderungen veranschaulicht, indem gezeigt wird, wie libion und libdmabufheap eine Zuweisung des System-Heaps ohne Cache durchführen.
| Zuweisungstyp | libion | libdmabufheap |
|---|---|---|
| Zuweisung mit Cache aus dem System-Heap | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd)
|
allocator->Alloc("system", size)
|
| Zuweisung ohne Cache aus dem System-Heap | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd)
|
allocator->Alloc("system-uncached", size)
|
Die
Variante des System-Heaps ohne Cache
wartet auf die Genehmigung im Upstream, ist aber bereits Teil des android12-5.10
Branchs.
Um das Upgrade von Geräten zu unterstützen, ermöglicht die API MapNameToIonHeap() das Zuordnen eines Heap-Namens zu ION-Heap-Parametern (Heap-Name oder Maske und Flags), damit diese Schnittstellen namensbasierte Zuweisungen verwenden können. Hier ist ein Beispiel
für eine namensbasierte Zuweisung.
Die Dokumentation für jede API, die von
libdmabufheap
bereitgestellt wird, ist verfügbar. Die
Bibliothek
stellt auch eine Header-Datei zur Verwendung durch C-Clients bereit.
Referenzimplementierung von Gralloc
Die Hikey960-Gralloc-Implementierung verwendet libdmabufheap. Sie können sie also als
Referenz
implementierung verwenden.
Erforderliche ueventd-Ergänzungen
Fügen Sie für alle neuen gerätespezifischen DMA-BUF-Heaps einen neuen Eintrag zur ueventd.rc-Datei des Geräts hinzu.
In diesem Beispiel für die Einrichtung von ueventd zur Unterstützung von DMA-BUF-Heaps
wird gezeigt, wie das für den DMA-BUF-System-Heap erfolgt.
Erforderliche sepolicy-Ergänzungen
Fügen Sie sepolicy-Berechtigungen hinzu, damit ein Userspace-Client auf einen neuen DMA-BUF-Heap zugreifen kann. In diesem Beispiel für das Hinzufügen erforderlicher Berechtigungen werden die sepolicy-Berechtigungen gezeigt, die für verschiedene Clients erstellt wurden, um auf den DMA-BUF-System-Heap zuzugreifen.
Zugriff auf Anbieter-Heaps über Framework-Code
Um Treble-konform zu sein, kann Framework-Code nur aus vorab genehmigten Kategorien von Anbieter-Heaps zuweisen.
Basierend auf dem Feedback von Partnern hat Google zwei Kategorien von Anbieter-Heaps identifiziert, auf die über Framework-Code zugegriffen werden muss:
- Heaps, die auf dem System-Heap mit geräte- oder SoC-spezifischen Leistungsoptimierungen basieren.
- Heaps für die Zuweisung aus geschütztem Speicher.
Heaps, die auf dem System-Heap mit geräte- oder SoC-spezifischen Leistungsoptimierungen basieren
Um diesen Anwendungsfall zu unterstützen, kann die Heap-Implementierung des Standard-DMA-BUF-Heap-Systems überschrieben werden.
CONFIG_DMABUF_HEAPS_SYSTEMist ingki_defconfigdeaktiviert, damit es ein Anbietermodul sein kann.- VTS-Konformitätstests stellen sicher, dass der Heap unter
/dev/dma_heap/systemvorhanden ist. Die Tests prüfen auch, ob aus dem Heap zugewiesen werden kann und ob der zurückgegebene Dateideskriptor (fd) aus dem Userspace in den Speicher abgebildet werden kann (mmapped).
Die vorstehenden Punkte gelten auch für die Variante des System-Heaps ohne Cache, obwohl seine Existenz für vollständig IO-kohärente Geräte nicht zwingend erforderlich ist.
Heaps für die Zuweisung aus geschütztem Speicher
Implementierungen von sicheren Heaps müssen anbieterspezifisch sein, da der Android Common Kernel keine generische Implementierung von 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, stellen VTS-Tests sicher, dass Zuweisungen daraus vorgenommen werden können.
- Framework-Komponenten haben Zugriff auf diese Heaps, damit sie die Verwendung von Heaps über die Codec2 HAL/nicht-binderisierte HALs im selben 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 Implementierung von sicheren Heaps hinzugefügt wird, muss sie eine andere ABI verwenden, um Konflikte mit dem Upgrade von Geräten zu vermeiden.
Codec2-Allokator für DMA-BUF-Heaps
In AOSP ist ein Codec2-Allokator für die DMA-BUF-Heaps Schnittstelle verfügbar.
Die Schnittstelle des Komponentenspeichers, mit der Heap-Parameter über die C2 HAL angegeben werden können, ist mit dem C2-DMA-BUF-Heap-Allokator verfügbar.
Beispiel für einen Umstellungsprozess für einen ION-Heap
Um die Umstellung von ION auf DMA-BUF-Heaps zu erleichtern, ermöglicht libdmabufheap das Umstellen eines Heaps nach dem anderen. In den folgenden Schritten wird ein vorgeschlagener Workflow für die Umstellung eines nicht veralteten ION-Heaps namens my_heap gezeigt, der ein Flag unterstützt, ION_FLAG_MY_FLAG.
Schritt 1:Erstellen Sie Entsprechungen 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_heapentspricht genau dem Verhalten des ION-Heaps, bei dem das FlagION_FLAG_MY_FLAGdeaktiviert ist. - Das Verhalten von
my_heap_specialentspricht genau dem Verhalten des ION-Heaps, bei dem das FlagION_FLAG_MY_FLAGaktiviert ist.
Schritt 2: Erstellen Sie die ueventd-Änderungen für die neuen my_heap und
my_heap_special DMA-BUF-Heaps. 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:Ändern Sie für Clients, die aus my_heap zuweisen, die 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 entsprechenden 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 für 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 für den ION-Heap-Namen leer lassen.
Schritt 4:Ersetzen Sie ion_alloc_fd()-Aufrufe durch BufferAllocator::Alloc() und verwenden Sie dabei den entsprechenden Heap-Namen.
| Zuweisungstyp | libion | libdmabufheap |
|---|---|---|
Zuweisung aus my_heap mit deaktiviertem Flag
ION_FLAG_MY_FLAG
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd)
|
allocator->Alloc("my_heap", size)
|
Zuweisung aus my_heap mit aktiviertem 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 aus dem ION-Heap zu, da er nicht die erforderlichen sepolicy-Berechtigungen hat, um den DMA-BUF-Heap zu öffnen.
Schritt 5:Erstellen Sie die sepolicy-Berechtigungen, die der Client benötigt, um auf die neuen DMA-BUF-Heaps zuzugreifen. Der Client ist jetzt vollständig ausgestattet, um aus dem neuen DMA-BUF-Heap zuzuweisen.
Schritt 6: Prüfen Sie anhand von Logcat , ob die Zuweisungen aus dem neuen DMA-BUF-Heap erfolgen.
Schritt 7:Deaktivieren Sie den ION-Heap my_heap im Kernel. Wenn der Clientcode keine Geräte unterstützen muss, die aktualisiert werden (deren Kernel möglicherweise nur ION-Heaps unterstützen), können Sie auch die MapNameToIonHeap()-Aufrufe entfernen.