学习 Android O HIDL

HIDL 简介

HIDL 即HAL interface definition language,在 Android Project Treble 中被起草,在 Android O 中被全面使用。

HIDL用于进程间通信(IPC)。对于c++和Java程序员来说,HIDL的语法看起来会很熟悉,即使它有一系列不同的关键字。HIDL还使用java风格的注解。

Project Treble

Project treble是Android O中引入的特性.
主要的目标是Android模块化,根据谷歌、SoC供应商和OEM的需求分离所有权和分配不同的模块。
Vendor 模块被分离到一个独立的可单独更新的image,从而改进了软件升级发布的过程

这里写图片描述

Treble由以下几部分组成:

  • Kernel modularization

  • HAL re-architecture (binderization)

  • Separation of the vendor and OEM modules from the system image

关于HIDL的设计

HIDL的设计目的是为了能够在不重新编译HALs的情况下能够替换framework。HALs将由供应商或SOC制造商构建,并放在设备的vendor下的分区中,而framework框架在它自己的分区中发挥作用,能够被OTA替换而不重新编译HALs。

HIDL的设计平衡了以下问题:
共用性
在进程间创建可靠的共用接口,而这些进程可能有不同的架构、工具链和构建配置。HIDL接口是版本化的,在发布后不能更改。
效率
HIDL会将复制的次数最小化。HIDL定义的数据以C++标准layout data structures的形式传递给c++代码,这种数据结构可以不打包的情况下使用。HIDL还提供共享内存接口,由于RPCs天生有点慢,HIDL无需使用RPC调用,而支持两种传输数据的方法:shared memory (共享内存)和 Fast Message Queue (FMQ).

直观
对于RPC,HIDL只使用参数(参见AIDL),避免了内存所有权的棘手问题;不能有效通过方法返回的值通过回调函数返回。既不将数据传递到HIDL,也不从HIDL接收数据,改变数据的所有权。数据只需要在被调用函数的持续时间内存在,并且可以在被调用函数返回后立即销毁。

使用 passthrough 模式

为了更新运行在Android系统早期版本的设备到Android O操作系统,你可以将传统的(和 legacy遗留的)HALs封装在新的HIDL接口中,这一接口以binderized 和same-process (passthrough)的模式服务于HAL。这种封装对HAL和Android框架都是透明的。

Passthrough模式仅适用于c++的客户端和实现。运行Android早期版本的设备没有Java编写的HALs,因此Java HALs必然使用binderized 的模式。

Passthrough header files

当一个.hal文件被编译后, hidl-gen除了用于binder通信的头文件外,还生成一个额外的 passthrough 头文件 BsFoo.h ;这个头文件定义了dlopened的函数. 由于passthrough HALs 运行在调用它们的相同的进程中,大多数情况下 passthrough 方法被直接通过函数调用 (相同线程)。oneway 方法在他们自己的线程中运行,因为它们并不打算等待HAL来处理它们(这意味着任何在passthrough模式中使用oneway方法的HAL必须是线程安全的)。

给定一个IFoo.hal文件,BsFoo.h封装了hidl生成的方法以提供额外的特性(比如在另一个线程中运行oneway事务)。这个文件类似于BpFoo。但是,不是通过binder进行IPC调用,而是直接调用所需的函数。未来HALs可能提供多种实现,例如FooFast HAL和FooAccurate HAL。在这种情况下,将创建每个额外实现的文件(例如:PTFooFast.cpp和PTFooAccurate.cpp)。

Binderizing passthrough HALs

支持passthrough 模式的HAL实现可以binderized 。对于一个HAL 接口a.b.c.d@M.N::IFoo,需要创建两个包:

  • a.b.c.d@M.N::IFoo-impl. 包含HAL的实现,并暴露函数IFoo * HIDL_FETCH_IFoo(const char * name)。在legacy hal设备上,这个包是dlopened 的,实现是使用HIDL_FETCH_IFoo实例化的。 您可以使用hidl - gen和- lc + + - impl和- landroidbp - impl生成基本代码。
  • a.b.c.d@M.N::IFoo-service. 打开passthrough HAL并将其注册为一个binder化服务,使相同的HAL实现被用作passthrough 和binderized。

给定类型IFoo,您可以调用sp < IFoo > IFoo::getService(string name, bool getStub)来获取IFoo的实例。

如果getStub值是true,getService尝试只以passthrough模式打开HAL。如果getStub为false,则getService尝试查找到一个binderized 服务;如果失败,则尝试找到passthrough服务。getStub参数除了defaultPassthroughServiceImplementation不应使用。(使用Android O的设备是完全binderized 的设备,因此不允许以passthrough模式打开一个服务。)

HIDL 语法

HIDL语言类似于C(但不使用C预处理器)

  • /* /    表示文档注释.
  • /* */     表示文档多行注释.
  • //     表示在一行结束后注释
  • [empty]    表明当前项的值为空
  • ?    放置在项前,表明该项为可选项.
  • …    表明该序列包含0个或多个如前述使用分隔符隔开的项
  • ,   逗号用于分隔序列中的元素
  • ;   分号用于标记每个元素的结束位置.
  • @entry   当前HAL模块被使用时应当被最先调用的接口
  • @exit   当前HAL模块被调用时应当被最后调用的接口
  • @callflow(next={“name_a”, “name_b”, “name_c”})  当前接口被调用后可能被调用的接口列表。其中name_a接口被调用的概率最大,name_c接口被调用的概率最小。如果只存在1个可能被调用的接口,那么花括号{ }可以省略不写。如果给定的接口名无效,则会导致VTS编译失败。
  • @callflow(next={“*”})  当前接口被调用后可能会调用任意接口

Example:

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 have been previously typedef'd
               // or defined with struct, union, enum, or import
|  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

(未完 待续)

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Android Q中引入了HIDL(HAL Interface Definition Language)作为一种新的硬件抽象层接口定义语言,用于定义跨进程的硬件访问接口。HIDL的实操主要包括以下几个方面: 1. HIDL的使用:HIDL提供了一套接口定义语言和代码生成工具,我们可以通过编写HIDL文件来定义硬件接口,并使用代码生成工具生成对应的客户端和服务器端的代码。我们可以通过HIDL接口访问相应的硬件功能,比如传感器、音频设备等。 2. HIDL Client的编写:HIDL Client是客户端的实现代码,它通过HIDL接口与相应的硬件模块进行通信。我们可以通过调用HIDL接口提供的方法来使用硬件功能,比如打开、关闭传感器、读取传感器数据等。 3. HIDL Server的编写:HIDL Server是服务器端的实现代码,它通过HIDL接口与客户端进行通信并提供相应的硬件功能。在HIDL Server中,我们需要实现HIDL接口定义的方法,并在方法中实现相应的硬件操作逻辑。 4. HIDL的跨进程通信:HIDL使用Binder机制实现跨进程通信。客户端通过Binder机制将请求发送到服务器端,服务器端接收到请求后执行相应的操作,并将结果返回给客户端。这样,我们就可以通过HIDL实现跨进程的硬件访问。 5. HIDL的注册和调用:在使用HIDL时,我们需要将HIDL实例注册到系统服务中,以便在需要时能够使用相应的硬件功能。我们可以使用ServiceManager类的add/get方法进行注册和调用。 总之,HIDL实操主要涉及HIDL文件的编写、HIDL Client和Server的实现、跨进程通信的处理以及HIDL的注册和调用。通过掌握这些内容,我们可以使用HIDL来访问Android Q中的硬件功能,并实现跨进程的硬件交互。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安德路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值