Android HIDL (1) 一文中提到了Android 8.0 之後使用 Treble 的架構,
為了解決 Android 系統的碎片化問題和提高系統更新的效率,
減少了 framework 和 HAL 的耦合性,進而引出了 HIDL 的概念。
本文將詳細的總結 HIDL 的使用。
HAL接口定義語言或 HIDL(發音為“hide-l”)是一種接口描述語言 (IDL) ,
用於指定 HAL 與其用戶之間的接口。
在 interfaces 和 packages 中它允許指定 types 和 methods 的調用。
更廣泛地說,HIDL 是用於在可以獨立編譯的代碼庫之間進行通信的系統。
HIDL 旨在用於 inter-process communication (IPC),
HIDL 的語法對於 C++ 和 Java 程序員來說看起來比較親和一點,
且這種封裝對於 HAL 和Android 框架來說都是透明的。
簡單講就是利用一個 service 主要呼叫 HAL 層來運作。
假設你宣告了一個 HAL interface 名稱叫做 a.b.c.d@M.N::IFoo
,
兩個 package 會被產生如下:
a.b.c.d@M.N::IFoo-impl
看到這個不用害怕,有邊讀邊、沒邊讀中間。
前面那些 abcd 先不用管他,impl 看起來就是 implementation 的縮寫,
所以直覺上來猜就是實作 HAL。
至於要怎麼實作呢?
透過 hidl-gen
或 -Lc++-impl
或 -Landroidbp-impl
工具,
會產生基本的函式作修改,
用來給傳統的 dlopen
函式來讀寫。
以 NFC 為例子大概長這樣:(但 1.0 版已廢棄,使用 1.1 版)hardware/interfaces/nfc/1.0/default/Nfc.cpp
78 INfc* HIDL_FETCH_INfc(const char * /*name*/) {
79 nfc_nci_device_t* nfc_device;
80 int ret = 0;
81 const hw_module_t* hw_module = nullptr;
82
83 ret = hw_get_module (NFC_NCI_HARDWARE_MODULE_ID, &hw_module);
84 if (ret == 0) {
85 ret = nfc_nci_open (hw_module, &nfc_device);
86 if (ret != 0) {
87 ALOGE ("nfc_nci_open failed: %d", ret);
88 }
89 }
90 else
91 ALOGE ("hw_get_module %s failed: %d", NFC_NCI_HARDWARE_MODULE_ID, ret);
92
93 if (ret == 0) {
94 return new Nfc(nfc_device);
95 } else {
96 ALOGE("Passthrough failed to load legacy HAL.");
97 return nullptr;
98 }
99 }
a.b.c.d@M.N::IFoo-service
可以是簡單的 passthrough 模式如下:hardware/interfaces/nfc/1.0/default/service.cpp
11 int main() {
12 return defaultPassthroughServiceImplementation<INfc>();
13 }
假如要用 Binderized 模式產生一個新的 IPC 來運行的話,
你可以透過呼叫 sp<IFoo> IFoo::getService(string name, bool getStub)
,
來得到 IFoo 的訪問權限。
如果 getStub
為 True,則 getService
會嘗試僅在 passthrough 模式下打開 HAL。
如果 getStub
為 False,則 getService
會嘗試找到 Binderized 服務;
如果未找到,則它會嘗試找到直通式服務。
除了在 defaultPassthroughServiceImplementation
中,
其餘情況一律不得使用 getStub
參數。
(搭載Android O的設備是完全Binder化的設備,因此不得在 passthrough 模式下打開服務。)
/** */
表示文檔註釋。這些只能應用於 type、method、field 和 enum 宣告中。
/* */
表示多行註釋。
////
表示對行尾的註釋。除此之外,換行符與任何其他空格相同。
在下面的示例語法中,從行**//
**到結尾的文本不是語法的一部分,而是對語法的註釋。
[empty]
意味著該術語可能為空。
?
遵循文字或術語意味著它是可選的。
...
表示包含零個或多個項目的序列,如圖所示具有分隔標點符號。HIDL中沒有可變參數。
逗號分隔序列元素。
分號終止每個元素,包括最後一個元素。
大寫是一個非終結者。
小寫是文字標記 (token)。
italics
是一個標記 (token) 系列,如 integer
或 identifier
(標準C解析規則)。
constexpr
是一個C風格的常量表達式(例如 1 + 1
和 1L << 3
)。
import_name
是一個 package 或 interface 名稱,符合 HIDL Versioning 描述。
範例:
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 | Android Open Source Project