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 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-Haufen unterstützen keine privaten Flags für Haufen. Jede Art der Zuordnung erfolgt stattdessen über einen 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 Zuweisung müssen die Heap-ID/-Maske und die 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. Außerdem wird beschrieben, wie diese auf das DMA-BUF-Heap-Framework umgestellt werden.
Kerneltreiber von ION auf DMA-BUF-Heaps umstellen
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. 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. Diese Tabelle zeigt die APIs für die ION-Heap-Registrierung und ihre entsprechenden DMA-BUF-Heap-APIs.
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. 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 im Cache gespeicherten und nicht zwischengespeicherten Varianten des System-Heaps.
Verwenden Sie diese dma-buf: heaps: Beispielvorlage, um einen DMA-BUF-Heap von Grund auf neu zu erstellen.
Kerneltreiber, die direkt aus ION-Haufen zuweisen
Das DMA-BUF-Heap-Framework bietet auch eine Zuweisungsschnittstelle 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 sehen Sie die IONS-Zuweisungs-API im Kernel und die entsprechenden DMA-BUF-Heap-Zuweisungs-APIs. Kernel-Treiber können die dma_heap_find()
API verwenden, um das Vorhandensein 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-Heaps | 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. 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 |
---|---|---|
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 nicht zwischengespeicherte System-Heap-Variante wartet auf Genehmigung in Upstream, ist aber bereits Teil des android12-5.10
-Zweigs.
Damit Geräteupgrades unterstützt werden, ermöglicht die MapNameToIonHeap()
API das Zuordnen eines Heap-Namens zu ION-Heap-Parametern (Heap-Name oder Maske und Flags), damit diese Schnittstellen namebasierte Zuweisungen verwenden können. Hier ist ein Beispiel für eine namenbasierte Zuweisung.
Die Dokumentation für jede API, die von libdmabufheap
bereitgestellt wird, 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 den 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.
- Zugewiesene Heaps aus dem geschützten Arbeitsspeicher
Heaps basierend auf dem System-Heap mit geräte- oder SoC-spezifischen Leistungsoptimierungen
Für diesen Anwendungsfall kann die Heap-Implementierung des Standard-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. Die Tests prüfen auch, ob der Heap aus dem Heap zugeordnet werden kann und ob der zurückgegebene Dateideskriptor (fd
) aus dem Nutzerbereich dem Arbeitsspeicher zugeordnet (mmapped) 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 Nutzung von Heaps über Codec2 HAL/nicht binderisierte HALs mit demselben Prozess ermöglichen 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 ein anderes ABI verwendet werden, um Konflikte mit Geräteupgrades zu vermeiden.
Codec 2-Allocator für DMA-BUF-Haufen
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 den Ü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
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. 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 die Makefiles für Clients, die von my_heap
zuweisen, so, dass sie mit libdmabufheap
verknüpft sind. 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“ 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)
|
Der Client ist zu diesem Zeitpunkt funktionsfähig, aber die Zuordnung erfolgt weiterhin über den ION-Heap, 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.