Schnittstellen & Pakete

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).
  • 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.