Datentypen

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 enums) 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).