HIDL

HAL-Schnittstellendefinitionssprache oder HIDL (ausgesprochen "hide-l") ist eine Schnittstellenbeschreibungssprache (IDL), um die Schnittstelle zwischen einer HAL und ihren Benutzern zu spezifizieren. Es ermöglicht die Angabe von Typen und Methodenaufrufen, die in Schnittstellen und Paketen gesammelt werden. Allgemeiner gesagt ist HIDL ein System zur Kommunikation zwischen Codebasen, die unabhängig kompiliert werden können. Ab Android 10 ist HIDL veraltet und Android migriert, um AIDL überall zu verwenden.

HIDL soll für die Interprozesskommunikation (IPC) verwendet werden. Die Kommunikation zwischen Prozessen wird als mit Bindemittel . Für Bibliotheken , die zu einem Prozess verknüpft werden müssen, ein Pass - Through - Modus ist ebenfalls verfügbar (nicht in Java unterstützt).

HIDL spezifiziert Datenstrukturen und Methodensignaturen, organisiert in Schnittstellen (ähnlich einer Klasse), die in Paketen gesammelt werden. Die Syntax von HIDL wird C++- und Java-Programmierern bekannt vorkommen, allerdings mit einem anderen Satz von Schlüsselwörtern. HIDL verwendet auch Anmerkungen im Java-Stil.

HIDL-Design

Das Ziel von HIDL besteht darin, dass das Framework ersetzt werden kann, ohne dass HALs neu erstellt werden müssen. HALs wird von einem Lieferanten oder SOC - Herstellern und in einer gebaut werden /vendor Partition auf dem Gerät, den Rahmen ermöglicht, in einer eigenen Partition mit einem OTA ersetzt werden , ohne dass der HALs neu zu kompilieren.

HIDL-Design gleicht die folgenden Bedenken aus:

  • Interoperabilität. Erstellen Sie zuverlässig interoperable Schnittstellen zwischen Prozessen, die mit verschiedenen Architekturen, Toolchains und Build-Konfigurationen kompiliert werden können. HIDL-Schnittstellen sind versioniert und können nach der Veröffentlichung nicht mehr geändert werden.
  • Effizienz. HIDL versucht, die Anzahl der Kopiervorgänge zu minimieren. HIDL-definierte Daten werden an C++-Code in C++-Standardlayout-Datenstrukturen geliefert, die ohne Entpacken verwendet werden können. HIDL bietet auch Shared-Memory-Schnittstellen und da RPCs von Natur aus etwas langsam sind, unterstützt HIDL zwei Möglichkeiten, Daten ohne einen RPC-Aufruf zu übertragen: Shared Memory und Fast Message Queue (FMQ).
  • Intuitive. HIDL vermeidet heikle Fragen von Speicherbesitz nur unter Verwendung von in für RPC - Parameter (siehe Android Interface Definition Language (AIDL) ); Werte, die von Methoden nicht effizient zurückgegeben werden können, werden über Callback-Funktionen zurückgegeben. Weder die Übergabe von Daten an HIDL zur Übertragung noch das Empfangen von Daten von HIDL ändert den Besitz der Daten – der Besitz verbleibt immer bei der aufrufenden Funktion. Daten müssen nur für die Dauer der aufgerufenen Funktion bestehen bleiben und können sofort nach der Rückkehr der aufgerufenen Funktion zerstört werden.

Verwenden des Passthrough-Modus

Um Geräte mit früheren Android-Versionen auf Android O zu aktualisieren, können Sie sowohl konventionelle (als auch ältere) HALs in eine neue HIDL-Schnittstelle einschließen, die die HAL im gebundenen und prozessgleichen (Passthrough) Modus bereitstellt. Diese Umhüllung ist sowohl für das HAL- als auch für das Android-Framework transparent.

Der Passthrough-Modus ist nur für C++-Clients und -Implementierungen verfügbar. Geräte, auf denen frühere Android-Versionen ausgeführt werden, verfügen nicht über in Java geschriebene HALs, sodass Java-HALs von Natur aus gebunden sind.

Wenn eine .hal Datei kompiliert wird, hidl-gen erzeugt eine zusätzliche Pass - Through - Header - Datei BsFoo.h zusätzlich zu dem für Bindemittel Kommunikation verwendet Header; Dieser Header definiert Funktionen sein dlopen ed. Da Passthrough-HALs im gleichen Prozess laufen, in dem sie aufgerufen werden, werden Passthrough-Methoden in den meisten Fällen durch einen direkten Funktionsaufruf (gleicher Thread) aufgerufen. oneway Verfahren laufen in ihren eigenen Thread , da sie nicht für die HAL warten sollen , sie verarbeiten (dies bedeutet , daß jede HAL Verwendungen oneway im Durchreichmodus Methoden threadsicher sein muss).

Bei einer gegebenen IFoo.hal , BsFoo.h hüllt die HIDL generierten Methoden zusätzliche Funktionen zur Verfügung zu stellen (wie macht oneway - Transaktionen in einem anderen Thread ausgeführt werden ). Diese Datei ist ähnlich BpFoo.h jedoch stattdessen auf Anrufe von geben IPC mit Bindemittel werden die gewünschten Funktionen direkt aufgerufen. Künftige Implementierungen von HALS können mehrere Implementierungen, wie FooFast HAL und einem FooAccurate HAL bieten. In solchen Fällen wäre eine Datei für jede weitere Implementierung erstellt werden (zB PTFooFast.cpp und PTFooAccurate.cpp ).

Binderisieren von Passthrough-HALs

Sie können HAL-Implementierungen binden, die den Passthrough-Modus unterstützen. Bei einer HAL - Schnittstelle abcd@MN::IFoo , zwei Pakete erstellt:

  • abcd@MN::IFoo-impl . Enthält die Umsetzung der HAL und Exposes funktionieren IFoo* HIDL_FETCH_IFoo(const char* name) . Auf älteren Geräten ist dieses Paket dlopen ed und die Umsetzung wird unter Verwendung instanziiert HIDL_FETCH_IFoo . Sie können den Basiscode erzeugen hidl-gen und -Lc++-impl und -Landroidbp-impl .
  • abcd@MN::IFoo-service . Öffnet die Passthrough-HAL und registriert sich selbst als gebundener Dienst, sodass dieselbe HAL-Implementierung sowohl als Passthrough als auch als gebundener Dienst verwendet werden kann.

In Anbetracht der Art IFoo , können Sie rufen sp<IFoo> IFoo::getService(string name, bool getStub) Zugriff auf eine Instanz zu bekommen IFoo . Wenn getStub wahr ist, getService Versuche , die HAL zu öffnen nur im Durchschreibemodus. Wenn getStub falsch ist, getService zu finden versucht , einen Dienst mit Bindemittel; Wenn dies fehlschlägt, wird versucht, den Passthrough-Dienst zu finden. Der getStub Parameter sollte nie außer in verwendet werden defaultPassthroughServiceImplementation . (Geräte, die mit Android O gestartet werden, sind vollständig gebundene Geräte, daher ist das Öffnen eines Dienstes im Passthrough-Modus nicht zulässig.)

HIDL-Grammatik

Die HIDL-Sprache ist C von Entwurf ähnlich (verwendet jedoch nicht den C-Präprozessor). Alle Interpunktion nicht unter (abgesehen von der offensichtlichen Verwendung beschrieben = und | ) ist Teil der Grammatik.

Hinweis: Weitere Informationen über HIDL Code - Stil finden Sie im Kodex Style Guide .

  • /** */ zeigt eine Dokumentation Kommentar. Diese können nur auf Typ-, Methoden-, Feld- und Aufzählungswertdeklarationen angewendet werden.
  • /* */ Zeigt einen mehrzeiligen Kommentar.
  • // gibt einen Kommentar zu der Linie zu beenden. Abgesehen von // , sind neue Zeilen das gleiche wie jeder andere Leerzeichen.
  • Im Beispiel Grammatik unten, Text von // bis zum Ende der Zeile ist nicht Teil der Grammatik sondern ein Kommentar über die Grammatik.
  • [empty] bedeutet , dass der Begriff leer sein kann.
  • ? nach einem Literal oder Begriff bedeutet, dass es optional ist.
  • ... anzeigt Sequenz enthält null oder mehr Elemente mit Interpunktion Trenn wie angegeben. Es gibt keine Variadic-Argumente in HIDL.
  • Kommas trennen Sequenzelemente.
  • Semikolons beenden jedes Element, einschließlich des letzten Elements.
  • GROSSBUCHSTABEN ist ein Nichtterminal.
  • italics ist eine Token - Familie, wie integer oder identifier (Standard C - Parsing - Regeln).
  • constexpr ist ein konstanter Ausdruck C Stil (wie 1 + 1 und 1L << 3 ).
  • import_name ist ein Paket oder Schnittstellennamen, qualifiziert , wie beschrieben in HIDL Versioning .
  • Kleine words sind wörtliche Token.

Beispiel:

ROOT =
    PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... }  // not for types.hal
  | PACKAGE IMPORTS ITEM ITEM...  // only for types.hal; no method definitions

ITEM =
    ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
  |  safe_union identifier { UFIELD; UFIELD; ...};
  |  struct identifier { SFIELD; SFIELD; ...};  // Note - no forward declarations
  |  union identifier { UFIELD; UFIELD; ...};
  |  enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar
  |  typedef TYPE identifier;

VERSION = integer.integer;

PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;

PREAMBLE = interface identifier EXTENDS

EXTENDS = <empty> | extends import_name  // must be interface, not package

GENERATES = generates (FIELD, FIELD ...)

// allows the Binder interface to be used as a type
// (similar to typedef'ing the final identifier)
IMPORTS =
   [empty]
  |  IMPORTS import import_name;

TYPE =
  uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t |
 float | double | bool | string
|  identifier  // must be defined as a typedef, struct, union, enum or import
               // including those defined later in the file
|  memory
|  pointer
|  vec<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]

FIELD =
   TYPE identifier

UFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...};
  |  struct identifier { FIELD; FIELD; ...};
  |  union identifier { FIELD; FIELD; ...};
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SIZE =  // Must be greater than zero
     constexpr

ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION

ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)

ANNO_ENTRY =
     identifier=VALUE

VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations

ENUM_ENTRY =
     identifier
  |  identifier = constexpr

Terminologie

In diesem Abschnitt werden die folgenden HIDL-bezogenen Begriffe verwendet:

gebunden Gibt an, dass HIDL für Remoteprozeduraufrufe zwischen Prozessen verwendet wird, implementiert über einen Binder-ähnlichen Mechanismus. Siehe auch Passthrough.
Rückruf, asynchron Schnittstelle, die von einem HAL-Benutzer bedient wird, an die HAL übergeben wird (über eine HIDL-Methode) und von der HAL aufgerufen wird, um jederzeit Daten zurückzugeben.
Rückruf, synchron Gibt Daten von der HIDL-Methodenimplementierung eines Servers an den Client zurück. Wird nicht für Methoden verwendet, die void oder einen einzelnen primitiven Wert zurückgeben.
Klient Prozess, der Methoden einer bestimmten Schnittstelle aufruft. Ein HAL- oder Framework-Prozess kann ein Client einer Schnittstelle und ein Server einer anderen sein. Siehe auch Passthrough.
erweitert Gibt eine Schnittstelle an, die Methoden und/oder Typen zu einer anderen Schnittstelle hinzufügt. Eine Schnittstelle kann nur eine andere Schnittstelle erweitern. Kann für ein kleineres Versionsinkrement im gleichen Paketnamen oder für ein neues Paket (zB eine Herstellererweiterung) verwendet werden, um auf einem älteren Paket aufzubauen.
erzeugt Gibt eine Schnittstellenmethode an, die Werte an den Client zurückgibt. Um einen nicht-primitiven Wert oder mehr als einen Wert zurückzugeben, wird eine synchrone Callback-Funktion generiert.
Schnittstelle Sammlung von Methoden und Typen. Übersetzt in eine Klasse in C++ oder Java. Alle Methoden in einer Schnittstelle werden in der gleichen Richtung aufgerufen: Ein Client-Prozess ruft Methoden auf, die von einem Server-Prozess implementiert wurden.
Einweg Gibt bei Anwendung auf eine HIDL-Methode an, dass die Methode keine Werte zurückgibt und nicht blockiert.
Paket Sammlung von Schnittstellen und Datentypen, die eine Version teilen.
Passthrough Modus HIDL in dem der Server eine gemeinsam benutzte Bibliothek, dlopen ed durch den Client. Im Passthrough-Modus sind Client und Server derselbe Prozess, aber separate Codebasen. Wird nur verwendet, um Legacy-Codebasen in das HIDL-Modell zu integrieren. Siehe auch Mit Bindemittel.
Server Prozess, der Methoden einer Schnittstelle implementiert. Siehe auch Passthrough.
Transport HIDL-Infrastruktur, die Daten zwischen Server und Client verschiebt.
Ausführung Version eines Pakets. Besteht aus zwei ganzen Zahlen, Major und Minor. Kleinere Versionsinkremente können Typen und Methoden hinzufügen (aber nicht ändern).