HAL接口定義語言或HIDL(發音為“ hide-1”)是一種接口描述語言(IDL),用於指定HAL及其用戶之間的接口。它允許指定收集到接口和程序包中的類型和方法調用。更廣泛地說,HIDL是一種用於在可以獨立編譯的代碼庫之間進行通信的系統。
HIDL旨在用於進程間通信(IPC)。進程之間的通信稱為Binderized 。對於必須鏈接到進程的庫,還可以使用直通模式(Java不支持)。
HIDL指定數據結構和方法簽名,這些結構和方法簽名以接口(類似於類)的形式組織,並收集到程序包中。儘管CID和Java程序員使用一組不同的關鍵字,但HIDL的語法看起來很熟悉。 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
除了用於綁定程序通信的頭之外, 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
,將創建兩個包:
-
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
為true,則getService
僅嘗試在直通模式下打開HAL。如果getStub
為false,則getService
嘗試查找綁定服務;如果失敗,則嘗試查找直通服務。除非在defaultPassthroughServiceImplementation
否則永遠不要使用getStub
參數。 (使用Android O啟動的設備是完全綁定的設備,因此不允許以直通模式打開服務。)
HIDL語法
根據設計,HIDL語言類似於C(但不使用C預處理程序)。下文中未描述的所有標點符號(除了明顯使用=
和|
)都是語法的一部分。
注意:有關HIDL代碼樣式的詳細信息,請參見《代碼樣式指南》 。
-
/** */
表示文檔註釋。這些只能應用於類型,方法,字段和枚舉值聲明。 -
/* */
表示多行註釋。 -
//
表示到行尾的註釋。除//
,換行符與其他任何空格相同。 - 在下面的示例語法中,從
//
到行尾的文本不是語法的一部分,而是對語法的註釋。 -
[empty]
表示該術語可能為空。 -
?
字面量或術語後面的含義表示它是可選的。 -
...
表示包含零個或多個項目的序列,並帶有標點符號。 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
術語
本節使用以下與HIDL相關的術語:
粘合劑 | 指示HIDL正在用於通過類Binder機制實現的進程之間的遠程過程調用。另請參見passthrough 。 |
---|---|
回調,異步 | 由HAL用戶提供服務的接口,該接口傳遞給HAL(通過HIDL方法),並由HAL調用以隨時返回數據。 |
回調,同步 | 從服務器的HIDL方法實現向客戶端返回數據。不用於返回void或單個原始值的方法。 |
客戶 | 調用特定接口方法的過程。 HAL或框架進程可以是一個接口的客戶端,而可以是另一個接口的服務器。另請參見passthrough 。 |
延伸 | 指示將方法和/或類型添加到另一個接口的接口。一個接口只能擴展另一個接口。可以用於相同軟件包名稱中的次要版本增量,也可以用於在較舊的軟件包上構建的新軟件包(例如,供應商擴展名)。 |
產生 | 指示將值返回給客戶端的接口方法。要返回一個非原始值或多個值,將生成一個同步回調函數。 |
接口 | 方法和類型的集合。轉換為C ++或Java類。接口中的所有方法都沿相同的方向調用:客戶端進程調用服務器進程實現的方法。 |
單程 | 當應用於HIDL方法時,表示該方法不返回任何值且不阻塞。 |
包 | 共享版本的接口和數據類型的集合。 |
直通 | 服務器為共享庫的HIDL模式,由客戶端dlopen 。在直通模式下,客戶端和服務器是相同的過程,但代碼庫分開。僅用於將遺留代碼庫引入HIDL模型。另請參見Binderized 。 |
服務器 | 實現接口方法的過程。另請參見passthrough 。 |
運輸 | 在服務器和客戶端之間移動數據的HIDL基礎結構。 |
版 | 軟件包的版本。由兩個整數組成,主要和次要。較小的版本增量可能會添加(但不能更改)類型和方法。 |