前言
这一系列文章基本都以英文原版的形式表现出来。
会补充一些自己在学习的过程中遇到的不懂的地方加上自己的一些见解。
官方文档(要梯子):https://source.android.com/devices/architecture/hidl
HAL interface definition language or HIDL (pronounced “hide-l”) is an interface description language (IDL) to specify the interface between a HAL and its users. It allows specifying types and method calls, collected into interfaces and packages. More broadly, HIDL is a system for communicating between codebases that may be compiled independently.HIDL is intended to be used for inter-process communication (IPC). Communication between processes is referred to as Binderized. For libraries that must be linked to a process, a passthough mode is also available (not supported in Java).HIDL specifies data structures and method signatures, organized in interfaces (similar to a class) that are collected into packages. The syntax of HIDL will look familiar to C++ and Java programmers, though with a different set of keywords. HIDL also uses Java-style annotations.
补充:
HAL(Hardware Abstract Layer),是Google开发的Android系统里上层应用对底层硬件操作屏蔽一个软件层次,也就是硬件独立,Android系统不依赖于某一个具体的硬件驱动,而是依赖于HAL代码。通俗点就是上层的应用不用关心底层硬件具体如何工作的,只要向上层提供一个统一的接口即可。
官方简介大致表明了这么几个点:
The goal of HIDL is that the framework can be replaced without having to rebuild HALs. HALs will be built by vendors or SOC makers and put in a /vendor partition on the device, enabling the framework, in its own partition, to be replaced with an OTA without recompiling the HALs.
HIDL design balances the following concerns:
也就是说HIDL的设计需要从Interoperability(互操作性)、Efficiency(效率性)和Intuitive(直观性)三个方面互相平衡。至于怎么平衡,取决于需求以及设计者的水平。
语法这部分在写代码的时候需要注意,但是目前处于了解基础的情况下可以不做深入理解。以下仅供参考
By design, the HIDL language is similar to C (but does not use the C preprocessor). All punctuation not described below (aside from the obvious use of = and |) is part of the grammar.
Note: For details on HIDL code style, see the Code Style Guide.
eg.
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 = | 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
| bitfield // TYPE is user-defined enum
| fmq_sync
| fmq_unsync
| 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
HIDL is built around interfaces, an abstract type used in object-oriented languages to define behaviors. Each interface is part of a package.Package names can have sublevels such as package.subpackage
. The root directory for published HIDL packages is hardware/interfaces
or vendor/vendorName
(e.g. vendor/google
for Pixel devices). The package name forms one or more subdirectories under the root directory; all files defining a package are in the same directory. For example, package [email protected]
could be found under hardware/interfaces/example/extension/light/2.0
.The package directory contains files with extension .hal
. Every file must contain a package
statement naming the package and version the file is part of. The file types.hal
, if present, does not define an interface but instead defines data types accessible to every interface in the package.
hardware/interfaces
或者 vendor/vendorName上。
根据包的命名方式可以在根目录下形成其子目录,也就是包的名字和目录有着对应的关系。eg.如果存在下面这样子的包名[email protected],就一定会存在这样子的文件夹hardware/interfaces/example/extension/light/2.0。
在包目录下的.hal文件都必须包含对包的名称和版本的声明。如果存在types.hal文件,它只是定义包中每个接口都可以访问的数据类型。
Aside from types.hal, every other .hal file defines an interface. For example, an interface is typically defined as follows:
interface IBar extends IFoo { // IFoo is another interface
// embedded types
struct MyStruct {/*...*/};
// interface methods
create(int32_t id) generates (MyStruct s);
close();
};
An interface without an explicit extends
declaration implicitly extends from [email protected]::IBase
(similar to java.lang.Objec
t in Java.) The IBase interface, implicitly imported, declares several reserved methods that should not and cannot be redeclared in user-defined interfaces or used otherwise. These methods include:
ping
interfaceChain
interfaceDescriptor
notifySyspropsChanged
linkToDeath
unlinkToDeath
setHALInstrumentation
getDebugInfo
debug
getHashChain
除了types.hal文件外,其他的.hal文件都被定义为接口。
上面描述的方法不能被重定义,无论显式还是隐式继承。
The import statement is HIDL mechanism to access package interfaces and types in another package. An import statement concerns itself with two entities:
The importing entity is determined by the location of the import
statement. When the statement is inside a package’s types.hal
, what is being imported is visible by the entire package; this is a package-level import. When the statement is inside an interface file, the importing entity is the interface itself; this is an interface-level import.
根据不同的导入声明的位置,可以分为包级别的导入和接口级别的导入。特别的是当导入types.hal时也是包级别的。
The imported entity is determined by the value after the import
keyword. The value need not be a fully-qualified name; if a component is omitted, it is automatically filled with information from the current package. For fully-qualified values, the following import cases are supported:
types.hal
, then only that UDT is imported into the importing entity (other types in types.hal
are not imported).根据导入的keyword,可以分为全包导入,局部导入和类型导入。
The importing entity gets access to a combination of:
types.hal
;导入的实体可以访问包中types.hal中通用的UDTs,可以访问所有接口或者部分接口。
The import statement uses the fully-qualified-type-name syntax to provide the name and version of the package or interface being imported:
An interface can be an extension of a previously-defined interface. Extensions can be one of the following three types:
An interface can extend only one other interface (no multiple inheritance). Each interface in a package with a non-zero minor version number must extend an interface in the previous version of the package. For example, if an interface IBar
in version 4.0 of package derivative
is based on (extends) an interface IFoo
in version 1.2 of package original
, and a version 1.3 of package original
is created, IBar
version 4.1 cannot extend version 1.3 of IFoo
. Instead, IBar
version 4.1 must extend IBar
version 4.0, which is tied to IFoo
version 1.2. IBar
version 5.0 could extend IFoo
version 1.3, if desired.
Interface extensions do not imply library dependence or cross-HAL inclusion in the generated code—they simply import the data structure and method definitions at the HIDL level. Every method in a HAL must be implemented in that HAL.
一个接口可以是一个预先定义接口的扩展。扩展有三种类型,接口对接口扩展功能,包对包扩展功能,接口导入包或者特定接口的类型。一个接口只能扩展一个其他接口,不支持多重继承。
This document describes HIDL interface hashing, a mechanism to prevent accidental interface changes and ensure interface changes are thoroughly vetted. This mechanism is required because HIDL interfaces are versioned, which means that after an interface is released it must not be changed except in an Application Binary Interface (ABI) preserving manner (such as a comment correction).
描述了接口哈希这个机制的目的和必要性。防止接口被意外被修改,除了特定的方式,任何已经发布的接口都不可以被改变。
Every package root directory (i.e. android.hardware
mapping to hardware/interfaces
or vendor.foo
mapping to vendor/foo/hardware/interfaces
) must contain a current.txt
file that lists all released HIDL interface files.
每个包根目录下必须包含一个具有全部已发布接口的current.txt文件。
You can add a hash to a current.txt
file manually or by using hidl-gen
. The following code snippet provides examples of commands you can use with hidl-gen
to manage a current.txt file (hashes have been shortened):
$ hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport [email protected]::types
9626fd18...f9d298a6 [email protected]::types
Warning: Do not replace a hash for a previously-released interface. When changing such an interface, add a new hash to the end of the current.txt
file. For details, refer to ABI stability.
Every interface definition library generated by hidl-gen
includes hashes, which can be retrieved by calling IBase::getHashChain
. When hidl-gen
is compiling an interface, it checks the current.txt
file in the root directory of the HAL package to see if the HAL has been changed:
current.txt
file must be modified before compilation can proceed.哈希值可以自己手动添加和hidl-gen自动生成。
An Application Binary Interface (ABI) includes the binary linkages/calling conventions/etc. If the ABI/API changes, the interface no longer works with a generic system.img
that was compiled with official interfaces.
为了保证官方编译的system.img正常工作,需要保证ABI稳定。也就是说没得商量,必须保证ABI稳定。
Making sure that interfaces are versioned and ABI stable is crucial for several reasons:
current.txt
a map of an interfaces directory that allows you to see the history and state of all interfaces being provided in a package root.确保接口版本化和ABI稳定的原因有:通过出版商测试套件的测试,对框架进行升级;提供一个板级支持包使用;可以跟踪接口。
When adding a new hash for an interface that already has an entry in current.txt
, make sure to add only the hashes that represent interfaces which maintain ABI stability. Review the following types of changes:
为已经存在的接口添加一个新的哈希值时,需要保证ABI稳定。允许被改变的和不允许被改变的如上。
Android HIDL基础篇(二)