Aus einer HIDL-Schnittstellendatei generiert das Java-HIDL-Backend Java-Schnittstellen, Stub- und Proxy-Code. Es unterstützt alle skalaren HIDL-Typen ([u
]int
{8,16,32,64}_t, float, double,
und
enum
s) sowie Strings, Schnittstellen, safe_union-Typen, struct-Typen und Arrays und Vektoren unterstützter HIDL-Typen. Das Java-HIDL-Backend unterstützt KEINE Union-Typen oder FMQ-Typen. In Android 11 wird Unterstützung für die Typen memory
und handle
hinzugefügt.
Da die Java-Laufzeit das Konzept von vorzeichenlosen Ganzzahlen nicht nativ unterstützt, werden alle vorzeichenlosen Typen (und darauf basierende Enums) stillschweigend als ihre vorzeichenbehafteten Entsprechungen behandelt, d.h. uint32_t
wird im Java-Interface zu int
. Es erfolgt keine Wertkonvertierung. Der Implementierer auf der Java-Seite muss die signierten Werte so verwenden, als wären sie nicht signiert.
Aufzählungen
Für Enums werden keine Java-Enum-Klassen generiert, sondern sie werden in innere Klassen übersetzt, die für jeden Enum-Fall eine statische Konstantendefinition enthalten. Wenn die Enum-Klasse von einer anderen Enum-Klasse abgeleitet wird, erbt sie den Speichertyp dieser Klasse. Auf einem vorzeichenlosen Ganzzahltyp basierende Aufzählungen werden in ihr signiertes Äquivalent umgeschrieben. Da der zugrunde liegende Typ ein Primitiv ist, ist der Standardwert für Enum-Felder/-Variablen null, auch wenn es keinen Enumerator mit dem Wert null gibt.
Beispiel: Ein SomeBaseEnum
mit dem Typ uint8_t
:
enum SomeBaseEnum : uint8_t { foo = 3 }; enum SomeEnum : SomeBaseEnum { quux = 33, goober = 127 };
… wird zu:
public final class SomeBaseEnum { public static final byte foo = 3; } public final class SomeEnum { public static final byte foo = 3; public static final byte quux = 33; public static final byte goober = 127; }
Und:
enum SomeEnum : uint8_t { FIRST_CASE = 10, SECOND_CASE = 192 };
… wird umgeschrieben als:
public final class SomeEnum { static public final byte FIRST_CASE = 10; // no change static public final byte SECOND_CASE = -64; }
Strings
String
in Java ist UTF-8 oder UTF-16, wird aber beim Transport in UTF-8 als gemeinsamer HIDL-Typ konvertiert. Außerdem darf String
nicht null sein, wenn es an HIDL übergeben wird.
Griff und Arbeitsspeicher
Mit Android 11 wird die Java-Unterstützung für die Typen handle
und memory
eingeführt. Sie werden in android.os.NativeHandle
und android.os.HidlMemory
übersetzt. Ein Null-Handle gilt als gültig, ein Null-Speicher jedoch nicht.
Im generierten Server-Code sind empfangene Speicher- und Handle-Argumente nur im Rahmen des Methodenaufrufs gültig. Wenn die Serverimplementierung ihre Lebensdauer verlängern möchte, müssen sie mit den entsprechenden dup()
-Methoden dupliziert werden. Die zurückgegebene Instanz kann über den Methodenaufruf hinaus verwendet werden und sollte nach Abschluss der Verwendung ordnungsgemäß geschlossen werden.
Im generierten client-Code müssen Handles und Speicherinstanzen, die als Eingabeargumente der aufgerufenen Methode gesendet werden, nicht dupliziert oder nach der Rückgabe der Methode gültig gehalten werden. Handles und Speicherinstanzen, die als Ausgabeargumente empfangen werden, werden jedoch automatisch durch den automatisch generierten Code dupliziert und müssen nach der Verwendung ordnungsgemäß geschlossen werden. Das gilt unabhängig davon, ob diese Rückgabeargumente als Rückgabewerte der Methode (im Fall eines einzelnen Rückgabewerts) oder im synchronen Callback-Stil (im Fall mehrerer Rückgabewerte) angegeben werden.
Weitere Informationen zum Duplizieren und Schließen finden Sie in der Dokumentation der Java-Klassen.
Arrays und Vektoren
Arrays werden in Java-Arrays und Vektoren in ArrayList<T>
übersetzt, wobei T der entsprechende Objekttyp ist, der möglicherweise skalare Typen wie vec<int32_t> =>
ArrayList<Integer>
umschließt. Beispiel:
takeAnArray(int32_t[3] array); returnAVector() generates (vec<int32_t> result);
… wird zu:
void takeAnArray(int[] array); ArrayList<Integer> returnAVector();
Strukturen
Strukturen werden in Java-Klassen mit einem ähnlichen Layout übersetzt. Beispiel:
struct Bar { vec<bool> someBools; }; struct Foo { int32_t a; int8_t b; float[10] c; Bar d; };
… wird zu:
class Bar { public final ArrayList<Boolean> someBools = new ArrayList(); }; class Foo { public int a; public byte b; public final float[] c = new float[10]; public final Bar d = new Bar(); }
Deklarierte Typen
Für jeden in types.hal
deklarierten Typ der obersten Ebene wird eine eigene .java-Ausgabedatei erstellt (wie von Java gefordert). Die folgende types.hal
-Datei führt beispielsweise dazu, dass zwei zusätzliche Dateien erstellt werden (Foo.java und Bar.java):
struct Foo { ... }; struct Bar { ... struct Baz { }; ... };
Die Definition von Baz befindet sich in einer statischen inneren Klasse von Bar (in Bar.java
).