一勘纯、HIDL
1截碴、什么是HIDL
HIDL(HAL Interface Definition Language)是用于指定HAL和其用戶之間的接口的一種接口描述語言(IDL)凝颇,AIDL是架構(gòu)在Android binder之上玩焰,用來定義Android基于Binder通信的Client與Service之間的接口奶甘;而HIDL定義的則是Android Framework與Android HAL實現(xiàn)之間的接口。
2砂客、HIDL底層實現(xiàn)原理
使用 HDL 創(chuàng)建的 HAL 稱為綁定式 HAL,使用 Binder 進程間通信 (IPC) 調(diào)用與其他架構(gòu)層進行通信
3呵恢、binder的種類
參考鏈接:
https://source.android.google.cn/docs/core/architecture/hidl/binder-ipc?hl=zh-cn
3.1鞠值、binder種類介紹
-
3.1 dev/binder
這個是我們最熟悉的Binder,App開發(fā)中渗钉,ActivityManagerService用的都是這個彤恶,Java繼承Binder,C++中繼承Bbbinder鳄橘,然后通過servicemanager進程注冊實名Binder粤剧,然后通過已經(jīng)創(chuàng)建好的Binder接口傳遞匿名Binder對象,拿到BinderProxy或者BpBinder以后挥唠,就可以Binder通信了抵恋。
-
3.2 dev/vndbinder
其實dev/vndbinde和dev/binder使用方式基本一樣而且是共用一套Binder SDK,也是Java繼承Binder宝磨,C++中繼承Bbbinder弧关,但是通過vndservicemanager進程注冊實名Binder盅安,然后通過已經(jīng)創(chuàng)建好的Binder接口傳遞匿名Binder對象,拿到BinderProxy或者BpBinder以后世囊,就可以Binder通信了别瞭。如何在使用同一套Binder SDK的代碼,最后訪問的設(shè)備節(jié)點變成dev/vndbinder株憾,servicemanager變成vndservicemanager蝙寨。
dev/binder和dev/vndbinder無法在一個進程中同時使用,原因兩類進程的任意一個進程無法同時使用dev/binder和dev/vndbinder,這一點不單是android官方約定嗤瞎,也是目前android binder sdk的限制墙歪,因為兩者都是共用Binder SDK,所以只能指定一個設(shè)備節(jié)點贝奇,要么dev/binder虹菲,要么dev/vndbinder
-
3.3 、dev/hwbinder
解決無法可以在一個進程同時使用掉瞳,強制由所有供應(yīng)商按照android官方定義的hal接口來實現(xiàn)毕源,由HIDL方案去實現(xiàn)
4、舉例說明三種binder
假如手機中有如下3類進程
4.1陕习、應(yīng)用進程:
Camera APP
手電筒 APP
4.2霎褐、框架進程:
System Server進程
4.3、供應(yīng)商進程:
Camera HAL進程
Light HAL進程
這些進程之間需要使用Binder機制跨進程通信该镣,Android提供了三個Binder設(shè)備節(jié)點dev/binder冻璃,dev/hwbinder,dev/vndbinder拌牲,也就是Android系統(tǒng)同時提供了三個獨立運行的Binder通信模塊俱饿,Android團隊規(guī)定每類進程使用的這三個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)用
......
注意:主要是強調(diào)應(yīng)用層與vendor/bin和system/bin之間區(qū)別,這個坑對于我這小白掉進去還砸了一個大坑
二土居、HAL服務(wù)創(chuàng)建與HIDL的調(diào)用
1枣购、hal層服務(wù)啟動
參考鏈接: 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", //啟動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調(diào)用LoadBootScripts方法去啟動對應(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目錄下即可查看你寫的啟動文件
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所有相關(guān)拉起)
user system
group system
1.3棉圈、配置selinux權(quán)限
注意:selinux每個放的位置不同,但原理是相通的
- 在system/sepolicy/vendor下創(chuàng)建hal_led_default.te
//定義一個hal_led_default 進程
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 進程
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í)行文件添加適當?shù)臉撕灒员?SELinux在適當?shù)挠蛑羞\行相應(yīng)服務(wù)吁系。在添加完這些文件重新編譯后德召,在開機時就可以啟動該服務(wù)白魂,但是不會注冊成功,還需要配置hal上岗。
1.4福荸、配置hal服務(wù)
- 在system/sepolicy/public/attributes文件中,需要定義HAL的名稱:
hal_attribute(led);
- 定義詳細規(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
//這個是aidl文件包名+類名,這里不能寫錯
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標簽定義類型
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生成的庫呆瞻,千萬不能用cpp生成的庫台夺。
//原因是兩個是不同的binder,無法通信
aidl_interface {
name: "vendorabcd.hardware.sensorscalibrate",
vendor_available: true, //這里設(shè)置為true栋烤,因為是vendor目錄下的模塊
owner: "vendorabcd", //作為vendor模塊谒养,需要設(shè)定owner才可以通過編譯
srcs: ["vendorabcd/hardware/sensorscalibrate/*.aidl"],
stability: "vintf", //標示此接口為Stable AIDL挺狰,必需
backend: {
cpp: {
enabled: false, //產(chǎn)生一個cpp backend明郭,.cpp文件(unstable版)
},
java: {
sdk_version: "module_current", //產(chǎn)生一個java backend,
//默認enabled丰泊,用來在framework層使用此接口
},
ndk: {
enabled: true, //產(chǎn)生一個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可以調(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名字,這個一定要與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服務(wù),通過init.cpp加載來啟動
- 定義rc文件滴劲,在bp中編譯
2攻晒、配置hal服務(wù)的selinux相關(guān)
- 訪問權(quán)限
- 添加標簽為標簽定義類型
- 配置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在運行時通過selinux的接口動態(tài)檢查權(quán)限