HIDL

HAL 接口定義語言或 HIDL(發音為“hide-l”)是一種接口描述語言 (IDL),用於指定 HAL 與其用戶之間的接口。它允許指定類型和方法調用,收集到接口和包中。更廣泛地說,HIDL 是一種用於在可以獨立編譯的代碼庫之間進行通信的系統。從 Android 10 開始,HIDL 已棄用,Android 正在遷移以在任何地方使用 AIDL。

HIDL 旨在用於進程間通信 (IPC)。進程之間的通信被稱為Binderized 。對於必須鏈接到一個過程庫,一個直通模式也可以(在Java中不支持)。

HIDL 指定數據結構和方法簽名,組織在接口(類似於類)中,這些接口被收集到包中。 HIDL 的語法對於 C++ 和 Java 程序員來說看起來很熟悉,儘管它們有一組不同的關鍵字。 HIDL 還使用 Java 樣式的註釋。

HIDL 設計

HIDL 的目標是無需重建 HAL 即可更換框架。的HAL將由供應商或製造商SOC來構建並放入/vendor設備上的分區,使框架在其自己的分區,以與OTA替換而無需重新編譯的HAL。

HIDL 設計平衡了以下問題:

  • 互操作性。在可以使用各種架構、工具鍊和構建配置編譯的進程之間創建可靠的可互操作的接口。 HIDL 接口受版本控制,發布後無法更改。
  • 效率。 HIDL 會盡量減少複製操作的數量。 HIDL 定義的數據以 C++ 標準佈局數據結構傳遞給 C++ 代碼,無需解包即可使用。 HIDL 還提供共享內存接口,並且由於 RPC 本質上有些慢,因此 HIDL 支持兩種不使用 RPC 調用的數據傳輸方式:共享內存和快速消息隊列 (FMQ)。
  • 直觀。 HIDL避免棘手僅使用內存所有權的問題, in對RPC(見參數的Android接口定義語言(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來處理它們(這意味著任何HAL使用oneway直通模式方法必須是線程安全的)。

給定一個IFoo.halBsFoo.h包裹HIDL生成的方法,以提供額外的功能(例如使oneway在另一個線程運行的事務)。此文件類似於BpFoo.h的但是不是傳遞上使用粘合劑IPC呼叫,所需的功能被直接調用。 HAL中的將來的實現可以提供多個實施方式中,如FooFast HAL和FooAccurate HAL。在這種情況下,每增加一個執行文件將被創建(例如, PTFooFast.cppPTFooAccurate.cpp )。

綁定直通 HAL

您可以綁定支持直通模式的 HAL 實現。給定一個HAL接口abcd@MN::IFoo ,兩個包創建:

  • abcd@MN::IFoo-impl 。包含HAL的執行,並公開功能IFoo* HIDL_FETCH_IFoo(const char* name) 。在傳統的設備,這個包是dlopen ED和執行使用實例化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是真的, getService嘗試只在直通模式打開HAL。如果getStub是假的, getService試圖找到一個binderized服務;如果失敗,它將嘗試查找直通服務。該getStub參數不應該只是在使用defaultPassthroughServiceImplementation 。 (使用 Android O 啟動的設備是完全綁定的設備,因此不允許以直通模式打開服務。)

HIDL 語法

根據設計,HIDL 語言類似於 C(但不使用 C 預處理器)。 (從明顯的用途的一邊下面未描述的所有標點=| )是語法的一部分。

注:有關HIDL代碼風格的詳細信息,請參閱代碼風格指南

  • /** */表示文檔註釋。這些只能應用於類型、方法、字段和枚舉值聲明。
  • /* */表示多行註釋。
  • //表示註釋結束行。除了// ,換行符是相同的任何其他空白。
  • 在下面的例子中的語法,從文字//到行到底是不是語法的一部分,但不是在語法評論。
  • [empty]的裝置,該術語可以是空的。
  • ?跟隨文字或術語意味著它是可選的。
  • ...表示包含零個或多個項目進行所指示的分離標點符號序列。 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

術語

本部分使用以下與 HIDL 相關的術語:

裝訂的表示 HIDL 用於進程之間的遠程過程調用,通過類似 Binder 的機制實現。又見直通
回調,異步由 HAL 用戶提供服務的接口,傳遞給 HAL(通過 HIDL 方法),並由 HAL 隨時調用以返回數據。
回調,同步將數據從服務器的 HIDL 方法實現返回給客戶端。不用於返回 void 或單個原始值的方法。
客戶調用特定接口的方法的進程。 HAL 或框架進程可能是一個接口的客戶端和另一個接口的服務器。又見直通
延伸指示將方法和/或類型添加到另一個接口的接口。一個接口只能擴展一個其他接口。可用於相同包名中的次要版本增量,或用於在舊包上構建的新包(例如供應商擴展)。
產生表示向客戶端返回值的接口方法。要返回一個非原始值或多個值,將生成一個同步回調函數。
界面方法和類型的集合。轉換為 C++ 或 Java 中的類。接口中的所有方法都以相同的方向調用:客戶端進程調用由服務器進程實現的方法。
單程當應用於 HIDL 方法時,表示該方法不返回任何值且不會阻塞。
包裹共享一個版本的接口和數據類型的集合。
直通HIDL的模式,其中服務器是共享庫, dlopen由客戶端編輯。在直通模式下,客戶端和服務器是相同的進程,但不同的代碼庫。僅用於將舊代碼庫引入 HIDL 模型。參見Binderized。
服務器實現接口方法的進程。又見直通
運輸在服務器和客戶端之間移動數據的 HIDL 基礎設施。
版本包的版本。由兩個整數組成,主要和次要。次要版本增量可能會添加(但不會更改)類型和方法。