Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

HIDL Java

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

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 の 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) などのメソッドを含める必要があります。

バージョン 1.0 の android.hardware.foo パッケージから IFooCallback を設定するには、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.
}