一、HIDL
1、什么是HIDL
HIDL(HAL Interface Definition Language)是用于指定HAL和其用戶之間的接口的一種接口描述語(yǔ)言(IDL),AIDL是架構(gòu)在Android binder之上,用來(lái)定義Android基于Binder通信的Client與Service之間的接口;而HIDL定義的則是Android Framework與Android HAL實(shí)現(xiàn)之間的接口。
2、HIDL底層實(shí)現(xiàn)原理
使用 HDL 創(chuàng)建的 HAL 稱為綁定式 HAL,使用 Binder 進(jìn)程間通信 (IPC) 調(diào)用與其他架構(gòu)層進(jìn)行通信
3、binder的種類
參考鏈接:
https://source.android.google.cn/docs/core/architecture/hidl/binder-ipc?hl=zh-cn

3.1、binder種類介紹
-
3.1 dev/binder
這個(gè)是我們最熟悉的Binder,App開(kāi)發(fā)中,ActivityManagerService用的都是這個(gè),Java繼承Binder,C++中繼承Bbbinder,然后通過(guò)servicemanager進(jìn)程注冊(cè)實(shí)名Binder,然后通過(guò)已經(jīng)創(chuàng)建好的Binder接口傳遞匿名Binder對(duì)象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。
-
3.2 dev/vndbinder
其實(shí)dev/vndbinde和dev/binder使用方式基本一樣而且是共用一套Binder SDK,也是Java繼承Binder,C++中繼承Bbbinder,但是通過(guò)vndservicemanager進(jìn)程注冊(cè)實(shí)名Binder,然后通過(guò)已經(jīng)創(chuàng)建好的Binder接口傳遞匿名Binder對(duì)象,拿到BinderProxy或者BpBinder以后,就可以Binder通信了。如何在使用同一套Binder SDK的代碼,最后訪問(wèn)的設(shè)備節(jié)點(diǎn)變成dev/vndbinder,servicemanager變成vndservicemanager。
dev/binder和dev/vndbinder無(wú)法在一個(gè)進(jìn)程中同時(shí)使用,原因兩類進(jìn)程的任意一個(gè)進(jìn)程無(wú)法同時(shí)使用dev/binder和dev/vndbinder,這一點(diǎn)不單是android官方約定,也是目前android binder sdk的限制,因?yàn)閮烧叨际枪灿肂inder SDK,所以只能指定一個(gè)設(shè)備節(jié)點(diǎn),要么dev/binder,要么dev/vndbinder
-
3.3 、dev/hwbinder
解決無(wú)法可以在一個(gè)進(jìn)程同時(shí)使用,強(qiáng)制由所有供應(yīng)商按照android官方定義的hal接口來(lái)實(shí)現(xiàn),由HIDL方案去實(shí)現(xiàn)
4、舉例說(shuō)明三種binder
假如手機(jī)中有如下3類進(jìn)程
4.1、應(yīng)用進(jìn)程:
Camera APP
手電筒 APP
4.2、框架進(jìn)程:
System Server進(jìn)程
4.3、供應(yīng)商進(jìn)程:
Camera HAL進(jìn)程
Light HAL進(jìn)程
這些進(jìn)程之間需要使用Binder機(jī)制跨進(jìn)程通信,Android提供了三個(gè)Binder設(shè)備節(jié)點(diǎn)dev/binder,dev/hwbinder,dev/vndbinder,也就是Android系統(tǒng)同時(shí)提供了三個(gè)獨(dú)立運(yùn)行的Binder通信模塊,Android團(tuán)隊(duì)規(guī)定每類進(jìn)程使用的這三個(gè)Binder通信模塊的規(guī)則如下圖:

5、aidl使用和hidl使用范疇
5.1、aidl使用范疇
- 適用于應(yīng)用層與應(yīng)用層之間調(diào)用
- 適用于應(yīng)用層與java framework之間調(diào)用
- 適用于應(yīng)用層與native framework(僅限于system/bin)之間調(diào)用
.......
5.2、hidl使用范疇
- 適用于native framework之間調(diào)用
- 適用于應(yīng)用層與native framework(僅限于vendor/bin)之間調(diào)用
......
注意:主要是強(qiáng)調(diào)應(yīng)用層與vendor/bin和system/bin之間區(qū)別,這個(gè)坑對(duì)于我這小白掉進(jìn)去還砸了一個(gè)大坑
二、HAL服務(wù)創(chuàng)建與HIDL的調(diào)用
1、hal層服務(wù)啟動(dòng)
參考鏈接: https://android.googlesource.com/platform/system/core/+/master/init/README.md
本次案例是 :app調(diào)用/vendor/bin/hw 的service
1.1、service的編寫
cc_binary {
name: "vendor.melrose.hardware.led@1.0-service", //啟動(dòng)service的名字
proprietary: true, (安裝在/vendor/bin)
relative_install_path: "hw", //最終安裝在放在/vendor/bin/hw目錄下
init_rc: ["vendor.melrose.hardware.led@1.0-service.rc"], //啟動(dòng)文件配置
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、配置啟動(dòng)service文件.rc
手機(jī)開(kāi)機(jī)會(huì)通過(guò)init.cpp調(diào)用LoadBootScripts方法去啟動(dòng)對(duì)應(yīng)的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目錄下即可查看你寫的啟動(dòng)文件
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 (啟動(dòng)時(shí)候會(huì)把hal所有相關(guān)拉起)
user system
group system
1.3、配置selinux權(quán)限
注意:selinux每個(gè)放的位置不同,但原理是相通的
- 在system/sepolicy/vendor下創(chuàng)建hal_led_default.te
//定義一個(gè)hal_led_default 進(jìn)程
type hal_led_default, domain;
//hal_led_default_exec 是可執(zhí)行文件、vendor文件、文件三種類型
type hal_led_default_exec, exec_type, vendor_file_type, file_type;
//初始化hal_led_default 進(jìn)程
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的名字

這可確保為該可執(zhí)行文件添加適當(dāng)?shù)臉?biāo)簽,以便 SELinux在適當(dāng)?shù)挠蛑羞\(yùn)行相應(yīng)服務(wù)。在添加完這些文件重新編譯后,在開(kāi)機(jī)時(shí)就可以啟動(dòng)該服務(wù),但是不會(huì)注冊(cè)成功,還需要配置hal。
1.4、配置hal服務(wù)
- 在system/sepolicy/public/attributes文件中,需要定義HAL的名稱:
hal_attribute(led);
- 定義詳細(xì)規(guī)則在system/sepolicy/public目錄下創(chuàng)建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
//這個(gè)是aidl文件包名+類名,這里不能寫錯(cuò)
vendor.melrose.hardware.led : 包名
ILed : 類名
如何查看配置是否正確
adb shell ps -Z | grep i "com.xiaomi.marekt"

1.5、添加seliunx權(quán)限
- 在system/sepolicy/public/service.te末尾添加
//給service_context中的led_service標(biāo)簽定義類型
type led_service, system_api_service, system_server_service, service_manager_type;
- 在system/sepolicy/private/system_server.te添加權(quán)限
hal_client_domain(system_server, hal_led)
2、aidl文件生成
2.1、bp文件編寫
//注意:native 側(cè)調(diào)用一定要使用ndk生成的庫(kù),千萬(wàn)不能用cpp生成的庫(kù)。
//原因是兩個(gè)是不同的binder,無(wú)法通信
aidl_interface {
name: "vendorabcd.hardware.sensorscalibrate",
vendor_available: true, //這里設(shè)置為true,因?yàn)槭莢endor目錄下的模塊
owner: "vendorabcd", //作為vendor模塊,需要設(shè)定owner才可以通過(guò)編譯
srcs: ["vendorabcd/hardware/sensorscalibrate/*.aidl"],
stability: "vintf", //標(biāo)示此接口為Stable AIDL,必需
backend: {
cpp: {
enabled: false, //產(chǎn)生一個(gè)cpp backend,.cpp文件(unstable版)
},
java: {
sdk_version: "module_current", //產(chǎn)生一個(gè)java backend,
//默認(rèn)enabled,用來(lái)在framework層使用此接口
},
ndk: {
enabled: true, //產(chǎn)生一個(gè)ndk backend,.cpp文件(stable版)
//要使用aidl通信,需要ndk后端
//不允許使用vndk,因?yàn)樗皇莝table的
},
},
}
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>
//生成的版本號(hào)
<version>1.0</version>
<interface>
//aidl類名
<name>ISensorsCalibrate</name>
//默認(rèn)這樣寫
<instance>default</instance>
</interface>
</hal>
作用: java client可以調(diào)用到
2.3、 配置使AIDL編譯
<manifest version="1.0" type="device">
<hal format="hidl" override="true">
//aidl的包名
<name>vendorabcd.hardware.sensorscalibrate</name>
//ISensorsCalibrate/default 在client中調(diào)用使用
<fqname>ISensorsCalibrate/default</fqname>
</hal>
</manifest>
//vendorabcd.hardware.sensorscalibrate.xml文件位置:vendor/etc/vintf/manifest/目錄下可找到
三、案例調(diào)用
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名字,這個(gè)一定要與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注冊(cè)字符串);
四、流程梳理
每個(gè)公司流程不同,但是大致流程相似,我在這里整體梳理流程
1、定義一個(gè)hal服務(wù),通過(guò)init.cpp加載來(lái)啟動(dòng)
- 定義rc文件,在bp中編譯
2、配置hal服務(wù)的selinux相關(guān)
- 訪問(wèn)權(quán)限
- 添加標(biāo)簽為標(biāo)簽定義類型
- 配置hal
3、編譯aidl文件
- 在framework_compatibility_matrix配置客戶端
- 配置service.xml文件,在bp中編譯
4、調(diào)用方式
file_context和service_context的作用
關(guān)聯(lián)了android系統(tǒng)的服務(wù)與type, 文件的內(nèi)容由service manager在運(yùn)行時(shí)通過(guò)selinux的接口動(dòng)態(tài)檢查權(quán)限