HIDL Java

Android 8.0 では Android OS が再構築され、デバイスに依存しない Android プラットフォームとデバイスおよびベンダーに固有のコードとの間に明確なインターフェースが定義されました。このようなインターフェースは、HAL インターフェースの形式ですでに数多く定義されており、C ヘッダーとして hardware/libhardware で定義されていますが、HIDL では、これらの HAL インターフェースがバージョニングされた安定したインターフェースに置き換えられました。その結果、Java(後述)もしくは C++ のクライアント側 / サーバー側 HIDL インターフェースとして使用できます。

HIDL インターフェースでは主にネイティブ コードでの使用が意図されており、C++ での効率的なコードの自動生成に重点が置かれています。ただし、一部の Android サブシステム(電話など)には Java の HIDL インターフェースが含まれていることが多く、HIDL インターフェースが Java から直接使用できることも求められます。

このセクションでは、HIDL インターフェース用の Java フロントエンドについて説明し、サービスの作成方法、登録方法、使用方法を詳述します。また、HAL および Java で記述された HAL クライアントが HIDL RPC システムと相互作用する仕組みについても紹介します。

クライアントの例

以下では、サービス名 default として登録されているパッケージ android.hardware.foo@1.0 内のインターフェース IFoo と、カスタム サービス名 second_impl を持つ追加サービス用のクライアントの例を示します。

ライブラリの追加

対応する HIDL スタブ ライブラリを使用したい場合、依存関係を追加する必要があります。通常、これは静的ライブラリです。

// in Android.bp
    static_libs: [ "android.hardware.foo-V1.0-java", ],
    // in Android.mk
    LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

これらのライブラリにすでに依存関係が組み込まれていることがわかっている場合は、次のように共有リンケージも使用できます。

// in Android.bp
    libs: [ "android.hardware.foo-V1.0-java", ],
    // in Android.mk
    LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Android 10 でライブラリを追加する際の追加の考慮事項

Android 10 以上をターゲットとするシステムアプリ / ベンダーアプリを使用する場合は、これらのライブラリを静的にインクルードする必要があります。Android 10 より前のバージョンをターゲットとするアプリの場合は、従来の動作が維持されます。また、システムアプリ用の既存の uses-library メカニズムを使って Java API をデバイス上で安定稼働させ、そのデバイスにカスタム JAR をインストールして、JAR の HIDL クラスのみを使用する方法もあります。デバイスの容量を節約するには、この方法をおすすめします。詳細については、Java SDK ライブラリの実装をご覧ください。

10 以降では、これらのライブラリの「浅い」バージョンも利用できます。つまり、該当のクラスは含まれていますが、依存関係にあるクラスは含まれていないバージョンです。たとえば、android.hardware.foo-V1.0-java-shallow には foo パッケージのクラスが含まれていますが、すべての HIDL インターフェースの基本クラスなどの android.hidl.base-V1.0-java のクラスは含まれていません。ライブラリを作成する際に、必要なインターフェースの基本クラスを依存関係として利用する場合には、次のように指定します。

    // in Android.bp
    static_libs: [ "android.hardware.foo-V1.0-java-shallow", ],
    // in Android.mk
    LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow
    

ブート クラスパスでは、HIDL のベース ライブラリとマネージャ ライブラリが使用できなくなり、jarjar を使用する新しい名前空間に移されました。ブート クラスパス上の HIDL を使用するモジュールでは、これらのライブラリの「浅い」バリアントを使用するとともに、jarjar_rules: ":framework-jarjar-rules"Android.bp に追加する必要があります。これは、コードの重複を避け、システムアプリやベンダーアプリで非公開の API を使用できるようにするためです。

Java ソースの変更

このサービスにはバージョンが 1 つ(@1.0)しかないため、このコードで取得するのはそのバージョンのみです。サービスの複数のバージョンを処理する方法については、インターフェース拡張をご覧ください。

    import android.hardware.foo.V1_0.IFoo;
    ...
    // retry to wait until the service starts up if it is in the manifest
    IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
    IFoo anotherServer = IFoo.getService("second_impl", true /* retry */);
    server.doSomething(…);
    

サービスの提供

フレームワーク コードを Java で記述する場合、HAL からの非同期コールバックを受信するインターフェースを提供する必要があります。

android.hardware.foo パッケージのバージョン 1.0 で IFooCallback インターフェースを Java で実装する場合は、次の手順で行います。

  1. HIDL でインターフェースを定義します。
  2. 参照先として /tmp/android/hardware/foo/IFooCallback.java を開きます。
  3. Java 実装用の新しいモジュールを作成します。
  4. 抽象クラス android.hardware.foo.V1_0.IFooCallback.Stub を確認します。拡張用の新しいクラスを作成して抽象メソッドを実装します。

自動生成されたファイルの表示

自動生成されたファイルを表示するには、次のコマンドを実行します。

    hidl-gen -o /tmp -Ljava \
      -randroid.hardware:hardware/interfaces \
      -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0
    

このコマンドにより、ディレクトリ /tmp/android/hardware/foo/1.0 が生成されます。ファイル hardware/interfaces/foo/1.0/IFooCallback.hal の場合、ファイル /tmp/android/hardware/foo/1.0/IFooCallback.java が生成されます。このファイルにより、Java インターフェース、プロキシコード、スタブがカプセル化されます(プロキシとスタブは両方ともインターフェースに適合します)。

-Lmakefile によりビルド時にこのコマンドを実行するルールが生成され、android.hardware.foo-V1.0-java をインクルードして適切なファイルにリンクできるようになります。hardware/interfaces/update-makefiles.sh に、プロジェクトのすべてのインターフェースで自動処理を行うためのスクリプトが用意されています 例に示されたパスは相対パスです。したがって、hardware/interfaces は、コードツリーの下の一時ディレクトリとして、公開前の HAL の開発に使用できます。

サービスの実行

HAL では IFoo インターフェースが提供されていますが、IFooCallback インターフェースを介してフレームワークに非同期コールバックを行う必要があります。IFooCallback インターフェースは、検出可能サービスとして名前での登録が行われていません。その代わり、IFoo には setFooCallback(IFooCallback x) などのメソッドを含める必要があります。

IFooCallbackandroid.hardware.foo パッケージのバージョン 1.0 から設定するには、Android.mkandroid.hardware.foo-V1.0-java を追加します。サービスを実行するコードは次のとおりです。

    import android.hardware.foo.V1_0.IFoo;
    import android.hardware.foo.V1_0.IFooCallback.Stub;
    ....
    class FooCallback extends IFooCallback.Stub {
        // implement methods
    }
    ....
    // Get the service you will be receiving callbacks from.
    // This also starts the threadpool for your callback service.
    IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
    ....
    // This must be a persistent instance variable, not local,
    //   to avoid premature garbage collection.
    FooCallback mFooCallback = new FooCallback();
    ....
    // Do this once to create the callback service and tell the "foo-bar" service
    server.setFooCallback(mFooCallback);
    

インターフェース拡張

あるサービスがすべてのデバイスで IFoo インターフェースを実装しているとします。この場合、特定のデバイス上のサービスでインターフェース拡張 IBetterFoo に追加機能を実装するには、次のようにします。

    interface IFoo {
       ...
    };

    interface IBetterFoo extends IFoo {
       ...
    };
    

拡張されたインターフェースに対応しているコードを呼び出す際には、castFrom() Java メソッドを使用して、基本インターフェースを拡張されたインターフェースに安全にキャストすることができます。

    IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
    IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
    if (extendedService != null) {
      // The service implements the extended interface.
    } else {
      // The service implements only the base interface.
    }