Android O 前期预研之二:HIDL相关介绍
在上一篇博客里,大致介紹了下Android O 中treble計劃的一些背景與相關基本架構(gòu),這一篇中跟大家一起來探討下HIDL相關的內(nèi)容。
Android HAL類型?
在此之前的ANDROID版本當中Android HAL沒有什么特殊的特殊的,也么有什么分類,但是從android 8.0開始,Android重構(gòu)了HAL與Android FW之間的聯(lián)系結(jié)構(gòu),所以Android HAL會被區(qū)分成以下2種類型:?
1,Binderized HALs,從名字上應該是指Binder化的HAL,對Android 比較熟悉的同學應該對binder這個東西很熟悉,我們是不是可以大膽猜猜下Android 8.0里的HAL是不是都是binder化了?也就是說HAL都被寫成了binder service了?Android FW都是binder client?后續(xù)我們研究研究再來看看我們的猜測是不是正確的。?
2,Passthrough HALs,從google的官方介紹來說,這個是對原先HAL的包裝,但是最終的binder service 跟binder client都是活在同一個進程當中。這個應該是對老版本HAL的兼容。?
3,Same-Process HALs,由于某些性能的因素,這些HALs必須運行在Android Framework 所在的進程當中。
按照google的要求,新設計生產(chǎn)的Android O設備,必須而且只能支持 Binderized HALs,而老版本的設備升級到Android O可以支持 Passthrough HALs,但是有些HAL也必須修改成 Binderized HALs。?
以下HAL可以根據(jù)是升級設備或者新設備自由選擇:?
以下跟graphic相關的HAL因為涉及到性能問題,只能在同一個進程當中運行:?
HIDL的相關介紹?
HIDL的全稱是HAL interface definition language(硬件抽象層接口定義語言),在此之前Android 有AIDL,架構(gòu)在Android binder 之上,用來定義Android 基于Binder通信的Client 與Service之間的接口。HIDL也是類似的作用,只不過定義的是Android Framework與Android HAL實現(xiàn)之間的接口。
在AIDL機制中Android 會提供一系列工具會將用戶定義的*.aidl文件編譯生成Client端代碼與Service端代碼,用戶僅僅 需要1)在Service端實現(xiàn)所需要實現(xiàn)的接口。2)在Client端調(diào)用相關接口。基于Binder機制,在Clinet端的調(diào)用會自動通過binder驅(qū)動跨進程到service進程當中。
而在HIDL里,與AIDL比較類似,底層也是基于binder機制。但是也有稍微不一樣的地方。為了支持HIDL,Android 對BInder做了一定程度的修改。
接下來,我們來研究下HIDL的語法,以及通過一個實際的例子來真實感受下HIDL。
HIDL的基本語法:
1)定義接口:
package android.hardware.tests.foo@1.0;interface ISimpleTest {enum SomeBaseEnum : uint8_t {bar = 66};struct Goober {int32_t q;string name;string address;};getCookie() generates (int32_t cookie);customVecInt() generates (vec<int32_t> chain);customVecStr() generates (vec<string> chain);mystr() generates (string str);myhandle() generates (handle str);};- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
在這里,我們定義一個新的HIDL接口,取名叫做 ISimpleTest, 從語法上看有點像JAVA的語法。interface是關鍵字,代表要創(chuàng)建一個HIDL的接口。我們把上述接口保存成 IsimpleTest.hal文件存放在hardware/interfaces/tests/foo/1.0/ISimpleTest.hal,其實我們完全可以新建一個新目錄,使用一個新的package名,而不使用android.hardware.tests.foo,
2)定義成員:?
如上所示,HIDL當中可以像JAVA/C代碼一樣,很容易定義出聯(lián)合體/結(jié)構(gòu)體變量。
3)定義成員函數(shù):?
如上所示,定義的都是無參函數(shù),如果需要定義一個帶有參數(shù)的函數(shù),可以寫成doThis(float param);,這就代表是一個有參數(shù),但是無返回值的函數(shù)。
而以上定義的 getCookie() generates (int32_t cookie); 其含義為:函數(shù)名為 getCookie,無參數(shù)傳入,函數(shù)的返回值為一個int32_t 類型。
HIDL編譯?
在根目錄執(zhí)行./hardware/interfaces/update-makefiles.sh,我們能夠看到會把Android 在hardware/interfaces下的所有package都會更新一遍,我們看下hardware/interfaces/tests/foo/1.0/Android.bp,在Android O當中,貌似使用了 Android.bp來替代Android.mk來作為編譯管理工具。至于Android.bp的東西可以后續(xù)在研究,這里我們只關注于HIDL。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
我們可以看到”ISimpleTest.hal”,已經(jīng)被加進編譯文件列表當中。
而在生成的C++文件:
16 genrule {17 name: "android.hardware.tests.foo@1.0_genc++",18 tools: ["hidl-gen"],19 cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.foo@1.0",20 srcs: [21 ":android.hardware.tests.foo@1.0_hal",22 ],23 out: [24 "android/hardware/tests/foo/1.0/types.cpp",25 "android/hardware/tests/foo/1.0/FooAll.cpp",26 "android/hardware/tests/foo/1.0/FooCallbackAll.cpp",27 "android/hardware/tests/foo/1.0/MyTypesAll.cpp",28 "android/hardware/tests/foo/1.0/SimpleAll.cpp",29 "android/hardware/tests/foo/1.0/SimpleTestAll.cpp",30 "android/hardware/tests/foo/1.0/TheirTypesAll.cpp",31 ], 32 }33- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
我們可以看到這段邏輯是利用 hidl-gen工具來生成.cpp文件。命令是: cmd: “(locationhidl?gen)?o(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.foo@1.0”,?
.hal源碼是:
- 1
- 2
- 3
而這部分就是上面所定義的各種.hal文件。最終輸出就是各種.cpp文件。我們比較關注的就是 SimpleTestAll.cpp文件。
同時會生成以下一些頭文件:
34 genrule {35 name: "android.hardware.tests.foo@1.0_genc++_headers",36 tools: ["hidl-gen"],37 cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.foo@1 .0",38 srcs: [39 ":android.hardware.tests.foo@1.0_hal",40 ],41 out: [……………………….64 "android/hardware/tests/foo/1.0/ISimpleTest.h",65 "android/hardware/tests/foo/1.0/IHwSimpleTest.h",66 "android/hardware/tests/foo/1.0/BnHwSimpleTest.h",67 "android/hardware/tests/foo/1.0/BpHwSimpleTest.h",68 "android/hardware/tests/foo/1.0/BsSimpleTest.h",………………………...74 ],75 }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
從生成的頭文件里看,我們看到有 ISimpleTest.h, BnHwSimpleTest.h, BpHwSimpleTest.h,Bnxxxxx與Bpxxxxx這兩個東西我們是不是看起來很眼熟?在Binder里, Ixxxxx.h定義了client與service統(tǒng)一的通用接口,而Bnxxxxx.h 派生自 Ixxxxx.h,做為service端實現(xiàn)的頭文件,Bpxxxxx.h同樣派生自 Ixxxxx.h做為client端的頭文件。這樣調(diào)用Bpxxxxx.h定義的接口,就自動利用binder機制跨進程由service端實現(xiàn)了Bnxxxxx.h定義函數(shù)。
我們大膽的猜測下,HIDL編譯生成的這些頭文件使用方式應該是與AIDL編譯出來的Bnxxxxx/Bpxxxxx作用類似,恭喜你,你的猜測很正確。
IFoo.h. Describes the pure IFoo interface in a C++ class; it contains the methods and types defined in the IFoointerface in the IFoo.hal file, translated to C++ types where necessary. Does not contain details related to the RPC mechanism (e.g., HwBinder) used to implement this interface. The class is namespaced with the package and version, e.g. ::android::hardware::samples::IFoo::V1_0. Both clients and servers include this header: Clients for calling methods on it and servers for implementing those methods.?
IHwFoo.h. Header file that contains declarations for functions that serialize data types used in the interface. Developers should never include his header directly (it does not contain any classes).?
BpFoo.h. A class that inherits from IFoo and describes the HwBinder proxy (client-side) implementation of the interface. Developers should never refer to this class directly.?
BnFoo.h. A class that holds a reference to an IFoo implementation and describes the HwBinder stub (server-side) implementation of the interface. Developers should never refer to this class directly.
FooAll.cpp. A class that contains the implementations for both the HwBinder proxy and the HwBinder stub. When a client calls an interface method, the proxy automatically marshals the arguments from the client and sends the transaction to the binder kernel driver, which delivers the transaction to the stub on the other side (which then calls the actual server implementation).
Google的解釋還是挺清楚,我就不畫蛇添足的翻譯成中文了。
.hal最終編譯出來的結(jié)果是:
cc_library_shared {name: "android.hardware.tests.foo@1.0",defaults: ["hidl-module-defaults"],generated_sources: ["android.hardware.tests.foo@1.0_genc++"],generated_headers: ["android.hardware.tests.foo@1.0_genc++_headers"],export_generated_headers: ["android.hardware.tests.foo@1.0_genc++_headers"],vendor_available: true,shared_libs: ["libhidlbase","libhidltransport","libhwbinder","liblog","libutils","libcutils","android.hidl.base@1.0",],export_shared_lib_headers: ["libhidlbase","libhidltransport","libhwbinder","libutils","android.hidl.base@1.0",],- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
從上面看得很清楚,.hal文件被編譯后會生成一個動態(tài)庫文件 android.hardware.tests.foo@1.0.so
HIDL的使用?
HIDL的使用,其實就是指怎么在service端實現(xiàn),怎么在client端調(diào)用。其實也挺簡單,基本流程就是service端往系統(tǒng)里注冊,client從系統(tǒng)里拿到service 的proxy,然后調(diào)用。跟AIDL的Binder一樣一樣的。
Client端拿service的proxy:?
foo = IFoo::getService(“foo”, mode == PASSTHROUGH /* getStub */);
使用的是Ixxx里自動生成的 getService函數(shù),拿到之后就能使用.hal定義的接口了。
Service端往系統(tǒng)注冊:?
int main() {?
return defaultPassthroughServiceImplementation();?
}?
而且nfc 模塊自己寫了一個.rc文件:?
service nfc_hal_service /vendor/bin/hw/android.hardware.nfc@1.0-service?
class hal?
user nfc?
group nfc
這樣就能讓系統(tǒng)的Init進程在開機階段就把這個service啟動起來。
稍微總結(jié)下HIDL相關的內(nèi)容:?
1)HIDL是Android O里的Treble計劃的核心。目的是通過HIDL語法構(gòu)建出一個松耦合的系統(tǒng),最終目的是為了方便Android 升級,解決碎片化的問題。?
2)Android為了實現(xiàn) Binderized HAL有一個比較清晰的road map:?
不過其實還有些東西還沒有涉及到,比如FMQ,后續(xù)再來做探討。下一部分,我們開始來研究下Android 新給出的Vendor NDK.
原文地址: http://blog.csdn.net/ljp1205/article/details/77876008
總結(jié)
以上是生活随笔為你收集整理的Android O 前期预研之二:HIDL相关介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android O 前期预研之一:And
- 下一篇: GDB 调试多进程或者多线程应用