HIDL(一)(摘录)

原文:https://www.jianshu.com/p/f8e2556499ca

HIDL(一)

定义
HAL 接口定义语言(简称 HIDL,发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL)。HIDL 允许指定类型和方法调用(会汇集到接口和软件包中)。从更广泛的意义上来说,HIDL 是用于在可以独立编译的代码库之间进行通信的系统。

其实HIDL的出现是为了更好的服务于Treble这个项目,由于Android的发展比较迅猛,各大手机厂商和芯片厂商都在做,Google当然作为一个领导者在指引我们做出更好的手机操作系统,但是由于版本太多,Android版本的碎片化越来越严重,而且系统的更新又是一个耗时和复杂的过程,Google试图来解决这个问题而引入了Treble,大家都知道做手机的,比如:小米,华为,VIVO等厂商,他们维护自己的BSP,基本上他们的BSP包含几部分:
在这里插入图片描述注意,这里的Framework是vendor修改过的,这样子的话,这四部分都耦合在一起,因为Google每次更新Android大版本,基本上都是framework的升级,与vendor改的代码理论上是可以独立开来的,所以Google尝试通过Treble来独立更新system.img来帮助vendor更快的移植新的Android版本。

以前HAL是以so的形式存在的,作为一堆标准接口,供Android framework调用,无论是通过jni还是别的途径,如果要被framework调用,那这些so就一定要存在于system分区,但是我们现在要把system分区独立开来,这样子,vendor修改的代码全部要在vendor分区,所以,引入了HIDL来解决这个问题,vendor设计的HAL都以独立的service存在,每一个HAL模块都是一个独立的binder server进程,Android framework想用调用HAL的接口就必须作为binder的client来调用,后面会详细描述,这里大家只要记住这个概念就OK。

HIDL 旨在用于进程间通信 (IPC)。进程之间的通信经过 Binder 化。对于必须与进程相关联的代码库,还可以使用直通模式(在 Java 中不受支持)。

HIDL 可指定数据结构和方法签名,这些内容会整理归类到接口(与类相似)中,而接口会汇集到软件包中。尽管 HIDL 具有一系列不同的关键字,但 C++ 和 Java 程序员对 HIDL 的语法并不陌生。此外,HIDL 还使用 Java 样式的注释。
HIDL C++
Android O 对 Android 操作系统的架构重新进行了设计,以在独立于设备的 Android 平台与特定于设备和供应商的代码之间定义清晰的接口。Android 已经以 HAL 接口的形式(在 hardware/libhardware 中定义为 C 标头)定义了许多此类接口。HIDL 将这些 HAL 接口替换为稳定的带版本接口,它们可以是采用 C++(如下所述)或 Java 的客户端和服务器端 HIDL 接口。

本部分中的几页内容介绍了 HIDL 接口的 C++ 实现,其中详细说明了 hidl-gen 编译器基于 HIDL .hal 文件自动生成的文件,这些文件如何打包,以及如何将这些文件与使用它们的 C++ 代码集成。
HIDL 设计
HIDL 的目标是,框架可以在无需重新构建 HAL 的情况下进行替换。HAL 将由供应商或 SOC 制造商构建,放置在设备的 /vendor 分区中,这样一来,框架就可以在其自己的分区中通过 OTA 进行替换,而无需重新编译 HAL。

HIDL 设计在以下方面之间保持了平衡:

互操作性。在可以使用各种架构、工具链和编译配置来编译的进程之间创建可互操作的可靠接口。HIDL 接口是
分版本的,发布后不得再进行更改。

效率。HIDL 会尝试尽可能减少复制操作的次数。HIDL 定义的数据以 C++ 标准布局数据结构传递至 C++ 代
码,无需解压,可直接使用。此外,HIDL 还提供共享内存接口;由于 RPC 本身有点慢,因此 HIDL 支持两种
无需使用 RPC 调用的数据传输方法:共享内存和快速消息队列 (FMQ)。

直观。通过仅针对 RPC 使用 in 参数,HIDL 避开了内存所有权这一棘手问题(请参阅 Android 接口定义
语言 (AIDL));无法从方法高效返回的值将通过回调函数返回。无论是将数据传递到 HIDL 中以进行传输,
还是从 HIDL 接收数据,都不会改变数据的所有权,也就是说,数据所有权始终属于调用函数。数据仅需要在
函数被调用期间保留,可在被调用的函数返回数据后立即清除。

HIDL的架构模式
在这里插入图片描述什么是Binder化?

一直以来,供应商进程都使用 Binder 进程间通信 (IPC) 技术进行通信。在 Android O 中,/dev/binder 设备节点成为了框架进程的专属节点,这意味着供应商进程将无法再访问该节点。供应商进程可以访问 /dev/hwbinder,但必须将其 AIDL 接口转为使用 HIDL。

HIDL 语法

根据设计,HIDL 语言与 C 语言类似(但前者不使用 C 预处理器)。下面未描述的所有标点符号(用途明显的 = 和 | 除外)都是语法的一部分。

/** */ 表示文档注释。此样式只能应用于类型、方法、字段和枚举值声明。
/* */ 表示多行注释。
// 表示注释一直持续到行结束。除了 //,换行符与任何其他空白一样。
在以下示例语法中,从 // 到行结束的文本不是语法的一部分,而是对语法的注释。
[empty] 表示该字词可能为空。
? 跟在文本或字词后,表示它是可选的。
... 表示包含零个或多个项、用指定的分隔符号分隔的序列。HIDL 中不含可变参数。
逗号用于分隔序列元素。
分号用于终止各个元素,包括最后的元素。
大写字母是非终止符。
italics 是一个令牌系列,例如 *integer* 或 *identifier*(标准 C 解析规则)。
constexpr 是 C 样式的常量表达式(如 1 + 1 和 1L << 3)。
import_name 是软件包或接口名称,HIDL 版本编号中所述的方式加以限定。
小写 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 = <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

接口描述
HIDL 是围绕接口进行编译的,接口是面向对象的语言使用的一种用来定义行为的抽象类型。每个接口都是软件包的一部分。
软件包
软件包名称可以具有子级,例如 package.subpackage。
已发布的 HIDL 软件包的根目录是 hardware/interfaces 或 vendor/vendorName(例如 Pixel 设备为 vendor/google)。
软件包名称在根目录下形成一个或多个子目录;定义软件包的所有文件都位于同一目录下。
例:
package android.hardware.example.extension.light@2.0
可以在
hardware/interfaces/example/extension/light/2.0
下找到。

软件包目录中包含扩展名为 .hal 的文件。
每个文件均必须包含一个指定文件所属的软件包和版本的 package 语句。

文件 types.hal(如果存在)并不定义接口,而是定义软件包中每个接口可以访问的数据类型。
接口定义
除了 types.hal 之外,其他 .hal 文件均定义一个接口。
接口通常定义如下:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

不含显式 extends 声明的接口会从 android.hidl.base@1.0::IBase(类似于 Java 中的 
java.lang.Object)隐式扩展。

导入
import 语句是用于访问其他软件包中的软件包接口和类型的 HIDL 机制。
import 语句本身涉及两个实体:

导入实体:可以是软件包或接口;
被导入实体:也可以是软件包或接口。

导入实体由 import 语句的位置决定。
当该语句位于软件包的 types.hal 中时,导入的内容对整个软件包是可见的;这是软件包级导入。
当该语句位于接口文件中时,导入实体是接口本身;这是接口级导入。

被导入实体由 import 关键字后面的值决定。
该值不必是完全限定名称;如果某个组成部分被删除了,系统会自动使用当前软件包中的信息填充该组成部分。
对于完全限定值,支持的导入情形有以下几种:
完整软件包导入
如果该值是一个软件包名称和版本(语法见下文),则系统会将整个软件包导入至导入实体

import android.hardware.nfc@1.0;            // import a whole package

部分导入
如果值为:
1.一个接口,则系统会将该软件包的 types.hal 和该接口导入至导入实体中。
2.在 types.hal 中定义的 UDT,则系统仅会将该 UDT 导入至导入实体中(不导入 types.hal 中的其他类型)。

import android.hardware.example@1.0::IQuux; 
// import an interface and types.hal

仅类型导入
如果该值将上文所述的“部分导入”的语法与关键字 types 而不是接口名称配合使用,则系统仅会导入指定软件包

import android.hardware.example@1.0::types; // import just types.hal

接口继承
接口可以是之前定义的接口的扩展。
扩展可以是以下三种类型中的一种:

1.接口可以向其他接口添加功能,并按原样纳入其 API。
2.软件包可以向其他软件包添加功能,并按原样纳入其 API。
3.接口可以从软件包或特定接口导入类型。

接口只能扩展一个其他接口(不支持多重继承)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值