一、HIDL
1、什么是HIDL
HIDL(HAL Interface Definition Language)是用于指定HAL和其用户之间的接口的一种接口描述语言(IDL),AIDL是架构在Android binder之上,用来定义Android基于Binder通信的Client与Service之间的接口;而HIDL定义的则是Android Framework与Android HAL实现之间的接口。
2、HIDL底层实现原理
使用 HDL 创建的 HAL 称为绑定式 HAL,使用 Binder 进程间通信 (IPC) 调用与其他架构层进行通信
3、binder的种类
参考链接:
https://source.android.google.cn/docs/core/architecture/hidl/binder-ipc?hl=zh-cn
![](https://img.haomeiwen.com/i16293373/ded9870416fa7da2.png)
3.1、binder种类介绍
-
3.1 dev/binder
这个是我们最熟悉的Binder,App开发中,ActivityManagerService用的都是这个,Java继承Binder,C++中继承Bbbinder,然后通过servicemanager进程注册实名Binder,然后通过已经创建好的Binder接口传递匿名Binder对象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。
-
3.2 dev/vndbinder
其实dev/vndbinde和dev/binder使用方式基本一样而且是共用一套Binder SDK,也是Java继承Binder,C++中继承Bbbinder,但是通过vndservicemanager进程注册实名Binder,然后通过已经创建好的Binder接口传递匿名Binder对象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。如何在使用同一套Binder SDK的代码,最后访问的设备节点变成dev/vndbinder,servicemanager变成vndservicemanager。
dev/binder和dev/vndbinder无法在一个进程中同时使用,原因两类进程的任意一个进程无法同时使用dev/binder和dev/vndbinder,这一点不单是android官方约定,也是目前android binder sdk的限制,因为两者都是共用Binder SDK,所以只能指定一个设备节点,要么dev/binder,要么dev/vndbinder
-
3.3 、dev/hwbinder
解决无法可以在一个进程同时使用,强制由所有供应商按照android官方定义的hal接口来实现,由HIDL方案去实现
4、举例说明三种binder
假如手机中有如下3类进程
4.1、应用进程:
Camera APP
手电筒 APP
4.2、框架进程:
System Server进程
4.3、供应商进程:
Camera HAL进程
Light HAL进程
这些进程之间需要使用Binder机制跨进程通信,Android提供了三个Binder设备节点dev/binder,dev/hwbinder,dev/vndbinder,也就是Android系统同时提供了三个独立运行的Binder通信模块,Android团队规定每类进程使用的这三个Binder通信模块的规则如下图:
![](https://img.haomeiwen.com/i16293373/2f2dcb0b4696b460.png)
5、aidl使用和hidl使用范畴
5.1、aidl使用范畴
- 适用于应用层与应用层之间调用
- 适用于应用层与java framework之间调用
- 适用于应用层与native framework(仅限于system/bin)之间调用
.......
5.2、hidl使用范畴
- 适用于native framework之间调用
- 适用于应用层与native framework(仅限于vendor/bin)之间调用
......
注意:主要是强调应用层与vendor/bin和system/bin之间区别,这个坑对于我这小白掉进去还砸了一个大坑
二、HAL服务创建与HIDL的调用
1、hal层服务启动
参考链接: https://android.googlesource.com/platform/system/core/+/master/init/README.md
本次案例是 :app调用/vendor/bin/hw 的service
1.1、service的编写
cc_binary {
name: "vendor.melrose.hardware.led@1.0-service", //启动service的名字
proprietary: true, (安装在/vendor/bin)
relative_install_path: "hw", //最终安装在放在/vendor/bin/hw目录下
init_rc: ["vendor.melrose.hardware.led@1.0-service.rc"], //启动文件配置
vintf_fragments: ["vendor.melrose.hardware.led.xml"], //编译HIDL文件
srcs: [
"Led.cpp",
"service.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
"libmwnode",
"libmwinit",
"libmwtime",
"libmwcommon",
"liblog",
"vendor.melrose.hardware.led@1.0",
],
}
1.2、配置启动service文件.rc
手机开机会通过init.cpp调用LoadBootScripts方法去启动对应的native service
static void LoadBootScripts(ActionManager&action_manager, ServiceList&service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
查看方式 :
adb shell
cd system|vendor|odm|product/etc/init目录下即可查看你写的启动文件
cd system|vendor|odm|product/bin或者system|vendor|odm|product/bin/hw目录即可查看你写的service
service led(名字随意) /vendor/bin/hw/vendor.melrose.hardware.led@1.0-service (service的名字)
class hal (启动时候会把hal所有相关拉起)
user system
group system
1.3、配置selinux权限
注意:selinux每个放的位置不同,但原理是相通的
- 在system/sepolicy/vendor下创建hal_led_default.te
//定义一个hal_led_default 进程
type hal_led_default, domain;
//hal_led_default_exec 是可执行文件、vendor文件、文件三种类型
type hal_led_default_exec, exec_type, vendor_file_type, file_type;
//初始化hal_led_default 进程
init_daemon_domain(hal_led_default)
- 在下system/sepolicy/vendor/file_contexts添加:
/(vendor|system/vendor)/bin/hw/vendor\.melrose\.hardware\.led@1\.0-service u:object_r:hal_led_default_exec:s0
如何查看该配置是否正确:
adb shell
cd vendor/bin
ls -AZ | grep -i "whoami" whoami: 替换为你要查看的service的名字
![](https://img.haomeiwen.com/i16293373/115254f91003e5cd.png)
这可确保为该可执行文件添加适当的标签,以便 SELinux在适当的域中运行相应服务。在添加完这些文件重新编译后,在开机时就可以启动该服务,但是不会注册成功,还需要配置hal。
1.4、配置hal服务
- 在system/sepolicy/public/attributes文件中,需要定义HAL的名称:
hal_attribute(led);
- 定义详细规则在system/sepolicy/public目录下创建hal_led.te:
# HwBinder IPC from client to server, and callbacks
binder_call(hal_led_client, hal_led_server)
binder_call(hal_led_server, hal_led_client)
add_hwservice(hal_led_server, hal_led_hwservice)
allow hal_led_client hal_led_hwservice:hwservice_manager find;
- 在system/sepolicy/private/service_contexts文件中添加:
vendor.melrose.hardware.led.ILed u:object_r:hal_led_hwservice:s0
//这个是aidl文件包名+类名,这里不能写错
vendor.melrose.hardware.led : 包名
ILed : 类名
如何查看配置是否正确
adb shell ps -Z | grep i "com.xiaomi.marekt"
![](https://img.haomeiwen.com/i16293373/d6b0fe236420c498.png)
1.5、添加seliunx权限
- 在system/sepolicy/public/service.te末尾添加
//给service_context中的led_service标签定义类型
type led_service, system_api_service, system_server_service, service_manager_type;
- 在system/sepolicy/private/system_server.te添加权限
hal_client_domain(system_server, hal_led)
2、aidl文件生成
2.1、bp文件编写
//注意:native 侧调用一定要使用ndk生成的库,千万不能用cpp生成的库。
//原因是两个是不同的binder,无法通信
aidl_interface {
name: "vendorabcd.hardware.sensorscalibrate",
vendor_available: true, //这里设置为true,因为是vendor目录下的模块
owner: "vendorabcd", //作为vendor模块,需要设定owner才可以通过编译
srcs: ["vendorabcd/hardware/sensorscalibrate/*.aidl"],
stability: "vintf", //标示此接口为Stable AIDL,必需
backend: {
cpp: {
enabled: false, //产生一个cpp backend,.cpp文件(unstable版)
},
java: {
sdk_version: "module_current", //产生一个java backend,
//默认enabled,用来在framework层使用此接口
},
ndk: {
enabled: true, //产生一个ndk backend,.cpp文件(stable版)
//要使用aidl通信,需要ndk后端
//不允许使用vndk,因为它不是stable的
},
},
}
2.2、配置 Framework Compatibility Matrix
在vendor/device/framework_compatibility_matrix.xml添加adil文件
<hal format="hidl" optional="true">
//vendorabcd.hardware.sensorscalibrate : adil包名
<name>vendorabcd.hardware.sensorscalibrate</name>
//生成的版本号
<version>1.0</version>
<interface>
//aidl类名
<name>ISensorsCalibrate</name>
//默认这样写
<instance>default</instance>
</interface>
</hal>
作用: java client可以调用到
2.3、 配置使AIDL编译
<manifest version="1.0" type="device">
<hal format="hidl" override="true">
//aidl的包名
<name>vendorabcd.hardware.sensorscalibrate</name>
//ISensorsCalibrate/default 在client中调用使用
<fqname>ISensorsCalibrate/default</fqname>
</hal>
</manifest>
//vendorabcd.hardware.sensorscalibrate.xml文件位置:vendor/etc/vintf/manifest/目录下可找到
三、案例调用
1、service.cpp文件
#include <string>
#include <thread>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "Service.h"
int main() {
ABinderProcess_startThreadPool();
std::shared_ptr<Service> securityCa = ::ndk::SharedRefBase::make<Service>();
const std::string instance = std::string() + Service::descriptor + "/default";
//在sp中添加service名字,这个一定要与client端相同
binder_status_t status = AServiceManager_addService(securityCa->asBinder().get(),
instance.c_str());
CHECK(status == STATUS_OK);
ALOGD("Start jsse service.");
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should never be reached
}
2、client.java
Service service = Service.Stub.asInterface(ServiceManager.checkService(service注册字符串);
四、流程梳理
每个公司流程不同,但是大致流程相似,我在这里整体梳理流程
1、定义一个hal服务,通过init.cpp加载来启动
- 定义rc文件,在bp中编译
2、配置hal服务的selinux相关
- 访问权限
- 添加标签为标签定义类型
- 配置hal
3、编译aidl文件
- 在framework_compatibility_matrix配置客户端
- 配置service.xml文件,在bp中编译
网友评论