Android HIDL 官方文档(一)—— 概述(Overview)

  • HIDL 简介
  • HIDL 设计原则
  • 使用 Passthrough 模式
    • 1 Passthrough 头文件
    • 2 Binder 化的 Passthrough HALs
  • HIDL 语法
  • 术语解释


  • 最近因为业务上的需求,老大让我先看着 HIDL 的官方文档学习学习。然而直接看英文文档还是很不习惯,就打算一边翻译一边学习。
  • 这个翻译就当做我的学习笔记了。
  • 翻译相关的内容都是以中英文对照的形式贴出来。
  • 由于翻译水平比较一般,如有错误,还请指正。
  • 对应的官方文档地址:HIDL(General) - Overview

1. 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 是用于指定 HAL 与其用户之间接口的一个接口描述语言(Interface Description Language),它允许将指定的类型与函数调用收集到接口(Interface)包(Package)中。更广泛地说,HIDL 是一个可以让那些独立编译的代码库(Libraries)之间进行通信的系统。

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 实际上是用于进行进程间通信(Inter-process Communication,IPC)的。进程间的通信可以称为 Binder 化(Binderized)。对于必须连接到进程的库,也可以使用 passthough 模式(但在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.

       HIDL 将指定的数据结构与方法签名组织到接口中,这些接口又会被收集到包中以供使用。它的语法与 C++、JAVA 是类似的,不过关键字集合不尽相同。其注释风格与 JAVA 是一致的。

2. HIDL 设计原则

(HIDL design)

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 这个机制的目的,主要是想把框架(framework)与 HAL 进行隔离,使得框架部分可以直接被覆盖、更新,而不需要重新对 HAL 进行编译。HAL 的部分将会放在设备的 /vendor 分区中,并且是由设备供应商(vendors)或 SOC 制造商来构建。这使得框架部分可以通过 OTA 方式更新,同时不需要重新编译 HAL。

HIDL design balances the following concerns:

  • Interoperability. Create reliably interoperable interfaces between processes which may be compiled with various architectures, toolchains, and build configurations. HIDL interfaces are versioned and cannot be changed after they are published.
  • Efficiency. HIDL tries to minimize the number of copy operations. HIDL-defined data is delivered to C++ code in C++ standard layout data structures that can be used without unpacking. HIDL also provides shared memory interfaces and, as RPCs are inherently somewhat slow, HIDL supports two ways to transfer data without using an RPC call: shared memory and a Fast Message Queue (FMQ).
  • Intuitive. HIDL avoids thorny issues of memory ownership by using only in parameters for RPC (see Android Interface Definition Language (AIDL)); values that cannot be efficiently returned from methods are returned via callback functions. Neither passing data into HIDL for transfer nor receiving data from HIDL changes the ownership of the data—ownership always remains with the calling function. Data needs to persist only for the duration of the called function and may be destroyed immediately after the called function returns.

       在设计时,工程师们平衡了几个要点:

  • 互用(Interoperability):在可能与各种架构、工具链和构建配置一起编译的进程之间,创建可靠并且具有互用性的接口。HIDL 接口是版本化的,在发布后不能更改。
  • 效率(Efficiency):HIDL 尝试将拷贝操作最小化。HIDL 定义的数据会被交付到 c++ 标准布局(C++ Standard Layout)数据结构中的 c++ 代码,这些数据结构可以在不打包的情况下使用。HIDL 还提供了共享内存(Share Memory)的接口,并且 RPC 由于自身的限制,它的效率是较低的,而 HIDL 则支持了两种方法,使得无需调用 RPC 就能传输数据,这两种方法分别是:
    • 共享内存
    • 快速消息队列(Fast Message Queue,FMQ)
  • 直观(Intuitive):通过只使用 RPC 中的一个参数 in ,HIDL 避免了棘手的内存所有权(Memory Ownership)问题。不能有效地从方法中返回的值,我们通过回调函数来返回。这样我们就能把数据的所有权保留在调用的函数中,使得无论是从 HIDL 接收数据,或者通过 HIDL 发送数据,都不会改变数据的所有权。数据只需要在被调用函数的持续时间内存在,在被调用的函数返回后,数据可被立即销毁。

3. 使用 Passthrough 模式

(Using passthrough mode)

       (直译为 ”透明传输模式“)

To update devices running earlier versions of Android to Android O, you can wrap both conventional (and legacy) HALs in a new HIDL interface that serves the HAL in binderized and same-process (passthrough) modes. This wrapping is transparent to both the HAL and the Android framework.

Passthrough mode is available only for C++ clients and implementations. Devices running earlier versions of Android do not have HALs written in Java, so Java HALs are inherently binderized.

       为了将以往设备的 Android 版本更新到 Android O,开发者需要将传统的 HAL 封装到新的 HIDL 接口中,这个接口为 HAL 提供了 Binder 化以及 Passthrough 模式。这个封装过程对 HAL 以及 Android Framework 都是透明的。
       Passthrough 模式仅对 C++ 客户端与实现适用,以往的 Android 版本设备中,HAL 不会采用 JAVA 语言来写,所以 JAVA HAL 必然是 Binder 化的。

3.1 Passthrough 头文件

(Passthrough header files)

When a .hal file is compiled, hidl-gen produces an extra passthrough header file BsFoo.h in addition to the headers used for binder communication; this header defines functions to be dlopened. As passthrough HALs run in the same process in which they are called, in most cases passthrough methods are invoked by direct function call (same thread). oneway methods run in their own thread as they are not intended to wait for the HAL to process them (this means any HAL that uses oneway methods in passthrough mode must be thread-safe).

       当一个 .hal 文件被编译时,hidl-gen 除了生成用于 Binder 通信的头文件以外,还会产生一个头文件 BsFoo.h ,这个头文件定义了被 dlopen 操作打开的函数。由于 Passthrough HAL 是在调用它们的进程中运行,在大部分情况下 Passthrough 方法是通过函数调用直接使用的(在同线程中)。oneway 方法是在自己的线程中运行的,因为它们不需要等待 HAL 对它们进行处理(这就意味着任何使用 oneway 方法的 HAL 都需要保证是线程安全的)。

Given an IFoo.hal, BsFoo.h wraps the HIDL-generated methods to provide additional features (such as making oneway transactions run in another thread). This file is similar to BpFoo.h, however instead of passing on calls IPC using binder, the desired functions are directly invoked. Future implementations of HALs may provide multiple implementations, such as FooFast HAL and a FooAccurate HAL. In such cases, a file for each additional implementation would be created (e.g., PTFooFast.cpp and PTFooAccurate.cpp).

       给定一个 IFoo.halBsFoo.h 封装了由 HIDL 生成的方法以提供一些附加特性(比如使 oneway 事务在另一个线程中运行)。这个文件与 BpFoo.h (Binder 相关)是类似的,然而它并不是通过 Binder ,而是直接调用所需的函数来调用 IPC。在以后的实现中,HAL 可能会提供多种实现方式,比如 FooFast HAL 以及 FooAccurate HAL。在这种情况下,相应的附加实现的文件将被创建(比如 PTFooFast.cppPTFooAccurate.cpp)。

3.2 Binder 化的 Passthrough HALs

(Binderizing passthrough HALs)

You can binderize HAL implementations that support passthrough mode. Given a HAL interface [email protected]::IFoo, two packages are created:

  • [email protected]::IFoo-impl. Contains the implementation of the HAL and exposes function IFoo* HIDL_FETCH_IFoo(const char* name). On legacy devices, this package is dlopened and the implementation is instantiated using HIDL_FETCH_IFoo. You can generate the base code using hidl-gen and -Lc++-impl and -Landroidbp-impl.
  • [email protected]::IFoo-service. Opens the passthrough HAL and registers itself as a binderized service, enabling the same HAL implementation to be used as both passthrough and binderized.

       您可以将 HAL 的实现 Binder 化,使其支持 Passthrough 模式。给定一个 HAL 接口 [email protected]::IFoo,则有两个包会随之被创建:

  • [email protected]::IFoo-impl:包含了 HAL 的实现以及一个公开的函数 IFoo* HIDL_FETCH_IFoo(const char* name)。在传统设备上,这个包是由 dlopen 打开的,并使用 HIDL_FETCH_IFoo 来实例化接口的实现。您可以使用 hidl-gen-Lc++-impl 以及 -Landroidbp-impl 来生成基本的代码。
  • [email protected]::IFoo-service:打开 Passthrough HAL 并将自己注册为 Binder 化服务,使得相同的 HAL 实现可以被 Passthrough 与 Binder 化所使用。

Given the type IFoo, you can call sp IFoo::getService(string name, bool getStub) to get access to an instance of IFoo. If getStub is true, getService attempts to open the HAL only in passthrough mode. If getStub is false, getService attempts to find a binderized service; if that fails, it then tries to find the passthrough service. The getStub parameter should never be used except in defaultPassthroughServiceImplementation. (Devices launching with Android O are fully binderized devices, so opening a service in passthrough mode is disallowed.)

       给定一个类型 IFoo,您可以通过 sp IFoo::getService(string name, bool getStub) 来获得一个 IFoo 实例。若 getStubtrue,则 getService 将只会在 Passthrough 模式中尝试打开 HAL。若 getStubfalse,则 getService 会尝试寻找一个 Binder 化的服务,如果尝试失败,则会继续尝试寻找 Passthrough 服务。参数 getStub 在除了 defaultPassthroughServiceImplementation 以外的地方都不应被使用(使用 Android O 的设备是完全 Binder 化的设备,因此不允许在 Passthrough 模式中打开服务)。

4. HIDL 语法

(HIDL grammar)

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.

  • /* / indicates a documentation comment.
  • /* */ indicates a multiline comment.
  • // indicates a comment to end of line. Aside from //, newlines are the same as any other whitespace.
  • In the example grammar below, text from // to the end of the line is not part of the grammar but is instead a comment on the grammar.
  • [empty] means that the term may be empty.
  • ? following a literal or term means it is optional.
  • … indicates sequence containing zero or more items with separating punctuation as indicated. There are no variadic arguments in HIDL.
  • Commas separate sequence elements.
  • Semicolons terminate each element, including the last element.
  • UPPERCASE is a nonterminal.
  • italics is a token family such as integer or identifier (standard C parsing rules).
  • constexpr is a C style constant expression (such as 1 + 1 and 1L << 3).
  • import_name is a package or interface name, qualified as described in HIDL Versioning.
  • Lowercase words are literal tokens.

       HIDL 语言与 C 语言是相似的(但没有使用 C 的预处理器),以下没有描述的标点符号(除了明显使用 |= 的)是语法的一部分:

  • NOTEtoken 翻译为”符号“。
  • /** */ 表示文档的注释。
  • /* */ 表示多行注释。
  • // 表示单行注释。
  • [empty] 表示这个项是空的。
  • ? 表明该项是可选的。
  • 则表示该序列包含 0 个或者多个如前述使用分隔符隔开的项。
  • , 用于分隔序列中的元素。
  • ; 用于标记每个元素的结束位置。
  • 大写字母是一个非终结符。
  • italics 则是如 integer 或者 identifier 的符号族(标准 C 解析规则)。
  • constexpr 是 C 风格的常量表达式。
  • import_name 是一个包或者接口的名称,其标准在 HIDL Versioning 中有详细阐述。
  • 小写的 words 则是文字符号。

       例子如下:

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

5. 术语解释

Terminology Explain
binderized Indicates HIDL is being used for remote procedure calls between processes, implemented over a Binder-like mechanism. See also passthrough.
callback, asynchronous Interface served by a HAL user, passed to the HAL (via a HIDL method), and called by the HAL to return data at any time.
callback, synchronous Returns data from a server’s HIDL method implementation to the client. Unused for methods that return void or a single primitive value.
client Process that calls methods of a particular interface. A HAL or framework process may be a client of one interface and a server of another. See also passthrough.
extends Indicates an interface that adds methods and/or types to another interface. An interface can extend only one other interface. Can be used for a minor version increment in the same package name or for a new package (e.g. a vendor extension) to build on an older package.
generates Indicates an interface method that returns values to the client. To return one non-primitive value, or more than one value, a synchronous callback function is generated.
interface Collection of methods and types. Translated into a class in C++ or Java. All methods in an interface are called in the same direction: a client process invokes methods implemented by a server process.
oneway When applied to a HIDL method, indicates the method returns no values and does not block.
package Collection of interfaces and data types sharing a version.
passthrough Mode of HIDL in which the server is a shared library, dlopened by the client. In passthrough mode, client and server are the same process but separate codebases. Used only to bring legacy codebases into the HIDL model. See also Binderized.
server Process that implements methods of an interface. See also passthrough.
transport HIDL infrastructure that moves data between the server and client.
version Version of a package. Consists of two integers, major and minor. Minor version increments may add (but not change) types and methods.

       下面列出的是 HIDL 相关的术语:

术语 翻译 解释
binderized Binder 化 标明 HIDL 被用于进程间的远程方法调用,它是通过一个类似 Binder 的机制来实现的。另请参阅 passthrough 的解释。
callback, asynchronous 异步回调 由 HAL 用户所提供的接口,通过 HIDL 的方法传递给 HAL,并由 HAL 来调用,以随时返回所需数据。
callback, synchronous 同步回调 从服务端的 HIDL 方法实现向客户端返回数据,未使用的方法返回 void 或一个原始类型值。
client 客户端 调用一个特定接口的方法的进程。一个 HAL 或者 Framework 进程可以是一个接口的客户端,也可以是另一个接口的服务端。另请参阅 passthrough 的解释。
extends 扩展 表示了一个将方法与(或)类型添加到另一个接口的接口。一个接口只能扩展另外的一个接口。它可以用于对于同一个包名的从版本升级,或者也可用来在一个旧的包的基础之上建立一个新的包(比如供应商的扩展)。
generates 生成 表示一个返回值给客户端的接口方法。为了返回一个非原始类型值,或者更多的值给客户端,则需要生成一个同步回调函数。
interface 接口 这是方法与类型的集合,在 C++ 与 Java 中转换为类。在接口中的所有方法都被调用在同一方向:客户端进程调用由服务端进程实现的方法。
oneway 单向 这个概念应用到 HIDL 方法时,表示其无返回值,且不会阻塞。
package 共享同一版本的接口与数据类型的集合。
passthrough 透明传输 服务端是一个共享库时的 HIDL 模式,通过 dlopen 被客户端打开。在这个 passthrough 模式下,客户端与服务端是相同的进程,但是是不同的代码库。仅仅用于将旧的代码库引用到 HIDL 模型中。另请参阅 Binderized 的解释。
server 服务端 实现了接口方法的进程。另请参阅 passthrough 的解释。
transport 传送带 HIDL 在客户端与服务端之间移动数据的基本结构。
version 版本 包的版本。包含两个整数,表示主版本与从版本。从版本的升级可以增加(但不会改变原来的)类型或者方法。

你可能感兴趣的:(Android-翻译)