HIDL

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

HAL インターフェース定義言語または HIDL は、HAL とそのユーザー間のインターフェースを指定するためのインターフェース記述言語 (IDL) です。 HIDL では、インターフェイスとパッケージに収集された型とメソッド呼び出しを指定できます。より広義には、HIDL は、独立してコンパイルできるコードベース間で通信するためのシステムです。 Android 10 の時点で、HIDL は非推奨になり、Android はあらゆる場所でAIDLを使用するように移行しています。

HIDL は、プロセス間通信 (IPC) に使用することを目的としています。 HDL で作成された HALS は、バインダー プロセス間通信 (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 メソッドに適用された場合、メソッドが値を返さず、ブロックしないことを示します。
パッケージバージョンを共有するインターフェイスとデータ型のコレクション。
パススルーサーバーが共有ライブラリである HIDL のモードで、クライアントによってdlopenされます。パススルー モードでは、クライアントとサーバーは同じプロセスですが、コードベースは異なります。レガシー コードベースを HIDL モデルに組み込むためにのみ使用されます。バインダ化も参照してください。
サーバインターフェイスのメソッドを実装するプロセス。パススルーも参照してください。
輸送サーバーとクライアント間でデータを移動する HIDL インフラストラクチャ。
バージョンパッケージのバージョン。メジャーとマイナーの 2 つの整数で構成されます。マイナー バージョンの増分により、型とメソッドが追加される場合があります (変更はされません)。

HIDL 設計

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

HIDL 設計では、次の懸念事項のバランスを取ります。

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

パススルー モードの使用

以前のバージョンの Android を実行しているデバイスを Android O に更新するには、バインダライズ モードと同一プロセス (パススルー) モードで HAL を提供する新しい HIDL インターフェースで、従来の (および従来の) HAL の両方をラップできます。このラッピングは、HAL と Android フレームワークの両方に対して透過的です。

パススルー モードは、C++ クライアントと実装でのみ使用できます。以前のバージョンの Android を実行しているデバイスには Java で記述された HAL がないため、Java HAL は本質的にバインダ化されています。

.halファイルがコンパイルされると、 hidl-genは、バインダー通信に使用されるヘッダーに加えて、追加のパススルー ヘッダー ファイルBsFoo.hを生成します。このヘッダーは、 dlopenされる関数を定義します。パススルー HAL は呼び出されたプロセスと同じプロセスで実行されるため、ほとんどの場合、パススルー メソッドは直接関数呼び出し (同じスレッド) によって呼び出されます。 onewayメソッドは、HAL が処理するのを待つことを意図していないため、独自のスレッドで実行されます (つまり、パススルー モードでonewayメソッドを使用する HAL はスレッドセーフでなければなりません)。

IFoo.halを指定すると、 BsFoo.honewayで生成されたメソッドをラップして追加機能を提供します (一方向のトランザクションを別のスレッドで実行するなど)。このファイルは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 には可変引数はありません。
  • コンマは、シーケンス要素を区切ります。
  • セミコロンは、最後の要素を含む各要素を終了します。
  • 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