Mit Android 11 wird die Möglichkeit eingeführt, AIDL für HALs in Android zu verwenden. So können Sie Android kann auch ohne HIDL implementiert werden. HALs auf AIDL umstellen ausschließlich, wo möglich (wenn vorgelagerte HALs HIDL verwenden, muss HIDL verwendet werden).
HALs, die AIDL für die Kommunikation zwischen Framework-Komponenten wie denen in
system.img
und Hardwarekomponenten wie die in vendor.img
müssen
Stabile AIDL. Um jedoch innerhalb einer Partition zu kommunizieren, z. B. von einem
HAL zu einem anderen HAL führt, gibt es keine Einschränkungen für den IPC-Mechanismus.
Ziel
AIDL gibt es schon länger als HIDL und wird auch an vielen anderen Stellen verwendet, zwischen Android-Framework-Komponenten oder in Apps. Da AIDL jetzt stabil ist, unterstützen, ist es möglich, einen gesamten Stack mit einer einzigen IPC-Laufzeit zu implementieren. AIDL hat auch ein besseres Versionsverwaltungssystem als HIDL.
- Die Verwendung einer IPC-Sprache braucht nur eine Sache, die Sie lernen müssen: optimieren und sichern.
- AIDL unterstützt die direkte Versionsverwaltung für die Inhaber einer Schnittstelle:
<ph type="x-smartling-placeholder">
- </ph>
- Inhaber können Methoden am Ende von Schnittstellen oder Feldern zu Parcelables hinzufügen. Das bedeutet, dass es im Laufe der Jahre einfacher ist, Code zu versionieren, im Vergleich zum Vorjahr geringer sind (Typen können direkt geändert werden und es gibt keine zusätzliche Bibliotheken für jede Schnittstellenversion benötigt.)
- Erweiterungsschnittstellen können zur Laufzeit hinzugefügt werden, nicht im Typ Daher ist es nicht notwendig, ein Rebase von Downstream-Erweiterungen auf neuere Versionen von Schnittstellen.
- Eine vorhandene AIDL-Schnittstelle kann direkt verwendet werden, wenn der Inhaber stabilisieren Sie es. Bisher musste eine vollständige Kopie der Benutzeroberfläche die in HIDL erstellt wurden.
Build für die AIDL-Laufzeit
AIDL hat drei verschiedene Back-Ends: Java, NDK und CPP. Zur Verwendung der stabilen AIDL müssen Sie
Verwenden Sie immer die Systemkopie von libbinder unter system/lib*/libbinder.so
und sprechen Sie
am /dev/binder
. Für Code für das Anbieterbild bedeutet dies, dass libbinder
(vom VNDK) kann nicht verwendet werden: Diese Bibliothek enthält eine instabile C++ API und
instabilen internen Strukturen. Stattdessen muss der Code des nativen Anbieters das NDK-Backend von
AIDL, Verknüpfung mit libbinder_ndk
(unterstützt vom System libbinder.so
),
und eine Verknüpfung mit den von aidl_interface
-Einträgen erstellten NDK-Bibliotheken erstellen. Für
die genauen Modulnamen,
Benennungsregeln für Module.
AIDL HAL-Schnittstelle schreiben
Damit eine AIDL-Schnittstelle zwischen System und Anbieter verwendet werden kann, muss sie zwei Änderungen:
- Jede Typdefinition muss mit
@VintfStability
annotiert werden. - Die Deklaration zu
aidl_interface
mussstability: "vintf",
enthalten.
Nur der Inhaber einer Benutzeroberfläche kann diese Änderungen vornehmen.
Wenn Sie diese Änderungen vornehmen, muss sich die Oberfläche im
VINTF-Manifest konfiguriert ist. Testen Sie diese (und ähnliche)
wie z. B. das Einfrieren freigegebener Schnittstellen mithilfe des
VTS-Test vts_treble_vintf_vendor_test
. Du kannst einen @VintfStability
verwenden
ohne diese Anforderungen zu nutzen, indem Sie entweder
AIBinder_forceDowngradeToLocalStability
im NDK-Back-End
android::Stability::forceDowngradeToLocalStability
im C++ Back-End,
oder android.os.Binder#forceDowngradeToSystemStability
im Java-Back-End
an einem Binderobjekt an,
bevor es an einen anderen Prozess gesendet wird. Downgrade eines Dienstes ausführen
Anbieterstabilität wird in Java nicht unterstützt, da alle Anwendungen in einem System
Kontext.
Darüber hinaus sorgen Sie für maximale Codeportabilität und vermeiden potenzielle Probleme wie als unnötige zusätzliche Bibliotheken, deaktivieren Sie das CPP-Back-End.
Beachten Sie, dass die Verwendung von backends
im Codebeispiel unten korrekt ist, da
sind drei Back-Ends (Java, NDK und CPP). Der folgende Code zeigt, wie die
CPP-Back-End, um es zu deaktivieren.
aidl_interface: {
...
backends: {
cpp: {
enabled: false,
},
},
}
AIDL HAL-Schnittstellen finden
AOSP Stable AIDL-Schnittstellen für HALs befinden sich in denselben Basisverzeichnissen wie
HIDL-Schnittstellen in aidl
Ordnern.
- Hardware/Schnittstellen
- Frameworks/Hardware/Schnittstellen
- System/Hardware/Schnittstellen
Erweiterungsoberflächen in anderen hardware/interfaces
Unterverzeichnisse in vendor
oder hardware
.
Erweiterungsoberflächen
Android hat mit jedem Release eine Reihe von offiziellen AOSP-Oberflächen. Wenn Android möchten unsere Partner Funktionen zu diesen Oberflächen hinzufügen, da dies bedeutet, dass ihre Android-Laufzeit nicht mit der Android-Laufzeit von AOSP kompatibel. Bei GMD-Geräten sollten Durch diese Oberflächen wird auch sichergestellt, dass das GSI-Image weiterhin funktioniert.
Erweiterungen können auf zwei verschiedene Arten registriert werden:
- finden Sie unter angehängte Erweiterungen.
- eigenständig, global und in VINTF registriert.
Eine Erweiterung wird jedoch registriert, wenn sie anbieterspezifisch, d. h. nicht Teil des vorgelagerte AOSP-Komponenten die Schnittstelle nutzen, ist eine Zusammenführung Konflikt. Wenn jedoch nachgelagerte Änderungen an vorgelagerten AOSP-Komponenten auftreten, können Zusammenführungskonflikte auftreten, und die folgenden Strategien werden empfohlen:
- Die Ergänzungen der Benutzeroberfläche können im nächsten Release an AOSP übertragen werden.
- Ergänzungen der Benutzeroberfläche, die mehr Flexibilität ohne Zusammenführungskonflikte kann in der nächsten Version vorgeschaltet werden
Erweiterungsparcelables: ParcelableHolder
ParcelableHolder
ist eine Parcelable
, die ein weiteres Parcelable
enthalten kann.
Der Hauptanwendungsfall von ParcelableHolder
besteht darin, eine Parcelable
erweiterbar zu machen.
Beispiel: Bild, das Geräteimplementierungen für die Erweiterung eines
AOSP-definierte Parcelable
, AospDefinedParcelable
, um ihren Mehrwert einzubeziehen
Funktionen.
Bisher ohne ParcelableHolder
konnten Geräte-Implementierer die Änderungen nicht ändern
eine AOSP-definierte stabile AIDL-Schnittstelle, da es ein Fehler wäre, weitere
Felder:
parcelable AospDefinedParcelable {
int a;
String b;
String x; // ERROR: added by a device implementer
int[] y; // added by a device implementer
}
Wie im vorherigen Code zu sehen ist, funktioniert diese Vorgehensweise nicht, da die Felder die vom Geräte-Implementierer hinzugefügt wurden, kann zu Konflikten führen, wenn das Paket die in den nächsten Android-Versionen überarbeitet wurden.
Mit ParcelableHolder
kann der Eigentümer eines Pakets eine Erweiterung definieren
Punkt in einem Parcelable
.
parcelable AospDefinedParcelable {
int a;
String b;
ParcelableHolder extension;
}
Dann können die Geräteimplementierungen ihre eigene Parcelable
für ihre
.
parcelable OemDefinedParcelable {
String x;
int[] y;
}
Schließlich kann die neue Parcelable
mit folgendem Befehl an die ursprüngliche Parcelable
angehängt werden:
Das Feld ParcelableHolder
.
// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;
ap.extension.setParcelable(op);
...
OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);
// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();
ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);
...
std::shared_ptr<OemDefinedParcelable> op_ptr;
ap.extension.getParcelable(&op_ptr);
// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);
...
std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);
// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });
ap.extension.set_parcelable(Rc::clone(&op));
...
let op = ap.extension.get_parcelable::<OemDefinedParcelable>();
AIDL HAL-Serverinstanznamen
Konventionsgemäß haben AIDL HAL-Dienste einen Instanznamen im folgenden Format:
$package.$type/$instance
Eine Instanz des Vibrations HAL ist beispielsweise
registriert als android.hardware.vibrator.IVibrator/default
.
AIDL HAL-Server schreiben
@VintfStability
AIDL-Server müssen im VINTF-Manifest deklariert sein, für
Beispiel wie folgt:
<hal format="aidl">
<name>android.hardware.vibrator</name>
<version>1</version>
<fqname>IVibrator/default</fqname>
</hal>
Andernfalls sollte der AIDL-Dienst normal registriert werden. Bei Ausführung von VTS Tests durchgeführt werden, sollten alle deklarierten AIDL HALs verfügbar sein.
AIDL-Client schreiben
AIDL-Clients müssen sich selbst in der Kompatibilitätsmatrix deklarieren, z. B.: wie hier:
<hal format="aidl" optional="true">
<name>android.hardware.vibrator</name>
<version>1-2</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
</interface>
</hal>
Vorhandene HAL von HIDL in AIDL konvertieren
Verwenden Sie das hidl2aidl
-Tool, um eine HIDL-Schnittstelle in AIDL zu konvertieren.
hidl2aidl
-Funktionen:
.aidl
-Dateien basierend auf den.hal
-Dateien für das angegebene Paket erstellen- Build-Regeln für das neu erstellte AIDL-Paket mit allen Back-Ends erstellen aktiviert
- Erstellen von Übersetzungsmethoden in den Java-, CPP- und NDK-Back-Ends für die Übersetzung von den HIDL-Typen bis zu den AIDL-Typen
- Build-Regeln für Übersetzungsbibliotheken mit erforderlichen Abhängigkeiten erstellen
- Erstellen Sie statische Assertions, um sicherzustellen, dass HIDL- und AIDL-Enumeratoren die dieselben Werte in den CPP- und NDK-Back-Ends
Führen Sie die folgenden Schritte aus, um ein Paket mit .hal-Dateien in AIDL-Dateien zu konvertieren:
Erstellen Sie das Tool in
system/tools/hidl/hidl2aidl
.Die Erstellung dieses Tools aus der neuesten Quelle bietet die umfassendste Nutzererfahrung. Sie können die neueste Version verwenden, um Schnittstellen auf ältere Versionen zu konvertieren. aus früheren Releases.
m hidl2aidl
Führen Sie das Tool mit einem Ausgabeverzeichnis, gefolgt vom gewünschten Paket aus. Conversion durchgeführt haben.
Optional können Sie mit dem Argument
-l
den Inhalt einer neuen Lizenzdatei hinzufügen. am Anfang aller generierten Dateien. Achten Sie darauf, die richtige Lizenz und das richtige Datum zu verwenden.hidl2aidl -o <output directory> -l <file with license> <package>
Beispiel:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
Lesen Sie sich die generierten Dateien durch und beheben Sie eventuelle Probleme mit der Konvertierung.
conversion.log
enthält alle unbehandelten Probleme, die zuerst behoben werden müssen.- Die generierten
.aidl
-Dateien enthalten möglicherweise Warnungen und Vorschläge, die möglicherweise Maßnahme erforderlich. Diese Kommentare beginnen mit//
. - Nutzen Sie die Gelegenheit, bereinigen und verbessern Sie das Paket.
- Prüfen Sie die
@JavaDerive
. für Funktionen, die möglicherweise erforderlich sind, wietoString
oderequals
Erstellen Sie nur die Ziele, die Sie benötigen.
- Deaktivieren Sie Back-Ends, die nicht verwendet werden. NDK-Backend gegenüber CPP bevorzugen finden Sie unter Laufzeit auswählen.
- Entfernen Sie Übersetzungsbibliotheken und jeglichen generierten Code, der nicht verwendet wird.
Siehe Wichtige Unterschiede zu AIDL/HIDL.
- Die Verwendung der integrierten
Status
von AIDL und Ausnahmen verbessern in der Regel die und überflüssige andere schnittstellenspezifische Statustypen. - AIDL-Schnittstellenargumente in Methoden sind standardmäßig nicht
@nullable
, wie sie im HIDL.
- Die Verwendung der integrierten
SEPolicy für AIDL HALs
Ein für den Anbietercode sichtbarer AIDL-Diensttyp muss die
Attribut „hal_service_type
“. Andernfalls ist die sepolicy-Konfiguration die gleiche
wie bei jedem anderen AIDL-Dienst (obwohl es spezielle Attribute für HALs gibt). Hier
ist eine Beispieldefinition eines HAL-Dienstkontexts:
type hal_foo_service, service_manager_type, hal_service_type;
Für die meisten von der Plattform definierten Dienste ist ein Dienstkontext mit dem korrekten
Typ wurde bereits hinzugefügt. android.hardware.foo.IFoo/default
würde zum Beispiel
bereits als hal_foo_service
gekennzeichnet sein). Wenn ein Framework-Client jedoch
mehrere Instanznamen, müssen zusätzliche Instanznamen hinzugefügt werden.
gerätespezifische service_contexts
-Dateien.
android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0
HAL-Attribute müssen hinzugefügt werden, wenn ein neuer HAL-Typ erstellt wird. Ein bestimmter HAL
kann mehreren Dienstleistungstypen zugeordnet sein (jeweils
wie wir gerade besprochen haben. Für einen HAL, foo
, haben wir
hal_attribute(foo)
. Mit diesem Makro werden die Attribute hal_foo_client
und
hal_foo_server
. Für eine bestimmte Domain werden die hal_client_domain
und
hal_server_domain
-Makros verknüpfen eine Domain mit einem bestimmten HAL-Attribut. Für
Beispiel: Der Systemserver, der ein Client dieses HAL ist, entspricht der Richtlinie
hal_client_domain(system_server, hal_foo)
Ein HAL-Server umfasst ähnlich
hal_server_domain(my_hal_domain, hal_foo)
Normalerweise wird für einen bestimmten HAL
erstellen wir auch eine Domain wie hal_foo_default
als Referenz oder
Beispiel-HALs. Einige Geräte verwenden diese Domains jedoch für ihre eigenen Server.
Die Unterscheidung zwischen Domains für mehrere Server ist nur wichtig, wenn
Auf mehreren Servern, die dieselbe Schnittstelle bedienen und unterschiedliche Berechtigungen benötigen
Implementierung festgelegt. In all diesen Makros ist hal_foo
nicht wirklich
ein sepolicy-Objekt. Stattdessen wird dieses Token von diesen Makros verwendet, um auf
Die Gruppe von Attributen, die einem Client-Server-Paar zugeordnet sind.
Bisher haben wir hal_foo_service
und hal_foo
jedoch noch nicht verknüpft.
(Attributpaar aus hal_attribute(foo)
). Ein HAL-Attribut wird
mit AIDL HAL-Diensten unter Verwendung des Makros hal_attribute_service
(HIDL HALs verwenden
hal_attribute_hwservice
-Makro einfügen. Beispiel:
hal_attribute_service(hal_foo, hal_foo_service)
Das bedeutet, dass
hal_foo_client
-Prozesse können den HAL abrufen und hal_foo_server
Prozesse können den HAL registrieren. Die Durchsetzung dieser Registrierungsregeln
vom Kontextmanager (servicemanager
) ausgeführt. Beachten Sie, dass Dienstnamen
nicht immer HAL-Attributen entsprechen. Zum Beispiel könnten wir
hal_attribute_service(hal_foo, hal_foo2_service)
Generell gilt jedoch,
bedeutet dies, dass die Dienste immer zusammen genutzt werden. Wir könnten überlegen,
hal_foo2_service
und die Nutzung von hal_foo_service
für alle unsere Dienste
Kontexte. Die meisten HALs, die mehrere hal_attribute_service
festlegen, sind aus folgenden Gründen:
Der ursprüngliche HAL-Attributname ist nicht allgemein genug und kann nicht geändert werden.
Zusammenfassend sieht ein HAL-Beispiel wie folgt aus:
public/attributes:
// define hal_foo, hal_foo_client, hal_foo_server
hal_attribute(foo)
public/service.te
// define hal_foo_service
type hal_foo_service, hal_service_type, protected_service, service_manager_type
public/hal_foo.te:
// allow binder connection from client to server
binder_call(hal_foo_client, hal_foo_server)
// allow client to find the service, allow server to register the service
hal_attribute_service(hal_foo, hal_foo_service)
// allow binder communication from server to service_manager
binder_use(hal_foo_server)
private/service_contexts:
// bind an AIDL service name to the selinux type
android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0
private/<some_domain>.te:
// let this domain use the hal service
binder_use(some_domain)
hal_client_domain(some_domain, hal_foo)
vendor/<some_hal_server_domain>.te
// let this domain serve the hal service
hal_server_domain(some_hal_server_domain, hal_foo)
Angehängte Erweiterungsoberflächen
Eine Erweiterung kann an jede Binder-Oberfläche angehängt werden, unabhängig davon, ob es sich um eine oberste Ebene handelt direkt beim Dienstmanager registriert oder eine Subschnittstelle. Wenn Sie eine Erweiterung erhalten, müssen Sie bestätigen, dass der Erweiterungstyp zu erwarten war. Erweiterungen können nur über den Prozess festgelegt werden, in dem ein Binder bereitgestellt wird.
Angehängte Erweiterungen sollten immer dann verwendet werden, wenn eine Erweiterung die eines vorhandenen HAL. Wenn völlig neue Funktionen benötigt werden, Dieser Mechanismus muss nicht verwendet werden und eine Erweiterungsoberfläche die direkt beim Dienstmanager registriert sind. Angehängte Erweiterungsoberflächen ist am sinnvollsten, wenn sie an Subschnittstellen angehängt sind. Hierarchien können tief oder mehrere Instanzen sein. Globale Erweiterung zum Spiegeln verwenden würde die Hierarchie der Binder-Schnittstelle eines anderen Dienstes Buchführung, um eine gleichwertige Funktionalität wie direkt angehängte Erweiterungen zur Verfügung zu stellen.
Verwenden Sie die folgenden APIs, um eine Erweiterung für Binder festzulegen:
- Im NDK-Back-End:
AIBinder_setExtension
- Im Java-Back-End:
android.os.Binder.setExtension
- Im CPP-Back-End:
android::Binder::setExtension
- Im Rust-Back-End:
binder::Binder::set_extension
Verwenden Sie die folgenden APIs, um eine Erweiterung für einen Binder zu erhalten:
- Im NDK-Back-End:
AIBinder_getExtension
- Im Java-Back-End:
android.os.IBinder.getExtension
- Im CPP-Back-End:
android::IBinder::getExtension
- Im Rust-Back-End:
binder::Binder::get_extension
Weitere Informationen zu diesen APIs finden Sie in der Dokumentation der
getExtension
im entsprechenden Back-End. Ein Beispiel für die Verwendung
finden Sie unter
Hardware/Schnittstellen/Tests/Erweiterungen/Vibration
Wesentliche AIDL- und HIDL-Unterschiede
Beachten Sie bei der Verwendung von AIDL HALs oder AIDL HAL-Schnittstellen die Unterschiede im Vergleich zum Schreiben von HIDL HALs.
- Die Syntax der AIDL-Sprache kommt der Java-Syntax näher. Die HIDL-Syntax ähnelt der C++-Syntax.
- Alle AIDL-Schnittstellen haben integrierte Fehlerstatus. Anstelle von benutzerdefinierten
erstellen Sie konstante Status-intts in Benutzeroberflächendateien und verwenden
EX_SERVICE_SPECIFIC
in den CPP/NDK-Back-Ends undServiceSpecificException
im Java-Back-End. Siehe Fehler Handhabung. - AIDL startet Threadpools nicht automatisch, wenn Binderobjekte gesendet werden. Sie müssen manuell gestartet werden (siehe Thread Verwaltung).
- AIDL bricht bei ungeprüften Transportfehlern nicht ab (HIDL
Return
bricht ab am ungeprüften Fehlern). - AIDL kann nur einen Typ pro Datei deklarieren.
- AIDL-Argumente können zusätzlich zur Ausgabe als Ein-/Ausgang/In-Out angegeben werden -Parameter (es gibt keine "synchronen Callbacks").
- AIDL verwendet „fd“ anstelle von „Handle“ als primitiven Typ.
- HIDL verwendet Hauptversionen für inkompatible Änderungen und Nebenversionen für
kompatible Änderungen vornehmen. In AIDL werden abwärtskompatible Änderungen direkt vorgenommen.
AIDL hat kein explizites Konzept von Hauptversionen. Stattdessen ist dies
in Paketnamen integriert werden. AIDL könnte beispielsweise den Paketnamen
bluetooth2
- AIDL übernimmt nicht standardmäßig die Echtzeitpriorität. Das
setInheritRt
muss pro Binder verwendet werden, um die Prioritätsübernahme in Echtzeit zu ermöglichen.