copy from : https://blog.csdn.net/qq_19923217/article/details/88398660
1. HIDL 概述
在 Andoird 8.0 版本框架代碼中,加入了 HIDL(HAL 接口定義語言),HIDL 的出現是為了將用戶層和 HAL 層分割開,它指定了 HAL 和用戶之間的接口,讓用戶能夠替換 Android 框架,而無需重新編譯 HAL,以便讓廠商能夠以更低的成本、更快速地將設備更新到新版 Android 版本中。
通俗的來說,HIDL 設計了一套通過的框架接口,將 HAL 層實現與 Android 操作系統框架分離開來,設備廠商只需要構建一次 HAL,並將其放置在 /vendor 分區中,便能適應大部分 Android 操作系統框架版本的升級。
圖:HIDL 設計下的升級方式
在 HIDL 設計理念中,HAL 模塊以一個獨立的 Service 運行,用戶通過 Binder IPC 與 HAL 模塊進行通信。因此 在 Android 8.0 以上的版本中查看用戶進程會發現很多 HAL 模塊 Service 運行,如下:
consule:/ $ ps -A | grep android.hardware
system 219 1 9728 4852 0 0 S android.hardware.keymaster@3.0-service
audioserver 235 1 21268 8916 0 0 S android.hardware.audio@2.0-service
bluetooth 236 1 7716 3408 0 0 S android.hardware.bluetooth@1.0-service
cameraserver 237 1 28412 11948 0 0 S android.hardware.camera.provider@2.4-service
media 238 1 10232 4312 0 0 S android.hardware.cas@1.0-service
system 239 1 9976 3648 0 0 S android.hardware.configstore@1.1-service
這些 Service 提供了設備 HAL 模塊具體接口實現(由 HIDL 主導設計),這些接口獨立於 Android 平台與設備廠商 HAL 實現。下面會主要以 HIDL 設計下 Android 9.0 composer HAL 實現來插入分析。
2. HIDL 設計分析
HIDL 是一種接口定義語言,描述了 HAL 和它的用戶之間的接口,因此首先需要設計一套通用接口實現。HIDL 為每個 HAL 模塊設計了不同接口定義 hal 文件,以 .hal 結尾,在 hidl-gen 工具的幫助下即可自動編譯生成對應接口 C++ 實現或者 Java 實現。
下面先來理清幾個概念。
2.1 軟件包
Google 為每個 HAL 模塊設計一個接口軟件包,大部分 HIDL 接口軟件包位於 hardware/interfaces 下,hardware/interfaces 頂層會直接映射到 android.hardware 軟件包命名空間,軟件包名稱可以具有子級,表示接口軟件包的版本,如 HAL Service:android.hardware.graphics.composer@2.1-service 的接口軟件包可以在 hardware/interfaces/graphics/composer/2.1 目錄下找到。
下表列出了 Android 所有軟件包前綴和位置:
軟件包前綴 位置
android.hardware.* hardware/interfaces/*
android.frameworks.* frameworks/hardware/interfaces/*
android.system.* system/hardware/interfaces/*
android.hidl.* system/libhidl/transport/*
軟件包結構
.hal 文件
軟件包是 HIDL 設計的關鍵所在,每個接口軟件包都包含一個 .hal 文件,.hal 文件包含一個指定文件所屬的軟件包和版本的 package 語句。如路徑 hardware/interfaces/graphics/composer/2.1/IComposer.hal 聲明。
package android.hardware.graphics.composer@2.1;
interface IComposer {
...
}
.hal 文件中定義了 HAL 模塊向用戶提供的訪問接口及數據類型
interface IComposer {
struct MyStruct {/*...*/};
...
getCapabilities() generates (vec<Capability> capabilities);
dumpDebugInfo() generates (string debugInfo);
....
}
不含顯式 extends 聲明的接口會從 android.hidl.base@1.0::IBase 隱式擴展,其他語法不做分析,可以訪問 Google 官網 做深入了解。
hidl-gen 編譯器會將 .hal 文件編譯成一組 .h 和 .cpp 文件,這些自動生成的文件用於編譯客戶端/服務端實現鏈接到的共享庫,用於編譯此共享庫的 Android.bp 文件由 hardware/interfaces/update-makefiles.sh 腳本自動生成。每次將新軟件包添加到 hardware/interfaces 或在現有軟件包中添加/移除 .hal 文件時,都必須重新運行該腳本,以確保生成的共享庫是最新的。
hidl-gen 工具
在 HIDL 架構中,系統定義的所有的 .hal 接口,都是通過 hidl-gen 工具在編譯時轉換成對應的代碼。比如:
hal 文件:hardware/interfaces/graphics/composer/2.1/IComposer.hal
1. 生成文件路徑:
out/soong/.intermediates/hardware/interfaces/graphics/composer/2.1
2. 頭文件自動生成在:
android.hardware.graphics.composer@2.1_genc++_headers
3. C++文件自動生成在:
android.hardware.graphics.composer@2.1_genc++
hidl-gen 源碼路徑:system/tools/hidl,是在 ubuntu 上可執行的二進制文件,這里不對工具源碼做分析。
hidl-gen 工具以 .hal 文件為輸入,自動生成的文件主要以下幾個,這些文件會鏈接到與軟件包同名的單個共享庫(例如 android.hardware.samples@1.0)。
圖:由編譯器生成的文件
其中,
IFoo.h - 描述 C++ 類中的純 IFoo 接口;它包含 IFoo.hal 文件中的 IFoo 接口中所定義的方法和類型,類的命名空間包含軟件包名稱和版本號,例如 ::android::hardware::samples::IFoo::V1_0。客戶端和服務器都包含此標頭:客戶端用它來調用方法,服務器用它來實現這些方法。
IHwFoo.h - 頭文件,其中包含用於對接口中使用的數據類型進行序列化的函數的聲明。開發者不得直接包含其標頭(它不包含任何類)。
BpFoo.h - 從 IFoo 繼承的類,可描述接口的 HwBinder 代理(客戶端)實現。開發者不得直接引用此類。
BnFoo.h - 保存對 IFoo 實現的引用的類,可描述接口的 HwBinder 服務器端實現。開發者不得直接引用此類。
FooAll.cpp - 包含 HwBinder 客戶端和 HwBinder 服務器端的實現的類。當客戶端調用接口方法時,代理會自動從客戶端封送參數,並將事務發送到綁定內核驅動程序,該內核驅動程序會將事務傳送到另一端的服務器端實現。
2.2 共享庫與 Service
軟件包中編譯,如 在hardware/interfaces/graphics/composer 目錄下 mm 編譯將生成:
android.hardware.graphics.composer@2.1 .so
android.hardware.graphics.composer@2.1-impl.so
android.hardware.graphics.composer@2.1-service.rc
android.hardware.graphics.composer@2.1-service
下面會簡單介紹一下這些庫及文件的用途,以及一個 HIDL 架構下的 HAL 模塊是怎么運轉起來的,在下一章的實例分析中會具體分析它的代碼實現。
首先,android.hardware.graphics.composer@2.1-service 是一個服務,是一個 Hal 模塊可執行程序,而 android.hardware.graphics.composer@2.1-service.rc 正是它的啟動配置腳本:
service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
class hal animation
user system
group graphics drmrpc
capabilities SYS_NICE
writepid /dev/cpuset/system-background/tasks
也就是說,Android HIDL 架構下,所有 HAL 模塊實現都以服務的形式運行在獨立的進程空間:
$ ps -A
system 245 1 29084 8000 0 0 S android.hardware.graphics.composer@2.1-service
...
而 HAL 服務進程會鏈接 android.hardware.graphics.composer@2.1.so。
cc_binary {
name: "android.hardware.graphics.composer@2.1-service",
defaults: ["hidl_defaults"],
vendor: true,
relative_install_path: "hw",
srcs: ["service.cpp"],
init_rc: ["android.hardware.graphics.composer@2.1-service.rc"],
shared_libs: [
"android.hardware.graphics.composer@2.1", // 鏈接 HIDL 生成主要庫
"libbinder",
"libhidlbase",
"libhidltransport",
"liblog",
"libsync",
"libutils",
],
}
首先,android.hardware.graphics.composer@2.1-service 服務的作用就是向 hwservicemanager 注冊 HAL,以便客戶端調用,因此需要開機啟動。
android.hardware.graphics.composer@2.1.so 中包含必要的 binder IPC 通信機制,包含 HAL 對象如 IComposer 對象的客戶端和服務器端通信實現及接口調用。而 android.hardware.graphics.composer@2.1.so 又會鏈接 android.hardware.graphics.composer@2.1-impl.so,這個動態庫具體實現了接口邏輯,如在 passthrought 模式下,鏈接舊版 HAL(hw_moudle_get)實現邏輯。
在最后一節會通過 composer HAL 來具體分析。
2.3 HAL 兼容類型
Google 的 HIDL 設計目的是讓 HAL 與 用戶調用在不同的進程中,HAL 被寫成 binder service,而用戶接口如 frameworks 作為 binder client 通過 IPC 機制實現跨進程接口調用。
但是理想很豐滿,現實卻很殘酷,很多廠商還停留在 Android 老版本,為了給廠商改變時間,同時保持 Android 向前兼容性,Google 另外設計了 Passthrough 類型的 HAL 框架。請看,
圖:HAL 的發展歷程
Legacy Hal:Android 8.0 之前版本的 HAL 都是編譯成 so,然后動態鏈接到各個 frameworks service 中去。
Passthrough Hal:該模式是為了兼容舊版的 HAL,舊版 HAL 實現仍以動態庫的方式提供,只是 binder service 鏈接了動態庫 HAL 實現,即 binder service 通過 hw_get_module 鏈接了舊版的 hal 實現,而用戶端通過與 binder service IPC 通信,間接實現了與舊版 HAL 的交互。
Binderized HAL:HAL 與 用戶調用在不同的進程中,HAL 被寫成 binder service,而用戶接口如 frameworks 作為 binder client 通過 IPC 機制實現跨進程接口調用。這個是 Google 的最終設計目標。
2.4 通用客戶端與服務端實現
HIDL 接口具有客戶端和服務器實現:
HIDL 接口的客戶端實現是指通過在該接口上調用方法來使用該接口的代碼。
服務器實現是指 HIDL 接口的實現,它可接收來自客戶端的調用並返回結果(如有必要)。
在從 libhardware HAL 轉換為 HIDL HAL 的過程中,HAL 實現成為服務器,而調用 HAL 的進程則成為客戶端。
創建 HAL 客戶端
通過 HAL Service 的注冊,hwservicemanager 中已經保存了 HAL 模塊對象(如 IComposer),因此我們只需如下操作客戶端。
首先將 HAL 庫添加到 makefile 中:
Make:LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer@2.1
Soong:shared_libs: [ …, android.hardware.graphics.composer@2.1 ]
接下來,添加 HAL 頭文件:
#include <android/hardware/graphics/composer/2.1/IComposer.h>
…
// in code:
sp<IFoo> client = IComposer::getService();
client->doThing();
創建 HAL 服務器
要創建 HAL 實現,必須具有表示 HAL 的 .hal 文件並已在 hidl-gen 上使用 -Lmakefile 或 -Landroidbp 為 HAL 生成 makefile(./hardware/interfaces/update-makefiles.sh 完成)。
為了讓 HAL 在 Passthrough 模式下工作(兼容舊版 HAL),必須具備 HIDL_FETCH_IModuleName 函數(位於 /(system|vendor|…)/lib(64)?/hw/android.hardware.graphics/composer@2.1-impl.so 下)。
接下來,完成服務器端代碼並設置守護進程。守護進程代碼(支持 Passthrough 模式)示例:
#include <hidl/LegacySupport.h>
int main(int /* argc */, char* /* argv */ []) {
return defaultPassthroughServiceImplementation<INfc>("nfc");
}
defaultPassthroughServiceImplementation 將對提供的 -impl 庫執行 dlopen() 操作,並將其作為綁定式服務提供。守護進程代碼(對於純綁定式服務)示例:
int main(int /* argc */, char* /* argv */ []) {
// This function must be called before you join to ensure the proper
// number of threads are created. The threadpool will never exceed
// size one because of this call.
::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);
sp nfc = new Nfc();
const status_t status = nfc->registerAsService();
if (status != ::android::OK) {
return 1; // or handle error
}
// Adds this thread to the threadpool, resulting in one total
// thread in the threadpool. We could also do other things, but
// would have to specify 'false' to willJoin in configureRpcThreadpool.
::android::hardware::joinRpcThreadpool();
return 1; // joinRpcThreadpool should never return
}
此守護進程通常存在於 $PACKAGE + “-service-suffix”(例如 android.hardware.graphics.composer@1.0-service)中,但也可以位於任何位置。HAL 的特定類的 sepolicy 是屬性 hal_(例如 hal_composer))。您必須將此屬性應用到運行特定 HAL 的守護進程(如果同一進程提供多個 HAL,則可以將多個屬性應用到該進程)。
————————————————
版權聲明:本文為CSDN博主「歲月斑駁7」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_19923217/java/article/details/88398660