データ型

Java の HIDL バックエンドでは、HIDL のインターフェース ファイルに対して、Java インターフェース、スタブ、プロキシコードが生成されます。HIDL のすべてのスカラー型([u]int{8,16,32,64}_t, float, double, および enum)がサポートされ、文字列、インターフェース、safe_union 型、struct 型、サポートされている HIDL 型の配列とベクトルも対象です。Java の HIDL バックエンドでは、union 型、fmq 型はサポートされません。Android 11 において、memory 型と handle 型のサポートが追加されています。

Java ランタイムでは符号なし整数の概念がネイティブ サポートされていないため、すべての符号なし型とそれらに基づく列挙型は自動的に符号付き型として処理されます。たとえば、uint32_t は Java インターフェースでは int になります。値変換は実行されません。Java 側の実装元で、符号付きの値を符号なしの値として処理する必要があります。

列挙型

列挙型で Java 列挙型クラスが生成されることはありませんが、各列挙型の静的な定数定義を含む内部クラスに変換されます。列挙型クラスが他の列挙型クラスから派生している場合、列挙型クラスはそのクラスのストレージ型を継承します。符号なし整数型に基づく列挙型は、同等の符号付き型に書き換えられます。基になる型がプリミティブ型であるため、列挙型フィールドまたは変数のデフォルト値は 0 になります(enumerator が 0 でなくとも 0 になります)。

たとえば、型が uint8_tSomeBaseEnum を見てみましょう。

enum SomeBaseEnum : uint8_t { foo = 3 };
enum SomeEnum : SomeBaseEnum {
    quux = 33,
    goober = 127
};

これは、次のようになります。

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;
}

次の例もご覧ください。

enum SomeEnum : uint8_t {
    FIRST_CASE = 10,
    SECOND_CASE = 192
};

これは、次のように書き換えられます。

public final class SomeEnum {
    static public final byte FIRST_CASE  = 10;  // no change
    static public final byte SECOND_CASE = -64;
}

文字列

Java の String は utf-8 または utf-16 ですが、変換される際には一般的な HIDL 型である utf-8 に変換されます。また、String は、HIDL に渡される場合には null であってはなりません。

ハンドルとメモリ

Android 11 において、handle 型と memory 型に対する Java サポートが導入されました。これらの型はそれぞれ、android.os.NativeHandleandroid.os.HidlMemory に変換されます。null ハンドルは有効とみなされますが、null メモリは有効とみなされません。

生成されたサーバーコードでは、受け取ったメモリ引数とハンドル引数が有効なのは、メソッドの呼び出しの範囲内だけです。サーバーの実装でこれらの引数の有効期間を延長したい場合は、それぞれの dup() メソッドを使用して複製する必要があります。返されたインスタンスはメソッドの呼び出しの範囲外で使用できるため、使用し終えたときに適切にクローズする必要があります。

生成されたクライアント コードでは、呼び出されたメソッドの入力引数として送信されるハンドルとメモリ インスタンスを複製する必要はなく、メソッドが返った後にそれらを有効なままにする必要もありません。ただし、出力引数として受け取ったハンドルとメモリ インスタンスは、生成されたコードによって自動的に複製されるため、使用し終えたときに適切にクローズする必要があります。これは、これらの引数の戻り値がメソッドの戻り値として表示される場合(戻り値が 1 つの場合)にも、同期コールバックのスタイルを使用する場合(戻り値が複数の場合)にも当てはまります。

複製とクローズについて詳しくは、Java クラスのドキュメントをご覧ください。

配列とベクトル

配列は Java 配列に変換され、ベクトルは ArrayList<T> に変換されます。T は対応するオブジェクト型を意味しており、vec<int32_t> => ArrayList<Integer> のようにラップされたスカラー型を使用できます。次の例をご覧ください。

takeAnArray(int32_t[3] array);
returnAVector() generates (vec<int32_t> result);

これは、次のようになります。

void takeAnArray(int[] array);
ArrayList<Integer> returnAVector();

構造体

構造体は、同様のレイアウトを持った Java クラスに変換されます。次に例を示します。

struct Bar {
 vec<bool> someBools;
};
struct Foo {
 int32_t a;
 int8_t b;
 float[10] c;
 Bar d;
};

これは、次のようになります。

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();
}

宣言済みの型

types.hal で宣言された型のうち、最上位の型については、Java で必要とされるため、それぞれ独自の .java 出力ファイルが取得されます。たとえば、次の types.hal ファイルの場合、2 つの追加ファイル(Foo.java と Bar.java)が作成されます。

struct Foo {
 ...
};

struct Bar {
 ...

 struct Baz {
 };

 ...
};

Baz の定義は、Bar.java 内の Bar の静的内部クラスに存在します。