HIDL

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 integeridentifierなどのトークン ファミリです (標準の C 解析規則)。
  • constexpr 、C スタイルの定数式 ( 1 + 11L << 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