Android HIDL 基础知识,源码分析。
概念
在 Android O 8.0 后引入的 Treble 项目,目的是将 Framework 和 HAL 层分开;Google 重点关注 Framework 及以上部分,HAL 及以下交给各厂商实现, HAL 层及厂商实现都会放到新的 /vendor 分区中;这样 Google 在后续 OTA 系统升级时,可以单独升级系统部分,而不需要修改厂商实现部分。因此重新定义了 Framework 和 HAL 层的接口,即 HIDL ;以及新增了接口层的测试 VTS: Vendor Test Suite ,确保厂商实现部分接口设计符合规范并能向前兼容。简而言之,Google 这么做主要目的是:不管厂商如何实现,修改了哪些东西,需要确保 Android 原生系统都能在这台设备上升级并使用。当然这种结构也方便手机厂商做 system 升级,如果当前版本已经是 Android O ,各个分区已经分配好,可以做到仅仅更新 AOSP 部分到 P ,而其他 vendor 可以保持不变,提供了一种可能性和便利性,实际上厂商是否愿意这么做呢?
HIDL: HAL Interface Definition Language , HIDL 发音为 hide-l ,指定了 HAL 层和 Framework 层通信的接口,目的是 Framework和 HAL 层能相互通信;这样用户能够替换 Android 框架,而无需重新编译 HAL 。
HAL 类型
HAL 有两种类型:
-
Binder HAL
绑定式HAL,通过Binder机制实现跨进程通信。 -
Passthrough HAL
直通式HAL,通过dlopen方式加载库,也就是在同一进程直接调用。这里需要注意,默认情况下通常会使用 *Binder化直通式HAL*,也就是说最后仍然是跨进程Binder通信。
Binder HAL
Android O 开始,Framework 和 HAL 跨进程也是使用 Binder 互相通信,这种通信方式极大地增加了老版本中的 Binder 流量,因此新增了 Binder 域,官网推荐三个域的使用范围:
-
/dev/binder
用于Framework和APP之间的IPC,使用AIDL接口。 -
/dev/hwbinder
用于Framework和Vendor进程之间的IPC,使用HIDL接口。
用于供应商进程之间的IPC,使用HIDL接口。 -
/dev/vndbinder
供应商/供应商进程之间的IPC,使用AIDL接口。
Binder 化直通式 HAL
它实际是直通模式的 HAL ,通过 Binder 化来实现。比如 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
打开直通式HAL,并将其自身注册为Binder化服务,从而使同一HAL实现能够同时以直通模式和Binder化模式使用。
如果有一个IFoo,可以调用sp<IFoo> IFoo::getService(string name, bool getStub),以获取对IFoo实例的访问权限。如果getStub为True,则getService会尝试仅在直通模式下打开HAL。如果getStub为False,则getService会尝试找到Binder化服务;如果未找到,则它会尝试找到直通式服务。除了在defaultPassthroughServiceImplementation中,其余情况一律不得使用getStub参数。(搭载Android O的设备是完全Binder化的设备,因此不得在直通模式下打开服务。)
网络配置工具
Android 中包含标准的 Linux 网络实用程序: ifconfig, ip, ip6tables 等,但是这些程序都在 system/bin 目录下, 在 Android O 之后,避免系统更新导致这些程序使用时不匹配,这些程序都被集成到 netutils-wrapper-1.0 工具中:
1 2 3 4 5 6 7 |
ELUGA_Ray_710:/system/bin # ls *wrapper-* -l lrwxr-xr-x 1 root shell 20 20*:56 ip-wrapper-1.0 -> netutils-wrapper-1.0 lrwxr-xr-x 1 root shell 20 20*:56 ip6tables-wrapper-1.0 -> netutils-wrapper-1.0 lrwxr-xr-x 1 root shell 20 20*:56 iptables-wrapper-1.0 -> netutils-wrapper-1.0 lrwxr-xr-x 1 root shell 20 20*:56 ndc-wrapper-1.0 -> netutils-wrapper-1.0 lrwxr-xr-x 1 root shell 20 20*:56 tc-wrapper-1.0 -> netutils-wrapper-1.0 -rwxr-xr-x 1 root shell 65248 20*:56 netutils-wrapper-1.0 |
Android O 之后,vendor 中不能直接调用 /system/bin/netutils-wrapper-1.0 ,否则会出错;也不能直接调用 /system/bin/ip <FOO> <BAR> ,而只能使用封装程序 /system/bin/ip-wrapper-1.0 <FOO> <BAR> ;如果 vendor 进程调用这些命令,需要在 SELinux policy 中添加:
1 |
domain_auto_trans(VENDOR-DOMAIN-NAME, netutils_wrapper_exec, netutils_wrapper) |
转换工具
Android 源码中提供了工具将老旧版本的 hal 模块转换为 HIDL HAL 格式,工具: c2hal: system/tools/hidl/c2hal ,使用示例:
1 |
c2hal -r android.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport -p [email protected] hardware/libhardware/include/hardware/nfc.h |
转换完成后,可以进一步手动修正部分小错误。
术语
-
Binder化
表示HIDL用于进程之间的远程过程调用,并通过类似Binder的机制来实现。 - 异步回调
由HAL用户提供、传递给HAL(通过HIDL方法)并由HAL调用以随时返回数据的接口。 - 同步回调
将数据从服务器的HIDL方法实现返回到客户端;不用于返回无效值或单个原始值的方法。 - 客户端
调用特定接口的方法的进程。HAL进程或框架进程可以是一个接口的客户端和另一个接口的服务器。 - 扩展
也可以理解为继承;表示向另一接口添加方法和/或类型的接口,一个接口只能扩展另一个接口。可用于具有相同软件包名称的Minor版本递增,也可用于在旧软件包的基础上构建的新软件包。 - 生成
表示将值返回给客户端的接口方法。要返回一个非原始值或多个值,则会生成同步回调函数。 - 接口
方法和类型的集合。会转换为C++或Java中的类。接口中的所有方法均按同一方向调用:客户端进程会调用由服务器进程实现的方法。 - 单向
应用到HIDL方法时,表示该方法既不返回任何值也不会造成阻塞。 - 直通式
HIDL的一种模式,使用这种模式时,服务器是共享库,由客户端进行dlopen处理。在直通模式下,客户端和服务器是相同的进程,但代码库不同。此模式仅用于将旧版代码库并入HIDL模型。 - 服务器
实现接口的方法的进程。 - 传输
在服务器和客户端之间移动数据的HIDL基础架构。 - 版本
软件包的版本。由两个整数组成:Major版本和Minor版本。Minor版本递增可以添加(但不会更改)类型和方法。 - 应用二进制接口 `ABI
应用编程接口 + 所需的任何二进制链接。 - 完全限定名称
fqName
用于区分hidl类型的名称。例如:[email protected]::IFoo。 - 软件包
共用一个版本的接口和数据类型的集合。包含HIDL接口和类型的软件包。例如:[email protected]。 - 软件包根目录
包含HIDL接口的根目录软件包。例如:HIDL接口android.hardware在软件包根目录[email protected]中。 - 软件包根目录路径
软件包根目录映射到的Android源代码树中的位置。
基础语法
规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
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
|
- 可以使用
/** */, /* */, //来注释 -
[empty]表示该字词可能为空 -
?跟在文本或字词后,表示它是可选的 -
...表示包含零个或多个项、用指定的分隔符号分隔的序列。HIDL中不含可变参数 - 逗号
,用于分隔序列元素 - 分号
;用于终止各个元素,包括最后的元素 - 大写字母是非终止符
- italics 是一个令牌系列,例如 integer 或 identifier(标准 C 解析规则)
- constexpr 是 C 样式的常量表达式(如 1 + 1 和 1L << 3)
- import_name 是软件包或接口名称,按 HIDL 版本编号中所述的方式加以限定
- 小写 words 是文本令牌
软件包
软件包名称可以具有子级,例如 package.subpackage 。软件包前缀和对应的位置如下:
| 软件包前缀 | 位置 |
|---|---|
| android.hardware.* | hardware/interfaces/* |
| android.frameworks.* | frameworks/hardware/interfaces/* |
| android.system.* | system/hardware/interfaces/* |
| android.hidl.* | system/libhidl/transport/* |
例如 package [email protected] 软件包:
可以在 hardware/interfaces/example/extension/light/2.0 下找到。软件包目录中包含扩展名为 .hal 的文件,每个文件均必须包含一个指定文件所属的软件包和版本的 package 语句;文件 types.hal(如果存在)并不定义接口,而是定义软件包中每个接口可以访问的数据类型。
版本编号
软件包分版本,用两个整数表示: major.minor :
-
Major版本不向后兼容
递增Major版本号将会使Minor版本号重置为 0 。 -
Minor版本向后兼容
如果递增Minor版本号,则意味着较新版本完全向后兼容之前的版本。可以添加新的数据结构和方法,但不能更改现有的数据结构或方法签名。
可同时在一台设备上提供 HAL 的多个 Major 或 Minor 版本。不过 Minor 版本应优先于 Major 版本,因为与之前的 Minor 版本接口一起使用的客户端代码也适用于同一接口的后续 Minor 版本。
支持的注解
主要用于 VTS 测试
-
@callflownext= @entry@exit
hal 定义
1 2 3 4 5 6 7 8 |
interface IBar extends IFoo { // IFoo is another interface
// embedded types
struct MyStruct {/*...*/};
// interface methods
create(int32_t id) generates (MyStruct s);
close();
};
|
不含显式 extends 声明的接口会从 [email protected]::IBase (类似于 Java 中的 java.lang.Object )隐式扩展。隐式导入的 IBase 接口声明了多种不应也不能在用户定义的接口中重新声明或以其他方式使用的预留方法,也就是说 hal 中不存在重载和重写!
接口只能扩展一个其他接口(不支持多重继承),具有非零 Minor 版本号的软件包中的每个接口必须扩展一个以前版本的软件包中的接口:
- 存在 1.2 版本的软件包
original中的接口IFoo - 小版本
Minor升级到 1.3 版本,软件包original中的接口IFoo必须继承 1.2 版本的IFoo - 假设大版本
Major升级到 4.0 版本,而软件包derivative中的接口IBar是继承于 1.2 版本的软件包original中的接口IFoo - 小版本
Minor升级到 4.1 版本,IBar必须扩展 4.0 版本的IBar;而不能继承 1.3 版本的IFoo,因为它是与 1.2 版本的IFoo绑定的 - 大版本
Major再次升级到 5.0 版本,此时IBar可以直接 1.3 版本的 `IFoo
接口扩展并不意味着生成的代码中存在代码库依赖关系或跨 HAL 包含关系,接口扩展只是在 HIDL 级别导入数据结构和方法定义。HAL 中的每个方法必须在相应 HAL 中重新实现。
import 导入
import 语句是用于访问其他软件包中的软件包接口和类型的 HIDL 机制,存在两种导入情况:
-
import语句位于types.hal文件中时,导入的内容对整个软件包可见,属于软件包级导入 -
improt语句位于custom.hal接口文件中时,导入的内容只对当前接口文件可见,属于接口级导入
import 语句后,根据导入值分三种情况:
- 完整软件包导入
导入值是一个软件包名称和版本,则系统会将整个软件包导入,即可访问整个软件包的接口或类型。 - 接口导入
导入值是一个接口文件,则导入该接口以及types.hal两个文件。 - 类型导入
导入值是types.hal中定义的某个类型,则仅将该类型导入,而types.hal中的其他类型不导入。
1 2 3 |
import [email protected]; // 导入整个软件包 import [email protected]::IQuux; // 导入接口文件和 types.hal import [email protected]::types; // 仅仅导入 types.hal 中定义的 types 类型 |
接口哈希 Hash 和版本控制文件 current.txt
HIDL 接口哈希,是一种旨在防止意外更改接口并确保接口更改经过全面审查的机制。因为 HIDL 接口带有版本编号,也就是说接口一经发布便不得再更改。
软件包根目录必须有版本控制文件 current.txt ;如果创建一个软件包路径,如 -r vendor.awesome:vendor/awesome/interfaces ),则还应创建文件 $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt 。current.txt 必须包含接口哈希及接口全限定名称,比如 system/libhidl/transport/current.txt 文件内容为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Do not change this file except to add new interfaces. Changing # pre-existing interfaces will fail VTS and break framework-only OTAs # HALs released in Android O fc6c***da68 [email protected]::IAllocator bdda***0fd9 [email protected]::IBase 500e***7567 [email protected]::types 4d04***0d3f [email protected]::IServiceManager 5055***50fb [email protected]::IServiceNotification 2b88***27c8 [email protected]::IMapper 4632***a16b [email protected]::IMemory 7c9f***4b7c [email protected]::ITokenManager # HALs released in Android O-MR1 0b94***4ef6 [email protected]::IServiceManager |
current.txt中的内容按照Android大版本来分隔,比如上半部分为Android O,下半部分为Android O-MR1,厂商自定义的接口文件也应该遵循这个格式。
可以手动将哈希添加到 current.txt 文件中,也可以使用 hidl-gen 加上参数 -Lhash 选项添加。
如下为针对类型文件、接口、整个软件包生成哈希:
1 2 3 4 5 6 7 8 |
$ 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 $ hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport [email protected]::INfc 07ac2dc9...11e3cf57 [email protected]::INfc $ hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport [email protected] 9626fd18...f9d298a6 [email protected]::types 07ac2dc9...11e3cf57 [email protected]::INfc f2fe5442...72655de6 [email protected]::INfcClientCallback |
如果是新添加的 hal 软件包,则将生成哈希及对应接口文件,一并写入 current.txt 文件中:
1 |
$ hidl-gen -L hash -r vendor.awesome:vendor/awesome/hardware/interfaces -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport [email protected] >> vendor/awesome/hardware/interfaces/current.txt |
接口文件的哈希,可以通过调用 IBase::getHashChain 来查看。 hidl-gen 编译接口时,会检查 HAL 软件包根目录中的 current.txt 文件,以查看 HAL 是否已被更改:
- 如果没有找到对应的哈希值,则继续编译,并认为接口没有发布
- 如果找到了对应哈希值,则做相应检查:
- 如果接口与哈希值匹配,则继续编译
- 如果接口与哈希值不匹配,则意味着接口被更改了,停止编译
所以,如果接口文件处于调试阶段,需要等调试完成后再发布到 current.txt 中;而接口文件一旦发布,将无法更改;如果想更改接口,必须升级版本号,也就是重新定义接口。比如 camera 相关接口的修改,必须升级版本号:
1 2 3 4 5 6 7 8 |
// hardware/interfaces/current.txt c170***2d62f [email protected]::ICameraDevice 78e9***44076 [email protected]::ICameraDeviceCallback 28f0***44566 [email protected]::ICameraDevicePreviewCallback 4db4***352a3 [email protected]::types b32f***55918 [email protected]::ICameraDevice 63bf***b3b21 [email protected]3.2::ICameraDeviceCallback 0fa3***7208e [email protected]::ICameraDeviceSession |
数据传递
数据在传递过程中:
-
.hal文件接口中定义的方法默认为阻塞模式,如果需要采用非阻塞式则在方法前面使用关键字oneway - 方法调用和回调只能接受
in参数,并且不支持out, inout参数 - 方法在数据传递时超过 4KB 以上的数据便被认为是过度调用;同时跨进程调用是基于
Binder机制,所以总的数据传输不能超过 1MB
对于跨进程通信, HIDL 只使用参数回调函数,避免了内存所有权的棘手问题,特别是不能有效通过方法返回的值可以直接通过回调函数返回。这样既不将数据传递到 HIDL ,也不从 HIDL 接收数据,改变数据的所有权。数据只需要在被调用函数的持续时间内存在,并且可以在被调用函数返回后立即销毁。
HIDL 如果不使用 Binder RPC ,可以通过两种方法来转移数据:
- 共享内存
分配的内存通过映射来共享。 - 快速消息队列
FMQHIDL提供了一种可实现无等待消息传递的模板化消息队列类型。
快速消息队列 FMQ
HIDL 的远程过程调用 RPC 基础架构使用 Binder 机制,这意味着调用涉及开销、需要内核操作,并且可以触发调度程序操作。不过对于必须在开销较小且无内核参与的进程之间传输数据的情况, HIDL 提供了快速消息队列 FMQ 系统。FMQ 会创建具有所需属性的消息队列, MQDescriptorSync, MQDescriptorUnsync 对象可通过 HIDL RPC 调用发送,并可供接收进程用于访问消息队列。
它在直通式或绑定式模式下不使用内核或调度程序,从而创建可以借助内置 HIDL 类型 MQDescriptorSync 或 MQDescriptorUnsync 的参数通过 RPC 传递的对象。
MessageQueue 支持的队列类型 flavor 有两种:
- 未同步队列
flavor: kSynchronizedReadWrite
可以溢出,并且可以有多个读取器;每个读取器都必须及时读取数据,否则数据将会丢失。未同步队列只有一个写入器,但可以有任意多个读取器。此类队列有一个写入位置;不过,每个读取器都会跟踪各自的独立读取位置。执行写入操作一定会成功(不会检查是否出现溢出情况),但前提是写入的内容不超出配置的队列容量(如果写入的内容超出队列容量,则操作会立即失败)。由于各个读取器的读取位置可能不同,因此每当新的写入操作需要空间时,系统都允许数据离开队列,而无需等待每个读取器读取每条数据。 - 已同步队列
flavor: kUnsynchronizedWrite
不能溢出,并且只能有一个读取器。已同步队列有一个写入器和一个读取器,其中写入器有一个写入位置,读取器有一个读取位置。写入的数据量不可能超出队列可提供的空间;读取的数据量不可能超出队列当前存在的数据量。
这两种队列都不能下溢(从空队列进行读取将会失败),并且只能有一个写入器。
FMQ 相关源码路径如下,其中 MessageQueue 主要是模板,所以定义和代码实现都在该 .h 文件中:
1 2 |
system/libfmq/include/fmq/MessageQueue.h system/libhidl/base/include/hidl/MQDescriptor.h |
队列类型是在 MQDescriptor.h 中定义的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// MQDescriptor.h
enum MQFlavor : uint32_t {
/*
* represents the wait-free synchronized flavor of the
* FMQ. It is intended to be have a single reader and single writer.
* Attempts to overflow/underflow returns a failure.
*/
kSynchronizedReadWrite = 0x01,
/*
* represents the flavor of FMQ where writes always succeed.
* This flavor allows one writer and many readers. A read operation
* can detect an overwrite and reset the read counter.
*/
kUnsynchronizedWrite = 0x02
};
|
创建快速队列示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <fmq/MessageQueue.h>
using android::hardware::kSynchronizedReadWrite;
using android::hardware::kUnsynchronizedWrite;
using android::hardware::MQDescriptorSync;
using android::hardware::MQDescriptorUnsync;
using android::hardware::MessageQueue;
....
// For a synchronized non-blocking FMQ
mFmqSynchronized =
new (std::nothrow) MessageQueue<uint16_t, kSynchronizedReadWrite>
(kNumElementsInQueue);
// For an unsynchronized FMQ that supports blocking
mFmqUnsynchronizedBlocking =
new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>
(kNumElementsInQueue, true /* enable blocking operations */);
|
-
MessageQueue<T, flavor>(numElements)初始化程序负责创建并初始化支持消息队列功能的对象 -
MessageQueue<T, flavor>(numElements, configureEventFlagWord)初始化程序负责创建并初始化支持消息队列功能和阻塞的对象 -
flavor可以是kSynchronizedReadWrite同步队列或kUnsynchronizedWrite未同步队列 -
uint16_t可以是任意不涉及嵌套式缓冲区(无string或vec类型)、句柄或接口的HIDL定义的类型 -
kNumElementsInQueue表示队列的大小(以条目数表示);它用于确定将为队列分配的共享内存缓冲区的大小
内存共享
HIDL 共享内存 MemoryBlock 是构建在 hidl_memory , HIDL @1.0::IAllocator 和 HIDL @1.0::IMapper 之上的抽象层,专为有多个内存块共用单个内存堆的 HIDL 服务而设计。
也就是说, HIDL 共享内存块只是提供了一种使用思路,而不是像 FMQ 提供了具体实现;使用 MemoryBlock 可显著减少 mmap/munmap 数量和用户空间细分错误,从而提升性能。架构图如下,核心思想是多个内存块共用单个内存堆 hidl_memory :
基本数据类型
HIDL 基本数据类型及对应处理,都是在 system/libhidl/base 目录中实现的,基本数据类型的定义文件为 HidlSupport.h ,目录结构为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
├── Android.bp ├── HidlInternal.cpp ├── HidlSupport.cpp ├── include │ └── hidl │ ├── HidlInternal.h │ ├── HidlSupport.h │ ├── MQDescriptor.h │ ├── Status.h │ ├── SynchronizedQueue.h │ └── TaskRunner.h ├── Status.cpp └── TaskRunner.cpp 2 directories, 11 files |
hidl_death_recipient
服务死亡通知,如果客户端注册该通知,当服务端断开时,会发出通知。
1 2 3 4 |
struct hidl_death_recipient : public virtual RefBase {
virtual void serviceDied(uint64_t cookie,
const ::android::wp<::android::hidl::base::V1_0::IBase>& who) = 0;
};
|
hidl_handle
句柄基本类型,是对 native_handle_t 句柄的封装:
1 2 3 4 5 6 7 8 9 |
struct hidl_handle {
...
// explicit conversion
const native_handle_t *getNativeHandle() const;
private:
...
details::hidl_pointer<const native_handle_t>
mHandle __attribute__ ((aligned(8)));
};
|
调用传递 hidl_handle 对象(复合类型的顶级或一部分)的 HIDL 接口方法时,其中包含的文件描述符的所有权如下所述:
- 将
hidl_handle对象作为参数传递的调用程序会保留对其封装的native_handle_t中包含的文件描述符的所有权;该调用程序在完成对这些文件描述符的操作后,必须将这些文件描述符关闭 - 通过将
hidl_handle对象传递到_cb函数来返回该对象的进程会保留对该对象封装的native_handle_t中包含的文件描述符的所有权;该进程在完成对这些文件描述符的操作后,必须将这些文件描述符关闭 - 接收
hidl_handle的传输拥有对相应对象封装的native_handle_t中的文件描述符的所有权;接收器可在事务回调期间按原样使用这些文件描述符,但如果想在回调完成后继续使用这些文件描述符,则必须克隆原生句柄。事务完成时,transport将自动对文件描述符执行close操作
HIDL 不支持在 Java 中使用句柄。
hidl_string
HIDL 字符串;通过 HIDL 接口将字符串传递到 Java 或从 Java 传递字符串将会导致字符集转换,而此项转换可能无法精确保留原始编码。
1 2 3 4 5 6 7 8 9 10 11 |
struct hidl_string {
...
const char *c_str() const;
size_t size() const;
bool empty() const;
...
private:
details::hidl_pointer<const char> mBuffer;
uint32_t mSize; // NOT including the terminating '\0'.
...
};
|
hidl_memory
memory 类型用于表示 HIDL 中未映射的共享内存。
1 2 3 4 5 6 7 |
struct hidl_memory {
...
private:
hidl_handle mHandle __attribute__ ((aligned(8)));
uint64_t mSize __attribute__ ((aligned(8)));
hidl_string mName __attribute__ ((aligned(8)));
};
|
hidl_vec
vec<T> 模板用于表示包含 T 实例且大小可变的缓冲区。 T 可以是任何由 HIDL 提供的或由用户定义的类型,句柄除外。( vec<T> 的 vec<> 将指向 vec<T> 结构体数组,而不是指向内部 T 缓冲区数组。) T 可以是以下项之一:
- 基本类型(例如
uint32_t) - 字符串
- 用户定义的枚举
- 用户定义的结构体
- 接口,或
interface关键字(vec<IFoo>,vec<interface>仅在作为顶级参数时受支持) - 句柄
bitfield<U>-
vec<U>,其中U可以是此列表中的任何一项,接口除外(例如,vec<vec<IFoo>>不受支持) -
U[](有大小的U数组),其中U可以是此列表中的任何一项,接口除外
hidl_array
表示多维数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
template<typename T, size_t SIZE1, size_t... SIZES>
struct hidl_array {
...
private:
T mBuffer[elementCount()];
};
// An array of T's. Assumes that T::operator=(const T &) is defined.
template<typename T, size_t SIZE1>
struct hidl_array<T, SIZE1> {
...
private:
T mBuffer[SIZE1];
};
|
hidl_version
HIDL 版本号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct hidl_version {
...
constexpr uint16_t get_major() const { return mMajor; }
constexpr uint16_t get_minor() const { return mMinor; }
private:
uint16_t mMajor;
uint16_t mMinor;
};
inline android::hardware::hidl_version make_hidl_version(
uint16_t major, uint16_t minor) {
return hidl_version(major,minor);
}
|
.hal 文件自动生成代码
基本步骤
比如 .hal 文件准备添加到 hardware/interface 目录下:
- 新建包名对应的文件夹,比如
myintere - 在包文件夹下新建主次版本对应的文件夹,比如
1.0 - 在版本目录下定义并编写
.hal文件 - 执行
.hal文件所在位置的update-makefiles.sh脚本(实际还是调用的hidl-gen),自动生成Android.bp/mk文件
因为是在hardware/interface目录下添加的,则执行:./hardware/interfaces/update-makefiles.sh,自动生成对应Android.bp。
1 2 3 4 5 6 |
// 1. 新建目录 [email protected]:~/**/hardware/interfaces/tests/$ mkdir -p myintere/1.0 // 2. 新建 .hal 文件 [email protected]:~/**/hardware/interfaces/tests/myintere/1.0$ touch IMyCallback.hal IMyIntere.hal // 3. 根目录下执行 update-makefiles.sh 脚本 [email protected]:~/**/$ ./hardware/interfaces/update-makefiles.sh |
hidl-gen 规则
hidl-gen 转换规则以及生成哪些文件都是在自动生成的 Android.bp 文件中定义的; hidl, aidl 文件自动生成 java, cpp, h 文件工具源码都是在 system/tools/ 目录下:
1 2 3 |
system/tools/ ├── aidl └── hidl |
绑定式模式使用 hidl-gen 编译器并以 IFoo.hal 接口文件作为输入,它具有以下自动生成的文件:
由编译器生成的文件:
-
IFoo.h
描述C++类中的纯IFoo接口;它包含IFoo.hal文件中的IFoo接口中所定义的方法和类型,必要时会转换为C++类型。不包含与用于实现此接口的RPC机制(例如HwBinder)相关的详细信息。类的命名空间包含软件包名称和版本号,例如::android::hardware::samples::IFoo::V1_0。客户端和服务器都包含此标头:客户端用它来调用方法,服务器用它来实现这些方法。 -
IHwFoo.h
头文件,其中包含用于对接口中使用的数据类型进行序列化的函数的声明。开发者不得直接包含其标头(它不包含任何类)。 -
BpFoo.h
从IFoo继承的类,可描述接口的HwBinder代理(客户端)实现。开发者不得直接引用此类。 -
BnFoo.h
保存对IFoo实现的引用的类,可描述接口的HwBinder存根Stub(服务器端)实现。开发者不得直接引用此类。 -
FooAll.cpp
包含HwBinder代理和HwBinder存根Stub的实现的类。当客户端调用接口方法时,代理会自动从客户端封送参数,并将事务发送到绑定内核驱动程序,该内核驱动程序会将事务传送到另一端的存根Stub(该存根随后会调用实际的服务器实现)。
生成的这些文件结构类似于由 aidl-cpp 生成的文件。独立于 HIDL 使用的 RPC 机制的自动生成的文件是 IFoo.h ,其他所有文件都与 HIDL 使用的 HwBinder RPC 机制相关联。因此客户端和服务器实现不得直接引用除 IFoo 之外的任何内容。为了满足这项要求,只包含 IFoo.h 并链接到生成的共享库。
在直通式模式中,在编译 IFoo.hal 文件时,标头文件除了用于 Binder 通信的标头之外, hidl-gen 还会生成一个额外的直通标头文件 BsFoo.h ;此标头定义了会被执行 dlopen 操作的函数。由于直通式 HAL 在它们被调用的同一进程中运行,因此在大多数情况下,直通方法由直接函数调用(同一线程)来调用。 oneway 方法在各自的线程中运行,因为它们不需要等待 HAL 来处理它们(这意味着,在直通模式下使用 oneway 方法的所有 HAL 对于线程必须是安全的)。 BsFoo.h 文件类似于 BpFoo.h ,不过所需函数是直接调用的,并未使用 Binder 传递调用 IPC 。未来 HAL 的实现可能提供多种实现结果,例如 FooFast HAL 和 FooAccurate HAL 。在这种情况下,系统会针对每个额外的实现结果创建一个文件(例如 PTFooFast.cpp 和 PTFooAccurate.cpp )。
hidl-gen 语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
usage: hidl-gen [-p <root path>] -o <output path> -L <language> (-r <interface root>)+ [-t] fqname+
-h: Prints this menu.
-L <language>: The following options are available:
check : Parses the interface to see if valid but doesn't write any files.
c++ : (internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.
c++-headers : (internal) Generates C++ headers for interface files for talking to HIDL interfaces.
c++-sources : (internal) Generates C++ sources for interface files for talking to HIDL interfaces.
export-header : Generates a header file from @export enumerations to help maintain legacy code.
c++-impl : Generates boilerplate implementation of a hidl interface in C++ (for convenience).
c++-impl-headers: c++-impl but headers only
c++-impl-sources: c++-impl but sources only
java : (internal) Generates Java library for talking to HIDL interfaces in Java.
java-constants : (internal) Like export-header but for Java (always created by -Lmakefile if @export exists).
vts : (internal) Generates vts proto files for use in vtsd.
makefile : (internal) Generates makefiles for -Ljava and -Ljava-constants.
androidbp : (internal) Generates Soong bp files for -Lc++-headers and -Lc++-sources.
androidbp-impl : Generates boilerplate bp files for implementation created with -Lc++-impl.
hash : Prints hashes of interface in `current.txt` format to standard out.
-o <output path>: Location to output files.
-p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.
-r <package:path root>: E.g., android.hardware:hardware/interfaces.
-t: generate build scripts (Android.bp) for tests.
|
-
fqName: 完全限定名 -
-L:指定生成的语言包 -
-r:hal文件路径
文件路径映射
每个 hal 文件都可以通过软件包根目录映射及其完全限定名称找到,软件包根目录以参数 -r android.hardware:hardware/interfaces 的形式指定给 hidl-gen 。例如:
1 |
hidl-gen -r vendor.awesome:some/device/independent/path/interfaces [email protected]::IFoo |
- 根目录参数为
vendor.awesome:some/device/independent/path/interfaces
表示vendor.awesome对应的目录路径为:$ANDROID_BUILD_TOP/some/device/independent/path/interfaces。 - 软件包为
[email protected]::IFoo
表示接口文件应该位于vendor.awesome目录路径下的foo接口的1.0版本下的IFoo.hal文件,即:$ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal。
软件包路径映射不得重复,比如如果同时存在 -rsome.package:$PATH_A 和 -rsome.package:$PATH_B ,则 $PATH_A 必须等于 $PATH_B 才能实现一致的接口目录(这也能让接口版本控制起来更简单)。
代码文件生成
-
定义
hal文件组1 2 3 4 5 6 7
filegroup { name: "[email protected]_hal", srcs: [ "ICameraProvider.hal", "ICameraProviderCallback.hal", ], } -
生成头文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// hardware/interfaces/camera/provider/2.4/Android.bp genrule { name: "android.hardware.camera.[email protected]_genc++_headers", tools: ["hidl-gen"], cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected]", srcs: [ ":[email protected]_hal", // hal 文件组 ], out: [ "android/hardware/camera/provider/2.4/ICameraProvider.h", "android/hardware/camera/provider/2.4/IHwCameraProvider.h", "android/hardware/camera/provider/2.4/BnHwCameraProvider.h", "android/hardware/camera/provider/2.4/BpHwCameraProvider.h", "android/hardware/camera/provider/2.4/BsCameraProvider.h", "android/hardware/camera/provider/2.4/ICameraProviderCallback.h", "android/hardware/camera/provider/2.4/IHwCameraProviderCallback.h", "android/hardware/camera/provider/2.4/BnHwCameraProviderCallback.h", "android/hardware/camera/provider/2.4/BpHwCameraProviderCallback.h", "android/hardware/camera/provider/2.4/BsCameraProviderCallback.h", ], } -
生成
CPP文件1 2 3 4 5 6 7 8 9 10 11 12 13
// hardware/interfaces/camera/provider/2.4/Android.bp genrule { name: "[email protected]_genc++", tools: ["hidl-gen"], cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected]", srcs: [ ":[email protected]_hal", // hal 文件组 ], out: [ "android/hardware/camera/provider/2.4/CameraProviderAll.cpp", "android/hardware/camera/provider/2.4/CameraProviderCallbackAll.cpp", ], }
HIDL 服务新增函数
HIDL 服务在代码自动生成,每个服务对应的头文件中,比如 IFoo.h 都会自动添加如下几个函数:
1 2 3 4 5 6 7 8 9 |
// 获取服务
static ::android::sp<IFoo> getService(
const std::string &serviceName="default", bool getStub=false);
// 注册服务
::android::status_t registerAsService(
const std::string &serviceName="default");
// 服务注册成功后的通知
static bool registerForNotifications( const std::string &serviceName,
const ::android::sp<IServiceNotification> ¬ification);
|
-
getService:获取服务 -
registerAsService:注册服务 -
registerForNotifications:注册通知监听事件,服务注册成功后会发出通知
服务注册与获取
服务端注册 Binder 服务
HIDL 接口使用 IInterface::registerAsService 来注册 Binder 服务,注册的名称不需要与接口或软件包名称相关。如果没有指定名称,则默认为 default ; HIDL 接口调用 android::hardware::IInterface::getInterfaceVersion 可以查看当前接口的版本。
1 2 3 4 5 |
sp<IFoo> myFoo = new Foo();
status_t status = myFoo->registerAsService(); // 默认值为 "default"
sp<IFoo> anotherFoo = new Foo();
status_t anotherStatus =
anotherFoo->registerAsService("another_foo_service"); // 显示指定服务名称
|
Binder 化直通式
首先要理解 Binder 化直通式 HAL ,指的是 HAL 服务端注册的方式:以直通的方式加载服务端,并向 hwservicemanager 注册该服务;通过函数 defaultPassthroughServiceImplementation<IFoo> 来注册:
1 2 |
defaultPassthroughServiceImplementation<ICameraProvider>(
"legacy/0", /*maxThreads*/ 6);
|
下面是源码分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
// LegacySupport.h
namespace android {
namespace hardware {
/**
* Registers passthrough service implementation.
*/
template<class Interface>
__attribute__((warn_unused_result))
status_t registerPassthroughServiceImplementation(
std::string name = "default") {
// 直通式加载服务端
sp<Interface> service =
Interface::getService(name, true /* getStub */);
if (service == nullptr) {
ALOGE(...);
return EXIT_FAILURE;
}
LOG_FATAL_IF(...);
// 向 hwservicemanager 注册服务
status_t status = service->registerAsService(name);
if (status == OK) {
ALOGI(...);
} else {
ALOGE(...);
}
return status;
}
template<class Interface>
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(std::string name,
size_t maxThreads = 1) {
configureRpcThreadpool(maxThreads, true);
status_t result =
registerPassthroughServiceImplementation<Interface>(name);
if (result != OK) {
return result;
}
joinRpcThreadpool();
return 0;
}
template<class Interface>
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(size_t maxThreads = 1) {
return defaultPassthroughServiceImplementation<Interface>(
"default", maxThreads);
}
|
registerPassthroughServiceImplementation 函数中,在 getService 时,参数 getStub 为 ture ,即通过直通式加载服务端;拿到直通式服务端 Interface 后,又通过 registerAsService 向 hwservicemanager 注册该服务。
即加载服务端的当前进程,作为服务进程;客户端从 hwservicemanager 可以查到服务端,并通过 Binder 和服务进程通信。
客户端获取服务
HIDL 接口因为有版本区分,所以每个接口文件都可以被认为是单独的、唯一的。因此 IFooService 版本 1.1 和 IFooService 版本 2.2 都可以注册为 foo_service ,并且两个接口上的 getService("foo_service") 都可获取该接口的已注册服务。因此在大多数情况***册或发现服务均无需提供名称参数(也就是说名称为 default )。
1 2 3 4 5 6 7 8 |
// C++
sp<V1_1::IFooService> service = V1_1::IFooService::getService();
sp<V1_1::IFooService> alternateService =
V1_1::IFooService::getService("another_foo_service");
// Java
V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */);
V1_1.IFooService alternateService =
V1_1.IFooService.getService("another", true /* retry */);
|
客户端通过 getService 来获取服务端,而 getService 是每个 .hal 文件在自动生成源码时,都会自动添加的函数,函数原型为(这里以 IServiceManager.hal 为例):static ::android::sp<IServiceManager> getService(const std::string &serviceName="default", bool getStub=false);
除了 <> 里的接口文件类型不一样,所有的 .hal 文件都会生成同样的代码;而它的实现则是在对应的 .cpp 文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
// ServiceManagerAll.cpp
::android::sp<IServiceManager> IServiceManager::getService(
const std::string &serviceName, const bool getStub) {
using ::android::hardware::defaultServiceManager;
using ::android::hardware::getPassthroughServiceManager;
...
sp<IServiceManager> iface = nullptr;
// 获取绑定式 IServiceManager
const sp<IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
ALOGE("getService: defaultServiceManager() is null");
return nullptr;
}
...
for (int tries = 0; !getStub &&
(vintfHwbinder || (vintfLegacy && tries == 0)); tries++) {
...
// 通过绑定式 IServiceManager 获取服务端
Return<sp<::android::hidl::base::V1_0::IBase>> ret =
sm->get(IServiceManager::descriptor, serviceName);
...
sp<::android::hidl::base::V1_0::IBase> base = ret;
...
// 强制转换为服务端对应类型,这里以 IServiceManager 为例
Return<sp<IServiceManager>> castRet =
IServiceManager::castFrom(base, true /* emitError */);
...
iface = castRet;
...
return iface;
}
if (getStub || vintfPassthru || vintfLegacy) {
// 获取直通式 IServiceManager
const sp<IServiceManager> pm = getPassthroughServiceManager();
if (pm != nullptr) {
// 通过直通式 IServiceManager 获取服务端
Return<sp<::android::hidl::base::V1_0::IBase>> ret =
pm->get(IServiceManager::descriptor, serviceName);
if (ret.isOk()) {
sp<::android::hidl::base::V1_0::IBase> baseInterface = ret;
if (baseInterface != nullptr) {
// 强制转换为服务端对应类型,这里以 IServiceManager 为例
iface = IServiceManager::castFrom(baseInterface);
// 直通模式中如果 getStub 为 false,返回的是 BsServiceManager
if (!getStub || trebleTestingOverride) {
iface = new BsServiceManager(iface);
}
}
}
}
}
return iface;
}
|
getService 主要是根据参数 getStub 的值来决定采用哪种方式获取服务端:
- 为
false时
通过defaultServiceManager获取服务端,即绑定式。 - 为
true时
通过getPassthroughServiceManager获取服务端,即直通式。
这两个函数下面会详细介绍。
服务死亡通知
客户端需要注册服务终止通知接收器,当服务终止时,客户端收到通知;接收器需要继承 hidl_death_recipient 子类,并实现对应的方法。
1 2 3 4 5 6 7 8 9 |
class IMyDeathReceiver : hidl_death_recipient {
virtual void serviceDied(uint64_t cookie,
wp<IBase>& service) override {
log("RIP service %d!", cookie); // Cookie should be 42
}
};
....
IMyDeathReceiver deathReceiver = new IMyDeathReceiver();
m_importantService->linkToDeath(deathReceiver, 42);
|
源码结构
源码目录速查表
实现源码路径为:
1 2 3 |
system/libhidl system/libhwbinder system/hwservicemanager |
libhidl
主要包含三个动态库: libhidlbase, libhidltransport, libhidlmemory ;其中 libhidlbase 主要是 hidl 的基本类型相关; libhidlmemory 是封装了 memory 通过 IMapper 来映射;libhidltransport 包含直通式 IServiceManager.hal 的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
libhidl/ ├── base │ ├── Android.bp │ ├── HidlInternal.cpp │ ├── HidlSupport.cpp │ ├── include │ ├── Status.cpp │ └── TaskRunner.cpp ├── libhidlmemory │ ├── Android.bp │ ├── include │ └── mapping.cpp ├── transport │ ├── allocator │ ├── Android.bp │ ├── base │ ├── current.txt │ ├── HidlBinderSupport.cpp │ ├── HidlTransportSupport.cpp │ ├── HidlTransportUtils.cpp │ ├── include │ ├── manager │ ├── memory │ ├── ServiceManagement.cpp │ ├── Static.cpp │ └── token └── ... |
libhwbinder
对应生成 libhwbinder 库,是 .hal 文件 Binder 通信相关库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
libhwbinder/
├── Android.bp
├── Binder.cpp
├── BpHwBinder.cpp
├── BufferedTextOutput.cpp
├── Debug.cpp
├── IInterface.cpp
├── include
│ └── hwbinder
├── IPCThreadState.cpp
├── MODULE_LICENSE_APACHE2
├── NOTICE
├── OWNERS
├── Parcel.cpp
├── PREUPLOAD.cfg
├── ProcessState.cpp
├── Static.cpp
├── TextOutput.cpp
└── vts
├── OWNERS
└── performance
|
hwservicemanager
生成可执行文件 hwservicemanager ,是 HIDL 绑定式服务的大管家。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
hwservicemanager/ ├── AccessControl.cpp ├── AccessControl.h ├── Android.bp ├── HidlService.cpp ├── HidlService.h ├── hwservicemanager.rc ├── hwservicemanagerTest.cpp ├── MODULE_LICENSE_APACHE2 ├── NOTICE ├── OWNERS ├── service.cpp ├── ServiceManager.cpp ├── ServiceManager.h ├── TokenManager.cpp ├── TokenManager.h ├── Vintf.cpp └── Vintf.h |
libhidl 目录
libhidlbase 库
libhidlbase 库对应的源码列表如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
base/ ├── Android.bp ├── HidlInternal.cpp ├── HidlSupport.cpp ├── include │ └── hidl │ ├── HidlInternal.h │ ├── HidlSupport.h │ ├── MQDescriptor.h │ ├── Status.h │ ├── SynchronizedQueue.h │ └── TaskRunner.h ├── Status.cpp └── TaskRunner.cpp |
-
HidlInternalhidl内部使用的一些类、字符串定义等等。hal客户端/服务端都不会使用。 -
HidlSupporthidl支持的基本数据类型(不包含C++, Java类型)。 -
MQDescripto
快速消息队列fmq中相关类型。 -
Status
表示hidl通信的状态和返回值,比如成功、失败、异常等等。 -
SynchronizedQueue
同步队列。 -
TaskRunner
后台无限循环的任务,使用SynchronizedQueue队列保存任务。
libhidlmemory 库
libhidlmemory 库对应的源码列表如下:
1 2 3 4 5 6 |
libhidlmemory/ ├── Android.bp ├── include │ └── hidlmemory │ └── mapping.h └── mapping.cpp |
就一个有效文件 mapping ,对应头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// mapping.h
namespace android {
namespace hardware {
/**
* Returns the IMemory instance corresponding to a hidl_memory object.
* If the shared memory cannot be fetched, this returns nullptr.
*/
sp<android::hidl::memory::V1_0::IMemory> mapMemory(
const hidl_memory &memory);
} // namespace hardware
} // namespace android
|
只包含一个功能函数:将 hidl_memory 内存映射后,返回对应的 IMemory 。 libhidlmemory 库是对 system/libhidl/transport/memory 的封装,而 transport/memory 则是具体的实现。
android.hidl.* 软件包
system/libhidl/transport/* 目录下包含 5 个软件包,这些软件包以 android.hidl.* 开头,它们是 hidl 的基础软件包:
-
base
定义了IBase.hal,它的功能类似Java Object,也就是说Ibase.hal是所有hal文件的父类。每个hal文件在自动生成源码时,都会自动添加IBase中的函数及其默认实现。 -
allocator
定义了内存分配接口IAllocator.hal,内存分配的具体实现为AshmemAllocator。 -
memory
定义了内存映射接口IMapper.hal以及内存接口IMemory.hal;而内存映射的具体实现为AshmemMapper,内存块IMemory的具体实现为AshmemMemory。 -
manager
定义了IServiceManager.hal相关功能接口;它有两个实现:直通式是在system/libhidl/ServiceManagement.cpp中实现的,对应libhidltransport库;绑定式是在system/hwservicemanager/ServiceManager.cpp中实现的,对应hwservicemanager可执行文件。 -
token
定义了接口ITokenManager.hal,它可以将hidl接口转换为token方便跨进程传输;该接口是在hwservicemanager中实现的。
hidl相关的内存分配和映射,都是使用的匿名共享内存机制Ashmem;IServiceManager服务管理分为直通式和绑定式,是在不同文件中实现的。
IBase 文件路径为 system/libhidl/transport/base/1.0/IBase.hal ,是所有 hal 的基础接口,类似 Java 中的 Object 类;因为 hidl 中不存在重写和重载,所以自定义的 hal 文件中函数名不能和下面的重复:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
package [email protected]; interface IBase { // 测试服务是否正在运行 ping(); /* * Provides run-time type information for this object. * For example, for the following interface definition: * package [email protected]; * interface IParent {}; * interface IChild extends IParent {}; * return:interfaceChain on an IChild object must yield the following * ["[email protected]::IChild", * "[email protected]::IParent" * "[email protected]::IBase"] */ interfaceChain() generates (vec<string> descriptors); /* * Provides run-time type information for this object. * For example, for the following interface definition: * package [email protected]; * interface IParent {}; * interface IChild extends IParent {}; * Calling interfaceDescriptor on an IChild object must yield * "[email protected]::IChild" * * @return descriptor a descriptor of the run-time type of the * object (the first element of the vector returned by * interfaceChain()) */ interfaceDescriptor() generates (string descriptor); oneway notifySyspropsChanged(); linkToDeath(death_recipient recipient, uint64_t cookie) generates (bool success); unlinkToDeath(death_recipient recipient) generates (bool success); oneway setHALInstrumentation(); getDebugInfo() generates (DebugInfo info); debug(handle fd, vec<string> options); /* * For example, for the following interface definition: * package [email protected]; * interface IParent {}; * interface IChild extends IParent {}; * return:interfaceChain on an IChild object must yield the following * [(hash of IChild.hal), * (hash of IParent.hal) * (hash of IBase.hal)]. * * SHA-256 is used as the hashing algorithm. Each hash has 32 bytes * according to SHA-256 standard. * * @return hashchain a vector of SHA-1 digests */ getHashChain() generates (vec<uint8_t[32]> hashchain); }; |
libhidltransport 库
libhidltransport 库中的头文件 #include <hidl/ServiceManagement.h> ,包含了几组重要函数,用来区分当前是客户端采用绑定式还是直通式来获取服务端:
1 2 3 4 5 6 7 |
// ServiceManagement.h // These functions are for internal use by hidl. If you want to get ahold // of an interface, the best way to do this is by calling IFoo::getService() sp<::android::hidl::manager::V1_0::IServiceManager> defaultServiceManager(); sp<::android::hidl::manager::V1_1::IServiceManager> defaultServiceManager1_1(); sp<::android::hidl::manager::V1_0::IServiceManager> getPassthroughServiceManager(); sp<::android::hidl::manager::V1_1::IServiceManager> getPassthroughServiceManager1_1(); |
-
defaultServiceManager:绑定式服务管理IServiceManager -
getPassthroughServiceManager:直通式服务管理IServiceManager
它们都是在 ServiceManagement.cpp 中实现的,先看绑定式源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// ServiceManagement.cpp
sp<IServiceManager1_0> defaultServiceManager() {
return defaultServiceManager1_1();
}
sp<IServiceManager1_1> defaultServiceManager1_1() {
{
AutoMutex _l(details::gDefaultServiceManagerLock);
if (details::gDefaultServiceManager != NULL) {
return details::gDefaultServiceManager;
}
if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) {
// HwBinder not available on this device or not accessible to
// this process.
return nullptr;
}
waitForHwServiceManager();
while (details::gDefaultServiceManager == NULL) {
details::gDefaultServiceManager =
fromBinder<IServiceManager1_1, BpHwServiceManager,
BnHwServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (details::gDefaultServiceManager == NULL) {
LOG(ERROR) << "...";
sleep(1);
}
}
}
return details::gDefaultServiceManager;
}
|
它的核心代码是 fromBinder 这个模板函数,这里需要注意 ProcessState::self()->getContextObject(NULL) 这句代码的含义是:获取 handle 为 0 的 IBinder ,而 handle 为 0 表示是 hwservicemanager 守护进程,后续在 hwservicemanager 进程中做详细介绍。这里 ProcessState, IPCThreadState 等,虽然都是在 libhwbinder 库中,实际上和 Framework Binder 中代码很多都是相同,实现的功能也大致相同。fromBinder 是在 HidlBinderSupport.h 头文件中定义的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// HidlBinderSupport.h
template <typename IType, typename ProxyType, typename StubType>
sp<IType> fromBinder(const sp<IBinder>& binderIface) {
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::base::V1_0::BnHwBase;
if (binderIface.get() == nullptr) {
return nullptr;
}
if (binderIface->localBinder() == nullptr) {
return new ProxyType(binderIface);
}
sp<IBase> base = static_cast<BnHwBase*>(binderIface.get())->getImpl();
if (details::canCastInterface(base.get(), IType::descriptor)) {
StubType* stub = static_cast<StubType*>(binderIface.get());
return stub->getImpl();
} else {
return nullptr;
}
}
|
模板代码表示,如果是远程访问,则新建代理对象即 BpHwServiceManager ,即客户端持有服务端的代理;如果是本地调用,则直接转换为 BnHwServiceManager ,换句话说这里客户端就是服务端自己。
当是远程访问时,实际的 IServiceManager 是由 hwservicemanager 进程中 ServiceManager 实现的。
再看直通式源码:
1 2 3 4 5 6 7 8 9 |
// ServiceManagement.cpp
sp<IServiceManager1_0> getPassthroughServiceManager() {
return getPassthroughServiceManager1_1();
}
sp<IServiceManager1_1> getPassthroughServiceManager1_1() {
static sp<PassthroughServiceManager> manager(
new PassthroughServiceManager());
return manager;
}
|
直通模式获取服务端时,直接返回的 PassthroughServiceManager 对象,通过它获取服务端 get 方法源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
struct PassthroughServiceManager : IServiceManager1_1 {
static void openLibs(
const std::string& fqName,
std::function<bool /* continue */
(void* /* handle */, const std::string& /* lib */,
const std::string& /* sym */)> eachLib) {
//fqName looks like [email protected]::IFoo
size_t idx = fqName.find("::");
...
std::string packageAndVersion = fqName.substr(0, idx);
std::string ifaceName = fqName.substr(idx + strlen("::"));
const std::string prefix = packageAndVersion + "-impl";
// hardcode 服务端必须包含一个 HIDL_FETCH_ 开头的函数
const std::string sym = "HIDL_FETCH_" + ifaceName;
const int dlMode = RTLD_LAZY;
void *handle = nullptr;
...
std::vector<std::string> paths =
{HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR,
HAL_LIBRARY_PATH_VNDK_SP, HAL_LIBRARY_PATH_SYSTEM};
...
for (const std::string& path : paths) {
std::vector<std::string> libs = search(path, prefix, ".so");
for (const std::string &lib : libs) {
const std::string fullPath = path + lib;
// 找到库文件,打开后返回句柄
if (path != HAL_LIBRARY_PATH_SYSTEM) {
handle = android_load_sphal_library(
fullPath.c_str(), dlMode);
} else {
handle = dlopen(fullPath.c_str(), dlMode);
}
// 没有找到则继续循环查找
if (handle == nullptr) {
const char* error = dlerror();
LOG(ERROR)...;
continue;
}
// 回调传入的函数
if (!eachLib(handle, lib, sym)) {
return;
}
}
}
}
Return<sp<IBase>> get(const hidl_string& fqName,
const hidl_string& name) override {
sp<IBase> ret = nullptr;
openLibs(fqName, [&](void* handle,
const std::string &lib, const std::string &sym) {
IBase* (*generator)(const char* name);
*(void **)(&generator) = dlsym(handle, sym.c_str());
if(!generator) {
const char* error = dlerror();
LOG(ERROR)...;
dlclose(handle);
return true;
}
ret = (*generator)(name.c_str());
if (ret == nullptr) {
dlclose(handle);
return true;
}
registerReference(fqName, name);
return false;
});
return ret;
}
...
}
|
openLibs 首先根据全限定名解析出版本号,以及 .hal 接口名称,再查找其实现库即 IFoo-impl.so 库,查找路径为 HAL_LIBRARY_PATH_SYSTEM 等等,它们的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// HidlInternal.h #define HAL_LIBRARY_PATH_SYSTEM_64BIT "/system/lib64/hw/" #define HAL_LIBRARY_PATH_VNDK_SP_64BIT "/system/lib64/vndk-sp/hw/" #define HAL_LIBRARY_PATH_VENDOR_64BIT "/vendor/lib64/hw/" #define HAL_LIBRARY_PATH_ODM_64BIT "/odm/lib64/hw/" #define HAL_LIBRARY_PATH_SYSTEM_32BIT "/system/lib/hw/" #define HAL_LIBRARY_PATH_VNDK_SP_32BIT "/system/lib/vndk-sp/hw/" #define HAL_LIBRARY_PATH_VENDOR_32BIT "/vendor/lib/hw/" #define HAL_LIBRARY_PATH_ODM_32BIT "/odm/lib/hw/" #if defined(__LP64__) #define HAL_LIBRARY_PATH_SYSTEM HAL_LIBRARY_PATH_SYSTEM_64BIT #define HAL_LIBRARY_PATH_VNDK_SP HAL_LIBRARY_PATH_VNDK_SP_64BIT #define HAL_LIBRARY_PATH_VENDOR HAL_LIBRARY_PATH_VENDOR_64BIT #define HAL_LIBRARY_PATH_ODM HAL_LIBRARY_PATH_ODM_64BIT #else #define HAL_LIBRARY_PATH_SYSTEM HAL_LIBRARY_PATH_SYSTEM_32BIT #define HAL_LIBRARY_PATH_VNDK_SP HAL_LIBRARY_PATH_VNDK_SP_32BIT #define HAL_LIBRARY_PATH_VENDOR HAL_LIBRARY_PATH_VENDOR_32BIT #define HAL_LIBRARY_PATH_ODM HAL_LIBRARY_PATH_ODM_32BIT #endif |
也就是说在这些路径中搜索 IFoo-impl.so 库文件,直到找到为止。
IFoo.hal的实现文件Foo.cpp中,必须包含HIDL_FETCH_IFoo的函数,这个是在openLibs中代码写死的。通常在HIDL_FETCH_IFoo中,new Foo()来新建Foo对象。
直通式中获取服务端的流程:先通过 openLibs 加载实现库 IFoo-impl.so ,再调用 HIDL_FETCH_IFoo 方法,得到 Foo 对象(即服务端)。
也就是说,直通式 Passthrough HAL 中客户端直接将服务端的代码库加载到当前进程中,这也是 Treble 架构中对老版本 HAL 的兼容:在 HIDL 之前, HAL 都是通过 dlopen 来直接加载的。
libhwbinder 目录
libhwbinder 库目录,主要是实现了 hwbinder 通信,它的实现方式绝大部分都和 Framework Binder 中一致,参考Android Binder 机制 。libhwbinder 目录的代码基本是从 Framework Binder 代码拷贝过来,修改了部分 Bp, Bn Binder 的名称,以及 /dev/hwbinder 驱动设备文件。
hwBinder 类图结构
-
BpHwRefBase中的mRemote指向了BpHwBinder -
BpHwBinder中的mHandle是一个句柄,指向BHwBinder,它们两个之间通过Binder Driver来通信
IBase 类图结构
IBase 是所有 HIDL 服务的基类, BnHwBase 中的 _hidl_mImpl 指向了 HIDL 服务的具体实现类。
ProcessState
这里主要介绍 ProcessState 中两个函数:构造函数和 getContextObject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// ProcessState.cpp
// 大约 1 M
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 0 // 默认最大线程数为 0
static int open_driver()
{
// 打开驱动文件
int fd = open("/dev/hwbinder", O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
...
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
// 设置默认最大线程数
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("...);
}
} else {
ALOGW(...);
}
return fd;
}
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, ...
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual
// address space to receive transactions.
// 映射内存空间
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ,
MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/hwbinder failed...\n");
close(mDriverFD);
mDriverFD = -1;
}
}
else {
ALOGE("...");
}
}
|
ProcessState 构造函数中实现了如下功能:
- 打开
/dev/hwbinder设备,该文件节点和Binder通信 - 初始配置驱动的最大线程数为 0 ,后续可以通过
setThreadPoolConfiguration来修改 -
mmap映射内存空间,大概1MB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpHwBinder if there isn't currently
// one, OR we are unable to acquire a weak reference on this
// current one. See comment in getWeakProxyForHandle()
// for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpHwBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a
// primary reference to the remote proxy when this
// team doesn't have one but another team is
// sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
|
getContextObject 函数中调用 getStrongProxyForHandle(0) ,即返回句柄为 0 的代理,而句柄为 0 表示是服务大管家,后面 hwservicemanager 中会详细介绍。
当查到句柄存在时,新建 BpHwBinder ,它是所有 Bp***Binder 的父类。
hwservicemanager 进程
hwservicemanager 是 HIDL 服务大管家,负责管理系统中的所有 HIDL 注册的绑定式服务,由 init 进程启动。
Binder 通信基础知识
先复习下 Framework Binder 通信的基础知识:
-
IInterface表示服务端能够提供的服务 -
IBinder用来实现跨进程通信,分为BnBinder, BpBinder
客户端和服务端通信过程:
- 服务端通过
BnBinder实现IInterface对应功能 - 客户端通过
BpBinder调用IInterface对应功能;BpBinder是BnBinder的代理,代理的实现过程为通过Binder Driver转发
Framework Binder 中两个重要概念:
-
service_manager进程:它是服务大管家,负责保存注册的服务 -
IServiceManager供客户端和服务端查询和注册服务,它和service_manager是跨进程通信
IServiceManager.cpp 作为客户端和服务大管家 service_manager 进程通过 Binder 来通信;其他 aidl 服务进程作为客户端,通过 IServiceManager.cpp 注册服务;其他 app 进程作为客户端,通过 IServiceManager.cpp 查询服务。
IServiceManager 类图结构
这个类图体现了一般的 HIDL 服务的类结构:
-
IServiceManager可以看做一个标准的HIDL服务,默认继承IBase -
IServiceManager服务的实现类有两个:PassthroughServiceManager, ServiceManager -
BnHwServiceManager中_hidl_mImpl指向IServiceManager的具体实现类,这里具体是ServiceManager -
BpHwServiceManager是代理类,父类BpHwRefBase中的mRemote指向了BpHwBinder,而BpHwBinder中的mHandle是指向BHwBinder的句柄,这里实际指向的是它的子类BnHwServiceManager -
Bp**和Bn**是通过Binder驱动来通信的,设备名/dev/hwbinder
hwBinder 简述
hwBinder 和 Binder 模型基本一样,而且是共用 Binder Driver ,仅仅是设备关键字不一样。 hwBinder 中,服务端持有 BnHw 并实现 IInterface 的具体功能;客户端持有 BpHw 调用 IInterface 对应功能, BpHw 是 BnHw 的代理,通过 Binder Driver 来通信。 BpHw, BnHw 的通信过程(读写 Parcel ),都是在自动生成的 IFooAll.cpp 中实现的。hwservicemanager 进程功能和 Framework Binder 中的 service_manager 进程相同,它是 HIDL 的服务大管家;但具体由 ServiceManager.cpp 来保存注册的服务, ServiceManager 属于 hwservicemanager 进程,所以通信过程是函数直接调用。
客户端和服务端通过 ServiceManagement.cpp 来和 hwservicemanager 通信。 ServiceManagement 会根据绑定式或是直通式来返回 IServiceManager 的具体实现:如果是绑定式,则 ServiceManagement 持有 BpHwServiceManager (即 BnHwServiceManager 的代理),它会和 hwservicemanager 通过 Binder 通信,查询并返回服务接口。
rc 文件
hwservicemanager.rc 文件定义了 hwservicemanager 进程的启动方式:
1 2 3 4 5 6 7 8 9 10 11 |
service hwservicemanager /system/bin/hwservicemanager
user system
disabled
group system readproc
critical
onrestart setprop hwservicemanager.ready false
onrestart class_restart hal
onrestart class_restart early_hal
writepid /dev/cpuset/system-background/tasks
class animation
shutdown critical
|
main 方法
主进程文件为 service.cpp ,对应的 main 方法为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// service.cpp
int main() {
configureRpcThreadpool(1, true /* callerWillJoin */);
ServiceManager *manager = new ServiceManager();
if (!manager->add(serviceName, manager)) {
ALOGE("Failed to register hwservicemanager with itself.");
}
TokenManager *tokenManager = new TokenManager();
if (!manager->add(serviceName, tokenManager)) {
ALOGE("Failed to register ITokenManager with hwservicemanager.");
}
sp<Looper> looper(Looper::prepare(0 /* opts */));
int binder_fd = -1;
IPCThreadState::self()->setupPolling(&binder_fd);
if (binder_fd < 0) {
ALOGE("Failed to aquire binder FD. Aborting...");
return -1;
}
// Flush after setupPolling(), to make sure the binder driver
// knows about this thread handling commands.
IPCThreadState::self()->flushCommands();
sp<BinderCallback> cb(new BinderCallback);
if (looper->addFd(binder_fd, Looper::POLL_CALLBACK,
Looper::EVENT_INPUT, cb, nullptr) != 1) {
ALOGE("Failed to add hwbinder FD to Looper. Aborting...");
return -1;
}
// Tell IPCThreadState we're the service manager
sp<BnHwServiceManager> service = new BnHwServiceManager(manager);
IPCThreadState::self()->setTheContextObject(service);
// Then tell binder kernel
ioctl(binder_fd, BINDER_SET_CONTEXT_MGR, 0);
...
while (true) {
looper->pollAll(-1 /* timeoutMillis */);
}
return 0;
}
|
main 中主要实现了这些功能:
- 新建
ServiceManager对象,并将它注册到hwservicemanager中(注册过程实际是存储到一个map中) - 新建
TokenManager对象,并将它注册为服务 - 轮询
/dev/hwbinder设备文件,监听事件 - 新建
BnHwServiceManager对象,并将ServiceManager传入作为IServiceManager的实现 -
ioctl向驱动发送消息,将hwservicemanager进程,以句柄 0 向驱动注册为服务大管家BINDER_SET_CONTEXT_MGR(这就是为什么拿到句柄 0 ,即表示为hwservicemanager)
ServiceManager
ServiceManager 用于管理服务的注册和查询, mServiceMap 中保存了服务端相关信息,以全限定名称作为 key 保存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
struct ServiceManager : public IServiceManager, hidl_death_recipient {
//Methods from::android::hidl::manager::V1_0::IServiceManager follow
Return<sp<IBase>> get(const hidl_string& fqName,
const hidl_string& name) override;
Return<bool> add(const hidl_string& name,
const sp<IBase>& service) override;
...
using InstanceMap = std::map<
std::string, // instance name e.x. "manager"
std::unique_ptr<HidlService>
>;
struct PackageInterfaceMap {
...
private:
InstanceMap mInstanceMap{};
...
};
/**
* Access to this map doesn't need to be locked, since hwservicemanager
* is single-threaded.
*
* e.x.
* mServiceMap["[email protected]::IServiceManager"]["manager"]
* -> HidlService object
*/
std::map<
std::string, // package::interface
// e.x. "[email protected]::IServiceManager"
PackageInterfaceMap
> mServiceMap;
};
|
-
mServiceMap
关键字为全限定名:package::interface,比如:[email protected]::IServiceManager。 -
mInstanceMap
关键字为服务名称,默认为default;服务端也可以在注册时,指定服务名称;比如CameraProvider中注册时,指定为"legacy/0"。
因为先通过全限定从 mServiceMap 中取 mInstanceMap ,而全限定名称包含软件包、主次版本号、接口名称,全限定名称一定不会重复,所以拿到的是唯一的 mInstanceMap ;此时再根据服务名称获取服务端接口时,服务名已经不是很重要,所以通常服务名称使用的默认的 default 。
服务注册
服务端通过 Binder 注册,最终是在 ServiceManager 中实现的,并保存在 mServiceMap 中。
注意: add 来注册服务,是 hwbinder 机制内部使用的;服务端应该使用 registerAsService 来注册,而自动生成代码 IFooAll.cpp 中在实现 registerAsService 时,会调用 add 来完成注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// ServiceManager.cpp
Return<bool> ServiceManager::add(const hidl_string& name,
const sp<IBase>& service) {
...
auto ret = service->interfaceChain(
[&](const auto &interfaceChain) {
...
for(size_t i = 0; i < interfaceChain.size(); i++) {
// 拿到全限定名
std::string fqName = interfaceChain[i];
// 根据全限定名查找 mInstanceMap
PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
// 根据服务名称查找对应服务
HidlService *hidlService = ifaceMap.lookup(name);
// 没有找到或找到为空,则添加或更新
if (hidlService == nullptr) {
ifaceMap.insertService(std::make_unique<HidlService>(
fqName, name, service, pid));
} else {
...
hidlService->setService(service, pid);
}
ifaceMap.sendPackageRegistrationNotification(fqName, name);
}
...
});
...
}
|
注册的过程为:
- 先根据全限定名和服务名,查找服务是否存在
- 如果不存在,则添加并保存;如果存在则更新
服务查询
查询 Binder 服务,最终是在 ServiceManager 中实现的,也就是从 mServiceMap 中查找。
注意: get 来查询服务,是 hwbinder 机制内部使用的;客户端应该通过接口 Interface::getService 获取:它会先使用 defaultServiceManager 来获取 IServiceManager ,然后再调用 get 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// ServiceManager.cpp
Return<sp<IBase>> ServiceManager::get(const hidl_string& fqName,
const hidl_string& name) {
pid_t pid = IPCThreadState::self()->getCallingPid();
if (!mAcl.canGet(fqName, pid)) {
return nullptr;
}
auto ifaceIt = mServiceMap.find(fqName);
if (ifaceIt == mServiceMap.end()) {
return nullptr;
}
const PackageInterfaceMap &ifaceMap = ifaceIt->second;
const HidlService *hidlService = ifaceMap.lookup(name);
if (hidlService == nullptr) {
return nullptr;
}
return hidlService->getService();
}
|
查询过程很简单:就是从 mServiceMap 中根据全限定名和服务名查找。
示例
hardware/interfaces/tests 中有简单的 HIDL 服务示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
tests/ ├── Android.bp ├── bar ├── baz ├── expression ├── extension ├── foo ├── hash ├── inheritance ├── libhwbinder ├── memory ├── msgq ├── multithread ├── myintere └── pointer |
小结
Binder 总结
Binder 域有三个,但它们都是共用了 Binder Driver ,只是设备文件名称不一样(在 kernel 编译配置中设定 CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" ):
-
/dev/binder
标准的Framework Binder,使用AIDL接口;服务大管家对应的是servicemanager进程。 -
/dev/hwbinderHIDL服务相关,使用HIDL接口;服务大管家对应的是hwservicemanager进程。 -
/dev/vndbinder
供应商之间的通信,使用AIDL接口;服务大管家对应的是vndservicemanager进程。
在 HIDL 服务中,除了使用 /dev/hwbinder 和 Framework 通信外;还可以同时使用 /dev/vndbinder 和 vendor 通信:
1 2 3 4 5 6 7 |
// hardware/interfaces
camera/provider/2.4/default/service.cpp:32: android::ProcessState::initWithDriver("/dev/vndbinder");
cas/1.0/default/service.cpp:37: android::ProcessState::initWithDriver("/dev/vndbinder");
drm/1.0/default/service.cpp:38: android::ProcessState::initWithDriver("/dev/vndbinder");
gnss/1.0/default/service.cpp:15: android::ProcessState::initWithDriver("/dev/vndbinder");
graphics/composer/2.1/default/service.cpp:31: android::ProcessState::initWithDriver("/dev/vndbinder");
hal-server/hal-server.cpp:107:android::ProcessState::initWithDriver("/dev/vndbinder");
|
这里 vndservicemanager, servicemanager 进程对应的源码文件都是 service-manager.c 文件,只是在 Android.bp 中做了编译区分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// frameworks/native/cmds/servicemanager/Android.bp
cc_binary {
name: "servicemanager",
defaults: ["servicemanager_flags"],
srcs: [
"service_manager.c",
"binder.c",
],
shared_libs: ["libcutils", "libselinux"],
init_rc: ["servicemanager.rc"],
}
cc_binary {
name: "vndservicemanager",
defaults: ["servicemanager_flags"],
vendor: true,
srcs: [
"service_manager.c",
"binder.c",
],
cflags: [
"-DVENDORSERVICEMANAGER=1",
],
shared_libs: ["libcutils", "libselinux_vendor"],
init_rc: ["vndservicemanager.rc"],
}
|
后续
-
HIDL分别用cpp, java实现两个示例 -
vts相关