HAL インターフェイス定義言語 (HIDL) は、HAL とそのユーザー間のインターフェイスを指定するインターフェイス記述言語 (IDL) です。 HIDL では、インターフェイスとパッケージにまとめられた型とメソッド呼び出しを指定できます。より広義には、HIDL は、独立してコンパイルできるコードベース間で通信するためのシステムです。 Android 10 の時点で、HIDL は非推奨となり、Android はあらゆる場所でAIDL を使用するように移行しています。
HIDL は、プロセス間通信 (IPC) に使用することを目的としています。 HDL で作成された HAL は、バインダー プロセス間通信 (IPC) 呼び出しを使用して他のアーキテクチャ層と通信できるため、バインダー化された HAL と呼ばれます。バインダ化された HAL は、それを使用するクライアントとは別のプロセスで実行されます。プロセスにリンクする必要があるライブラリの場合、パススルー モードも利用できます (Java ではサポートされていません)。
HIDL は、パッケージに収集されるインターフェイス (クラスに似たもの) に編成されたデータ構造とメソッド シグネチャを指定します。 HIDL の構文は C++ および Java プログラマーにとって馴染みのあるものですが、キーワードのセットが異なります。 HIDL は Java スタイルのアノテーションも使用します。
用語
このセクションでは、次の HIDL 関連の用語を使用します。
バインダー化された | プロセス間のリモート プロシージャ コールに HIDL が使用されており、バインダーのようなメカニズムで実装されていることを示します。 「パススルー」も参照してください。 |
---|---|
コールバック、非同期 | HAL ユーザーによって提供され、(HIDL メソッドを使用して) HAL に渡され、いつでもデータを返すために HAL によって呼び出されるインターフェイス。 |
コールバック、同期 | サーバーの HIDL メソッド実装からクライアントにデータを返します。 void または単一のプリミティブ値を返すメソッドには使用されません。 |
クライアント | 特定のインターフェイスのメソッドを呼び出すプロセス。 HAL または Android フレームワーク プロセスは、あるインターフェイスのクライアントであり、別のインターフェイスのサーバーである場合があります。 「パススルー」も参照してください。 |
伸びる | 別のインターフェイスにメソッドや型を追加するインターフェイスを示します。インターフェイスは他のインターフェイスを 1 つだけ拡張できます。同じパッケージ名でマイナー バージョンを増やす場合や、新しいパッケージ (ベンダー拡張機能など) を古いパッケージ上に構築する場合に使用できます。 |
生成する | クライアントに値を返すインターフェイス メソッドを示します。 1 つの非プリミティブ値、または複数の値を返すには、同期コールバック関数が生成されます。 |
インターフェース | メソッドとタイプのコレクション。 C++ または Java のクラスに変換されます。インターフェイス内のすべてのメソッドは同じ方向に呼び出されます。クライアント プロセスは、サーバー プロセスによって実装されたメソッドを呼び出します。 |
一方通行 | HIDL メソッドに適用すると、メソッドが値を返さず、ブロックしないことを示します。 |
パッケージ | バージョンを共有するインターフェイスとデータ型のコレクション。 |
パススルー | サーバーが共有ライブラリであり、クライアントによってdlopen れる HIDL のモード。パススルー モードでは、クライアントとサーバーは同じプロセスですが、別のコードベースになります。従来のコードベースを HIDL モデルに取り込むためにのみ使用されます。 「バインダ化」も参照してください。 |
サーバ | インターフェースのメソッドを実装するプロセス。 「パススルー」も参照してください。 |
輸送 | サーバーとクライアント間でデータを移動する HIDL インフラストラクチャ。 |
バージョン | パッケージのバージョン。メジャーとマイナーの 2 つの整数で構成されます。マイナー バージョンの増分により、型とメソッドが追加される (ただし変更はされない) 場合があります。 |
HIDL設計
HIDL の目標は、HAL を再構築することなく Android フレームワークを置き換えることができることです。 HAL はベンダーまたは SOC メーカーによって構築され、デバイスの/vendor
パーティションに配置されます。これにより、HAL を再コンパイルすることなく、独自のパーティション内の Android フレームワークを OTA に置き換えることができます。
HIDL 設計では、次の懸念事項のバランスがとれています。
- 相互運用性。さまざまなアーキテクチャ、ツールチェーン、ビルド構成でコンパイルできるプロセス間に、信頼性の高い相互運用可能なインターフェイスを作成します。 HIDL インターフェイスはバージョン管理されており、公開後に変更することはできません。
- 効率。 HIDL は、コピー操作の数を最小限に抑えようとします。 HIDL で定義されたデータは、解凍せずに使用できる C++ 標準レイアウト データ構造で C++ コードに配信されます。 HIDL は共有メモリ インターフェイスも提供します。RPC は本質的に多少遅いため、HIDL は RPC 呼び出しを使用せずにデータを転送する 2 つの方法、共有メモリと高速メッセージ キュー (FMQ) をサポートします。
- 直感的。 HIDL は、RPC のパラメータ
in
のみを使用することで、メモリ所有権に関する厄介な問題を回避します ( Android Interface Definition Language (AIDL)を参照)。メソッドから効率的に返すことができない値は、コールバック関数を介して返されます。転送のために HIDL にデータを渡したり、HIDL からデータを受信したりしても、データの所有権は変更されません。所有権は常に呼び出し元の関数に残ります。データは、呼び出された関数の存続期間中のみ存続する必要があり、呼び出された関数が戻った直後に破棄される可能性があります。
パススルーモードの使用
以前のバージョンの Android を実行しているデバイスを Android O に更新するには、従来の (および従来の) HAL の両方を、バインダ化された同一プロセス (パススルー) モードで HAL を提供する新しい HIDL インターフェイスでラップできます。このラッピングは、HAL と Android フレームワークの両方に対して透過的です。
パススルー モードは、C++ クライアントと実装でのみ使用できます。以前のバージョンの Android を実行しているデバイスには Java で記述された HAL が含まれていないため、Java HAL は本質的にバインドされています。
パススルーヘッダーファイル
.hal
ファイルがコンパイルされると、 hidl-gen
バインダー通信に使用されるヘッダーに加えて、追加のパススルー ヘッダー ファイルBsFoo.h
を生成します。このヘッダーは、 dlopen
される関数を定義します。パススルー HAL は呼び出されるのと同じプロセスで実行されるため、ほとんどの場合、パススルー メソッドは直接関数呼び出し (同じスレッド) によって呼び出されます。 oneway
メソッドは、HAL による処理を待つことを目的としていないため、独自のスレッドで実行されます (つまり、パススルー モードでoneway
メソッドを使用する HAL はスレッドセーフである必要があります)。
IFoo.hal
を指定すると、 BsFoo.h
HIDL で生成されたメソッドをラップして、追加機能 ( oneway
トランザクションを別のスレッドで実行するなど) を提供します。このファイルはBpFoo.h
に似ていますが、バインダーを使用して IPC 呼び出しを渡す代わりに、必要な関数が直接呼び出されます。 HAL の将来の実装では、FooFast HAL や FooAccurate HAL などの複数の実装が提供される可能性があります。このような場合、追加の実装ごとにファイルが作成されます (例: PTFooFast.cpp
およびPTFooAccurate.cpp
)。
パススルー HAL のバインダ化
パススルー モードをサポートする HAL 実装をバインダ化できます。 HAL インターフェースabcd@MN::IFoo
を指定すると、2 つのパッケージが作成されます。
-
abcd@MN::IFoo-impl
。 HAL の実装が含まれており、関数IFoo* HIDL_FETCH_IFoo(const char* name)
を公開します。従来のデバイスでは、このパッケージはdlopen
され、実装はHIDL_FETCH_IFoo
を使用してインスタンス化されます。hidl-gen
、-Lc++-impl
、-Landroidbp-impl
を使用して基本コードを生成できます。 -
abcd@MN::IFoo-service
。パススルー HAL を開き、それ自体をバインダ化されたサービスとして登録し、同じ HAL 実装をパススルーとバインダ化の両方で使用できるようにします。
IFoo
型を指定すると、 sp<IFoo> IFoo::getService(string name, bool getStub)
呼び出してIFoo
のインスタンスにアクセスできます。 getStub
が true の場合、 getService
パススルー モードでのみ HAL を開こうとします。 getStub
が false の場合、 getService
バインドされたサービスを見つけようとします。それが失敗した場合は、パススルー サービスを見つけようとします。 getStub
パラメータは、 defaultPassthroughServiceImplementation
以外では決して使用しないでください。 (Android O で起動するデバイスは完全にバインドされたデバイスであるため、パススルー モードでサービスを開くことは許可されません。)
HIDL 文法
設計上、HIDL 言語は C に似ています (ただし、C プリプロセッサは使用しません)。以下で説明されていないすべての句読点は ( =
と|
の明白な使用を除いて) 文法の一部です。
注: HIDL コード スタイルの詳細については、 「コード スタイル ガイド」を参照してください。
-
/** */
はドキュメントのコメントを示します。これらは、型、メソッド、フィールド、列挙値の宣言にのみ適用できます。 -
/* */
は複数行のコメントを示します。 -
//
は行末までのコメントを示します。//
を除けば、改行は他の空白と同じです。 - 以下の文法の例では、
//
から行末までのテキストは文法の一部ではなく、文法に関するコメントです。 -
[empty]
用語が空である可能性があることを意味します。 -
?
リテラルまたは用語の後に続く場合は、それがオプションであることを意味します。 -
...
示されているように句読点で区切られた 0 個以上の項目を含むシーケンスを示します。 HIDL には可変長引数はありません。 - シーケンス要素はカンマで区切られます。
- セミコロンは、最後の要素を含む各要素を終了します。
- 大文字は非終端です。
-
italics
integer
やidentifier
などのトークン ファミリです (標準の C 解析規則)。 -
constexpr
、C スタイルの定数式 (1 + 1
や1L << 3
など) です。 -
import_name
、 「 HIDL のバージョン管理 」で説明されているように修飾されたパッケージ名またはインターフェイス名です。 - 小文字の
words
リテラルのトークンです。
例:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr