In diesem Abschnitt werden HIDL-Datentypen beschrieben. Implementierungsdetails: HIDL C++ (für C++ Implementierungen) oder HIDL Java (für Java-Implementierungen).
Zu den Ähnlichkeiten in C++ gehören:
structs
verwendet die C++-Syntax.unions
unterstützen die C++-Syntax ist standardmäßig aktiviert. Beide müssen benannt werden: anonyme Structs und Unions werden nicht unterstützt.- Typedefs sind in HIDL zulässig (wie in C++).
- Kommentare im C++-Stil sind zulässig und werden in die generierte Headerdatei kopiert.
Zu den Ähnlichkeiten mit Java gehören:
- Für jede Datei definiert HIDL einen Namespace im Java-Stil, der mit
android.hardware.
Der generierte C++-Namespace ist::android::hardware::…
- Alle Definitionen der Datei sind in einem Java-Stil enthalten.
interface
-Wrapper. - HIDL-Array-Deklarationen folgen dem Java-Stil, nicht dem C++-Stil. Beispiel:
struct Point { int32_t x; int32_t y; }; Point[3] triangle; // sized array
- Kommentare ähneln dem Javadoc-Format.
Datendarstellung
Ein struct
oder union
bestehend aus
Standard-Layout
(eine Teilmenge der Anforderung an „einfache alte Datentypen“) verfügt über einen konsistenten Arbeitsspeicher
Layout im generierten C++-Code, erzwungen mit expliziten Ausrichtungsattributen auf
struct
und union
Mitglieder.
Einfache HIDL-Typen sowie enum
und bitfield
-Typen (die immer aus primitiven Typen abgeleitet werden) werden den standardmäßigen C++-Typen zugeordnet.
wie z. B. std::uint32_t
von
cstdint.
Da Java keine vorzeichenlosen Typen unterstützt, werden unsignierte HIDL-Typen den entsprechenden signierten Java-Typ. Structs sind Java-Klassen zugeordnet. arrays sind Java-Arrays zugeordnet. unions werden derzeit nicht unterstützt in Java. Strings werden intern als UTF8 gespeichert. Da Java die werden nur UTF16-Strings und Stringwerte, die an eine oder von einer Java-Implementierung gesendet werden, übersetzt und sind möglicherweise bei einer erneuten Übersetzung nicht identisch, da die Zeichensätze nicht immer reibungslos kartografieren.
In C++ über IPC empfangene Daten sind mit const
gekennzeichnet und befinden sich in
schreibgeschützten Speicher, der nur für die Dauer des Funktionsaufrufs bestehen bleibt. Daten
in Java empfangene IPC-Daten
bereits in Java-Objekte kopiert wurden.
ohne zusätzliches Kopieren aufbewahrt (und geändert werden).
Anmerkungen
Anmerkungen im Java-Stil können zu Typdeklarationen hinzugefügt werden. Anmerkungen sind vom Vendor Test Suite (VTS) Backend des HIDL-Compilers geparst, aber keine der wie geparste Anmerkungen vom HIDL-Compiler tatsächlich verstanden werden. Stattdessen geparste VTS-Annotationen vom VTS Compiler (VTSC).
Für Anmerkungen wird die Java-Syntax verwendet: @annotation
oder
@annotation(value)
oder @annotation(id=value, id=value…)
Dabei kann value entweder ein konstanter Ausdruck, ein String oder eine Liste von Werten sein
in {}
genau wie in Java. Mehrere Anmerkungen mit demselben Namen
an dasselbe Objekt angehängt werden können.
Weiterleitende Deklarationen
In HIDL sind Strukturen möglicherweise nicht vorwärts deklariert. selbstreferenzielle Datentypen nicht möglich (z. B. können Sie keine verknüpfte Liste oder ein Baum im HIDL). In den meisten HALs (vor Android 8.x) werden Forward-Deklarationen, die durch eine Neuanordnung der Datenstruktur entfernt werden können Deklarationen.
Diese Einschränkung ermöglicht das Kopieren von Datenstrukturen nach Wert mit einer einfachen
Deepcopy, anstatt Zeigerwerte nachzuverfolgen, die mehrere Male auftreten können
in einer selbstreferenziellen Datenstruktur. Werden dieselben Daten zweimal übergeben,
z. B. mit zwei Methodenparametern oder vec<T>
s, die auf
werden zwei separate Kopien erstellt und geliefert.
Verschachtelte Deklarationen
HIDL unterstützt verschachtelte Deklarationen auf beliebig vielen Ebenen (mit einem Ausnahme siehe unten). Beispiel:
interface IFoo { uint32_t[3][4][5][6] multidimArray; vec<vec<vec<int8_t>>> multidimVector; vec<bool[4]> arrayVec; struct foo { struct bar { uint32_t val; }; bar b; } struct baz { foo f; foo.bar fb; // HIDL uses dots to access nested type names } …
Die Ausnahme ist, dass Schnittstellentypen nur in
vec<T>
und nur eine Ebene tiefer (keine
vec<vec<IFoo>>
).
Rohzeigersyntax
Die HIDL-Sprache verwendet weder * noch unterstützt sie volle Flexibilität bei C/C++-Rohzeigern. Weitere Informationen dazu, wie HIDL Zeiger und Arrays/Vektoren, siehe vec<T> Vorlage.
Schnittstellen
Das Keyword interface
kann in zweierlei Hinsicht verwendet werden.
- Die Definition einer Schnittstelle wird in einer .hal-Datei geöffnet.
- Sie kann als besonderer Typ in Struktur-/Union-Feldern, Methodenparametern
und Rückgaben. Es wird als allgemeine Benutzeroberfläche und Synonym für
android.hidl.base@1.0::IBase
IServiceManager
hat beispielsweise die folgende Methode:
get(string fqName, string name) generates (interface service);
Die Methode verspricht, eine Schnittstelle anhand des Namens zu suchen. Es ist auch
ist identisch mit der Ersetzung der Schnittstelle durch android.hidl.base@1.0::IBase
.
Schnittstellen können nur auf zwei Arten übergeben werden: als Parameter der obersten Ebene oder als
Mitglieder von vec<IMyInterface>
. Sie dürfen nicht Mitglied von
verschachtelte vecs, Structs, Arrays oder Unions.
MQDescriptorSync und MQDescriptorUnsync
Die Typen MQDescriptorSync
und MQDescriptorUnsync
Synchronisierte oder nicht synchronisierte FMQ-Deskriptoren (Fast Message Queue) übergeben
über eine HIDL-Schnittstelle. Weitere Informationen finden Sie unter
HIDL C++ (FMQs sind nicht
in Java unterstützt).
Speichertyp
Mit dem Typ memory
wird ein nicht zugeordneter gemeinsamer Speicher in
HIDL Es wird nur in C++ unterstützt. Ein Wert dieses Typs kann im
empfangendes Ende zum Initialisieren eines IMemory
-Objekts, wobei der Speicher zugeordnet wird
und sie nutzungsfreundlich zu machen. Weitere Informationen finden Sie unter
HIDL C++:
Warnung:Strukturierte Daten wurden freigegeben
Speicher MUSS ein Typ sein, dessen Format sich während der Lebensdauer des
Schnittstellenversion übergeben, die den memory
übergibt. Andernfalls können HALs
schwerwiegenden Kompatibilitätsproblemen.
Zeigertyp
Der Typ pointer
ist nur für den internen Gebrauch mit HIDL vorgesehen.
Bitfield<T> Typvorlage
bitfield<T>
, wobei T
ein
user-defined enum legt nahe, dass der Wert ein bitweises ODER des
In T
definierte Enum-Werte Im generierten Code
bitfield<T>
wird als zugrunde liegender Typ von T angezeigt. Für
Beispiel:
enum Flag : uint8_t { HAS_FOO = 1 << 0, HAS_BAR = 1 << 1, HAS_BAZ = 1 << 2 }; typedef bitfield<Flag> Flags; setFlags(Flags flags) generates (bool success);
Der Compiler verarbeitet die Typ-Flags wie uint8_t
.
Vorteile
(u)int8_t
/(u)int16_t
/(u)int32_t
/(u)int64_t
?
Mit bitfield
werden dem Leser zusätzliche HAL-Informationen bereitgestellt.
der jetzt weiß, dass setFlags
einen bitweisen ODER-Wert von Flag annimmt (d.h.
weiß, dass der Aufruf von setFlags
mit 16 ungültig ist. Ohne
bitfield
, werden diese Informationen nur in Form von Dokumentationen übermittelt. In
VTS kann tatsächlich prüfen, ob der Wert von Flags ein bitweises ODER von Flag ist.
Ziehpunkte des einfachen Typs
WARNUNG:Adressen jeder Art (auch physische) Geräteadressen) dürfen niemals Teil eines nativen Alias sein. Bestanden Informationen zwischen Prozessen sind gefährlich und anfällig für Angriffe. Alle zwischen Prozessen übergebenen Werte müssen validiert werden, bevor sie für Folgendes verwendet werden: den zugewiesenen Speicher in einem Prozess zu finden. Andernfalls können schlechte Aliasse zu oder eine Beschädigung des Arbeitsspeichers.
Die HIDL-Semantik basiert auf Kopieren pro Wert, was impliziert, dass Parameter kopiert werden.
Alle großen Datenmengen, die zwischen Prozessen geteilt werden müssen
(z. B. ein Synchronisierungszaun) werden durch die Übergabe von Dateideskriptoren verarbeitet, die auf
in persistente Objekte: ashmem
für gemeinsamen Arbeitsspeicher, tatsächliche Dateien oder
was sich hinter einer Dateibeschreibung verbirgt. Binder-Treiber
dupliziert die Dateibeschreibung im anderen Prozess.
natives_Handle_t
Android unterstützt native_handle_t
, ein allgemeines Handle-Konzept
definiert in libcutils
.
typedef struct native_handle { int version; /* sizeof(native_handle_t) */ int numFds; /* number of file-descriptors at &data[0] */ int numInts; /* number of ints at &data[numFds] */ int data[0]; /* numFds + numInts ints */ } native_handle_t;
Ein natives Handle ist eine Sammlung von Ganzzahlen und Dateideskriptoren, die übergeben wird.
nach Wert sortiert. Ein einzelner Dateideskriptor kann in einem nativen Handle mit
keine Ganzzahlen und einen einzelnen Dateideskriptor enthalten. Aliasse mit nativen Aliassen übergeben
Die Kapselung mit dem Primitivtyp handle
sorgt dafür, dass native
Aliasse sind direkt in HIDL enthalten.
Da native_handle_t
eine variable Größe hat, kann sie nicht aufgenommen werden
in einer Struktur hinzufügen. Ein Handle-Feld generiert einen Zeiger auf ein separat
native_handle_t
zugewiesen.
In früheren Android-Versionen wurden native Aliasse mit demselben
und Funktionen, die in
libcutils
In Android 8.0 und höher werden diese Funktionen nun in den
android::hardware::hidl
-Namespace wurde in das NDK verschoben. HIDL
automatisch generierten Code serialisiert
und deserialisiert diese Funktionen,
ohne von Nutzenden geschriebenen Code zu verwenden.
Handle und Dateideskriptor-Eigentümerschaft
Wenn Sie eine HIDL-Schnittstellenmethode aufrufen,
hidl_handle
-Objekt (entweder der obersten Ebene oder als Teil eines zusammengesetzten Typs)
Die Eigentumsrechte für die darin enthaltenen Dateideskriptoren lauten wie folgt:
- Der Aufrufer übergibt ein
hidl_handle
-Objekt als behält die Eigentümerschaft der Dateideskriptoren imnative_handle_t
wird umschlossen; Der Aufrufer muss diese Datei schließen wenn sie fertig sind. - Der Prozess, der eine
hidl_handle
zurückgibt durch Übergeben an eine_cb
-Funktion behält die Inhaberschaft des Dateideskriptoren, die in dernative_handle_t
enthalten sind, umschlossen vom Objekt; Der Prozess muss diese Dateideskriptoren nach der Bearbeitung schließen. - Ein Verkehrsmittel, das ein
hidl_handle
erhält, hat Eigentumsrechte der Dateideskriptoren innerhalb dernative_handle_t
vom -Objekt umschlossen; kann der Empfänger diese Dateideskriptoren unverändert verwenden. den Transaktions-Callback, muss aber das native Handle klonen, um die Datei zu verwenden -Deskriptoren, die über den Callback hinausgehen. Das Transportunternehmen ruft automatisch anclose()
für die Dateideskriptoren, wenn die Transaktion abgeschlossen ist.
HIDL unterstützt keine Handles in Java (da Java keine Handles auf alle).
Arrays mit großen Größen
Bei Arrays mit einer bestimmten Größe in HIDL-Strukturen können die Elemente einen beliebigen kann Folgendes enthalten:
struct foo { uint32_t[3] x; // array is contained in foo };
Strings
Strings werden in C++ und Java unterschiedlich angezeigt, aber der zugrunde liegende Transport Speichertyp ist eine C++-Struktur. Weitere Informationen finden Sie unter HIDL C++ Datentypen oder HIDL-Java-Datentypen.
Hinweis: Die Übergabe eines Strings an oder von Java durch eine HIDL-Schnittstelle (einschließlich Java zu Java) verursacht Zeichensatzkonvertierungen die die ursprüngliche Codierung eventuell nicht beibehält.
vec<T> Typvorlage
Die Vorlage vec<T>
steht für einen Puffer mit variabler Größe
mit Instanzen von T
.
T
kann einer der folgenden Werte sein:
- Einfache Typen (z.B. uint32_t)
- Strings
- Benutzerdefinierte Enums
- Benutzerdefinierte Strukturen
- Benutzeroberflächen oder das Keyword
interface
(vec<IFoo>
,vec<interface>
wird unterstützt nur als Parameter der obersten Ebene) - Aliasse
- Bitfield<U>
- vec<U>, wobei U in dieser Liste enthalten ist, mit Ausnahme der Schnittstelle (z.B.
vec<vec<IFoo>>
wird nicht unterstützt) - U[] (großes Array von U), wobei U in dieser Liste mit Ausnahme der Schnittstelle steht
Benutzerdefinierte Typen
In diesem Abschnitt werden benutzerdefinierte Typen beschrieben.
Aufzählung
HIDL unterstützt keine anonymen Aufzählungen. Andernfalls ähneln sich die Enums in HIDL an C++11:
enum name : type { enumerator , enumerator = constexpr , … }
Ein Basis-enum wird in Bezug auf einen der Ganzzahltypen in HIDL definiert. Falls nein Der Wert wird für den ersten Zähler einer Aufzählung basierend auf einer Ganzzahl angegeben -Typ handelt, ist der Wert standardmäßig 0. Wenn für einen späteren Zähler kein Wert angegeben ist, wird standardmäßig der vorherige Wert plus eins verwendet. Beispiel:
// RED == 0 // BLUE == 4 (GREEN + 1) enum Color : uint32_t { RED, GREEN = 3, BLUE }
Eine Enum kann auch von einer zuvor definierten enum übernommen werden. Wenn kein Wert
der für den ersten Zähler einer untergeordneten Aufzählung angegeben ist (in diesem Fall
FullSpectrumColor
), wird standardmäßig der Wert des letzten
Zähler der übergeordneten Aufzählung plus eins. Beispiel:
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
Warnung:Die Enum-Übernahme funktioniert rückwärts. von den meisten anderen Vererbungsarten. Ein untergeordneter enum-Wert kann nicht als übergeordneter enum-Wert. Das liegt daran, dass eine untergeordnete Aufzählung mehr Werte als die Parent. Ein übergeordneter enum-Wert kann jedoch bedenkenlos als untergeordneter enum-Wert verwendet werden. da untergeordnete enum-Werte per Definition eine Obermenge von übergeordneten enum-Werten sind. Behalten Sie das beim Entwerfen von Schnittstellen im Hinterkopf, da es bedeutet, dass Typen, die sich auf Übergeordnete Aufzählungen dürfen nicht auf untergeordnete Aufzählungen in späteren Iterationen Ihres .
Werte von Enums werden mit der Doppelpunktsyntax bezeichnet (nicht mit der Punktsyntax als
verschachtelte Typen). Die Syntax lautet Type:VALUE_NAME
. Keine Angabe erforderlich
Typ, wenn auf den Wert im selben Enum-Typ oder in untergeordneten Typen verwiesen wird. Beispiel:
enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 }; enum Color : Grayscale { RED = WHITE + 1 }; enum Unrelated : uint32_t { FOO = Color:RED + 1 };
Ab Android 10 haben Enums eine
len
-Attribut, das in konstanten Ausdrücken verwendet werden kann.
MyEnum::len
ist die Gesamtzahl der Einträge in dieser Aufzählung.
Dies unterscheidet sich von der Gesamtzahl der Werte, die kleiner sein kann,
Werte dupliziert werden.
Struktur
HIDL unterstützt keine anonymen Strukturen. Andernfalls sind Strukturen in HIDL sehr ähnlich wie C.
HIDL unterstützt keine Datenstrukturen mit variabler Länge, die vollständig in
Struktur. Dazu gehört auch das Array mit unbegrenzter Länge, das manchmal als
das letzte Feld einer Struktur in C/C++ (manchmal mit einer
[0]
. HIDL vec<T>
repräsentiert die dynamische Größe
Arrays mit den in einem separaten Zwischenspeicher gespeicherten Daten; dass solche Instanzen
durch eine Instanz von vec<T>
in der struct
.
Entsprechend kann string
in einem struct
enthalten sein.
(Verknüpfte Zwischenspeicher sind separat). In der generierten C++-Instanz des HIDL
werden durch einen Zeiger zum eigentlichen nativen Alias
Instanzen des zugrunde liegenden Datentyps eine variable Länge.
Union
HIDL unterstützt keine anonymen Unions. Andernfalls ähneln Unions denen in C.
Unions dürfen keine Korrekturtypen enthalten (z. B. Verweise, Dateibeschreibungen, Binde-
-Objekten). Sie benötigen keine speziellen Felder oder zugehörigen Typen und
einfach mit memcpy()
oder einem gleichwertigen Element kopiert. Eine Union kann nicht direkt
Alles enthalten (oder unter Verwendung anderer Datenstrukturen enthalten), was festgelegt werden muss
Binder-Offsets (d. h. Handle- oder Binder-Interface-Referenzen) Beispiel:
union UnionType { uint32_t a; // vec<uint32_t> r; // Error: can't contain a vec<T> uint8_t b;1 }; fun8(UnionType info); // Legal
Unions können auch innerhalb von Strukturen deklariert werden. Beispiel:
struct MyStruct { union MyUnion { uint32_t a; uint8_t b; }; // declares type but not member union MyUnion2 { uint32_t a; uint8_t b; } data; // declares type but not member }