Google is committed to advancing racial equity for Black communities. See how.
Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

HIDL

Die HAL-Schnittstellendefinitionssprache oder HIDL (ausgesprochen "hide-l") ist eine Schnittstellenbeschreibungssprache (IDL) zur Angabe der Schnittstelle zwischen einer HAL und ihren Benutzern. Es ermöglicht die Angabe von Typen und Methodenaufrufen, die in Schnittstellen und Paketen zusammengefasst sind. Im weiteren Sinne ist HIDL ein System zur Kommunikation zwischen Codebasen, die unabhängig voneinander kompiliert werden können.

HIDL soll für die Interprozesskommunikation (IPC) verwendet werden. Die Kommunikation zwischen Prozessen wird als Binderized bezeichnet . Für Bibliotheken, die mit einem Prozess verknüpft sein müssen, steht auch ein Passthrough-Modus zur Verfügung (wird in Java nicht unterstützt).

HIDL gibt Datenstrukturen und Methodensignaturen an, die in Schnittstellen (ähnlich einer Klasse) organisiert sind, 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 ist, dass das Framework ersetzt werden kann, ohne dass HALs neu erstellt werden müssen. HALs werden von Anbietern oder SOC-Herstellern erstellt und in eine /vendor Partition auf dem Gerät eingefügt, sodass das Framework in seiner eigenen Partition durch eine OTA ersetzt werden kann, ohne die HALs neu zu kompilieren.

Das HIDL-Design berücksichtigt die folgenden Probleme:

  • 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 ihrer Veröffentlichung nicht mehr geändert werden.
  • Effizienz . HIDL versucht, die Anzahl der Kopiervorgänge zu minimieren. HIDL-definierte Daten werden in C ++ - Standardlayoutdatenstrukturen an C ++ - Code geliefert, die ohne Entpacken verwendet werden können. HIDL bietet auch Schnittstellen für gemeinsam genutzten Speicher. Da RPCs von Natur aus etwas langsam sind, unterstützt HIDL zwei Möglichkeiten, Daten ohne Verwendung eines RPC-Aufrufs zu übertragen: gemeinsam genutzten Speicher und eine Fast Message Queue (FMQ).
  • Intuitiv . 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 Rückruffunktionen zurückgegeben. Weder das Übergeben von Daten an HIDL zur Übertragung noch das Empfangen von Daten von HIDL ändern 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 unmittelbar nach der Rückkehr der aufgerufenen Funktion zerstört werden.

Passthrough-Modus verwenden

Um Geräte, auf denen frühere Versionen von Android ausgeführt werden, auf Android O zu aktualisieren, können Sie sowohl herkömmliche (als auch ältere) HALs in eine neue HIDL-Schnittstelle einbinden, die die HAL im Binder-Modus und im Passthrough-Modus für denselben Prozess 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. Auf Geräten, auf denen frühere Android-Versionen ausgeführt werden, sind keine HALs in Java geschrieben, sodass Java-HALs von Natur aus verknüpft sind.

Wenn eine .hal Datei kompiliert wird, erzeugt hidl-gen zusätzlich zu den für die Binder-Kommunikation verwendeten Headern eine zusätzliche Passthrough-Header-Datei BsFoo.h . Dieser Header definiert Funktionen, die dlopen werden dlopen . Da Passthrough-HALs in demselben Prozess ausgeführt werden, in dem sie aufgerufen werden, werden Passthrough-Methoden in den meisten Fällen durch direkten Funktionsaufruf (gleicher Thread) aufgerufen. oneway Methoden werden in einem eigenen Thread ausgeführt, da sie nicht darauf warten sollen, dass die HAL sie verarbeitet (dies bedeutet, dass jede HAL, die oneway Methoden im Passthrough-Modus verwendet, threadsicher sein muss).

Bei einer IFoo.hal schließt BsFoo.h die von HIDL generierten Methoden ab, um zusätzliche Funktionen bereitzustellen (z. B. das oneway Transaktionen in einem anderen Thread). Diese Datei ähnelt BpFoo.h , aber anstatt IPC-Aufrufe mit Binder BpFoo.h , werden die gewünschten Funktionen direkt aufgerufen. Zukünftige Implementierungen von HALs können mehrere Implementierungen bereitstellen , z. B. FooFast HAL und FooAccurate HAL. In solchen Fällen würde eine Datei für jede zusätzliche Implementierung erstellt (z. B. PTFooFast.cpp und PTFooAccurate.cpp ).

Binderisierung von Passthrough-HALs

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

  • abcd@MN::IFoo-impl . Enthält die Implementierung der HAL und macht die Funktion IFoo* HIDL_FETCH_IFoo(const char* name) . Auf älteren Geräten wird dieses Paket dlopen und die Implementierung mithilfe von HIDL_FETCH_IFoo instanziiert. Sie können den hidl-gen mit hidl-gen und -Lc++-impl und -Landroidbp-impl .
  • abcd@MN::IFoo-service . Öffnet die Passthrough-HAL und registriert sich selbst als binderisierter Dienst, sodass dieselbe HAL-Implementierung sowohl als Passthrough als auch als binderisiert verwendet werden kann.

Mit dem Typ IFoo können Sie sp<IFoo> IFoo::getService(string name, bool getStub) , um Zugriff auf eine Instanz von IFoo . Wenn getStub true ist, versucht getService , die HAL nur im Passthrough-Modus zu öffnen. Wenn getStub false ist, versucht getService , einen binderisierten Dienst zu finden. Wenn dies fehlschlägt, wird versucht, den Passthrough-Dienst zu finden. Der Parameter getStub sollte nur in defaultPassthroughServiceImplementation . (Geräte, die mit Android O gestartet werden, sind vollständig binderisierte Geräte. Das Öffnen eines Dienstes im Passthrough-Modus ist daher nicht zulässig.)

HIDL-Grammatik

Die HIDL-Sprache ähnelt standardmäßig C (verwendet jedoch nicht den C-Präprozessor). Alle im Folgenden nicht beschriebenen Satzzeichen (abgesehen von der offensichtlichen Verwendung von = und | ) sind Teil der Grammatik.

Hinweis: Einzelheiten zum HIDL-Codestil finden Sie im Code Style Guide .

  • /** */ zeigt einen Dokumentationskommentar an. Diese können nur auf Typ-, Methoden-, Feld- und Enum-Wertdeklarationen angewendet werden.
  • /* */ zeigt einen mehrzeiligen Kommentar an.
  • // zeigt einen Kommentar am Zeilenende an. Abgesehen von // sind Zeilenumbrüche dieselben wie alle anderen Leerzeichen.
  • In der folgenden Beispielgrammatik ist Text von // bis zum Ende der Zeile nicht Teil der Grammatik, sondern ein Kommentar zur Grammatik.
  • [empty] bedeutet, dass der Begriff möglicherweise leer ist.
  • ? Wenn Sie einem Literal oder Begriff folgen, ist dies optional.
  • ... zeigt eine Sequenz an, die null oder mehr Elemente enthält, wobei die Interpunktion wie angegeben getrennt ist. In HIDL gibt es keine variadischen Argumente.
  • Kommas trennen Sequenzelemente.
  • Semikolons beenden jedes Element, einschließlich des letzten Elements.
  • UPPERCASE ist ein Nichtterminal.
  • italics ist eine Token-Familie wie eine integer oder ein identifier (Standard-C-Parsing-Regeln).
  • constexpr ist ein konstanter Ausdruck im C-Stil (z. B. 1 + 1 und 1L << 3 ).
  • import_name ist ein Paket- oder Schnittstellenname, der wie unter HIDL-Versionierung beschrieben qualifiziert ist .
  • 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:

binderisiert Gibt an, dass HIDL für Remoteprozeduraufrufe zwischen Prozessen verwendet wird, die über einen Binder-ähnlichen Mechanismus implementiert werden. Siehe auch Passthrough .
Rückruf, asynchron Schnittstelle, die von einem HAL-Benutzer bereitgestellt, an die HAL übergeben (über eine HIDL-Methode) und von der HAL aufgerufen wird, um jederzeit Daten zurückzugeben.
Rückruf, synchron Gibt Daten von der Implementierung der HIDL-Methode eines Servers an den Client zurück. Nicht verwendet für Methoden, 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 einer anderen Schnittstelle Methoden und / oder Typen hinzufügt. Eine Schnittstelle kann nur eine andere Schnittstelle erweitern. Kann für ein geringfügiges Versionsinkrement im selben Paketnamen oder für ein neues Paket (z. B. 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 Rückruffunktion generiert.
Schnittstelle Sammlung von Methoden und Typen. In eine Klasse in C ++ oder Java übersetzt. Alle Methoden in einer Schnittstelle werden in derselben Richtung aufgerufen: Ein Client-Prozess ruft Methoden auf, die von einem Server-Prozess implementiert wurden.
Einweg Gibt an, dass die Methode bei Anwendung auf eine HIDL-Methode keine Werte zurückgibt und nicht blockiert.
Paket Sammlung von Schnittstellen und Datentypen, die eine Version gemeinsam nutzen.
Passthrough HIDL-Modus, in dem der Server eine gemeinsam genutzte Bibliothek ist, die vom Client dlopen wird. Im Passthrough-Modus sind Client und Server der gleiche Prozess, jedoch separate Codebasen. Wird nur verwendet, um ältere Codebasen in das HIDL-Modell zu integrieren. Siehe auch Binderized .
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, Dur und Moll. Kleinere Versionsinkremente können Typen und Methoden hinzufügen (aber nicht ändern).