AIDL并不是唯一的Binder的应用,除了AIDL还有一个经常在HAL层代码中出现的HIDL。本文就是通过HIDL展开描述,主要对于AIDL的介绍和使用。

一个同样基于Binder通信的一个架构

1HIDL

1.1HIDL介绍

HIDL 是用于指定 HAL 与其用户之间接口的一个接口描述语言(Interface Description Language),它允许将指定的类型与函数调用收集到接口(Interface)和包(Package)中。更广泛地说,HIDL 是一个可以让那些独立编译的代码库(Libraries)之间进行通信的系统。 HIDL 实际上是用于进行进程间通信(Inter-process Communication,IPC)的。进程间的通信可以称为 Binder 化(Binderized)。对于必须连接到进程的库,也可以使用 passthough 模式(但在Java中不支持)。 HIDL 将指定的数据结构与方法签名组织到接口中,这些接口又会被收集到包中以供使用。它的语法与 C++、JAVA 是类似的,不过关键字集合不尽相同。其注释风格与 JAVA 是一致的。

1.2AIDL和HIDL区别

三种Binder介绍以及之间的联系

在Android 8.0开始,Android引入了Treble的机制,为了方便Android系统的快速移植、升级,提升系统稳定性,Binder机制被拓展成了"/dev/binder", “/dev/hwbinder”,"/dev/vndbinder"。最明显的就是binder库发生变化,Binder和VndBinder共同使用libbinder, HwBinder使用libhwbinder。

libbinder libhwbinder
前缀/frameworks/native/libs/binder 前缀/system/libhwbinder
Binder.cpp Binder.cpp
BpBinder.cpp BpHwBinder.cpp
IIterface.cpp IIterface.cpp
IPCThreadState.cpp IPCThreadState.cpp
ProcessState.cpp ProcessState.cpp
Parcel.cpp Parcel.cpp
前缀+=/include/binder 前缀+=/include/hwbinder
Binder.h Binder.h
BpBinder.h BpHwBinder.h
IBinder.h IBinder.h
IIterface.h IIterface.h
IPCThreadState.h IPCThreadState.h
ProcessState.h ProcessState.h
Parcel.h Parcel.h

另外servicemanager的差异如下

servicemanager vndservicemanager hwservicemanager
前缀/frameworks/native/cmds/servicemanager 见servicemanager前缀 前缀/system/hwservicemanager
servicemanager.rc vndservicemanager.rc hwservicemanager.rc
service_manager.c service_manager.c ServiceManager.cpp
binder.c binder.c HidlService.cpp
binder.h binder.h HidlService.h

1.2.1 dev/binder

这个是我们最熟悉的Binder,App开发中,ActivityManagerService用的都是这个,Java继承BpBinder,C++中继承BBinder,然后通过servicemanager进程注册实名Binder,然后通过已经创建好的Binder接口传递匿名Binder对象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。

1.2.2 dev/vndbinder

其实dev/vndbinde和dev/binder使用方式基本一样而且是共用一套Binder SDK,也是Java继承Bpinder,C++中继承BBinder,但是通过vndservicemanager进程注册实名Binder,然后通过已经创建好的Binder接口传递匿名Binder对象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。如何在使用同一套Binder SDK的代码,最后访问的设备节点变成dev/vndbinder,servicemanager变成vndservicemanager。

其实和简单,知识进程初始化的时候执行下面这个代码

1ProcessState::initWithDriver("/dev/vndbinder");

注:dev/binder和dev/vndbinder无法在一个进程中同时使用

1.2.3 dev/hwbinder

那么dev/hwbinder是如何解决与dev/binder或dev/vndbinder之间的共存问题?有人肯定想到了,很简单,我们把所有Binder SDK复制一套新的Hw Binder SDK,改名成dev/hwbinder,HwBinder,HwBbinder,hwservicemanager,HwProcessState,这样子不就可以和dev/binder或dev/vndbinder共存了嘛?其实android团队就会类似这样子干的。

他们的目标有两个:

1.不能那么自由,强制所有供应商按照android官方定义的hal接口来实现 2.不能增加供应商开发人员的学习成本,学习一套复杂的Hw Binder SDK

为了达成上述的两个目标,android团队想出了HIDL这个方案。

1.2.4 总结

Binder和VndBinder 共用一套libbinder、servicemanager的代码,使用AIDL接口,两者不能共存。

HwBinder采用了单独的libhwbinder、hwservicemanager的代码,单独管理,使用HIDL接口。

三者之间互不干扰,在方便系统升级的同时,又提升了系统的安全和稳定性。

2HIDL实战

2.1定义接口文件

进入hardware/interfaces/目录下建立新的接口文件

首先建立对应的文件夹

1mkdir -p hardware/interfaces/yangyang/1.0/defaul

接着创建接口描述文件IYangyang.hal:

1vi hardware/interfaces/yangyang/1.0/IYangyang.hal

IYangyang.hal内容:

1//hardware/interfaces/yangyang/1.0/IYangyang.hal
2package android.hardware.yangyang@1.0;
3
4interface IYangyang{
5    helloWorld(string name) generates (string result);
6};

2.2使用工具,根据接口文件生成代码

系统定义的所有的.hal接口,都是通过hidl-gen工具转换成对应的代码。hidl-gen源码路径:system/tools/hidl,是在ubuntu上可执行的二进制文件。

aosp的部分翻译

hidl-gen 完整的文档可以在这里找到:https://source.android.com/devices/architecture/hidl/

hidl-gen 是 HIDL(HAL 接口设计语言)的编译器,它为 RPC 机制生成 C++ 和 Java 端点。该编译器使用的主要用户空间库可以在 system/libhidl 中找到。

  1. 构建 m hidl-gen

  2. 运行 请注意,预期将由构建系统调用的 hidl-gen 选项在帮助菜单中标记为“内部”。

hidl-gen -h

hidl-gen -o output -L c++-impl -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.nfc@1.0

hidl-gen -o output -L c++-impl android.hardware.nfc@1.0 hidl-gen -o output -L vts android.hardware.nfc@1.0 hidl-gen -L hash android.hardware.nfc@1.0

供应商项目的示例命令

hidl-gen -L c++-impl -r vendor.foo:vendor/foo/interfaces vendor.foo.nfc@1.0 有关如何生成 HIDL makefile(使用 -Landroidbp 选项)的示例,请参阅 update-makefiles-helper.sh 和 update-all-google-makefiles.sh。

使用方法:hidl-gen -o output-path -L language (-r interface-root) fqname

例子:

1hidl-gen -o hardware/interfaces/yangyang/1.0/default/ -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.yangyang@1.0

参数说明:

-L: 语言类型,包括c++, c++-headers, c++-sources, export-header, c++-impl, java, java-constants, vts, makefile, androidbp, androidbp-impl, hash等。hidl-gen可根据传入的语言类型产生不同的文件。 fqname: 完全限定名称的输入文件。比如本例中android.hardware.yangyang@1.0,要求在源码目录下必须有hardware/interfaces/ yangyang/1.0/目录。

对于单个文件来说,格式如下:package@version::fileName,比如android.hardware. yangyang@1.0::types.Feature。对于目录来说。格式如下package@version,比如android.hardware. yangyang@1.0。 -r: 格式package:path,可选,对fqname对应的文件来说,用来指定包名和文件所在的目录到Android系统源码根目录的路径。如果没有制定,前缀默认是:android.hardware,目录是Android源码的根目录。 -o:存放hidl-gen产生的中间文件的路径。

Google提供了一些工具来帮助制作HIDL的框架:

1make hidl-gen 

源码中编译生成hidl-gen。

注意:编译前需要执行全编译的环境变量加载(source build/envsetup.sh && lunch ,具体可以点击这里

使用hidl-gen工具生成代码

1## 设置两个临时变量PACKAGE和LOC
2$ PACKAGE=android.hardware.yangyang@1.0
3$ LOC=hardware/interfaces/yangyang/1.0/default/
4# 生成两个文件,一个c++实现文件和一个头文件
5$ hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
6# 生成一个bp文件
7$ hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

执行完后,会生成三个文件:

2.3完善接口函数

Yangyang.h

 1//hardware/interfaces/yangyang/1.0/default/Yangyang.h
 2#ifndef ANDROID_HARDWARE_YANGYANG_V1_0_YANGYANG_H
 3#define ANDROID_HARDWARE_YANGYANG_V1_0_YANGYANG_H
 4
 5#include <android/hardware/yangyang/1.0/IYangyang.h>
 6#include <hidl/MQDescriptor.h>
 7#include <hidl/Status.h>
 8
 9namespace android {
10namespace hardware {
11namespace yangyang {
12namespace V1_0 {
13namespace implementation {
14
15using ::android::hardware::hidl_array;
16using ::android::hardware::hidl_memory;
17using ::android::hardware::hidl_string;
18using ::android::hardware::hidl_vec;
19using ::android::hardware::Return;
20using ::android::hardware::Void;
21using ::android::sp;
22
23struct Yangyang : public IYangyang {
24    // Methods from IYangyang follow.
25    Return<void> helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) override;
26
27    // Methods from ::android::hidl::base::V1_0::IBase follow.
28
29};
30
31// FIXME: most likely delete, this is only for passthrough implementations
32// extern "C" IYangyang* HIDL_FETCH_IYangyang(const char* name);
33
34}  // namespace implementation
35}  // namespace V1_0
36}  // namespace yangyang
37}  // namespace hardware
38}  // namespace android
39
40#endif  // ANDROID_HARDWARE_YANGYANG_V1_0_YANGYANG_H

去掉extern注释,采用直通模式。

1// extern "C" IYangyang* HIDL_FETCH_IYangyang(const char* name);

Yangyang.cpp

 1//hardware/interfaces/yangyang/1.0/default/Yangyang.cpp
 2#include "Yangyang.h"
 3
 4namespace android {
 5namespace hardware {
 6namespace yangyang {
 7namespace V1_0 {
 8namespace implementation {
 9
10// Methods from IYangyang follow.
11Return<void> Yangyang::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
12    char buf[100];
13    ::memset(buf, 0x00, 100);
14    ::snprintf(buf, 100, "->>> Yangyang::helloWorld | Hello World, %s", name.c_str());
15    hidl_string result(buf);
16    _hidl_cb(result);
17    return Void();
18}
19
20
21// Methods from ::android::hidl::base::V1_0::IBase follow.
22
23//IYangyang* HIDL_FETCH_IYangyang(const char* /* name */) {
24//    return new Yangyang();
25//}
26
27}  // namespace implementation
28}  // namespace V1_0
29}  // namespace yangyang
30}  // namespace hardware
31}  // namespace android

去掉注释.

1//IYangyang* HIDL_FETCH_IYangyang(const char* /* name */) {
2//    return new Yangyang();
3//}

这些都是工具生成的代码,接下来我们来完善下接口.

主要修改的就是Yangyang.cpp代码helloWorld函数.

1Return<void> Yangyang::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
2    char buf[100];
3    ::memset(buf, 0x00, 100);
4    ::snprintf(buf, 100, "->>> Yangyang::helloWorld | Hello World, %s", name.c_str());
5    hidl_string result(buf);
6    _hidl_cb(result);
7    return Void();
8}

接着使用脚本来更新Makefile,下面这个文件用于更新 HAL 和 VTS 模块的 Android 生成文件的脚本。执行完成之后,会在自定义的package目录生成Android.bp和Android.mk

1./hardware/interfaces/update-makefiles.sh

2.4编译

因为已经生成了mk和bp文件,可以通过编译来生成android.hardware.yangyang@1.0-impl.so

1$ ./hardware/interfaces/update-makefiles.sh
2$ mmm hardware/interfaces/yangyang/1.0

可以通过mk和bp文件得知,实际上bp文件会生成对应的五个头文件,一个实现cpp文件和一个动态库android.hardware.yangyang@1.0.so。关于Android.bp文件语法和使用,可以点击这里

 1//hardware/interfaces/yangyang/1.0/Android.bp
 2//在本例中会生成一个实现的cpp类,android/hardware/yangyang/1.0/YangyangAll.cpp
 3//在本例中会生成五个头文件,
 4//"android/hardware/yangyang/1.0/IYangyang.h",
 5//"android/hardware/yangyang/1.0/IHwYangyang.h",
 6//"android/hardware/yangyang/1.0/BnHwYangyang.h",
 7//"android/hardware/yangyang/1.0/BpHwYangyang.h",
 8//"android/hardware/yangyang/1.0/BsYangyang.h",
 9// 除此之外,还会生成一个android.hardware.yangyang@1.0.so的动态库
10// This file is autogenerated by hidl-gen. Do not edit manually.
11
12filegroup {
13    name: "android.hardware.yangyang@1.0_hal",
14    srcs: [
15        "IYangyang.hal",
16    ],
17}
18
19genrule {
20    name: "android.hardware.yangyang@1.0_genc++",
21    tools: ["hidl-gen"],
22    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.yangyang@1.0",
23    srcs: [
24        ":android.hardware.yangyang@1.0_hal",
25    ],
26    out: [
27        "android/hardware/yangyang/1.0/YangyangAll.cpp",
28    ],
29}
30
31genrule {
32    name: "android.hardware.yangyang@1.0_genc++_headers",
33    tools: ["hidl-gen"],
34    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.yangyang@1.0",
35    srcs: [
36        ":android.hardware.yangyang@1.0_hal",
37    ],
38    out: [
39        "android/hardware/yangyang/1.0/IYangyang.h",
40        "android/hardware/yangyang/1.0/IHwYangyang.h",
41        "android/hardware/yangyang/1.0/BnHwYangyang.h",
42        "android/hardware/yangyang/1.0/BpHwYangyang.h",
43        "android/hardware/yangyang/1.0/BsYangyang.h",
44    ],
45}
46
47cc_library {
48    //这里的so跟下面的impl.so区别在于,这个更多的是接口,没有实现
49    name: "android.hardware.yangyang@1.0",
50    defaults: ["hidl-module-defaults"],
51    generated_sources: ["android.hardware.yangyang@1.0_genc++"],
52    generated_headers: ["android.hardware.yangyang@1.0_genc++_headers"],
53    export_generated_headers: ["android.hardware.yangyang@1.0_genc++_headers"],
54    vendor_available: true,
55    vndk: {
56        enabled: true,
57    },
58    shared_libs: [
59        "libhidlbase",
60        "libhidltransport",
61        "libhwbinder",
62        "liblog",
63        "libutils",
64        "libcutils",
65    ],
66    export_shared_lib_headers: [
67        "libhidlbase",
68        "libhidltransport",
69        "libhwbinder",
70        "libutils",
71    ],
72}

mk文件会生成对应的java文件

 1#hardware/interfaces/yangyang/1.0/Android.mk
 2#在本例中会生成编译出来的jar包
 3# android.hardware.yangyang-V1.0-java.jar和android.hardware.yangyang-V1.0-java-static.jar
 4#在本例中会生成java的hidl接口,类似aidl的java接口类
 5#  (intermediates)/android/hardware/yangyang/V1_0/IYangyang.java
 6# This file is autogenerated by hidl-gen. Do not edit manually.
 7
 8LOCAL_PATH := $(call my-dir)
 9
10################################################################################
11
12include $(CLEAR_VARS)
13LOCAL_MODULE := android.hardware.yangyang-V1.0-java
14LOCAL_MODULE_CLASS := JAVA_LIBRARIES
15
16intermediates := $(call local-generated-sources-dir, COMMON)
17
18HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
19
20LOCAL_JAVA_LIBRARIES := \
21    android.hidl.base-V1.0-java \
22
23#
24# Build IYangyang.hal
25#
26GEN := $(intermediates)/android/hardware/yangyang/V1_0/IYangyang.java
27$(GEN): $(HIDL)
28$(GEN): PRIVATE_HIDL := $(HIDL)
29$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IYangyang.hal
30$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
31$(GEN): PRIVATE_CUSTOM_TOOL = \
32        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
33        -Ljava \
34        -randroid.hardware:hardware/interfaces \
35        -randroid.hidl:system/libhidl/transport \
36        android.hardware.yangyang@1.0::IYangyang
37
38$(GEN): $(LOCAL_PATH)/IYangyang.hal
39	$(transform-generated-source)
40LOCAL_GENERATED_SOURCES += $(GEN)
41include $(BUILD_JAVA_LIBRARY)
42
43################################################################################
44
45include $(CLEAR_VARS)
46LOCAL_MODULE := android.hardware.yangyang-V1.0-java-static
47LOCAL_MODULE_CLASS := JAVA_LIBRARIES
48
49intermediates := $(call local-generated-sources-dir, COMMON)
50
51HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
52
53LOCAL_STATIC_JAVA_LIBRARIES := \
54    android.hidl.base-V1.0-java-static \
55
56#
57# Build IYangyang.hal
58#
59GEN := $(intermediates)/android/hardware/yangyang/V1_0/IYangyang.java
60$(GEN): $(HIDL)
61$(GEN): PRIVATE_HIDL := $(HIDL)
62$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IYangyang.hal
63$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
64$(GEN): PRIVATE_CUSTOM_TOOL = \
65        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
66        -Ljava \
67        -randroid.hardware:hardware/interfaces \
68        -randroid.hidl:system/libhidl/transport \
69        android.hardware.yangyang@1.0::IYangyang
70
71$(GEN): $(LOCAL_PATH)/IYangyang.hal
72	$(transform-generated-source)
73LOCAL_GENERATED_SOURCES += $(GEN)
74include $(BUILD_STATIC_JAVA_LIBRARY)
75
76include $(call all-makefiles-under,$(LOCAL_PATH))

2.5构建binder service

2.5.1 添加rc,service.cpp

虽然有了库,但是我们还需要构建binder通信服务,创建一个rc文件(rc文件是被init进程访问的)

1$vim hardware/interfaces/yangyang/1.0/default/android.hardware.yangyang@1.0-service.rc

android.hardware.yangyang@1.0-service.rc

1# hardware/interfaces/yangyang/1.0/default/android.hardware.yangyang@1.0-service.rc
2service yangyang_service_hal /vendor/bin/hw/android.hardware.yangyang@1.0-service
3    class hal
4    user system
5    group system

设定yangyang_service_hal服务,让rc文件启动的时候运行yangyang_service_hal的进程。

进程的入口就是下面的service.cpp文件的main函数

1vim hardware/interfaces/yangyang/1.0/default/service.cpp

具体内容

 1//hardware/interfaces/yangyang/1.0/default/service.cpp
 2#define LOG_TAG "android.hardware.yangyang@1.0-service"
 3#include <android/hardware/yangyang/1.0/IYangyang.h>
 4#include <hidl/LegacySupport.h>
 5using android::hardware::yangyang::V1_0::IYangyang;
 6using android::hardware::defaultPassthroughServiceImplementation;
 7
 8int main(){
 9    printf("hidl yangyang service is starting\n");
10    return defaultPassthroughServiceImplementation<IYangyang>();
11
12}

在Android.bp中添加yangyang_service_hal服务的编译:

1vim hardware/interfaces/yangyang/1.0/default/Android.bp 

Android.bp中添加

 1//hardware/interfaces/yangyang/1.0/default/Android.bp 
 2cc_library_shared {
 3    //通过之前编译的android.hardware.yangyang@1.0.so,Yangyang.cpp用来生成实现的so
 4    //这个实现的so为android.hardware.yangyang@1.0-impl.so
 5    name: "android.hardware.yangyang@1.0-impl",
 6    relative_install_path: "hw",
 7    proprietary: true,
 8    srcs: [
 9        "Yangyang.cpp",
10    ],
11    shared_libs: [
12        "libhidlbase",
13        "libhidltransport",
14        "libutils",
15        "android.hardware.yangyang@1.0",
16    ],
17}
18
19cc_binary {
20    //这个是一个全局唯一的名称,代表编译出来的是android.hardware.yangyang@1.0-service进程
21    name: "android.hardware.yangyang@1.0-service",
22    relative_install_path: "hw",
23    proprietary: true,
24    //这个是service启动的rc文件
25    init_rc: ["android.hardware.yangyang@1.0-service.rc"],
26    //这个是service的源文件
27    srcs: ["service.cpp"],
28
29    shared_libs: [
30        "liblog",
31        "libcutils",
32        "libdl",
33        "libbase",
34        "libutils",
35        "libhardware",
36        "libhidlbase",
37        "libhidltransport",
38        "android.hardware.yangyang@1.0",
39    ],
40}

最后的目录结构

2.5.2注册hidl到manifest中

为了能够定义之后让后续测试的客服端访问到,需要把这个hidl服务注册到manifest中。这个目的是为了在init进程的时候,去自动解析rc文件,找到对应的hidl的服务。当然也可以直接在设备中修改,笔者设备是红米手机,目录位于/vendor/manifest.xml中

 1<!-- 增加hidl的一个服务 -->
 2<hal format="hidl">
 3    <name>android.hardware.yangyang</name>
 4    <transport>hwbinder</transport>
 5    <impl level="generic"></impl>
 6    <version>1.0</version>
 7    <interface>
 8        <name>IYangyang</name>
 9        <instance>default</instance>
10    </interface>
11</hal>    

2.6最终编译

编译如下

1$ mmm hardware/interfaces/yangyang/1.0/default/

编译后生成的文件

1/vendor/lib64/hw/android.hardware.yangyang@1.0-impl.so
2/vendor/etc/init/android.hardware.yangyang@1.0-service.rc 
3/vendor/bin/hw/android.hardware.yangyang@1.0-service
4/system/lib64/android.hardware.yangyang@1.0.so 

2.7验证服务端代码

笔者这里用到了两种方法来验证。

第一种方法主要是在同目录下创造一个test目录,用这个客户端去测试这个服务端。

第二种方法主要用jar包,然后用源码编译app,最终通过手动click,用toast空间显示是否获取服务端成功。

2.7.1c++验证

2.7.1.1增加编译文件和测试源文件

这个test目录增加了两个文件,一个编译文件Android.bp和测试文件yangyangTest.cpp

 1//hardware/interfaces/yangyang/1.0/test/Android.bp
 2cc_binary {
 3    relative_install_path: "hw",
 4    defaults: ["hidl_defaults"],
 5    //生成一个yangyang_client进程,源文件为yangyangTest.cpp
 6    name: "yangyang_client",
 7    proprietary: true,
 8    srcs: ["yangyangTest.cpp"],
 9
10    shared_libs: [
11        "liblog",
12        "libhardware",
13        "libhidlbase",
14        "libhidltransport",
15        "libutils",
16        "android.hardware.yangyang@1.0",
17    ],
18
19}

测试实现文件

 1//hardware/interfaces/yangyang/1.0/test/yangyangTest.cpp
 2#include <android/hardware/yangyang/1.0/IYangyang.h>
 3#include <hidl/Status.h>
 4#include <hidl/LegacySupport.h>
 5#include <utils/misc.h>
 6#include <hidl/HidlSupport.h>
 7#include <stdio.h>
 8
 9using ::android::hardware::hidl_string;
10using ::android::sp;
11using android::hardware::yangyang::V1_0::IYangyang;
12
13int main(){
14    android::sp<IYangyang> service = IYangyang::getService();
15    if (service == nullptr){
16        printf("->>> yangyang48 | Failed to get service\n");
17        return -1;
18    }
19
20    service->helloWorld("I am Yangyang48", [&](hidl_string result){
21        printf("%s\n", result.c_str());
22    });
23    return 0;
24}

2.7.1.2编译

1# 执行第一条命令是为了更新hardware/interfaces/yangyang/目录下的Android.bp文件,自动增加1.0/test的目录
2$ ./hardware/interfaces/update-makefiles.sh
3$ mmm hardware/interfaces/yangyang/1.0/default/

编译完成之后,将文件导入到

1/vendor/bin/hw/yangyang_client

2.7.1.3测试方法

首先运行服务端进程,进程启动后会出现日志hidl yangyang service is starting

1./android.hardware.yangyang@1.0-service

然后启动测试端进程,这个时候服务端就会和客户端交互,打印成功的日志-»> Yangyang::helloWorld | Hello World, I am Yangyang48。

1./yangyang_client

2.7.2jar包验证

2.7.2.1更改mk并编译jar包

可以知道,包目录下的mk文件实际上跟java相关,除了编译java的interface之外,还会编译对应的jar包。为了编译出classes.jar,需要修改hardware/interfaces/yangyang/1.0目录的Android.mk

1#hardware/interfaces/yangyang/1.0/Android.mk
2LOCAL_PATH := $(call my-dir)
3include $(CLEAR_VARS)
4# 增加一个LOCAL_JACK_ENABLED disable的方式,这样编译的时候就不走jack编译了
5LOCAL_JACK_ENABLED := disabled
6LOCAL_MODULE := android.hardware.yangyang-V1.0-java
7LOCAL_MODULE_CLASS := JAVA_LIBRARIES
8...

2.7.2.2jar包集成到Android源码中

具体目录如下所示。

我们这边只看一个主界面MainActivity,注册AndroidManifest.xml和mk的编译脚本

MainActivity.java,笔者在主界面中用的还是v7的包,其实也可以用androidx的包

 1//packages/apps/HIDLdemo/src/com/example/hidldemo/MainActivity.java
 2package com.example.hidldemo;
 3
 4import android.hardware.yangyang.V1_0.IYangyang;
 5import android.os.Bundle;
 6import android.os.RemoteException;
 7import android.support.v7.app.AppCompatActivity;
 8import android.util.Log;
 9import android.view.View;
10import android.widget.Toast;
11
12public class MainActivity extends AppCompatActivity {
13    IYangyang iYangyangService;
14    @Override
15    protected void onCreate(Bundle savedInstanceState) {
16        super.onCreate(savedInstanceState);
17        setContentView(R.layout.activity_main);
18        try {
19            iYangyangService = IYangyang.getService(); //获取服务
20        } catch (RemoteException e) {
21            e.printStackTrace();
22        }
23    }
24
25    public void hidlTest(View view){
26        if (iYangyangService != null){
27            Log.d("MainActivity", "Yangyang48 | service is connect.");
28            String s = null;
29            try {
30                s = iYangyangService.helloWorld("I am Yangyang48_java");//调用HAL层接口
31            } catch (RemoteException e) {
32                e.printStackTrace();
33            }
34            Log.d("MainActivity", s);
35            Toast.makeText(this, s, Toast.LENGTH_LONG).show();
36        }
37    }
38}

AndroidManifest.xml,这个跟默认的app写法一致

 1<?xml version="1.0" encoding="utf-8"?>
 2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3    package="com.example.hidldemo">
 4    <application
 5        android:allowBackup="true"
 6        android:icon="@mipmap/ic_launcher"
 7        android:label="@string/app_name"
 8        android:roundIcon="@mipmap/ic_launcher_round"
 9        android:supportsRtl="true"
10        android:theme="@style/AppTheme">
11        <activity android:name=".MainActivity">
12            <intent-filter>
13                <action android:name="android.intent.action.MAIN" />
14                <category android:name="android.intent.category.LAUNCHER" />
15            </intent-filter>
16        </activity>
17    </application>
18</manifest>

Android.mk

 1LOCAL_PATH := $(call my-dir)
 2include $(CLEAR_VARS)
 3#定义app的apk名
 4LOCAL_PACKAGE_NAME := HIDLdemo
 5LOCAL_SRC_FILES := $(call all-java-files-under, src)
 6LOCAL_MODULE_TAGS :=optional
 7LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 8# 这里可以加入androidx的包,需要在同目录下也同样导入
 9LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
10# 增加yangyang的jar包,这个步骤不能缺
11LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.yangyang-V1.0-java-static
12
13LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
14LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
15
16LOCAL_CERTIFICATE := platform
17LOCAL_AAPT_FLAGS := --auto-add-overlay
18include $(BUILD_PACKAGE)

3总结

HIDL主要通过hwbinder注册,通过hwservicemanager来管理,通过一个客户端和一个服务端,总的来实现一个hidl的系统。本文主要简述关于HIDL的使用方式。通过自定义一个HIDL服务端,通过c++和java两种方式的客户端,去调用到服务端的最终实现。

当然HIDL的精髓不只是一个简单的小demo就可以描述清楚,这里笔者做一个抛砖引玉的作用,后续会持续更新关于HIDL方面的文章。

hwbinder的关系图如下图所示。

4下载

本文源码下载,点击这里

参考

[1] android官方文档, 使用Binder IPC, 2020.

[2] 木叶风神, Android HIDL学习(2) —- HelloWorld, 2018.

[3] IngresGe, Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要 — 注册回调, 2020.

[4] IngresGe, Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六), 2020.

[5] IngresGe, JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八), 2020.

[6] liujun3512159, Android HIDL学习(3) — 注册回调, 2022.

[7] 嵌入式Linux,, binder,hwbinder,vndbinder之间的关系, 2020.

[8] 私房菜,Android HIDL 中的数据类型, 2019.

[9] liujun3512159,HIDL实战笔记, 2022.

[10] 开发小院,CameraProvider进程启动流程, 2020.

[11] 私房菜,Android HIDL 中的函数, 2019.

[12] Gunder,HIDL最全编译流程, 2018.

[13] Gunder,HIDL概述, 2018.

[14] nginux,source /build/envsetup.sh和lunch), 2015.

[15] IT先森,Android.bp入门指南之浅析Android.bp语法, 2020.