Android O 前期預研之二:HIDL相關介紹


Android HAL類型
在此之前的ANDROID版本當中Android HAL沒有什么特殊的特殊的,也么有什么分類,但是從android 8.0開始,Android重構了HAL與Android FW之間的聯系結構,所以Android HAL會被區分成以下2種類型:
1,Binderized HALs,從名字上應該是指Binder化的HAL,對Android 比較熟悉的同學應該對binder這個東西很熟悉,我們是不是可以大膽猜猜下Android 8.0里的HAL是不是都是binder化了?也就是說HAL都被寫成了binder service了?Android FW都是binder client?后續我們研究研究再來看看我們的猜測是不是正確的。
2,Passthrough HALs,從google的官方介紹來說,這個是對原先HAL的包裝,但是最終的binder service 跟binder client都是活在同一個進程當中。這個應該是對老版本HAL的兼容。
3,Same-Process HALs,由於某些性能的因素,這些HALs必須運行在Android Framework 所在的進程當中。

按照google的要求,新設計生產的Android O設備,必須而且只能支持 Binderized HALs,而老版本的設備升級到Android O可以支持 Passthrough HALs,但是有些HAL也必須修改成 Binderized HALs。
這里寫圖片描述
以下HAL可以根據是升級設備或者新設備自由選擇:
這里寫圖片描述
以下跟graphic相關的HAL因為涉及到性能問題,只能在同一個進程當中運行:
這里寫圖片描述

HIDL的相關介紹
HIDL的全稱是HAL interface definition language(硬件抽象層接口定義語言),在此之前Android 有AIDL,架構在Android binder 之上,用來定義Android 基於Binder通信的Client 與Service之間的接口。HIDL也是類似的作用,只不過定義的是Android Framework與Android HAL實現之間的接口。

在AIDL機制中Android 會提供一系列工具會將用戶定義的*.aidl文件編譯生成Client端代碼與Service端代碼,用戶僅僅 需要1)在Service端實現所需要實現的接口。2)在Client端調用相關接口。基於Binder機制,在Clinet端的調用會自動通過binder驅動跨進程到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); };

在這里,我們定義一個新的HIDL接口,取名叫做 ISimpleTest, 從語法上看有點像JAVA的語法。interface是關鍵字,代表要創建一個HIDL的接口。我們把上述接口保存成 IsimpleTest.hal文件存放在hardware/interfaces/tests/foo/1.0/ISimpleTest.hal,其實我們完全可以新建一個新目錄,使用一個新的package名,而不使用android.hardware.tests.foo,

2)定義成員:
如上所示,HIDL當中可以像JAVA/C代碼一樣,很容易定義出聯合體/結構體變量。

3)定義成員函數:
如上所示,定義的都是無參函數,如果需要定義一個帶有參數的函數,可以寫成doThis(float param);,這就代表是一個有參數,但是無返回值的函數。

而以上定義的 getCookie() generates (int32_t cookie); 其含義為:函數名為 getCookie,無參數傳入,函數的返回值為一個int32_t 類型。

HIDL編譯
在根目錄執行./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的東西可以后續在研究,這里我們只關注於HIDL。

  3 filegroup { 4 name: "android.hardware.tests.foo@1.0_hal", 5 srcs: [ 6 "types.hal", 7 "IFoo.hal", 8 "IFooCallback.hal", 9 "IMyTypes.hal", 10 "ISimple.hal", 11 "ISimpleTest.hal", 12 "ITheirTypes.hal", 13 ], 14 }

我們可以看到”ISimpleTest.hal”,已經被加進編譯文件列表當中。

而在生成的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 

我們可以看到這段邏輯是利用 hidl-gen工具來生成.cpp文件。命令是: cmd: “(locationhidlgen)o

(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.foo@1.0”,
.hal源碼是:

 20 srcs: [ 21 ":android.hardware.tests.foo@1.0_hal", 22 ],

而這部分就是上面所定義的各種.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 }

從生成的頭文件里看,我們看到有 ISimpleTest.h, BnHwSimpleTest.h, BpHwSimpleTest.h,Bnxxxxx與Bpxxxxx這兩個東西我們是不是看起來很眼熟?在Binder里, Ixxxxx.h定義了client與service統一的通用接口,而Bnxxxxx.h 派生自 Ixxxxx.h,做為service端實現的頭文件,Bpxxxxx.h同樣派生自 Ixxxxx.h做為client端的頭文件。這樣調用Bpxxxxx.h定義的接口,就自動利用binder機制跨進程由service端實現了Bnxxxxx.h定義函數。

我們大膽的猜測下,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最終編譯出來的結果是:

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", ],

從上面看得很清楚,.hal文件被編譯后會生成一個動態庫文件 android.hardware.tests.foo@1.0.so

HIDL的使用
HIDL的使用,其實就是指怎么在service端實現,怎么在client端調用。其實也挺簡單,基本流程就是service端往系統里注冊,client從系統里拿到service 的proxy,然后調用。跟AIDL的Binder一樣一樣的。

Client端拿service的proxy:
foo = IFoo::getService(“foo”, mode == PASSTHROUGH /* getStub */);

使用的是Ixxx里自動生成的 getService函數,拿到之后就能使用.hal定義的接口了。

Service端往系統注冊:
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

這樣就能讓系統的Init進程在開機階段就把這個service啟動起來。

稍微總結下HIDL相關的內容:
1)HIDL是Android O里的Treble計划的核心。目的是通過HIDL語法構建出一個松耦合的系統,最終目的是為了方便Android 升級,解決碎片化的問題。
2)Android為了實現 Binderized HAL有一個比較清晰的road map:
這里寫圖片描述

不過其實還有些東西還沒有涉及到,比如FMQ,后續再來做探討。下一部分,我們開始來研究下Android 新給出的Vendor NDK.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM