HIDL basiert auf Schnittstellen, einem abstrakten Typ, der in objektorientierten Sprachen zur Definition von Verhaltensweisen verwendet wird. Jede Schnittstelle ist Teil eines Pakets.
Pakete
Paketnamen können Unterebenen wie package.subpackage
haben. Das Stammverzeichnis für veröffentlichte HIDL-Pakete ist hardware/interfaces
oder vendor/vendorName
(z. B. vendor/google
für Pixel-Geräte). Der Paketname bildet ein oder mehrere Unterverzeichnisse unter dem Stammverzeichnis; Alle Dateien, die ein Paket definieren, befinden sich im selben Verzeichnis. Beispielsweise könnte package android.hardware.example.extension.light@2.0
unter hardware/interfaces/example/extension/light/2.0
gefunden werden.
In der folgenden Tabelle sind Paketpräfixe und Speicherorte aufgeführt:
Paketpräfix | Standort | Schnittstellentypen |
---|---|---|
android.hardware.* | hardware/interfaces/* | HAL |
android.frameworks.* | frameworks/hardware/interfaces/* | Frameworks / verwandt |
android.system.* | system/hardware/interfaces/* | System/bezogen |
android.hidl.* | system/libhidl/transport/* | Kern |
Das Paketverzeichnis enthält Dateien mit der Erweiterung .hal
. Jede Datei muss eine package
enthalten, die das Paket und die Version benennt, zu der die Datei gehört. Die Datei types.hal
definiert, sofern vorhanden, keine Schnittstelle, sondern Datentypen, auf die jede Schnittstelle im Paket zugreifen kann.
Schnittstellendefinition
Abgesehen von types.hal
definiert jede andere .hal
Datei eine Schnittstelle. Eine Schnittstelle ist typischerweise wie folgt definiert:
interface IBar extends IFoo { // IFoo is another interface // embedded types struct MyStruct {/*...*/}; // interface methods create(int32_t id) generates (MyStruct s); close(); };
Eine Schnittstelle ohne explizite extends
Deklaration erstreckt sich implizit von android.hidl.base@1.0::IBase
(ähnlich wie java.lang.Object
in Java). Die implizit importierte IBase-Schnittstelle deklariert mehrere reservierte Methoden, die nicht erneut deklariert werden sollten und können in benutzerdefinierten Schnittstellen oder anderweitig verwendet werden. Zu diesen Methoden gehören:
-
ping
-
interfaceChain
-
interfaceDescriptor
-
notifySyspropsChanged
-
linkToDeath
-
unlinkToDeath
-
setHALInstrumentation
-
getDebugInfo
-
debug
-
getHashChain
Importieren
Die import
ist ein HIDL-Mechanismus für den Zugriff auf Paketschnittstellen und -typen in einem anderen Paket. Eine import
betrifft zwei Entitäten:
- Die importierende Entität, die entweder ein Paket oder eine Schnittstelle sein kann; Und
- Die importierte Entität, die ebenfalls entweder ein Paket oder eine Schnittstelle sein kann.
Die importierende Entität wird durch den Speicherort der import
bestimmt. Wenn sich die Anweisung in der types.hal
eines Pakets befindet, ist das, was importiert wird, für das gesamte Paket sichtbar. Dies ist ein Import auf Paketebene . Wenn sich die Anweisung in einer Schnittstellendatei befindet, ist die importierende Entität die Schnittstelle selbst; Dies ist ein Import auf Schnittstellenebene .
Die importierte Entität wird durch den Wert nach dem Schlüsselwort import
bestimmt. Der Wert muss kein vollständig qualifizierter Name sein; Wenn eine Komponente weggelassen wird, wird sie automatisch mit Informationen aus dem aktuellen Paket gefüllt. Für vollständig qualifizierte Werte werden die folgenden Importfälle unterstützt:
- Ganzpaket-Importe . Wenn es sich bei dem Wert um einen Paketnamen und eine Version handelt (Syntax unten beschrieben), wird das gesamte Paket in die importierende Entität importiert.
- Teilimporte . Wenn der Wert ist:
- Eine Schnittstelle, die
types.hal
des Pakets und diese Schnittstelle werden in die importierende Entität importiert. - Ein in
types.hal
“ definierter UDT, dann wird nur dieser UDT in die importierende Entität importiert (andere Typen in „types.hal
werden nicht importiert).
- Eine Schnittstelle, die
- Nur-Typ-Importe . Wenn der Wert die Syntax eines oben beschriebenen Teilimports verwendet, jedoch mit dem Schlüsselwort „
types
anstelle eines Schnittstellennamens, werden nur die UDTs in „types.hal
des angegebenen Pakets importiert.
Die importierende Entität erhält Zugriff auf eine Kombination aus:
- Die in
types.hal
definierten allgemeinen UDTs des importierten Pakets; - Die Schnittstellen des importierten Pakets (für einen vollständigen Paketimport) oder die angegebene Schnittstelle (für einen teilweisen Import), um sie aufzurufen, Handles an sie zu übergeben und/oder von ihnen zu erben.
Die Importanweisung verwendet die Syntax „vollständig qualifizierter Typname“, um den Namen und die Version des Pakets oder der Schnittstelle bereitzustellen, die importiert werden:
import android.hardware.nfc@1.0; // import a whole package import android.hardware.example@1.0::IQuux; // import an interface and types.hal import android.hardware.example@1.0::types; // import just types.hal
Schnittstellenvererbung
Eine Schnittstelle kann eine Erweiterung einer zuvor definierten Schnittstelle sein. Erweiterungen können einen der folgenden drei Typen haben:
- Die Schnittstelle kann einer anderen Schnittstelle Funktionalität hinzufügen und dabei ihre API unverändert einbeziehen.
- Das Paket kann einem anderen Paket Funktionalität hinzufügen und dabei seine API unverändert einbeziehen.
- Die Schnittstelle kann Typen aus einem Paket oder von einer bestimmten Schnittstelle importieren.
Eine Schnittstelle kann nur eine andere Schnittstelle erweitern (keine Mehrfachvererbung). Jede Schnittstelle in einem Paket mit einer Nebenversionsnummer ungleich Null muss eine Schnittstelle in der vorherigen Version des Pakets erweitern. Wenn beispielsweise eine Schnittstelle IBar
in Version 4.0 des derivative
auf einer Schnittstelle IFoo
in Version 1.2 des Pakets original
basiert (diese erweitert) und eine Version 1.3 des Pakets original
erstellt wird, kann IBar
Version 4.1 Version 1.3 von IFoo
nicht erweitern. Stattdessen muss IBar
Version 4.1 IBar
Version 4.0 erweitern, die an IFoo
Version 1.2 gebunden ist. IBar
Version 5.0 könnte bei Bedarf IFoo
Version 1.3 erweitern.
Schnittstellenerweiterungen implizieren keine Bibliotheksabhängigkeit oder HAL-übergreifende Einbindung in den generierten Code – sie importieren lediglich die Datenstruktur und Methodendefinitionen auf HIDL-Ebene. Jede Methode in einer HAL muss in dieser HAL implementiert werden.
Anbietererweiterungen
In einigen Fällen werden Anbietererweiterungen als Unterklasse des Basisobjekts implementiert, das die Kernschnittstelle darstellt, die sie erweitern. Dasselbe Objekt wird unter dem Basis-HAL-Namen und der Basis-HAL-Version sowie unter dem (Anbieter-)HAL-Namen und der Erweiterungsversion registriert.
Versionierung
Pakete sind versioniert und Schnittstellen verfügen über die Version ihres Pakets. Versionen werden in zwei Ganzzahlen ausgedrückt, Major . unerheblich .
- Hauptversionen sind nicht abwärtskompatibel. Durch Erhöhen der Hauptversionsnummer wird die Nebenversionsnummer auf 0 zurückgesetzt.
- Nebenversionen sind abwärtskompatibel. Das Erhöhen der Nebennummer zeigt an, dass die neuere Version vollständig abwärtskompatibel mit der vorherigen Version ist. Neue Datenstrukturen und Methoden können hinzugefügt werden, bestehende Datenstrukturen oder Methodensignaturen dürfen jedoch nicht geändert werden.
Auf einem Gerät können gleichzeitig mehrere Haupt- oder Nebenversionen eines HAL vorhanden sein. Allerdings sollte eine Nebenversion einer Hauptversion vorgezogen werden, da Clientcode, der mit einer früheren Nebenversionsschnittstelle funktioniert, auch mit späteren Nebenversionen derselben Schnittstelle funktioniert. Weitere Informationen zur Versionierung und Anbietererweiterungen finden Sie unter HIDL-Versionierung .
Zusammenfassung des Schnittstellenlayouts
In diesem Abschnitt wird die Verwaltung eines HIDL-Schnittstellenpakets (z. B. hardware/interfaces
) zusammengefasst und die im gesamten HIDL-Abschnitt präsentierten Informationen konsolidiert. Stellen Sie vor dem Lesen sicher, dass Sie mit der HIDL-Versionierung , den Hashing-Konzepten in Hashing mit hidl-gen , den Details der Arbeit mit HIDL im Allgemeinen und den folgenden Definitionen vertraut sind:
Begriff | Definition |
---|---|
Binäre Anwendungsschnittstelle (ABI) | Anwendungsprogrammierschnittstelle + alle erforderlichen binären Verknüpfungen. |
Vollqualifizierter Name (fqName) | Name zur Unterscheidung eines Hidl-Typs. Beispiel: android.hardware.foo@1.0::IFoo . |
Paket | Paket, das eine HIDL-Schnittstelle und -Typen enthält. Beispiel: android.hardware.foo@1.0 . |
Paketstamm | Root-Paket, das die HIDL-Schnittstellen enthält. Beispiel: Die HIDL-Schnittstelle android.hardware befindet sich im Paketstamm android.hardware.foo@1.0 . |
Paketstammpfad | Speicherort im Android-Quellbaum, dem ein Paketstamm zugeordnet ist. |
Weitere Definitionen finden Sie unter HIDL- Terminologie .
Jede Datei kann über die Paketstammzuordnung und ihren vollständig qualifizierten Namen gefunden werden
Paketwurzeln werden hidl-gen
als Argument -r android.hardware:hardware/interfaces
angegeben. Wenn das Paket beispielsweise vendor.awesome.foo@1.0::IFoo
ist und hidl-gen
-r vendor.awesome:some/device/independent/path/interfaces
gesendet wird, sollte sich die Schnittstellendatei in $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal
befinden. $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal
.
In der Praxis wird einem Anbieter oder OEM namens awesome
empfohlen, seine Standardschnittstellen in vendor.awesome
abzulegen. Nachdem ein Paketpfad ausgewählt wurde, darf dieser nicht mehr geändert werden, da dieser in die ABI der Schnittstelle integriert ist.
Die Paketpfadzuordnung sollte eindeutig sein
Wenn Sie beispielsweise -rsome.package:$PATH_A
und -rsome.package:$PATH_B
haben, muss $PATH_A
für ein konsistentes Schnittstellenverzeichnis gleich $PATH_B
sein (dies erleichtert auch die Versionierung von Schnittstellen erheblich).
Das Paketstammverzeichnis muss über eine Versionierungsdatei verfügen
Wenn Sie einen Paketpfad wie -r vendor.awesome:vendor/awesome/interfaces
erstellen, sollten Sie auch die Datei $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt
erstellen, die Hashes von Schnittstellen enthalten sollte, die mit -Lhash
erstellt wurden Option in hidl-gen
(dies wird ausführlich in Hashing mit hidl-gen besprochen).
Schnittstellen befinden sich an geräteunabhängigen Standorten
In der Praxis wird empfohlen, Schnittstellen zwischen Zweigen gemeinsam zu nutzen. Dies ermöglicht eine maximale Wiederverwendung des Codes und ein maximales Testen des Codes über verschiedene Geräte und Anwendungsfälle hinweg.