Android 11 では、Android で HAL に AIDL を使用する機能が導入されています。これにより、HIDL を使用せずに Android の一部を実装できます。可能であれば、HAL を移行して AIDL のみを使用します(上流の HAL が HIDL を使用する場合は、HIDL を使用する必要があります)。
system.img
などのフレームワーク コンポーネントと vendor.img などのハードウェア コンポーネント間の通信に AIDL を使用する HAL は、安定したvendor.img
を使用する必要があります。ただし、たとえばある HAL から別の HAL へなど、パーティション内で通信する場合、使用する IPC メカニズムに制限はありません。
動機
AIDL は HIDL よりも長く使用されており、Android フレームワーク コンポーネント間やアプリ内など、他の多くの場所で使用されています。 AIDL が安定性をサポートするようになったので、単一の IPC ランタイムでスタック全体を実装できます。 AIDL には、HIDL よりも優れたバージョン管理システムもあります。
- 単一の IPC 言語を使用するということは、学習、デバッグ、最適化、および保護することが 1 つだけであることを意味します。
- AIDL は、インターフェースの所有者向けのインプレース バージョニングをサポートしています。
- 所有者は、インターフェイスの最後にメソッドを追加したり、Parcelable にフィールドを追加したりできます。これは、何年にもわたってコードをバージョン管理することが容易になり、また、年々のコストが小さくなることを意味します (型はインプレースで修正でき、インターフェイス バージョンごとに追加のライブラリは必要ありません)。
- 拡張インターフェイスは、型システムではなく実行時にアタッチできるため、下流の拡張機能を新しいバージョンのインターフェイスにリベースする必要はありません。
- 既存の AIDL インターフェースは、その所有者が安定化することを選択したときに直接使用できます。以前は、HIDL でインターフェース全体のコピーを作成する必要がありました。
AIDL HAL インターフェースの作成
システムとベンダーの間で AIDL インターフェイスを使用するには、インターフェイスに次の 2 つの変更が必要です。
- すべての型定義に
@VintfStability
のアノテーションを付ける必要があります。 -
aidl_interface
宣言には、stability: "vintf",
.
これらの変更を行うことができるのは、インターフェースの所有者だけです。
これらの変更を行う場合、機能するためにはインターフェイスがVINTF マニフェストに含まれている必要があります。 VTS テストvts_treble_vintf_vendor_test
を使用して、これ (およびリリースされたインターフェイスが凍結されていることの確認などの関連要件) をテストします。 NDK バックエンドでAIBinder_forceDowngradeToLocalStability
、C++ バックエンドでandroid::Stability::forceDowngradeToLocalStability
、またはバインダー オブジェクトの送信前に Java バックエンドでandroid.os.Binder#forceDowngradeToSystemStability
を呼び出すことにより、これらの要件なしで@VintfStability
インターフェースを使用できます。別のプロセスに。すべてのアプリはシステム コンテキストで実行されるため、サービスをベンダー安定性にダウングレードすることは Java ではサポートされていません。
さらに、コードの移植性を最大限に高め、不要なライブラリの追加などの潜在的な問題を回避するために、CPP バックエンドを無効にします。
3 つのバックエンド (Java、NDK、および CPP) があるため、以下のコード例でのbackends
の使用は正しいことに注意してください。以下のコードは、CPP バックエンドを具体的に選択して無効にする方法を示しています。
aidl_interface: {
...
backends: {
cpp: {
enabled: false,
},
},
}
AIDL HAL インターフェースの検索
HAL 用の AOSP 安定 AIDL インターフェースは、HIDL インターフェースと同じベース ディレクトリのaidl
フォルダにあります。
- ハードウェア/インターフェース
- フレームワーク/ハードウェア/インターフェース
- システム/ハードウェア/インターフェース
拡張インターフェイスは、 vendor
またはhardware
の他のhardware/interfaces
サブディレクトリに配置する必要があります。
拡張インターフェイス
Android には、リリースごとに一連の公式 AOSP インターフェースがあります。 Android パートナーがこれらのインターフェースに機能を追加したい場合、これらを直接変更しないでください。これは、Android ランタイムが AOSP Android ランタイムと互換性がないことを意味するためです。 GMS デバイスの場合、これらのインターフェイスの変更を避けることは、GSI イメージが引き続き機能することを保証するものでもあります。
拡張機能は、次の 2 つの方法で登録できます。
- 実行時に、添付された拡張機能を参照してください。
- スタンドアロンで、グローバルに登録され、VINTF に登録されています。
ただし、拡張機能が登録されている場合、ベンダー固有の (上流の AOSP の一部ではないことを意味する) コンポーネントがインターフェイスを使用する場合、マージの競合が発生する可能性はありません。ただし、上流の AOSP コンポーネントに対して下流の変更が行われると、マージの競合が発生する可能性があるため、次の戦略をお勧めします。
- インターフェイスの追加は、次のリリースで AOSP にアップストリームできます
- マージの競合なしで、さらなる柔軟性を可能にするインターフェイスの追加は、次のリリースでアップストリームすることができます
拡張 Parcelables: ParcelableHolder
ParcelableHolder
は、別のParcelable
を含むことができるParcelable
です。 ParcelableHolder の主な使用例は、 ParcelableHolder
を拡張可能にすることParcelable
。たとえば、デバイスの実装者が、AOSP で定義されたParcelable
であるAospDefinedParcelable
を拡張して、付加価値機能を含めることができると期待しているイメージ。
以前はParcelableHolder
がなければ、フィールドを追加するとエラーになるため、デバイス実装者は AOSP 定義の安定した AIDL インターフェイスを変更できませんでした。
parcelable AospDefinedParcelable {
int a;
String b;
String x; // ERROR: added by a device implementer
int[] y; // added by a device implementer
}
前のコードに見られるように、Android の次のリリースで Parcelable が改訂されたときに、デバイスの実装者によって追加されたフィールドが競合する可能性があるため、このプラクティスは破られています。
ParcelableHolder
を使用すると、Parcelable の所有者はParcelable
の拡張ポイントを定義できます。
parcelable AospDefinedParcelable {
int a;
String b;
ParcelableHolder extension;
}
次に、デバイスの実装者は、拡張用に独自のParcelable
を定義できます。
parcelable OemDefinedParcelable {
String x;
int[] y;
}
最後に、 ParcelableHolder
フィールドを介して、新しいParcelable
を元のParcelable
にアタッチできます。
// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;
ap.extension.setParcelable(op);
...
OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);
// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();
ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);
...
std::shared_ptr<OemDefinedParcelable> op_ptr;
ap.extension.getParcelable(&op_ptr);
// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);
...
std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);
// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });
ap.extension.set_parcelable(Rc::clone(&op));
...
let op = ap.extension.get_parcelable::<OemDefinedParcelable>();
AIDL ランタイムに対するビルド
AIDL には、Java、NDK、CPP の 3 つの異なるバックエンドがあります。 Stable AIDL を使用するには、常にsystem/lib*/libbinder.so
にある libbinder のシステム コピーを使用し、 /dev/binder
で話す必要があります。ベンダー イメージのコードの場合、これはlibbinder
(VNDK から) を使用できないことを意味します。このライブラリには、不安定な C++ API と不安定な内部が含まれています。代わりに、ネイティブ ベンダー コードは AIDL の NDK バックエンドを使用し、 libbinder_ndk
(システムlibbinder.so
によってサポートされている) に対してリンクし、 aidl_interface
エントリによって作成された-ndk_platform
ライブラリに対してリンクする必要があります。
AIDL HAL サーバー インスタンス名
慣例により、AIDL HAL サービスのインスタンス名は$package.$type/$instance
の形式になります。たとえば、バイブレーター HAL のインスタンスはandroid.hardware.vibrator.IVibrator/default
として登録されます。
AIDL HAL サーバーの作成
@VintfStability
サーバーは、VINTF マニフェストで宣言する必要があります。たとえば、次のようになります。
<hal format="aidl">
<name>android.hardware.vibrator</name>
<version>1</version>
<fqname>IVibrator/default</fqname>
</hal>
それ以外の場合は、通常どおり AIDL サービスを登録する必要があります。 VTS テストを実行する場合、宣言されたすべての AIDL HAL が利用可能であることが期待されます。
AIDL クライアントの作成
AIDL クライアントは、たとえば次のように、互換性マトリックスで自分自身を宣言する必要があります。
<hal format="aidl" optional="true">
<name>android.hardware.vibrator</name>
<version>1-2</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
</interface>
</hal>
既存の HAL を HIDL から AIDL に変換する
hidl2aidl
ツールを使用して、HIDL インターフェースを AIDL に変換します。
hidl2aidl
機能:
- 指定されたパッケージの
.hal
ファイルに基づいて.aidl
ファイルを作成します - すべてのバックエンドを有効にして、新しく作成された AIDL パッケージのビルド ルールを作成する
- HIDL 型から AIDL 型に変換するための変換メソッドを Java、CPP、NDK バックエンドで作成する
- 必要な依存関係を持つ翻訳ライブラリのビルド ルールを作成する
- 静的アサートを作成して、HIDL および AIDL 列挙子が CPP および NDK バックエンドで同じ値を持つようにします
次の手順に従って、.hal ファイルのパッケージを .aidl ファイルに変換します。
system/tools/hidl/hidl2aidl
にあるツールをビルドします。このツールを最新のソースからビルドすると、最も完全なエクスペリエンスが提供されます。最新バージョンを使用して、以前のリリースから古いブランチのインターフェイスを変換できます。
m hidl2aidl
出力ディレクトリの後に変換するパッケージを指定してツールを実行します。
オプションで、
-l
引数を使用して、新しいライセンス ファイルの内容を生成されたすべてのファイルの先頭に追加します。必ず正しいライセンスと日付を使用してください。hidl2aidl -o <output directory> -l <file with license> <package>
例えば:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
生成されたファイルを読み、変換に関する問題を修正します。
-
conversion.log
には、最初に修正する未処理の問題が含まれています。 - 生成され
.aidl
ファイルには、対処が必要な警告や提案が含まれている場合があります。これらのコメントは//
で始まります。 - この機会に、パッケージをクリーンアップして改善してください。
-
toString
やequals
など、必要になる可能性がある機能については、@JavaDerive
アノテーションを確認してください。
-
必要なターゲットだけをビルドします。
- 使用しないバックエンドを無効にします。 CPP バックエンドよりも NDK バックエンドを優先します。「 runtime の選択」を参照してください。
- 使用されない翻訳ライブラリまたはその生成コードを削除します。
AIDL と HIDL の主な違いを参照してください。
- 通常、AIDL の組み込み
Status
と例外を使用すると、インターフェースが改善され、別のインターフェース固有のステータス タイプが不要になります。 - メソッドの AIDL インターフェース引数は、HIDL のようにデフォルトで
@nullable
ではありません。
- 通常、AIDL の組み込み
AIDL HAL のセポリシー
ベンダー コードに表示される AIDL サービス タイプには、 hal_service_type
属性が必要です。それ以外の場合、sepolicy 構成は他の AIDL サービスと同じです (ただし、HAL には特別な属性があります)。以下は、HAL サービス コンテキストの定義例です。
type hal_foo_service, service_manager_type, hal_service_type;
プラットフォームで定義されたほとんどのサービスでは、正しいタイプのサービス コンテキストがすでに追加されています(たとえば、 android.hardware.foo.IFoo/default
はすでにhal_foo_service
としてマークされています)。ただし、フレームワーク クライアントが複数のインスタンス名をサポートしている場合は、追加のインスタンス名をデバイス固有のservice_contexts
ファイルに追加する必要があります。
android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0
新しいタイプの HAL を作成するときは、HAL 属性を追加する必要があります。特定の HAL 属性が複数のサービス タイプに関連付けられている場合があります (前述のように、それぞれが複数のインスタンスを持つ場合があります)。 HAL foo
の場合、 hal_attribute(foo)
があります。このマクロは、属性hal_foo_client
およびhal_foo_server
を定義します。特定のドメインに対して、 hal_client_domain
およびhal_server_domain
マクロは、ドメインを特定の HAL 属性に関連付けます。たとえば、この HAL のクライアントであるシステム サーバーは、ポリシーhal_client_domain(system_server, hal_foo)
対応します。同様に、HAL サーバーにはhal_server_domain(my_hal_domain, hal_foo)
が含まれます。通常、特定の HAL 属性に対して、参照用またはサンプル HAL 用にhal_foo_default
のようなドメインも作成します。ただし、一部のデバイスはこれらのドメインを独自のサーバーに使用します。複数のサーバーのドメインを区別することは、同じインターフェースを提供し、実装で異なる権限セットを必要とする複数のサーバーがある場合にのみ問題になります。これらすべてのマクロで、 hal_foo
は実際には sepolicy オブジェクトではありません。代わりに、このトークンはこれらのマクロによって使用され、クライアント サーバー ペアに関連付けられた属性のグループを参照します。
ただし、これまでのところ、 hal_foo_service
とhal_foo
( hal_attribute(foo)
の属性ペア) を関連付けていません。 HAL 属性は、 hal_attribute_service
マクロを使用して AIDL HAL サービスに関連付けられます(HIDL HAL はhal_attribute_hwservice
マクロを使用します)。たとえば、 hal_attribute_service(hal_foo, hal_foo_service)
です。これは、 hal_foo_client
プロセスが HAL を取得でき、 hal_foo_server
プロセスが HAL を登録できることを意味します。これらの登録規則の適用は、コンテキスト マネージャー ( servicemanager
) によって行われます。サービス名が常に HAL 属性に対応しているとは限らないことに注意してください。たとえば、 hal_attribute_service(hal_foo, hal_foo2_service)
が表示される場合があります。ただし、一般に、これはサービスが常に一緒に使用されることを意味するため、hal_foo2_service をhal_foo_service
して、すべてのサービス コンテキストにhal_foo2_service
を使用することを検討できます。複数のhal_attribute_service
を設定するほとんどの HAL は、元の HAL 属性名が十分に一般的ではなく、変更できないためです。
これらをすべてまとめると、HAL の例は次のようになります。
public/attributes:
// define hal_foo, hal_foo_client, hal_foo_server
hal_attribute(foo)
public/service.te
// define hal_foo_service
type hal_foo_service, hal_service_type, protected_service, service_manager_type
public/hal_foo.te:
// allow binder connection from client to server
binder_call(hal_foo_client, hal_foo_server)
// allow client to find the service, allow server to register the service
hal_attribute_service(hal_foo, hal_foo_service)
// allow binder communication from server to service_manager
binder_use(hal_foo_server)
private/service_contexts:
// bind an AIDL service name to the selinux type
android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0
private/<some_domain>.te:
// let this domain use the hal service
binder_use(some_domain)
hal_client_domain(some_domain, hal_foo)
vendor/<some_hal_server_domain>.te
// let this domain serve the hal service
hal_server_domain(some_hal_server_domain, hal_foo)
付属の拡張インターフェース
拡張機能は、サービス マネージャーに直接登録された最上位のインターフェイスであるか、サブインターフェイスであるかに関係なく、任意のバインダー インターフェイスに接続できます。拡張機能を取得するときは、拡張機能のタイプが期待どおりであることを確認する必要があります。拡張子は、バインダーを提供するプロセスからのみ設定できます。
拡張機能が既存の HAL の機能を変更する場合は常に、添付された拡張機能を使用する必要があります。まったく新しい機能が必要な場合は、このメカニズムを使用する必要はなく、拡張インターフェイスをサービス マネージャーに直接登録できます。接続された拡張インターフェイスは、サブインターフェイスに接続されている場合に最も意味があります。これらの階層は深いか、複数インスタンス化されている可能性があるためです。グローバル拡張機能を使用して別のサービスのバインダー インターフェース階層をミラーリングすると、直接接続された拡張機能と同等の機能を提供するために大規模な簿記が必要になります。
バインダーに拡張機能を設定するには、次の API を使用します。
- NDK バックエンド:
AIBinder_setExtension
- Java バックエンド:
android.os.Binder.setExtension
- CPP バックエンド:
android::Binder::setExtension
バインダーで拡張機能を取得するには、次の API を使用します。
- NDK バックエンド:
AIBinder_getExtension
- Java バックエンド:
android.os.IBinder.getExtension
- CPP バックエンド:
android::IBinder::getExtension
これらの API の詳細については、対応するバックエンドのgetExtension
関数のドキュメントを参照してください。拡張機能の使用例は、 hardware/interfaces/tests/extension/vibratorにあります。
AIDL と HIDL の主な違い
AIDL HAL または AIDL HAL インターフェースを使用する場合は、HIDL HAL の記述との違いに注意してください。
- AIDL 言語の構文は Java に近いです。 HIDL 構文は C++ に似ています。
- すべての AIDL インターフェースには、組み込みのエラー ステータスがあります。カスタム ステータス タイプを作成する代わりに、インターフェイス ファイルで定数ステータス int を作成し、CPP/NDK バックエンドで
EX_SERVICE_SPECIFIC
を使用し、Java バックエンドでServiceSpecificException
を使用します。エラー処理を参照してください。 - AIDL は、バインダー オブジェクトが送信されたときにスレッドプールを自動的に開始しません。それらは手動で開始する必要があります (スレッド管理を参照)。
- AIDL は、チェックされていないトランスポート エラーで中止されません(HIDL
Return
は、チェックされていないエラーで中止されます)。 - AIDL は、ファイルごとに 1 つのタイプのみを宣言できます。
- AIDL 引数は、出力パラメーターに加えて、in/out/inout として指定できます (「同期コールバック」はありません)。
- AIDL は、ハンドルの代わりに fd をプリミティブ型として使用します。
- HIDL は、互換性のない変更にはメジャー バージョンを使用し、互換性のある変更にはマイナー バージョンを使用します。 AIDL では、下位互換性のある変更が適切に行われます。 AIDL には、メジャー バージョンの明確な概念はありません。代わりに、これはパッケージ名に組み込まれます。たとえば、AIDL はパッケージ名
bluetooth2
を使用する場合があります。 - デフォルトでは、AIDL はリアルタイムの優先度を継承しません。
setInheritRt
関数をバインダーごとに使用して、リアルタイムの優先順位の継承を有効にする必要があります。
Android 11 では、Android で HAL に AIDL を使用する機能が導入されています。これにより、HIDL を使用せずに Android の一部を実装できます。可能であれば、HAL を移行して AIDL のみを使用します(上流の HAL が HIDL を使用する場合は、HIDL を使用する必要があります)。
system.img
などのフレームワーク コンポーネントと vendor.img などのハードウェア コンポーネント間の通信に AIDL を使用する HAL は、安定したvendor.img
を使用する必要があります。ただし、たとえばある HAL から別の HAL へなど、パーティション内で通信する場合、使用する IPC メカニズムに制限はありません。
動機
AIDL は HIDL よりも長く使用されており、Android フレームワーク コンポーネント間やアプリ内など、他の多くの場所で使用されています。 AIDL が安定性をサポートするようになったので、単一の IPC ランタイムでスタック全体を実装できます。 AIDL には、HIDL よりも優れたバージョン管理システムもあります。
- 単一の IPC 言語を使用するということは、学習、デバッグ、最適化、および保護することが 1 つだけであることを意味します。
- AIDL は、インターフェースの所有者向けのインプレース バージョニングをサポートしています。
- 所有者は、インターフェイスの最後にメソッドを追加したり、Parcelable にフィールドを追加したりできます。これは、何年にもわたってコードをバージョン管理することが容易になり、また、年々のコストが小さくなることを意味します (型はインプレースで修正でき、インターフェイス バージョンごとに追加のライブラリは必要ありません)。
- 拡張インターフェイスは、型システムではなく実行時にアタッチできるため、下流の拡張機能を新しいバージョンのインターフェイスにリベースする必要はありません。
- 既存の AIDL インターフェースは、その所有者が安定化することを選択したときに直接使用できます。以前は、HIDL でインターフェース全体のコピーを作成する必要がありました。
AIDL HAL インターフェースの作成
システムとベンダーの間で AIDL インターフェイスを使用するには、インターフェイスに次の 2 つの変更が必要です。
- すべての型定義に
@VintfStability
のアノテーションを付ける必要があります。 -
aidl_interface
宣言には、stability: "vintf",
.
これらの変更を行うことができるのは、インターフェースの所有者だけです。
これらの変更を行う場合、機能するためにはインターフェイスがVINTF マニフェストに含まれている必要があります。 VTS テストvts_treble_vintf_vendor_test
を使用して、これ (およびリリースされたインターフェイスが凍結されていることの確認などの関連要件) をテストします。 NDK バックエンドでAIBinder_forceDowngradeToLocalStability
、C++ バックエンドでandroid::Stability::forceDowngradeToLocalStability
、またはバインダー オブジェクトの送信前に Java バックエンドでandroid.os.Binder#forceDowngradeToSystemStability
を呼び出すことにより、これらの要件なしで@VintfStability
インターフェースを使用できます。別のプロセスに。すべてのアプリはシステム コンテキストで実行されるため、サービスをベンダー安定性にダウングレードすることは Java ではサポートされていません。
さらに、コードの移植性を最大限に高め、不要なライブラリの追加などの潜在的な問題を回避するために、CPP バックエンドを無効にします。
3 つのバックエンド (Java、NDK、および CPP) があるため、以下のコード例でのbackends
の使用は正しいことに注意してください。以下のコードは、CPP バックエンドを具体的に選択して無効にする方法を示しています。
aidl_interface: {
...
backends: {
cpp: {
enabled: false,
},
},
}
AIDL HAL インターフェースの検索
HAL 用の AOSP 安定 AIDL インターフェースは、HIDL インターフェースと同じベース ディレクトリのaidl
フォルダにあります。
- ハードウェア/インターフェース
- フレームワーク/ハードウェア/インターフェース
- システム/ハードウェア/インターフェース
拡張インターフェイスは、 vendor
またはhardware
の他のhardware/interfaces
サブディレクトリに配置する必要があります。
拡張インターフェイス
Android には、リリースごとに一連の公式 AOSP インターフェースがあります。 Android パートナーがこれらのインターフェースに機能を追加したい場合、これらを直接変更しないでください。これは、Android ランタイムが AOSP Android ランタイムと互換性がないことを意味するためです。 GMS デバイスの場合、これらのインターフェイスの変更を避けることは、GSI イメージが引き続き機能することを保証するものでもあります。
拡張機能は、次の 2 つの方法で登録できます。
- 実行時に、添付された拡張機能を参照してください。
- スタンドアロンで、グローバルに登録され、VINTF に登録されています。
ただし、拡張機能が登録されている場合、ベンダー固有の (上流の AOSP の一部ではないことを意味する) コンポーネントがインターフェイスを使用する場合、マージの競合が発生する可能性はありません。ただし、上流の AOSP コンポーネントに対して下流の変更が行われると、マージの競合が発生する可能性があるため、次の戦略をお勧めします。
- インターフェイスの追加は、次のリリースで AOSP にアップストリームできます
- マージの競合なしで、さらなる柔軟性を可能にするインターフェイスの追加は、次のリリースでアップストリームすることができます
拡張 Parcelables: ParcelableHolder
ParcelableHolder
は、別のParcelable
を含むことができるParcelable
です。 ParcelableHolder の主な使用例は、 ParcelableHolder
を拡張可能にすることParcelable
。たとえば、デバイスの実装者が、AOSP で定義されたParcelable
であるAospDefinedParcelable
を拡張して、付加価値機能を含めることができると期待しているイメージ。
以前はParcelableHolder
がなければ、フィールドを追加するとエラーになるため、デバイス実装者は AOSP 定義の安定した AIDL インターフェイスを変更できませんでした。
parcelable AospDefinedParcelable {
int a;
String b;
String x; // ERROR: added by a device implementer
int[] y; // added by a device implementer
}
前のコードに見られるように、Android の次のリリースで Parcelable が改訂されたときに、デバイスの実装者によって追加されたフィールドが競合する可能性があるため、このプラクティスは破られています。
ParcelableHolder
を使用すると、Parcelable の所有者はParcelable
の拡張ポイントを定義できます。
parcelable AospDefinedParcelable {
int a;
String b;
ParcelableHolder extension;
}
次に、デバイスの実装者は、拡張用に独自のParcelable
を定義できます。
parcelable OemDefinedParcelable {
String x;
int[] y;
}
最後に、 ParcelableHolder
フィールドを介して、新しいParcelable
を元のParcelable
にアタッチできます。
// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;
ap.extension.setParcelable(op);
...
OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);
// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();
ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);
...
std::shared_ptr<OemDefinedParcelable> op_ptr;
ap.extension.getParcelable(&op_ptr);
// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);
...
std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);
// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });
ap.extension.set_parcelable(Rc::clone(&op));
...
let op = ap.extension.get_parcelable::<OemDefinedParcelable>();
AIDL ランタイムに対するビルド
AIDL には、Java、NDK、CPP の 3 つの異なるバックエンドがあります。 Stable AIDL を使用するには、常にsystem/lib*/libbinder.so
にある libbinder のシステム コピーを使用し、 /dev/binder
で話す必要があります。ベンダー イメージのコードの場合、これはlibbinder
(VNDK から) を使用できないことを意味します。このライブラリには、不安定な C++ API と不安定な内部が含まれています。代わりに、ネイティブ ベンダー コードは AIDL の NDK バックエンドを使用し、 libbinder_ndk
(システムlibbinder.so
によってサポートされている) に対してリンクし、 aidl_interface
エントリによって作成された-ndk_platform
ライブラリに対してリンクする必要があります。
AIDL HAL サーバー インスタンス名
慣例により、AIDL HAL サービスのインスタンス名は$package.$type/$instance
の形式になります。たとえば、バイブレーター HAL のインスタンスはandroid.hardware.vibrator.IVibrator/default
として登録されます。
AIDL HAL サーバーの作成
@VintfStability
サーバーは、VINTF マニフェストで宣言する必要があります。たとえば、次のようになります。
<hal format="aidl">
<name>android.hardware.vibrator</name>
<version>1</version>
<fqname>IVibrator/default</fqname>
</hal>
それ以外の場合は、通常どおり AIDL サービスを登録する必要があります。 VTS テストを実行する場合、宣言されたすべての AIDL HAL が利用可能であることが期待されます。
AIDL クライアントの作成
AIDL クライアントは、たとえば次のように、互換性マトリックスで自分自身を宣言する必要があります。
<hal format="aidl" optional="true">
<name>android.hardware.vibrator</name>
<version>1-2</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
</interface>
</hal>
既存の HAL を HIDL から AIDL に変換する
hidl2aidl
ツールを使用して、HIDL インターフェースを AIDL に変換します。
hidl2aidl
機能:
- 指定されたパッケージの
.hal
ファイルに基づいて.aidl
ファイルを作成します - すべてのバックエンドを有効にして、新しく作成された AIDL パッケージのビルド ルールを作成する
- HIDL 型から AIDL 型に変換するための変換メソッドを Java、CPP、NDK バックエンドで作成する
- 必要な依存関係を持つ翻訳ライブラリのビルド ルールを作成する
- 静的アサートを作成して、HIDL および AIDL 列挙子が CPP および NDK バックエンドで同じ値を持つようにします
次の手順に従って、.hal ファイルのパッケージを .aidl ファイルに変換します。
system/tools/hidl/hidl2aidl
にあるツールをビルドします。このツールを最新のソースからビルドすると、最も完全なエクスペリエンスが提供されます。最新バージョンを使用して、以前のリリースから古いブランチのインターフェイスを変換できます。
m hidl2aidl
出力ディレクトリの後に変換するパッケージを指定してツールを実行します。
オプションで、
-l
引数を使用して、新しいライセンス ファイルの内容を生成されたすべてのファイルの先頭に追加します。必ず正しいライセンスと日付を使用してください。hidl2aidl -o <output directory> -l <file with license> <package>
例えば:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
生成されたファイルを読み、変換に関する問題を修正します。
-
conversion.log
には、最初に修正する未処理の問題が含まれています。 - 生成され
.aidl
ファイルには、対処が必要な警告や提案が含まれている場合があります。これらのコメントは//
で始まります。 - この機会に、パッケージをクリーンアップして改善してください。
-
toString
やequals
など、必要になる可能性がある機能については、@JavaDerive
アノテーションを確認してください。
-
必要なターゲットだけをビルドします。
- 使用しないバックエンドを無効にします。 CPP バックエンドよりも NDK バックエンドを優先します。「 runtime の選択」を参照してください。
- 使用されない翻訳ライブラリまたはその生成コードを削除します。
AIDL と HIDL の主な違いを参照してください。
- 通常、AIDL の組み込み
Status
と例外を使用すると、インターフェースが改善され、別のインターフェース固有のステータス タイプが不要になります。 - メソッドの AIDL インターフェース引数は、HIDL のようにデフォルトで
@nullable
ではありません。
- 通常、AIDL の組み込み
AIDL HAL のセポリシー
ベンダー コードに表示される AIDL サービス タイプには、 hal_service_type
属性が必要です。それ以外の場合、sepolicy 構成は他の AIDL サービスと同じです (ただし、HAL には特別な属性があります)。以下は、HAL サービス コンテキストの定義例です。
type hal_foo_service, service_manager_type, hal_service_type;
プラットフォームで定義されたほとんどのサービスでは、正しいタイプのサービス コンテキストがすでに追加されています(たとえば、 android.hardware.foo.IFoo/default
はすでにhal_foo_service
としてマークされています)。ただし、フレームワーク クライアントが複数のインスタンス名をサポートしている場合は、追加のインスタンス名をデバイス固有のservice_contexts
ファイルに追加する必要があります。
android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0
新しいタイプの HAL を作成するときは、HAL 属性を追加する必要があります。特定の HAL 属性が複数のサービス タイプに関連付けられている場合があります (前述のように、それぞれが複数のインスタンスを持つ場合があります)。 HAL foo
の場合、 hal_attribute(foo)
があります。このマクロは、属性hal_foo_client
およびhal_foo_server
を定義します。特定のドメインに対して、 hal_client_domain
およびhal_server_domain
マクロは、ドメインを特定の HAL 属性に関連付けます。たとえば、この HAL のクライアントであるシステム サーバーは、ポリシーhal_client_domain(system_server, hal_foo)
対応します。同様に、HAL サーバーにはhal_server_domain(my_hal_domain, hal_foo)
が含まれます。通常、特定の HAL 属性に対して、参照用またはサンプル HAL 用にhal_foo_default
のようなドメインも作成します。ただし、一部のデバイスはこれらのドメインを独自のサーバーに使用します。複数のサーバーのドメインを区別することは、同じインターフェースを提供し、実装で異なる権限セットを必要とする複数のサーバーがある場合にのみ問題になります。これらすべてのマクロで、 hal_foo
は実際には sepolicy オブジェクトではありません。代わりに、このトークンはこれらのマクロによって使用され、クライアント サーバー ペアに関連付けられた属性のグループを参照します。
ただし、これまでのところ、 hal_foo_service
とhal_foo
( hal_attribute(foo)
の属性ペア) を関連付けていません。 HAL 属性は、 hal_attribute_service
マクロを使用して AIDL HAL サービスに関連付けられます(HIDL HAL はhal_attribute_hwservice
マクロを使用します)。たとえば、 hal_attribute_service(hal_foo, hal_foo_service)
です。これは、 hal_foo_client
プロセスが HAL を取得でき、 hal_foo_server
プロセスが HAL を登録できることを意味します。これらの登録規則の適用は、コンテキスト マネージャー ( servicemanager
) によって行われます。サービス名が常に HAL 属性に対応しているとは限らないことに注意してください。たとえば、 hal_attribute_service(hal_foo, hal_foo2_service)
が表示される場合があります。ただし、一般に、これはサービスが常に一緒に使用されることを意味するため、hal_foo2_service をhal_foo_service
して、すべてのサービス コンテキストにhal_foo2_service
を使用することを検討できます。複数のhal_attribute_service
を設定するほとんどの HAL は、元の HAL 属性名が十分に一般的ではなく、変更できないためです。
これらをすべてまとめると、HAL の例は次のようになります。
public/attributes:
// define hal_foo, hal_foo_client, hal_foo_server
hal_attribute(foo)
public/service.te
// define hal_foo_service
type hal_foo_service, hal_service_type, protected_service, service_manager_type
public/hal_foo.te:
// allow binder connection from client to server
binder_call(hal_foo_client, hal_foo_server)
// allow client to find the service, allow server to register the service
hal_attribute_service(hal_foo, hal_foo_service)
// allow binder communication from server to service_manager
binder_use(hal_foo_server)
private/service_contexts:
// bind an AIDL service name to the selinux type
android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0
private/<some_domain>.te:
// let this domain use the hal service
binder_use(some_domain)
hal_client_domain(some_domain, hal_foo)
vendor/<some_hal_server_domain>.te
// let this domain serve the hal service
hal_server_domain(some_hal_server_domain, hal_foo)
付属の拡張インターフェース
拡張機能は、サービス マネージャーに直接登録された最上位のインターフェイスであるか、サブインターフェイスであるかに関係なく、任意のバインダー インターフェイスに接続できます。拡張機能を取得するときは、拡張機能のタイプが期待どおりであることを確認する必要があります。拡張子は、バインダーを提供するプロセスからのみ設定できます。
拡張機能が既存の HAL の機能を変更する場合は常に、添付された拡張機能を使用する必要があります。まったく新しい機能が必要な場合は、このメカニズムを使用する必要はなく、拡張インターフェイスをサービス マネージャーに直接登録できます。接続された拡張インターフェイスは、サブインターフェイスに接続されている場合に最も意味があります。これらの階層は深いか、複数インスタンス化されている可能性があるためです。グローバル拡張機能を使用して別のサービスのバインダー インターフェース階層をミラーリングすると、直接接続された拡張機能と同等の機能を提供するために大規模な簿記が必要になります。
バインダーに拡張機能を設定するには、次の API を使用します。
- NDK バックエンド:
AIBinder_setExtension
- Java バックエンド:
android.os.Binder.setExtension
- CPP バックエンド:
android::Binder::setExtension
バインダーで拡張機能を取得するには、次の API を使用します。
- NDK バックエンド:
AIBinder_getExtension
- Java バックエンド:
android.os.IBinder.getExtension
- CPP バックエンド:
android::IBinder::getExtension
これらの API の詳細については、対応するバックエンドのgetExtension
関数のドキュメントを参照してください。拡張機能の使用例は、 hardware/interfaces/tests/extension/vibratorにあります。
AIDL と HIDL の主な違い
AIDL HAL または AIDL HAL インターフェースを使用する場合は、HIDL HAL の記述との違いに注意してください。
- AIDL 言語の構文は Java に近いです。 HIDL 構文は C++ に似ています。
- すべての AIDL インターフェースには、組み込みのエラー ステータスがあります。カスタム ステータス タイプを作成する代わりに、インターフェイス ファイルで定数ステータス int を作成し、CPP/NDK バックエンドで
EX_SERVICE_SPECIFIC
を使用し、Java バックエンドでServiceSpecificException
を使用します。エラー処理を参照してください。 - AIDL は、バインダー オブジェクトが送信されたときにスレッドプールを自動的に開始しません。それらは手動で開始する必要があります (スレッド管理を参照)。
- AIDL は、チェックされていないトランスポート エラーで中止されません(HIDL
Return
は、チェックされていないエラーで中止されます)。 - AIDL は、ファイルごとに 1 つのタイプのみを宣言できます。
- AIDL 引数は、出力パラメーターに加えて、in/out/inout として指定できます (「同期コールバック」はありません)。
- AIDL は、ハンドルの代わりに fd をプリミティブ型として使用します。
- HIDL は、互換性のない変更にはメジャー バージョンを使用し、互換性のある変更にはマイナー バージョンを使用します。 AIDL では、下位互換性のある変更が適切に行われます。 AIDL には、メジャー バージョンの明確な概念はありません。代わりに、これはパッケージ名に組み込まれます。たとえば、AIDL はパッケージ名
bluetooth2
を使用する場合があります。 - デフォルトでは、AIDL はリアルタイムの優先度を継承しません。
setInheritRt
関数をバインダーごとに使用して、リアルタイムの優先順位の継承を有効にする必要があります。