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

HIDL

HAL インターフェース定義言語(HIDL、「ハイドル」と発音)は、HAL とそのユーザー間のインターフェースを規定するインターフェース記述言語(IDL)です。インターフェースとパッケージに収集される型とメソッド呼び出しを指定できます。広義では、独立してコンパイルできるコードベース間の通信システムを指します。

HIDL は、プロセス間通信(IPC)に使用することを目的としています。プロセス間の通信は、バインダ化された通信とも呼ばれます。プロセスにリンクする必要があるライブラリには、パススルー モードも使用できます(Java ではサポートされていません)。

HIDL では、パッケージに収集される(クラスに似た)インターフェースで構成されるデータ構造とメソッド シグネチャを指定します。HIDL の構文は、C++ や Java のプログラマーにとってなじみやすいものですが、キーワードのセットが異なります。HIDL では、Java スタイルのアノテーションも使用します。

HIDL の設計

HIDL の目的は、HAL を再構築せずにフレームワークを交換できるようにすることです。HAL はベンダーまたは SOC メーカーによって作成され、デバイスの /vendor パーティションに配置されます。これにより、フレームワークをそのパーティション内で、HAL を再コンパイルすることなく OTA で交換できます。

HIDL の設計では、次の点のバランスが考慮されています。

  • 相互運用性。さまざまなアーキテクチャ、ツールチェーン、ビルド構成でコンパイルできる、信頼性の高い相互運用可能なプロセス間のインターフェースを作成します。HIDL インターフェースはバージョニングされており、公開後は変更できません。
  • 効率性。HIDL では、コピー オペレーションの回数を最小限に抑えようとしています。HIDL 定義のデータは、解凍しないで使用できる C++ 標準レイアウト データ構造の C++ コードに渡されます。HIDL は共有メモリ インターフェースも提供します。RPC は本質的にやや遅いため、HIDL は RPC 呼び出しを使用せずにデータを転送する方法として、共有メモリと高速メッセージキュー(FMQ)の 2 つをサポートしています。
  • 直感的。HIDL は、RPC に in パラメータのみを使用することで、メモリのオーナー権限に関する厄介な問題を回避します(Android インターフェース定義言語(AIDL)をご覧ください)。メソッドから効率的に返されない値は、コールバック関数を介して返されます。転送のために HIDL にデータを渡しても、HIDL からデータを受け取っても、データのオーナー権限は変更されません。つまり、オーナー権限は常に呼び出し元の関数が保持します。データは、呼び出された関数が存続する間のみ保持すればよく、呼び出された関数が結果を返したらすぐに破棄できます。

パススルー モードの使用

以前のバージョンの Android を搭載したデバイスを Android O にアップデートするには、バインダ化モードと same-process(パススルー)モードで HAL を提供する新しい HIDL インターフェースで、両方の伝統型 HAL(およびレガシー HAL)をラップします。このラップは、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.cppPTFooAccurate.cpp)。

パススルー HAL のバインダ化

パススルー モードをサポートする HAL 実装をバインダ化できます。a.b.c.d@M.N::IFoo という HAL インターフェースの場合、次の 2 つのパッケージが作成されます。

  • a.b.c.d@M.N::IFoo-impl。HAL の実装が含まれ、関数 IFoo* HIDL_FETCH_IFoo(const char* name) を公開します。レガシー デバイスでは、このパッケージは dlopen され、実装は HIDL_FETCH_IFoo でインスタンス化されます。hidl-gen-Lc++-impl-Landroidbp-impl を使用してベースコードを生成できます。
  • a.b.c.d@M.N::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 には可変個引数がありません。
  • カンマはシーケンス要素を区切ります。
  • セミコロンは、最後の要素を含め、各要素を終了します。
  • UPPERCASE は非終端記号です。
  • 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

用語

このセクションでは、次の HIDL 関連の用語を使用します。

バインダ化 プロセス間のリモート プロシージャ コールで HIDL が使用され、バインダに似たメカニズムで実装されていることを示します。パススルーも参照してください。
コールバック、非同期 HAL ユーザーが提供し、(HIDL メソッドを介して)HAL に渡され、データを返すためにHAL によって随時呼び出されるインターフェース。
コールバック、同期 サーバーの HIDL メソッド実装からクライアントにデータを返します。 void または単一のプリミティブ値を返すメソッドでは使用されません。
クライアント 特定のインターフェースのメソッドを呼び出すプロセス。HAL またはフレームワークのプロセスは、あるインターフェースのクライアントと別のインターフェースのサーバー間のプロセスであってもかまいません。パススルーも参照してください。
拡張 メソッドおよび / または型を別のインターフェースに追加するインターフェースを示します。1 つのインターフェースは、別の 1 つのインターフェースのみを拡張できます。同じパッケージ名でのマイナー バージョン インクリメントや、古いパッケージ上でビルドする新しいパッケージ(ベンダー拡張など)に使用できます。
生成 クライアントに値を返すインターフェース メソッドを示します。1 つの非プリミティブ値または複数の値を返すために、同期コールバック関数が生成されます。
インターフェース メソッドと型のコレクション。C++ または Java のクラスに変換されます。1 つのインターフェース内のメソッドはすべて同じ方向に呼び出されます。クライアント プロセスは、サーバー プロセスによって実装されたメソッドを呼び出します。
一方向 HIDL メソッドについて使用される場合は、メソッドが値を返さず、ブロックしないことを意味します。
パッケージ バージョンを共有するインターフェースとデータ型のコレクション。
パススルー サーバーが共有ライブラリである HIDL のモード。クライアントによって dlopen されます。パススルー モードでは、クライアントとサーバーは同じプロセスですが、コードベースは別です。レガシー コードベースを HIDL モデルに移行するためにのみ使用します。 バインダ化も参照してください。
サーバー インターフェースのメソッドを実装するプロセス。パススルーも参照してください。
トランスポート サーバーとクライアント間でデータを移動する HIDL インフラストラクチャ。
バージョン パッケージのバージョン。メジャーとマイナーを表す 2 つの整数で構成されます。マイナー バージョン インクリメントでは、型とメソッドを追加できますが、変更はできません。