AndroidQ 打通應(yīng)用層到HAL層—(HAL模塊實(shí)現(xiàn))這篇文章中我們已經(jīng)實(shí)現(xiàn)了自己的HAL,本篇我們實(shí)現(xiàn)一個(gè)HIDL服務(wù),通過這個(gè)服務(wù)來調(diào)用HAL模塊的函數(shù)
什么是HIDL
HIDL 全稱為HAL interface definition language(發(fā)音為“hide-l”)是用于指定 HAL 和其用戶之間的接口的一種接口描述語言 (IDL),Android O開始引入了HIDL這個(gè)概念。
HIDL和應(yīng)用層AIDL差不多,AIDL常用于連接App和Framework,HIDL則是用來連接Framework和HAL,AIDL使用Binder通信,HIDL則使用HwBinder通信,他們都是通過Binder驅(qū)動(dòng)完成通信,只不過兩個(gè)Binder域不一樣
為什么需要HIDL
目前Android系統(tǒng)生態(tài)是幾乎每年google都會(huì)出一個(gè)Android大版本,而普通手機(jī)用戶一部手機(jī)一般要用兩三年,所以你會(huì)發(fā)現(xiàn)盡管Android系統(tǒng)已經(jīng)升級到了10,馬上11出來了,然后還是有很多用戶依然使用的是Android 5,6,7等版本。
對普通用戶來說如果不更換手機(jī)就很難跟上Android版本,這是因?yàn)镺EM廠商在同一設(shè)備上進(jìn)行系統(tǒng)升級需要花費(fèi)時(shí)間金錢成本很高,導(dǎo)致他們不愿意升級,成本高的原因是Android O之前Android Framework的升級需要OEM將HAL也進(jìn)行對應(yīng)升級,F(xiàn)ramework和HAL是一起被編譯成system.img,它們存在高耦合。
針對這種情況google在Android O中引入了Treble計(jì)劃,Treble的目的就是解耦Framework和HAL,就是通過HIDL來實(shí)現(xiàn),F(xiàn)ramework不再直接調(diào)用HAL,而是通過HIDL來間接使用HAL模塊,每個(gè)HAL模塊都可以對應(yīng)一個(gè)HIDL服務(wù),F(xiàn)ramework層通過HwBinder創(chuàng)建HIDL服務(wù)。
通過HIDL服務(wù)來獲取HAL相關(guān)模塊繼而打開HAL下的設(shè)備,而最終HAL也從system.img中分離,被編進(jìn)一個(gè)單獨(dú)的分區(qū)vendor.img,從而簡化了Android系統(tǒng)升級的影響與難度。
HIDL的使用
HIDL可以分為:HIDL C++(C++實(shí)現(xiàn))、HIDL Java(Java 實(shí)現(xiàn)),并且還主要分為直通式和綁定式,本篇文章使用的C++和直通式的HIDL,HIDL用起來非常簡單,AOSP的hardware/interfaces/目錄下有很多的HIDL,我們仿照其他HIDL創(chuàng)建自己的HIDL目錄:hardware/interfaces/hello_hidl/1.0
并在此目錄下創(chuàng)建一個(gè)IHello.hal文件:
packageandroid.hardware.hello_hidl@1.0; interfaceIHello{ addition_hidl(uint32_ta,uint32_tb)generates(uint32_ttotal); };
這個(gè)文件定義了一個(gè)addition_hidl函數(shù),這個(gè)函數(shù)用來調(diào)用HAL的加法函數(shù)
然后就可以使用Android提供的工具h(yuǎn)idl-gen來生成HIDL框架,執(zhí)行如下命令:
PACKAGE=android.hardware.hello_hidl@1.0 LOC=hardware/interfaces/hello_hidl/1.0/default/ hidl-gen-o$LOC-Lc++-impl-randroid.hardware:hardware/interfaces-randroid.hidl:system/libhidl/transport$PACKAGE hidl-gen-o$LOC-Landroidbp-impl-randroid.hardware:hardware/interfaces-randroid.hidl:system/libhidl/transport$PACKAGE
執(zhí)行命令成功之后我們會(huì)發(fā)現(xiàn)hardware/interfaces/hello_hidl/1.0下多了一個(gè)default目錄,進(jìn)入default目錄,里面有三個(gè)文件Android.bp,Hello.cpp,Hello.h
在這里插入圖片描述
之后再在執(zhí)行./hardware/interfaces/update-makefiles.sh這個(gè)命令,update-makefiles.sh這個(gè)腳本目的是為HIDL生成對應(yīng)Android.bp文件
最后目錄結(jié)構(gòu)為:
在這里插入圖片描述
接著我們還需要在default目錄下增加一個(gè)空文件service.cpp,用作注冊HIDL服務(wù),我們采用直通式的HIDL,所以service.cpp的內(nèi)容為:
#include#include //GeneratedHIDLfiles usingandroid::IHello; usingandroid::defaultPassthroughServiceImplementation; intmain(){ returndefaultPassthroughServiceImplementation (); }
defaultPassthroughServiceImplementation函數(shù)最終會(huì)向HwServiceManager注冊HIDL服務(wù)
接著我們來看看之前生成的文件,首先看Hello.h
//FIXME:yourfilelicenseifyouhaveone #pragmaonce #include#include #include namespaceandroid{ namespacehardware{ namespacehello_hidl{ namespaceV1_0{ namespaceimplementation{ using::hidl_array; using::hidl_memory; using::hidl_string; using::hidl_vec; using::Return; using::Void; using::sp; structHello:publicIHello{ //Methodsfrom::IHellofollow. Return addition_hidl(uint32_ta,uint32_tb)override; //Methodsfrom::IBasefollow. }; //FIXME:mostlikelydelete,thisisonlyforpassthroughimplementations //去掉注釋 extern"C"IHello*HIDL_FETCH_IHello(constchar*name); }//namespaceimplementation }//namespaceV1_0 }//namespacehello_hidl }//namespacehardware }//namespaceandroid
系統(tǒng)自動(dòng)生成了Hello結(jié)構(gòu)體(當(dāng)然也可以自己改為class),繼承IHello接口,addition_hidl函數(shù)就需要在Hello.cpp中去實(shí)現(xiàn)了,因?yàn)槲覀儾捎弥蓖ㄊ紿IDL,所以需要將// extern “C” IHello* HIDL_FETCH_IHello(const char* name);的注釋去掉
接著來看看Hello.cpp:
//FIXME:yourfilelicenseifyouhaveone #include"Hello.h" #includenamespaceandroid{ namespacehardware{ namespacehello_hidl{ namespaceV1_0{ namespaceimplementation{ //Methodsfrom::IHellofollow. Return Hello::addition_hidl(uint32_ta,uint32_tb){ //TODOimplement ALOGE("hello_hidlserviceisinitsuccess....a:%d,b:%d",a,b); returnuint32_t{}; } //Methodsfrom::IBasefollow. IHello*HIDL_FETCH_IHello(constchar*/*name*/){ returnnewHello(); } }//namespaceimplementation }//namespaceV1_0 }//namespacehello_hidl }//namespacehardware }//namespaceandroid
同樣需要去掉HIDL_FETCH_IHello函數(shù)的注釋,采用直通式HIDL時(shí),通過前面service.cpp中的defaultPassthroughServiceImplementation函數(shù)注冊HIDL服務(wù)時(shí),內(nèi)部原理就是通過“HIDL_FETCH_”字串拼接defaultPassthroughServiceImplementation傳遞的IHello,找到HIDL_FETCH_IHello函數(shù)并獲取IHello對象,我們可以看到HIDL_FETCH_IHello初始代碼就是創(chuàng)建了一個(gè)Hello對象
在接著看default目錄下的Android.bp:
cc_library_shared{ name:"android.hardware.hello_hidl@1.0-impl", relative_install_path:"hw", proprietary:true, srcs:[ "Hello.cpp", ], shared_libs:[ "libhidlbase", "libhidltransport", "libutils", "android.hardware.hello_hidl@1.0", "liblog", "libutils", ], }
這個(gè)Android.bp會(huì)將Hello這個(gè)HIDL服務(wù)編譯成一個(gè)android.hardware.hello_hidl@1.0-impl.so,它還依賴一個(gè)android.hardware.hello_hidl@1.0.so,這個(gè)so哪來的呢?
再接著看1.0目錄下的Android.bp:
//Thisfileisautogeneratedbyhidl-gen-Landroidbp. hidl_interface{ name:"android.hardware.hello_hidl@1.0", root:"android.hardware", vndk:{ enabled:true, }, srcs:[ "IHello.hal", ], interfaces:[ "android.hidl.base@1.0", ], gen_java:true, }
這個(gè)Android.bp會(huì)將hardware/interfaces/hello_hidl/1.0這個(gè)HIDL編譯成一個(gè)android.hardware.hello_hidl@1.0.so,到這里我們發(fā)現(xiàn)service.cpp沒有用到,所以我們還需要修改default目錄下的Android.bp:
//FIXME:yourfilelicenseifyouhaveone cc_library_shared{ name:"android.hardware.hello_hidl@1.0-impl", relative_install_path:"hw", proprietary:true, srcs:[ "Hello.cpp", ], shared_libs:[ "libhidlbase", "libhidltransport", "libutils", "liblog", "libhardware", "android.hardware.hello_hidl@1.0", "liblog", "libutils", ], } cc_binary{ name:"android.hardware.hello_hidl@1.0-service", defaults:["hidl_defaults"], relative_install_path:"hw", vendor:true, srcs:["service.cpp"], shared_libs:[ "android.hardware.hello_hidl@1.0", "libhardware", "libhidlbase", "libhidltransport", "libutils", "liblog", ], }
新增加對service.cpp的編譯,我們將service.cpp編譯成一個(gè)二進(jìn)制可執(zhí)行文件android.hardware.hello_hidl@1.0-service.so,用來啟動(dòng)HIDL服務(wù),好了,最終我們這個(gè)HIDL會(huì)編譯出來如下三個(gè)so:
android.hardware.hello_hidl@1.0-impl.so
android.hardware.hello_hidl@1.0.so
android.hardware.hello_hidl@1.0-service.so
還有一點(diǎn)需要注意的是,這個(gè)HIDL想要被Framework獲取使用還需要在manifest.xml中注冊,
manifest.xml在手機(jī)vendor/etc/vintf/manifest.xml下,我們將這個(gè)文件pull出來然后添加如下代碼:
android.hardware.hello_hidl hwbinder 1.0 IHello default @1.0::IHello/default
然后在Hello.cpp中添加一行l(wèi)og,之后進(jìn)行編譯
IHello*HIDL_FETCH_IHello(constchar*/*name*/){ ALOGE("hello_hidlserviceisinitsuccess...."); returnnewHello(); }
執(zhí)行mmm hardware/interfaces/hello_hidl/1.0/
在這里插入圖片描述
編譯成功后我們將生成的三個(gè)so分別push到手機(jī)vendor/lib64/hw/,vendor/lib64/,vendor/bin/hw/目錄下
adb push vendor/lib64/hw/android.hardware.hello_hidl@1.0-impl.so vendor/lib64/hw/
adb push system/lib64/android.hardware.hello_hidl@1.0.so vendor/lib64/
adb push vendor/bin/hw/android.hardware.hello_hidl@1.0-service vendor/bin/hw/
接著我們到手機(jī)vendor/bin/hw/目錄下去執(zhí)行android.hardware.hello_hidl@1.0-service這個(gè)二進(jìn)制可執(zhí)行文件,這個(gè)文件就會(huì)執(zhí)行service.cpp的代碼,調(diào)用defaultPassthroughServiceImplementation注冊我們的HIDL服務(wù)
在這里插入圖片描述
再看看log輸出:
在這里插入圖片描述
在執(zhí)行android.hardware.hello_hidl@1.0-service時(shí)就會(huì)輸入這句log,代表我們這個(gè)HIDL服務(wù)已經(jīng)實(shí)現(xiàn),其實(shí)通常的HIDL服務(wù)都是通過rc文件來開機(jī)啟動(dòng)的,我這里為了方便演示就沒有寫
再執(zhí)行adb shell ps -A|grep -i --color "hello_hidl"命令看下這個(gè)服務(wù)狀態(tài)
我們發(fā)現(xiàn)HIDL服務(wù)啟動(dòng)之后就會(huì)一直在后臺,這個(gè)其實(shí)和AMS,WMS這種服務(wù)是類似的,啟動(dòng)之后在后臺會(huì)等待client端訪問
在這里插入圖片描述
HIDL這個(gè)服務(wù)已經(jīng)能夠正常啟動(dòng)了,接著寫一個(gè)測試程序看能否獲取這個(gè)服務(wù),并且調(diào)用該服務(wù)的函數(shù),我在Hello.cpp的addition_hidl函數(shù)中添加了一句log:
ReturnHello::addition_hidl(uint32_ta,uint32_tb){ //TODOimplement ALOGD("dongjiao...Hello::addition_hidla=%d,b=%d",a,b); returnuint32_t{}; }
測試程序?qū)懺趆ardware/interfaces/hello_hidl/1.0/default目錄下:
在這里插入圖片描述
Hello_hidl_test.cpp:
#include#include #include usingandroid::sp; usingandroid::IHello; usingandroid::Return; intmain(){ android::sp hw_device=IHello::getService(); if(hw_device==nullptr){ ALOGD("dongjiao...failedtogethello-hidl"); return-1; } ALOGD("dongjiao...successtogethello-hidl...."); Return total=hw_device->addition_hidl(3,4); return0; }
測試程序代碼也比較簡單,獲取IHello的服務(wù),然后調(diào)用addition_hidl函數(shù)
看一下Android.bp:
cc_binary{ name:"Hello_hidl_test", srcs:["Hello_hidl_test.cpp"], shared_libs:[ "liblog", "android.hardware.hello_hidl@1.0", "libhidlbase", "libhidltransport", "libhwbinder", "libutils", ], }
我們再編譯這個(gè)測試程序,它會(huì)被編譯成一個(gè)可執(zhí)行二進(jìn)制文件Hello_hidl_test
編譯命令:
mmm hardware/interfaces/hello_hidl/1.0/default/test/
在這里插入圖片描述
編譯成功了,將這個(gè)可執(zhí)行文件push到手機(jī)/system/bin/目錄下
在執(zhí)行Hello_hidl_test之前別忘了把HIDL服務(wù)啟動(dòng)起來
在這里插入圖片描述
接著執(zhí)行Hello_hidl_test
在這里插入圖片描述
然后看log輸出
在這里插入圖片描述
可以看到成功了,成功獲取到了HIDL服務(wù)并且調(diào)用了該服務(wù)的addition_hidl函數(shù),將我們的參數(shù)傳遞了過去,實(shí)際開發(fā)中就可以在獲取HIDL服務(wù)時(shí)打開HAL模塊,然后可以直接調(diào)用HAL的函數(shù)。 上一篇文章其實(shí)也寫了測試程序測自定義的HAL模塊,我們只需要將上一篇文章中的測試程序中的代碼copy到HIDL初始化代碼中就能夠調(diào)用HAL的那個(gè)加法函數(shù)了,具體就不測試了。
到這里HIDL服務(wù)已經(jīng)成功實(shí)現(xiàn)并且能夠正常使用,HIDL這個(gè)框架用起來還是比較簡單的,大部分代碼都是通過工具生成的。
審核編輯:湯梓紅
-
Android
+關(guān)注
關(guān)注
12文章
3917瀏覽量
127037 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4284瀏覽量
62325 -
C++
+關(guān)注
關(guān)注
21文章
2102瀏覽量
73453 -
應(yīng)用層
+關(guān)注
關(guān)注
0文章
46瀏覽量
11487 -
HAL
+關(guān)注
關(guān)注
2文章
69瀏覽量
12576
原文標(biāo)題:Android Q打通應(yīng)用層到HAL層(HIDL服務(wù)實(shí)現(xiàn))
文章出處:【微信號:哆啦安全,微信公眾號:哆啦安全】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論