学习 Android O HIDL

来源:互联网 发布:java网上商城系统源码 编辑:程序博客网 时间:2024/06/05 10:59

  • HIDL 简介
    • Project Treble
    • 关于HIDL的设计
    • 使用 passthrough 模式
    • Passthrough header files
    • Binderizing passthrough HALs
  • 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 definitionsITEM =    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 EXTENDSEXTENDS = <empty> | extends import_name  // must be interface, not packageGENERATES = 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 identifierUFIELD =   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     constexprANNOTATIONS =     [empty]  |  ANNOTATIONS ANNOTATIONANNOTATION =  |  @identifier  |  @identifier(VALUE)  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)ANNO_ENTRY =     identifier=VALUEVALUE =     "any text including \" and other escapes"  |  constexpr  |  {VALUE, VALUE ...}  // only in annotationsENUM_ENTRY =     identifier  |  identifier = constexpr

(未完 待续)

阅读全文
0 0
原创粉丝点击