HIDL介绍和使用
1600 Words|Read in about 8 Min|本文总阅读量次
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 中找到。
构建 m hidl-gen
运行 请注意,预期将由构建系统调用的 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.