概述
HIDL:HAL interface definition langurage。描述HAL和用戶之間的接口。接口可以是數據類型或方法。這些數據類型和方法組織在接口和包里。
HIDL也是軟件之間的一個通信系統,為接口添加了binder機制。
HIDL描述的數據結構和方法簽名組織在接口里,即.hal文件。HIDL語言的符號類似於C++和java語言,但也有不同的關鍵字。
HIDL設計
設計目標:framework和HALS之間互相獨立OTA,不依賴於對方。
HIDL工作模式
- binderized
- passthrough
passthrough
passthrough mode也就是same-process mode。
為了把運行早期版本的設備升級到ANDROID O,可以把傳統(和legacy)HALS封裝成HIDL接口,這個接口為HAL提供binderized和passthrough 模式。這種封裝對HAL和framework是透明的。
Passthrough模式只支持C++,運行早期版本的Android的設備沒有Java編寫的HALs,因此Java HALs只支持binderized。
Passthrough 頭文件
Hidl-gen在編譯.hal文件時生成一個用於passthrough 模式的頭文件:BsFoo.h。
其它頭文件則用於binder通信。
Passthrough方法調用:
1:直接調用 ,運行在調用者線程里
2:oneway 方法調用,運行在自己線程里
BsFoo.h包含由HIDL產生的方法提供了諸如讓oneway 方法運行在獨立線程的特性。
Binderized HALS
例如:HAL 接口 a.b.c.d@M.N::IFoo,需要實現兩部分:
實現a.b.c.d@M.N::IFoo-impl SO庫。它包含HAL實現以及導出函數IFoo* HIDL_FETCH_IFoo(const char* name)。HIDL_FETCH_IFoo函數可以獲取HAL實現的對象。
hidl-gen -Lc++-impl and -Landroidbp-impl
a.b.c.d@M.N::IFoo-service HAL服務。需要dlopen passthrough HAL以及把自己注冊成binder服務
sp
- getStub等於ture時,getservice以passthrough模式打開HAL實現。
- getStub等於false時,getservice會先獲取binder服務,如果失敗了才會獲取passthrough服務。
注冊HIDL 服務
egisterAsService(); // service name is default
registerAsService("another_foo_service"); // if needed
如果相同接口注冊多個hal服務實現,就可以給服務指定name。
獲取HIDL服務
通過name和version獲取服務。
每一個版本的HIDL 接口都是獨立的接口。版本1.1的IFooService’和版本2.2 的IFooServer都可以注冊成名為foo_service的服務。
不指定參數的化默認使用的是default服務。
如何實現client獲取服務死亡通知
Client需要實現:
1.從hidl_death_recipient 類繼承一個子類IDeathRecipient
2.重寫serviceDied()方法
3.實例化IDeathRecipient對象
4.調用服務的linkToDeath()方法,同時傳遞IDeathRecipient對象
例如:
死亡接受callback可以注冊到多個服務。
數據傳輸
兩種類型接口方法:
- Blocking 等待直到服務返回
- Oneway 單向調用,沒有返回值,no block,關鍵字oneway聲明
Callbacks
- Synchronous callbacks
- Asynchronous callbacks
語法
ROOT =
PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal
PREAMBLE = interface identifier EXTENDS
| PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions
ITEM =
ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
| 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
| struct identifier { FIELD; FIELD; ...} identifier;
| union identifier { FIELD; FIELD; ...} identifier;
SFIELD =
TYPE identifier
| struct identifier { FIELD; FIELD; ...};
| union identifier { FIELD; FIELD; ...};
| 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