Versionsverwaltung der Benutzeroberfläche

HIDL setzt voraus, dass jede in HIDL geschriebene Schnittstelle versioniert ist. Nach einem HAL angezeigt wird, ist sie eingefroren und weitere Änderungen an einer neue Version dieser Benutzeroberfläche. Eine veröffentlichte Oberfläche kann geändert wurde, kann er durch eine andere Schnittstelle erweitert werden.

HIDL-Codestruktur

HIDL-Code ist in benutzerdefinierten -Typen, Schnittstellen und Pakete:

  • Benutzerdefinierte Typen (User-Defined types, UDFs): HIDL bietet Zugriff auf eine Reihe von primitive Datentypen, die zur Erstellung komplexerer Typen über Strukturen, Vereinigungen und Aufzählungen. UDTs werden an Methoden der Schnittstellen und können auf Paketebene (allgemein für alle oder lokal zu einer Schnittstelle.
  • Schnittstellen. Ein Grundbaustein von HIDL ist eine Benutzeroberfläche, besteht aus UDT- und Methodendeklarationen. Schnittstellen können auch von eine andere Schnittstelle.
  • Pakete: Organisiert verwandte HIDL-Schnittstellen und die Daten Typen, für die sie zuständig sind. Ein Paket wird durch einen Namen, eine Version umfasst Folgendes: <ph type="x-smartling-placeholder">
      </ph>
    • Datentyp-Definitionsdatei mit dem Namen types.hal.
    • Null oder mehr Schnittstellen, jede in einer eigenen .hal-Datei.

Die Datentypdefinitionsdatei types.hal enthält nur UDTs (alle UDTs auf Paketebene werden in einer einzigen Datei gespeichert). Darstellungen im Ziel Sprache für alle Oberflächen im Paket verfügbar.

Philosophie der Versionsverwaltung

Ein HIDL-Paket (z. B. android.hardware.nfc), nachdem es die für eine bestimmte Version (z. B. 1.0) veröffentlicht wurden, unveränderlich ist. sie kann nicht geändert werden. Änderungen an den Schnittstellen im Paket oder an anderen können Änderungen an seinen UDTs nur in einem anderen Paket erfolgen.

In HIDL wird die Versionsverwaltung auf Paketebene angewendet, nicht auf und alle Schnittstellen und UDTs in einem Paket haben dieselbe Version. Paket Versionen folgen semantisch Versionsverwaltung, ohne die Patch- und Build-Metadatenkomponenten zu verwenden. Innerhalb eines eines bestimmten Pakets impliziert ein Bump der Nebenversion die neue Version von Das Paket ist abwärtskompatibel mit dem alten Paket und einer Hauptversion. version bump impliziert, dass die neue Version des Pakets nicht abwärtskompatibel mit dem alten Paket ist.

Konzeptionell kann ein Paket auf mehrere Arten mit einem anderen Paket verknüpft werden:

  • Überhaupt nicht.
  • Abwärtskompatible Erweiterbarkeit auf Paketebene. Dieses erfolgt bei neuen Uprevs der Nebenversion (nächste inkrementierte Überarbeitung) eines Pakets; hat das neue Paket denselben Namen und dieselbe Hauptversion wie das alte Paket, aber ein höhere Nebenversion. Funktionstechnisch ist das neue Paket eine Obermenge des alten Paket, was bedeutet: <ph type="x-smartling-placeholder">
      </ph>
    • Oberflächen der obersten Ebene des übergeordneten Pakets sind im neuen Paket vorhanden, obwohl die Schnittstellen über neue Methoden verfügen, neue Schnittstellen-lokale UDTs (die wie unten beschrieben) und neue UDTs in types.hal
    • Neue Oberflächen können auch zum neuen Paket hinzugefügt werden.
    • Alle Datentypen des übergeordneten Pakets sind im neuen Paket vorhanden und können von den (möglicherweise erneut implementiert) Methoden aus dem alten Paket gehandhabt werden.
    • Neue Datentypen können auch zur Verwendung durch neue Methoden vorhandene Schnittstellen oder neue Benutzeroberflächen verwendet werden.
  • Abwärtskompatible Erweiterbarkeit auf Schnittstellenebene. Das neue -Paket kann das ursprüngliche Paket auch erweitern, indem es aus logisch separaten Schnittstellen, die einfach zusätzliche Funktionen bieten und nicht die Hauptfunktion. Zu diesem Zweck könnte Folgendes sinnvoll sein: <ph type="x-smartling-placeholder">
      </ph>
    • Schnittstellen im neuen Paket müssen auf die Datentypen der alten Paket.
    • Schnittstellen im neuen Paket können Schnittstellen von einem oder mehreren alten Pakete.
  • Die ursprüngliche Abwärtsinkompatibilität verlängern. Dies ist ein Aktualisierungen der Hauptversion des Pakets durchgeführt werden und keine Korrelation zwischen die beiden. Soweit dies vorhanden ist, kann sie mit einer Kombination aus aus der älteren Version des Pakets und die Übernahme einer Teilmenge von alten Paket-Schnittstellen.

Schnittstellenstrukturierung

Für eine gut strukturierte Oberfläche können nicht Teil des ursprünglichen Designs sind, sollte eine Änderung an der HIDL erforderlich sein. . Umgekehrt gilt: Ob Sie eine Änderung auf beiden Seiten des Die Benutzeroberfläche, die neue Funktionen bietet, ohne die Benutzeroberfläche zu ändern ist die Benutzeroberfläche nicht strukturiert.

Treble unterstützt separat kompilierte Anbieter- und Systemkomponenten, bei denen der vendor.img auf einem Gerät und das system.img kann kompiliert werden. Alle Interaktionen zwischen vendor.img und system.img muss explizit und ausführlich definiert werden, weiterzubilden. Dies umfasst viele API-Oberflächen, aber ist der IPC-Mechanismus, den HIDL für die Interprozesskommunikation auf der Grenze: system.img/vendor.img.

Voraussetzungen

Alle über HIDL übergebenen Daten müssen explizit definiert werden. Um sicherzustellen, Implementierung und Client können weiter zusammenarbeiten, auch wenn separat oder unabhängig entwickelt wurden, müssen die Daten Anforderungen:

  • Können direkt in HIDL beschrieben werden (mithilfe von Structs enums usw.) mit semantische Namen und ihre Bedeutung.
  • Sie können durch einen öffentlichen Standard wie ISO/IEC 7816 beschrieben werden.
  • Kann durch einen Hardwarestandard oder ein physisches Layout der Hardware beschrieben werden.
  • Bei Bedarf können intransparente Daten wie öffentliche Schlüssel oder IDs sein.

Wenn opake Daten verwendet werden, dürfen sie nur von einer Seite des HIDL gelesen werden . Wenn zum Beispiel der vendor.img-Code eine Komponente system.img ist eine Stringnachricht oder vec<uint8_t> Daten enthalten, können diese Daten nicht vom system.img selbst geparst werden. kann es nur zur Interpretation an vendor.img zurückgegeben werden. Wann Wert von vendor.img an Anbietercode übergeben auf system.img oder auf ein anderes Gerät übertragen werden, muss genau beschrieben werden und dennoch Teil des Schnittstelle.

Richtlinien

Sie sollten in der Lage sein, eine Implementierung oder einen Client eines HAL nur mit die .hal-Dateien (Sie sollten sich also nicht die Android-Quelle oder öffentliche Standards). Wir empfehlen, das genaue erforderliche Verhalten anzugeben. Aussagen wie „Eine Implementierung könnte A oder B tun“, Implementierungen dazu anzuregen, die mit den Auftraggebenden verflochten sind, mit denen sie entwickelt werden.

HIDL-Codelayout

HIDL umfasst Kern- und Anbieterpakete.

Die wichtigsten HIDL-Schnittstellen werden von Google angegeben. Pakete, zu denen sie gehören mit android.hardware. beginnen und nach Subsystem benannt sind, möglicherweise mit verschachtelten Benennungsebenen. Das NFC-Paket trägt beispielsweise android.hardware.nfc und das Kamerapaket sind android.hardware.camera. Im Allgemeinen hat ein Kernpaket android.hardware.[name1].[name2]... HIDL-Pakete haben neben ihrem Namen auch eine Version. Zum Beispiel enthält das Paket android.hardware.camera ist möglicherweise Version 3.4. das ist da die Version eines Pakets seine Platzierung in der Quellstruktur beeinflusst.

Alle Kernpakete befinden sich unter hardware/interfaces/ in der zu erstellen. Das Paket android.hardware.[name1].[name2]... in Version $m.$n ist unter hardware/interfaces/name1/name2/.../$m.$n/; Paket android.hardware.camera-Version 3.4 befindet sich im Verzeichnis hardware/interfaces/camera/3.4/. Eine hartcodierte Zuordnung ist vorhanden. zwischen dem Paketpräfix android.hardware. und dem Pfad hardware/interfaces/

Nicht-Core-Pakete (Anbieter) werden vom SoC-Anbieter oder ODM erstellt. Die Präfix für Nicht-Kernpakete ist vendor.$(VENDOR).hardware., wobei $(VENDOR)bezieht sich auf einen SoC-Anbieter oder OEM/ODM. Dies entspricht dem Pfad vendor/$(VENDOR)/interfaces in der Baumstruktur (diese Zuordnung ist auch hartcodiert).

Voll qualifizierte Namen von benutzerdefinierten Typen

In HIDL hat jede UDT einen voll qualifizierten Namen, der aus dem UDT-Namen, den Namen des Pakets, in dem die UDT definiert ist, und die Paketversion. Die voll qualifizierter Name wird nur verwendet, wenn Instanzen des Typs deklariert sind und und nicht dort, wo der Typ selbst definiert ist. Angenommen, ein Paket android.hardware.nfc, Version 1.0 definiert eine Struktur mit dem Namen NfcData. Auf der Website der Erklärung (ob in types.hal oder in der Deklaration einer Benutzeroberfläche) enthalten ist), die Deklaration. lautet einfach:

struct NfcData {
    vec<uint8_t> data;
};

Bei der Deklaration einer Instanz dieses Typs (innerhalb einer Datenstruktur oder als Methodenparameter) verwenden, verwenden Sie den voll qualifizierten Typnamen:

android.hardware.nfc@1.0::NfcData

Die allgemeine Syntax lautet PACKAGE@VERSION::UDT. Dabei gilt:

  • PACKAGE ist der durch Punkte getrennte Name eines HIDL-Pakets. (z.B. android.hardware.nfc.
  • VERSION ist die durch Punkte getrennte Hauptversion. Format des Pakets (z.B. 1.0.
  • UDT ist der durch Punkte getrennte Name einer HIDL UDT. Da HIDL verschachtelte UDTs unterstützt und HIDL-Schnittstellen UDTs (eine Art von verschachtelte Deklaration) werden Punkte verwendet, um auf die Namen zuzugreifen.

Wenn beispielsweise die folgende verschachtelte Deklaration im allgemeinen Typendatei in Version des Pakets android.hardware.example 1.0:

// types.hal
package android.hardware.example@1.0;
struct Foo {
    struct Bar {
        // …
    };
    Bar cheers;
};

Der voll qualifizierte Name für Bar lautet android.hardware.example@1.0::Foo.Bar. Wenn Sie nicht nur in im obigen Paket befanden sich die verschachtelte Deklaration in einer Schnittstelle namens IQuux:

// IQuux.hal
package android.hardware.example@1.0;
interface IQuux {
    struct Foo {
        struct Bar {
            // …
        };
        Bar cheers;
    };
    doSomething(Foo f) generates (Foo.Bar fb);
};

Der voll qualifizierte Name für Bar lautet android.hardware.example@1.0::IQuux.Foo.Bar.

In beiden Fällen kann Bar nur als Bar bezeichnet werden im Geltungsbereich der Erklärung von Foo liegen. Am Paket oder Oberflächenebene müssen Sie über Foo auf Bar verweisen: Foo.Bar, wie in der Deklaration der Methode doSomething oben. Alternativ können Sie die Methode ausführlicher wie folgt deklarieren:

// IQuux.hal
doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);

Voll qualifizierte Aufzählungswerte

Wenn es sich bei einer UDT um einen Enum-Typ handelt, hat jeder Wert des enum-Typs eine vollständig qualifizierter Name, der mit dem voll qualifizierten Namen des enum-Typs beginnt, gefolgt von einem Doppelpunkt und dem Namen des enum-Werts. Beispiel: von Paket android.hardware.nfc, Version 1.0 ausgehen definiert einen Enum-Typ NfcStatus:

enum NfcStatus {
    STATUS_OK,
    STATUS_FAILED
};

Wenn auf STATUS_OK verwiesen wird, lautet der vollständig qualifizierte Name:

android.hardware.nfc@1.0::NfcStatus:STATUS_OK

Die allgemeine Syntax lautet PACKAGE@VERSION::UDT:VALUE, Dabei gilt:

  • PACKAGE@VERSION::UDT ist der/die/das genau denselben vollständig qualifizierten Namen für den Enum-Typ.
  • VALUE ist der Name des Werts.

Regeln für die automatische Inferenz

Ein voll qualifizierter UDT-Name muss nicht angegeben werden. Ein UDT-Name kann Lassen Sie Folgendes weg:

  • Das Paket, z.B. @1.0::IFoo.Type
  • Sowohl Paket als auch Version, z.B. IFoo.Type

HIDL versucht, den Namen mithilfe von Regeln für automatische Interferenzen zu vervollständigen (untere Regel Zahl bedeutet höhere Priorität).

Regel 1

Wenn kein Paket und keine Version angegeben werden, wird eine lokale Namenssuche durchgeführt. Beispiel:

interface Nfc {
    typedef string NfcErrorMessage;
    send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m);
};

NfcErrorMessage wurde lokal gesucht und typedef darüber gefunden wird. NfcData wurde auch lokal gesucht, aber da es derzeit ist nicht lokal definiert ist, werden Regel 2 und 3 angewendet. @1.0::NfcStatus stellt eine Version bereit, sodass Regel 1 nicht zutrifft.

Regel 2

Wenn Regel 1 fehlschlägt und eine Komponente des voll qualifizierten Namens fehlt (Paket, Version oder Paket und Version) enthält, wird die Komponente automatisch aus dem aktuellen Paket. Der HIDL-Compiler sucht dann im der aktuellen Datei (und aller Importe), um den automatisch ausgefüllten, voll qualifizierten Namen zu finden. Nehmen wir für das obige Beispiel die Deklaration ExtendedNfcData an. wurde im selben Paket (android.hardware.nfc) zur selben Zeit Version (1.0) als NfcData:

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

Der HIDL-Compiler füllt den Paketnamen und Versionsnamen aus der Aktuelles Paket zum Erstellen des voll qualifizierten UDT-Namens android.hardware.nfc@1.0::NfcData Da der Name bereits im (vorausgesetzt, es wurde ordnungsgemäß importiert), wird es für den Erklärung.

Ein Name im aktuellen Paket wird nur importiert, wenn einer der folgenden Punkte zutrifft: true:

  • Sie wird explizit mit einer import-Anweisung importiert.
  • Sie ist im aktuellen Paket in types.hal definiert.

Dies gilt auch, wenn NfcData nur durch Die Versionsnummer:

struct ExtendedNfcData {
    // autofill the current package name (android.hardware.nfc)
    @1.0::NfcData base;
    // … additional members
};

Regel 3

Wenn Regel 2 keine Übereinstimmung erzeugt (die UDT ist nicht in der aktuellen -Paket), sucht der HIDL-Compiler in allen importierten Paketen nach einer Übereinstimmung. Im obigen Beispiel wird davon ausgegangen, dass ExtendedNfcData deklariert ist in Version 1.1 des Pakets android.hardware.nfc, 1.1 importiert 1.0 wie vorgesehen (siehe Erweiterungen auf Paketebene) und die Definition gibt nur den UDT-Namen an:

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

Der Compiler sucht nach jeder UDT mit dem Namen NfcData und findet eine in android.hardware.nfc mit Version 1.0, was zu einer voll qualifizierte UDT von android.hardware.nfc@1.0::NfcData. Wenn mehr als eine Übereinstimmung für eine bestimmte teilweise qualifizierte UDT, den HIDL-Compiler, gefunden wird. wird ein Fehler ausgegeben.

Beispiel

Bei Verwendung von Regel 2 wird ein im aktuellen Paket definierter importierter Typ bevorzugt einem importierten Typ aus einem anderen Paket:

// hardware/interfaces/foo/1.0/types.hal
package android.hardware.foo@1.0;
struct S {};

// hardware/interfaces/foo/1.0/IFooCallback.hal
package android.hardware.foo@1.0;
interface IFooCallback {};

// hardware/interfaces/bar/1.0/types.hal
package android.hardware.bar@1.0;
typedef string S;

// hardware/interfaces/bar/1.0/IFooCallback.hal
package android.hardware.bar@1.0;
interface IFooCallback {};

// hardware/interfaces/bar/1.0/IBar.hal
package android.hardware.bar@1.0;
import android.hardware.foo@1.0;
interface IBar {
    baz1(S s); // android.hardware.bar@1.0::S
    baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback
};
  • S wird so interpoliert: android.hardware.bar@1.0::S und wird gefunden in bar/1.0/types.hal (weil types.hal automatisch importiert).
  • IFooCallback wird so interpoliert: android.hardware.bar@1.0::IFooCallback mithilfe von Regel 2, wurde nicht gefunden, da bar/1.0/IFooCallback.hal nicht importiert wurde automatisch (so wie types.hal). Somit wird sie durch Regel 3 in Stattdessen android.hardware.foo@1.0::IFooCallback, das importiert wird über import android.hardware.foo@1.0;).

Typen.hal

Jedes HIDL-Paket enthält eine types.hal-Datei mit UDTs. die von allen Benutzeroberflächen gemeinsam genutzt werden, die zu diesem Paket gehören. HIDL-Typen immer öffentlich sind; unabhängig davon, ob in den Dateien types.hal oder in einer Schnittstellendeklaration sind diese Typen die außerhalb des Bereichs zugänglich sind, in dem sie definiert sind. types.hal ist nicht dazu gedacht, die öffentliche API eines Pakets zu beschreiben, sondern vielmehr zum Hosten von UDTs. von allen Schnittstellen innerhalb des Pakets verwendet. Aufgrund der Beschaffenheit von HIDL werden alle UDTs sind Teil der Benutzeroberfläche.

types.hal besteht aus UDTs und import-Anweisungen. Da types.hal für jede Schnittstelle des Paket (Es handelt sich um einen impliziten Import), sind diese import-Anweisungen auf Paketebene festlegen. UDTs in types.hal können auch Auf diese Weise importierte UDTs und Schnittstellen.

Für ein IFoo.hal-Objekt beispielsweise:

package android.hardware.foo@1.0;
// whole package import
import android.hardware.bar@1.0;
// types only import
import android.hardware.baz@1.0::types;
// partial imports
import android.hardware.qux@1.0::IQux.Quux;
// partial imports
import android.hardware.quuz@1.0::Quuz;

Folgendes wird importiert:

  • android.hidl.base@1.0::IBase (implizit)
  • android.hardware.foo@1.0::types (implizit)
  • Alle Inhalte in android.hardware.bar@1.0 (einschließlich aller und seine types.hal)
  • types.hal von android.hardware.baz@1.0::types (Schnittstellen in android.hardware.baz@1.0 werden nicht importiert)
  • IQux.hal und types.hal von android.hardware.qux@1.0
  • Quuz von android.hardware.quuz@1.0 (vorausgesetzt, Quuz ist in types.hal definiert, der gesamte types.hal Datei wurde geparst, aber andere Typen als Quuz werden nicht importiert).

Versionsverwaltung auf Benutzeroberfläche

Jede Schnittstelle innerhalb eines Pakets befindet sich in einer eigenen Datei. Das Paket wird im oberen Bereich der Schnittstelle mit der Methode package-Anweisung. Nach der Paketdeklaration sind null oder mehr Möglicherweise sind Importe auf Schnittstellenebene (teilweise oder ganzes Paket) aufgeführt. Beispiel:

package android.hardware.nfc@1.0;

In HIDL können Schnittstellen mithilfe der extends Keyword. Damit eine Schnittstelle eine andere Schnittstelle erweitert, muss über eine import-Anweisung Zugriff darauf haben. Der Name des Erweiterung der Schnittstelle (Basisschnittstelle) folgt den Regeln für den Typnamen die oben erläuterten Voraussetzungen erfüllt. Eine Schnittstelle kann nur von einer Schnittstelle übernehmen. HIDL unterstützt keine mehrfache Vererbung.

In den folgenden Beispielen für die Uprev-Versionsverwaltung wird das folgende Paket verwendet:

// types.hal
package android.hardware.example@1.0
struct Foo {
    struct Bar {
        vec<uint32_t> val;
    };
};

// IQuux.hal
package android.hardware.example@1.0
interface IQuux {
    fromFooToBar(Foo f) generates (Foo.Bar b);
}

Uprev-Regeln

Um ein Paket package@major.minor zu definieren, entweder A oder alle B muss wahr sein:

Regel A "Ist eine Start-Nebenversion": alle früheren Nebenversionen, package@major.0, package@major.1, ..., package@major.(minor-1) darf nicht definiert sein.
OR
Regel B

Alle folgenden Aussagen treffen zu:

  1. „Die vorherige Nebenversion ist gültig“: package@major.(minor-1) definiert sein und derselben Regel A (keine der package@major.0 bis package@major.(minor-2) oder Regel B (wenn es sich um eine Steigerung von @major.(minor-2) handelt).

    UND

  2. "Übernehmen Sie mindestens eine Schnittstelle mit demselben Namen": Es gibt ein Schnittstelle package@major.minor::IFoo, die erweitert package@major.(minor-1)::IFoo (wenn das vorherige Paket eine Schnittstelle hat);

    UND

  3. "Keine übernommene Schnittstelle mit einem anderen Namen": Es darf nicht vorhanden sein. package@major.minor::IBar mit package@major.(minor-1)::IBaz, wobei IBar und IBaz sind zwei verschiedene Namen. Wenn es eine Schnittstelle mit der gleicher Name, package@major.minor::IBar muss erweitert werden package@major.(minor-k)::IBar, sodass keine IBar mit einer kleineres k

Aufgrund von Regel A gilt:

  • Das Paket kann mit einer beliebigen Nebenversionsnummer beginnen (z. B. android.hardware.biometrics.fingerprint beginnt um @2.1)
  • Die Anforderung „android.hardware.foo@1.0 ist nicht definiert“ bedeutet Das Verzeichnis hardware/interfaces/foo/1.0 sollte noch gar nicht vorhanden sein.

Regel A wirkt sich jedoch nicht auf ein Paket aus, das denselben Paketnamen, eine andere Hauptversion hat, z. B. android.hardware.camera.device enthält sowohl @1.0 als auch @3.2 definiert; @3.2 muss nicht mit @1.0. Daher kann @3.2::IExtFoo das Volumen @1.0::IFoo

Falls der Paketname abweicht, package@major.minor::IBar kann von einer Schnittstelle mit einem einen anderen Namen haben (z. B. kann android.hardware.bar@1.0::IBar erweitern android.hardware.baz@2.2::IBaz). Wenn eine Schnittstelle nicht explizit mit dem Keyword extend einen Super-Typ deklarieren, gilt für android.hidl.base@1.0::IBase (außer IBase)

B.2 und B.3 müssen gleichzeitig befolgt werden. Selbst wenn beispielsweise android.hardware.foo@1.1::IFoo erweitert android.hardware.foo@1.0::IFoo, um Regel B.2 zu bestehen, wenn eine android.hardware.foo@1.1::IExtBar verlängert android.hardware.foo@1.0::IBar, dies ist immer noch keine gültige Steigerung.

Uprev-Schnittstellen

Um android.hardware.example@1.0 (wie oben definiert) zu erhöhen auf @1.1:

// types.hal
package android.hardware.example@1.1;
import android.hardware.example@1.0;

// IQuux.hal
package android.hardware.example@1.1
interface IQuux extends @1.0::IQuux {
    fromBarToFoo(Foo.Bar b) generates (Foo f);
}

Dies ist eine import auf Paketebene der Version 1.0 von „android.hardware.example“ in types.hal. Obwohl keine neuen UDTs werden in Version 1.1 des Pakets hinzugefügt, Verweise auf UDTs in Version 1.0 wird noch benötigt, daher der Import auf Paketebene in types.hal. (Derselbe Effekt hätte auch mit einem Import auf Schnittstellenebene in IQuux.hal.)

In extends @1.0::IQuux in der Deklaration von IQuux haben wir die Version von IQuux angegeben, übernommen (Definition ist erforderlich, da IQuux für Folgendes verwendet wird: eine Schnittstelle deklarieren und von einer Schnittstelle übernehmen). Da Deklarationen einfach Namen, die alle Paket- und Versionsattribute auf der Website des -Deklaration im Namen der Basisschnittstelle. wir Es hätte auch die voll qualifizierte UDT nutzen können, redundant.

Die neue Schnittstelle IQuux deklariert die Methode nicht noch einmal fromFooToBar() wird von @1.0::IQuux übernommen. es einfach listet die neue Methode auf, die hinzugefügt wird fromBarToFoo(). In HIDL übernommen können in den untergeordneten Oberflächen nicht erneut deklariert werden. Die IQuux-Schnittstelle kann die fromFooToBar() nicht deklarieren explizit auf.

Uprev-Konventionen

Manchmal müssen Schnittstellennamen die erweiternde Schnittstelle umbenennen. Wir empfehlen, dass Enum-Erweiterungen, Structs und Unions denselben Namen haben wie die, die sie erweitern. es sei denn, sie unterscheiden sich so stark, dass ein neuer Name gerechtfertigt ist. Beispiele:

// in parent hal file
enum Brightness : uint32_t { NONE, WHITE };

// in child hal file extending the existing set with additional similar values
enum Brightness : @1.0::Brightness { AUTOMATIC };

// extending the existing set with values that require a new, more descriptive name:
enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };

Wenn eine Methode einen neuen semantischen Namen haben kann (z. B. fooWithLocation) ist das bevorzugt. Andernfalls sollte es einen ähnlichen Namen wie die Erweiterung hat. Die Methode foo_1_1 in @1.1::IFoo kann die Funktion ersetzen der foo-Methode in @1.0::IFoo, wenn es keine bessere Alternativname.

Versionsverwaltung auf Paketebene

Die HIDL-Versionsverwaltung erfolgt auf Paketebene. nachdem ein Paket veröffentlicht wurde, ist unveränderlich (seine Gruppe von Schnittstellen und UDTs kann nicht geändert werden). Pakete können beziehen sich in vielerlei Hinsicht aufeinander. All dies lässt sich über ein Kombination aus Vererbung auf Schnittstellenebene und Erstellen von UDTs durch Zusammensetzung.

Eine Art von Beziehung ist jedoch genau definiert und muss erzwungen werden: Abwärtskompatible Übernahme auf Paketebene: In diesem Szenario parent-Paket ist das Paket, von dem übernommen wird, und das child-Paket erweitert das übergeordnete Paket. Paketebene Für abwärtskompatible Übernahmeregeln gelten folgende Regeln:

  1. Alle Oberflächen der obersten Ebene des übergeordneten Pakets werden von Schnittstellen im Child-Paket.
  2. Neue Benutzeroberflächen können auch zum neuen Paket hinzugefügt werden (keine Einschränkungen hinsichtlich Beziehungen zu anderen Schnittstellen in anderen Paketen).
  3. Neue Datentypen können auch zur Verwendung durch neue Methoden vorhandene Schnittstellen oder neue Benutzeroberflächen verwendet werden.

Diese Regeln können mithilfe von HIDL-Schnittstellenvererbung und UDT implementiert werden. Komposition, erfordert aber Kenntnisse auf Metaebene, um diese Zusammenhänge zu verstehen eine abwärtskompatible Paketerweiterung darstellen. Dieses Wissen basiert auf wie folgt:

Wenn ein Paket diese Anforderung erfüllt, erzwingt hidl-gen Abwärtskompatibilitätsregeln.