程序員自我修養(yǎng)之HAL層與應(yīng)用框架通信之HIDL

一勘纯、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

671be4cc585db93a51ba0c811f8aaa4.png

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ī)則如下圖:


image.png

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的名字
a7a0b0b00e43fbc97e1ff687ff40126.png
這可確保為該可執(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"
52a82b0d1d249b1f721b9a54b2f0996.png

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)限

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萧芙,一起剝皮案震驚了整個濱河市给梅,隨后出現(xiàn)的幾起案子乙嘀,更是在濱河造成了極大的恐慌,老刑警劉巖破喻,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虎谢,死亡現(xiàn)場離奇詭異,居然都是意外死亡曹质,警方通過查閱死者的電腦和手機婴噩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羽德,“玉大人几莽,你說我怎么就攤上這事≌玻” “怎么了章蚣?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長姨夹。 經(jīng)常有香客問我纤垂,道長,這世上最難降的妖魔是什么磷账? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任峭沦,我火速辦了婚禮,結(jié)果婚禮上逃糟,老公的妹妹穿的比我還像新娘吼鱼。我一直安慰自己,他們只是感情好绰咽,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布菇肃。 她就那樣靜靜地躺著,像睡著了一般取募。 火紅的嫁衣襯著肌膚如雪琐谤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天矛辕,我揣著相機與錄音笑跛,去河邊找鬼。 笑死聊品,一個胖子當著我的面吹牛飞蹂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翻屈,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼陈哑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惊窖,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刽宪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后界酒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體圣拄,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年毁欣,在試婚紗的時候發(fā)現(xiàn)自己被綠了庇谆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡凭疮,死狀恐怖饭耳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情执解,我是刑警寧澤寞肖,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站衰腌,受9級特大地震影響新蟆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜桶唐,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一栅葡、第九天 我趴在偏房一處隱蔽的房頂上張望茉兰。 院中可真熱鬧尤泽,春花似錦、人聲如沸规脸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莫鸭。三九已至闹丐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間被因,已是汗流浹背卿拴。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留梨与,地道東北人堕花。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像粥鞋,于是被迫代替她去往敵國和親缘挽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容