概述
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