?1 Android? Treble? HAL
為了更好的了解Treble 架構(gòu)里面的HAL,首先了解一下Android的經(jīng)典架構(gòu)泰讽。
在Android O之前筒扒,HAL是一個(gè)個(gè)的.so庫,通過dlopen來進(jìn)行打開次屠,庫和framework位于同一個(gè)進(jìn)程媒楼。如圖所示:
2 Treble 架構(gòu)
為了能夠讓Android O之前的版本升級到Android O乐尊,Android設(shè)計(jì)了Passthrough模式,經(jīng)過轉(zhuǎn)換划址,可以方便的使用已經(jīng)存在代碼扔嵌,不需要重新編寫相關(guān)的HAL限府。HIDL分為兩種模式:Passthrough和Binderized。
Binderized: Google官方翻譯成綁定試HAL痢缎。
Passthrough:Google官方翻譯成直通式HAL胁勺。
大致框架圖如下,對于Android O之前的設(shè)備独旷,對應(yīng)圖1署穗,對于從之前的設(shè)備升級到O的版本,對應(yīng)圖2嵌洼、圖3. 對于直接基于Android O開發(fā)的設(shè)備案疲,對應(yīng)圖4。
新的架構(gòu)之下麻养,framework和hal運(yùn)行于不同的進(jìn)程褐啡,所有的HAL采用新的HIDL技術(shù)來完成。
3?HIDL 深入理解
HIDL是一種接口定義語言鳖昌,描述了HAL和它的用戶之間的接口备畦。接下來深入分析一下HIDL相關(guān)實(shí)現(xiàn)。
3.1 hidl-gen工具
在Treble架構(gòu)中许昨,經(jīng)常會提到HIDL懂盐,首先介紹和HIDL相關(guān)的一個(gè)工具h(yuǎn)idl-gen,系統(tǒng)定義的所有的.hal接口,都是通過hidl-gen工具轉(zhuǎn)換成對應(yīng)的代碼车要。比如hardware/interfaces/power/1.0/IPower.hal,會通過hidl-gen轉(zhuǎn)換成out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++/gen/android/hardware/power/1.0/PowerAll.cpp文件崭倘,為了深入了解翼岁,介紹相關(guān)原理,首先分析hidl-gen。
hidl-gen源碼路徑:system/tools/hidl司光,是在ubuntu上可執(zhí)行的二進(jìn)制文件琅坡。
使用方法:hidl-gen -o output-path -L language (-r interface-root) fqname
例子:
hidl-gen? -Lmakefile? -r? android.hardware:hardware/interfaces? -r? android.hidl:system/libhidl/transport? android.hardware.power@1.0
參數(shù)含義:
-L: 語言類型,包括c++, c++-headers, c++-sources, export-header, c++-impl, java, java-constants, vts, makefile, androidbp, androidbp-impl, hash等残家。hidl-gen可根據(jù)傳入的語言類型產(chǎn)生不同的文件榆俺。
fqname: 完全限定名稱的輸入文件。比如本例中android.hardware.power@1.0坞淮,要求在源碼目錄下必須有hardware/interfaces/power/1.0/目錄茴晋。?
對于單個(gè)文件來說,格式如下:package@version::fileName回窘,比如android.hardware.power@1.0::types.Feature诺擅。
對于目錄來說。格式如下package@version啡直,比如android.hardware.power@1.0烁涌。
-r: 格式package:path苍碟,可選,對fqname對應(yīng)的文件來說撮执,用來指定包名和文件所在的目錄到Android系統(tǒng)源碼根目錄的路徑微峰。如果沒有制定,前綴默認(rèn)是:android.hardware抒钱,目錄是Android源碼的根目錄蜓肆。
-o : 存放hidl-gen產(chǎn)生的中間文件的路徑。我們查看hardware/interfaces/power/1.0/Android.bp继效,可以看到症杏,-o參數(shù)都是寫的$(genDir),一般都是在out/soong/.intermediates/hardware/interfaces/power/1.0/下面,根據(jù)-L的不同瑞信,后面產(chǎn)生的路徑可能不太一樣厉颤,比如c++,那么就會就是out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++/gen凡简,如果是c++-headers逼友,那么就是out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++_headers/gen。
對于實(shí)例來說秤涩,fqname是:android.hardware.power@1.0帜乞,包名是android.hardware,文件所在的目錄是hardware/interfaces筐眷。例子中的命令會在out/soong/.intermediates/hardware/interfaces/power/1.0/下面產(chǎn)生對應(yīng)的c++文件黎烈。
2.2 生成子hal的Android.mk和Android.bp文件
正如我們所知,所有的HIDL Interface?都是通過一個(gè).hal文件來描述匀谣,為了方便編譯生成每一個(gè)子hal照棋。Google在系統(tǒng)默認(rèn)提供了一個(gè)腳本update-makefiles.sh,位于hardware/interfaces/武翎、frameworks/hardware/interfaces/烈炭、system/hardware/interfaces/、system/libhidl/宝恶。以hardware/interfaces/里面的代碼為實(shí)例做介紹符隙。
#!/bin/bash
source system/tools/hidl/update-makefiles-helper.sh
? ?do_makefiles_update \
? "android.hardware:hardware/interfaces" \
? "android.hidl:system/libhidl/transport"
這個(gè)腳本的主要作用:根據(jù)hal文件生成Android.mk(makefile)和Android.bp(blueprint)文件。在hardware/interfaces的子目錄里面垫毙,存在.hal文件的目錄霹疫,都會產(chǎn)生Android.bp和Android.mk文件。詳細(xì)分析如下:
a. source system/tools下面的update-makefiles-helper.sh综芥,然后執(zhí)行do_makefiles_update
b. 解析傳入進(jìn)去的參數(shù)更米。參數(shù)android.hardware:hardware/interfaces:
android.hardware: android.hardware表示包名。
hardware/interfaces:表示相對于根目錄的文件路徑毫痕。
會輸出如下LOG:
Updating makefiles for android.hardware in hardware/interfaces.?
Updating ….
c. 獲取所有的包名征峦。通過function get_packages()函數(shù)迟几,獲取hardware/interfaces路徑下面的所有hal文件所在的目錄路徑,比如子目錄power里面的hal文件的路徑是power/1.0栏笆,加上當(dāng)前的參數(shù)包名hardware/interfaces类腮,通過點(diǎn)的方式連接,將nfc/1.0+hardware/interfaces里面的斜線轉(zhuǎn)換成點(diǎn),最終獲取的包名就是 android.hardware.power@1.0蛉加,依次類推獲取所有的包名蚜枢。
d. 執(zhí)行hidl-gen命令.將c步驟里面獲取的參數(shù)和包名還有類名傳入hidl-gen命令,在hardware/interfaces/power/1.0目錄下產(chǎn)生Android.mk和Android.bp文件针饥。
Android.mk: hidl-gen -Lmakefile -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.power@1.0
Android.bp: hidl-gen -Landroidbp -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.power@1.0
關(guān)于hidl-gen厂抽,后續(xù)章節(jié)會介紹。
e. 在hardware/interfaces的每個(gè)子目錄下面產(chǎn)生Android.bp文件丁眼,文件內(nèi)容主要是subdirs的初始化筷凤,存放當(dāng)前目錄需要包含的子目錄。比如hardware/interfaces/power/下面的Android.bp文件苞七。
@hardware/interfaces/power/Android.bp
// This is an autogenerated file, do not edit.
subdirs= [? ? "1.0",? ??
? ? ? ? ? ? ? ? ? "1.0/default",? ?
? ? ? ? ? ? ? ? ? "1.0/vts/functional",
]
意思就是說藐守,編譯的時(shí)候,需要編譯hardware/interfaces/power目錄下面的三個(gè)子目錄蹂风。
經(jīng)過以上步驟卢厂,就會在對應(yīng)的子目錄產(chǎn)生Android.mk和Android.bp文件。這樣以后我們就可以執(zhí)行正常的編譯命令進(jìn)行編譯了惠啄。比如mmm hardware/interfaces/power/,默認(rèn)情況下慎恒,在源碼中,Android.mk和Android.bp文件已經(jīng)存在撵渡。
2.3 轉(zhuǎn)換.hal 文件為代碼
如前面所示融柬,每個(gè)接口都是定義在.hal文件里面,比如hardware/interfaces/power/1.0/IPower.hal姥闭,通過hidl-gen生成的android.bp文件里面會定義
可以看到在Android.bp里面丹鸿,通過hidl-gen在out下面產(chǎn)生了types.cpp和PowerAll.cpp. 實(shí)際例子很多越走,不做詳細(xì)介紹棚品。
對于生成的PowerAll.cpp來說,我們可以看到廊敌,除了IPower.hal里面定義的函數(shù)之外铜跑,還生成了很多其他的方法,這個(gè)是hidl-gen默認(rèn)產(chǎn)生骡澈,為了能夠支持binder通信锅纺。在IPower.hal里面定義的setInteractive(bool interactive);,在PowerAll.cpp里面對應(yīng)的是BpHwPower::setInteractive(bool interactive)。通過命名就可以知道肋殴,這個(gè)和Binder機(jī)制里面的命名一致囤锉。代碼如下:
經(jīng)過以上步驟坦弟,.hal文件就轉(zhuǎn)換成了對應(yīng)的代碼,而且具備了Binder通信的能力官地。
HIDL整個(gè)流程如圖所示:
3 HAL 層的通信機(jī)制
在Treble架構(gòu)中酿傍,framework/vendor之間的通信通過HIDL接口和dev/hwbinder的IPC域來完成。而且HIDL接口有兩種通信模式Passthrough和Binderized驱入。接下來我們介紹兩種模式下的交互原理赤炒。創(chuàng)建HAL服務(wù)器有兩種模式:
defaultPassthroughServiceImplementation
int main()
?{
? ? ?return defaultPassthroughServiceImplementation();
}
registerAsService
int main(int /* argc */, char* /* argv */ [])
?{??
? ? ? sp dumpstate = new DumpstateDevice;
? ? ? configureRpcThreadpool(1, true /* will join */);
? ? ? if (dumpstate->registerAsService() != OK) {
? ? ? ? ALOGE("Could not register service.");
? ? ? ? return 1;
? ? }
? ? ?joinRpcThreadpool();
? ? ?ALOGE("Service exited!");
? ? return 1;
}
接下來我們分別介紹兩種類型的詳細(xì)過程。
4.1 defaultPassthroughServiceImplementation
首先介紹Passthrough模式的HIDL實(shí)現(xiàn)機(jī)制亏较。以hardware/interfaces/power/1.0作為例子莺褒。當(dāng)編譯hardware/interfaces/power/1.0的時(shí)候,會生成:
1)中間文件PowerAll.cpp
2)/vendor/bin/hw/android.hardware.power@1.0-service的可執(zhí)行文件
3)/vendor/lib/hw/android.hardware.power@1.0-impl.so的庫文件
4)android.hardware.power@1.0-service.rc會被拷貝到vendor.img里面的vendor/etc/init目錄雪情。rc文件的內(nèi)容如下:
? ? service power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
? ? class hal
? ? user system? ? group system
接下來我們就一步步分析遵岩,power Server是如何初始化的。
5)對于init的解析機(jī)制旺罢,本文不做描述旷余,在開機(jī)過程的某一個(gè)階段,系統(tǒng)會啟動class是hal的服務(wù)扁达,會執(zhí)行/vendor/bin/hw/android.hardware.power@1.0-service正卧,從而調(diào)用hardware/interfaces/power/1.0/default/service.cpp的main方法。代碼如下:
int main()
?{
? ? return defaultPassthroughServiceImplementation();
}
接下來會調(diào)用
@PowerAll.cpp
:android::sp IPower::getService(const std::string &serviceName, const bool getStub) {
? ? using ::android::hardware::defaultServiceManager;
? ? using ::android::hardware::details::waitForHwService;
? ? using ::android::hardware::getPassthroughServiceManager;
? ? using ::android::hardware::Return;
? ? using ::android::sp;
? ? using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;
? ? sp iface = nullptr;
? ? // 獲取HwServiceManager? ? const sp<::android::hidl::manager::V1_0::IServiceManager> sm = defaultServiceManager();
? ? if (sm == nullptr) {
? ? ? ? ALOGE("getService: defaultServiceManager() is null");
? ? ? ? return nullptr;
? ? }
? ? // 獲取當(dāng)前Tranport類型跪解,passthrough或者binderized? ? Return transportRet = sm->getTransport(IPower::descriptor, serviceName);
? ? if (!transportRet.isOk()) {
? ? ? ? ALOGE("getService: defaultServiceManager()->getTransport returns %s", transportRet.description().c_str());
? ? ? ? return nullptr;
? ? }
? ? Transport transport = transportRet;
? ? const bool vintfHwbinder = (transport == Transport::HWBINDER);
? ? const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
? ? // 返回當(dāng)前的接口類? ? for (int tries = 0; !getStub && (vintfHwbinder || (vintfLegacy && tries == 0)); tries++) {
? ? ? ? if (tries > 1) {
? ? ? ? ? ? ALOGI("getService: Will do try %d for %s/%s in 1s...", tries, IPower::descriptor, serviceName.c_str());
? ? ? ? ? ? sleep(1);
? ? ? ? }
? ? ? ? if (vintfHwbinder && tries > 0) {
? ? ? ? ? ? waitForHwService(IPower::descriptor, serviceName);
? ? ? ? }
? ? ? ? Return> ret =
? ? ? ? ? ? ? ? sm->get(IPower::descriptor, serviceName);
? ? ? ? if (!ret.isOk()) {
? ? ? ? ? ? ALOGE("IPower: defaultServiceManager()->get returns %s", ret.description().c_str());
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? sp<::android::hidl::base::V1_0::IBase> base = ret;
? ? ? ? if (base == nullptr) {
? ? ? ? ? ? if (tries > 0) {
? ? ? ? ? ? ? ? ALOGW("IPower: found null hwbinder interface");
? ? ? ? ? ? }continue;
? ? ? ? }
? ? ? ? Return> castRet = IPower::castFrom(base, true /* emitError */);
? ? // ...? ? ? ? iface = castRet;
? ? ? ? if (iface == nullptr) {
? ? ? ? ? ? ALOGW("IPower: received incompatible service; bug in hwservicemanager?");
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? return iface;
? ? }
? ? // 獲取passthrough模式的類炉旷。? ? if (getStub || vintfPassthru || vintfLegacy) {
? ? ? ? const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();
? ? ? ? if (pm != nullptr) {
? ? ? ? ? ? Return> ret =
? ? ? ? ? ? ? ? ? ? pm->get(IPower::descriptor, serviceName);
? ? ? ? ? ? if (ret.isOk()) {
? ? ? ? ? ? ? ? sp<::android::hidl::base::V1_0::IBase> baseInterface = ret;
? ? ? ? ? ? ? ? if (baseInterface != nullptr) {
? ? ? ? ? ? ? ? ? ? iface = new BsPower(IPower::castFrom(baseInterface));
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return iface;
}
defaultPassthroughServiceImplementation(); @hardware/interfaces/power/1.0/default/service.cpp
IPower::getService @PowerAll.cpp 從HwServiceManager里面獲取注冊的服務(wù)。默認(rèn)情況下是沒有注冊這個(gè)服務(wù)的叉讥。
defaultServiceManager @system/libhidl/transport/ServiceManagement.cpp 打開/dev/hwbinder窘行,通過binder通信,獲取HwServiceManager服務(wù)端图仓。
sm->getTransport 基本就是按照Binder通信的機(jī)制來實(shí)現(xiàn)相關(guān)的流程罐盔。通過HwBinder調(diào)用服務(wù)端的getTransPort方法。
BpHwServiceManager::getTransport @ServiceManagerAll.cpp
BpHwBinder::transact
IPCThreadState::self()->transact
IPCThreadState::transact writeTransactionData waitForResponse
IPCThreadState::executeCommand
ServiceManager::getTransport@system/hwservicemanager/ServiceManager.cpp
getTransport @ system/hwservicemanager/Vintf.cpp 根據(jù)framework hal和device hal配置的manifest.xml里面的定義救崔,來判斷當(dāng)前的傳輸類型是HwBinder還是Passthrough模式惶看。在vendor/manifest.xml里面,power配置的是hwbinder,所以最終就是hwBinder模式六孵。(后續(xù)會講解manifest.xml的原理)
由于我們采取的是defaultPassthroughServiceImplementation();進(jìn)行注冊纬黎,所以getStub=true.所以會走到const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();?
-?getPassthroughServiceManager @ PowerAll.cpp?獲取passthrough服務(wù)管理。?
-?調(diào)用PassthroughServiceManager的get(const hidl_string& fqName, const hidl_string& name)函數(shù) @ServiceManagement.cpp, 根據(jù)傳入的fqName=(android.hardware.power@1.0::IPower"),獲取當(dāng)前的接口名IPower劫窒,拼接出后面需要載入的函數(shù)名HIDL_FETCH_IPower和庫名字android.hardware.power@1.0-impl本今,接著通過dlopen載入/vendor/lib/hw/android.hardware.power@1.0-impl.so,然后通過dlsym載入HIDL_FETCH_IPower函數(shù)。 代碼如下:
@hardware/interfaces/power/1.0/default/Power.cpp
IPower* HIDL_FETCH_IPower(const char* /* name */) {
? ? const hw_module_t* hw_module = nullptr;
? ? power_module_t* power_module = nullptr;
? ? int err = hw_get_module(POWER_HARDWARE_MODULE_ID, &hw_module);
? ? if (err) {
? ? ? ? ALOGE("hw_get_module %s failed: %d", POWER_HARDWARE_MODULE_ID, err);
? ? ? ? return nullptr;
? ? }
? ? if (!hw_module->methods || !hw_module->methods->open) {
? ? ? ? power_module = reinterpret_cast(
? ? ? ? ? ? const_cast(hw_module));
? ? } else {
? ? ? ? err = hw_module->methods->open(
? ? ? ? ? ? hw_module, POWER_HARDWARE_MODULE_ID,
? ? ? ? ? ? reinterpret_cast(&power_module));
? ? ? ? if (err) {
? ? ? ? ? ? ALOGE("Passthrough failed to load legacy HAL.");
? ? ? ? ? ? return nullptr;
? ? ? ? }
? ? }
? ? return new Power(power_module);
}
通過hw_get_module就和Android O以前的Hal模式一致冠息,這正是Passthrough復(fù)用原有hal的原理挪凑,測試用的是模擬器,所以最終獲取的庫文件是/system/lib/hw/power.ranchu.so逛艰,后續(xù)所有的和Power有關(guān)的接口調(diào)用岖赋,最終都是通過power.ranchu.so來實(shí)現(xiàn)功能。
接下來會調(diào)用registerReference("android.hardware.power@1.0::IPower"瓮孙,"default")唐断,接著調(diào)用BpHwServiceManager::registerPassthroughClient將fqName和服務(wù)名,注冊進(jìn)hwservicemanager的mServiceMap對象里面杭抠。
Return ServiceManager::registerPassthroughClient(const hidl_string &fqName,
? ? ? ? const hidl_string &name) {
? ? pid_t pid = IPCThreadState::self()->getCallingPid();
? ? if (!mAcl.canGet(fqName, pid)) {
? ? ? ? /* We guard this function with "get", because it's typically used in? ? ? ? * the getService() path, albeit for a passthrough service in this
? ? ? ? * case
? ? ? ? */? ? ? ? return Void();
? ? }
? ? PackageInterfaceMap &ifaceMap = mServiceMap[fqName];
? ? if (name.empty()) {
? ? ? ? LOG(WARNING) << "registerPassthroughClient encounters empty instance name for "? ? ? ? ? ? ? ? ? ? << fqName.c_str();? ? ? ? return Void();
? ? }
? ? HidlService *service = ifaceMap.lookup(name);
? ? if (service == nullptr) {
? ? ? ? auto adding = std::make_unique(fqName, name);
? ? ? ? adding->registerPassthroughClient(pid);
? ? ? ? ifaceMap.insertService(std::move(adding));
? ? } else {
? ? ? ? service->registerPassthroughClient(pid);
? ? }? ? return Void();
}
返回android::hidl::base::V1_0::IBase實(shí)例脸甘。
new BsPower:首先會通過interfaceChain判斷當(dāng)前的interface是否支持轉(zhuǎn)換,然后傳入包名和接口名"android.hardware.power@1.0", "IPower"構(gòu)造出一個(gè)new BsPower的實(shí)例偏灿。
IPower::registerAsService 接下來丹诀,調(diào)用status_t status = service->registerAsService(name),首先會創(chuàng)建BnHwPower對象翁垂,然后將當(dāng)前的service 添加進(jìn)hwservicemanager里面铆遭。初始化BnHwPower的過程中, _hidl_mImpl實(shí)際上就是BsPower的引用沿猜。代碼如下枚荣。 。
返回android::hidl::base::V1_0::IBase實(shí)例啼肩。
new BsPower:首先會通過interfaceChain判斷當(dāng)前的interface是否支持轉(zhuǎn)換橄妆,然后傳入包名和接口名"android.hardware.power@1.0", "IPower"構(gòu)造出一個(gè)new BsPower的實(shí)例。
IPower::registerAsService 接下來祈坠,調(diào)用status_t status = service->registerAsService(name)害碾,首先會創(chuàng)建BnHwPower對象,然后將當(dāng)前的service 添加進(jìn)hwservicemanager里面赦拘。初始化BnHwPower的過程中慌随, _hidl_mImpl實(shí)際上就是BsPower的引用。代碼如下躺同。?阁猜。
返回android::hidl::base::V1_0::IBase實(shí)例。
new BsPower:首先會通過interfaceChain判斷當(dāng)前的interface是否支持轉(zhuǎn)換笋籽,然后傳入包名和接口名"android.hardware.power@1.0", "IPower"構(gòu)造出一個(gè)new BsPower的實(shí)例蹦漠。
IPower::registerAsService 接下來椭员,調(diào)用status_t status = service->registerAsService(name)车海,首先會創(chuàng)建BnHwPower對象,然后將當(dāng)前的service 添加進(jìn)hwservicemanager里面。初始化BnHwPower的過程中侍芝, _hidl_mImpl實(shí)際上就是BsPower的引用研铆。代碼如下。
BnHwPower::BnHwPower(const ::android::sp &_hidl_impl)
? ? ? ? : ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "android.hardware.power@1.0", "IPower") {
? ? ? ? ? ? _hidl_mImpl = _hidl_impl;
? ? ? ? ? ? auto prio = ::android::hardware::details::gServicePrioMap.get(_hidl_impl, {SCHED_NORMAL, 0});
? ? ? ? ? ? mSchedPolicy = prio.sched_policy;
? ? ? ? ? ? mSchedPriority = prio.prio;
}
然后調(diào)用如下步驟州叠,將當(dāng)前通信加入IPC Binder的線程池進(jìn)行循環(huán)棵红。
android::hardware::joinRpcThreadpool at system/libhidl/transport/HidlTransportSupport.cpp:28 加入RpcThreadPool。
android::hardware::joinBinderRpcThreadpool at system/libhidl/transport/HidlBinderSupport.cpp:188
android::hardware::IPCThreadState::joinThreadPool at system/libhwbinder/IPCThreadState.cpp:497
android::hardware::IPCThreadState::getAndExecuteCommand at system/libhwbinder/IPCThreadState.cpp:443
至此咧栗,android.hardware.power@1.0::IPower服務(wù)就啟動成功了逆甜,可以響應(yīng)客戶端的請求了。
總結(jié)致板,通過defaultPassthroughServiceImplementation把當(dāng)前的服務(wù)注冊進(jìn)HwServiceManager,每個(gè)服務(wù)都是一個(gè)HidlService交煞。然后就可以等待客戶端的調(diào)用。
4.2 registerAsService 創(chuàng)建HAL
根據(jù)Android源碼網(wǎng)站介紹斟或,android.hardware.dumpstate@1.0是屬于綁定式HAL素征。接下來我們分析dumpstate服務(wù)初始化的流程。代碼位于:hardware/interfaces/dumpstate/1.0/default/萝挤,查看service.cpp御毅,代碼如下:
int main(int /* argc */, char* /* argv */ []) {
? ? sp dumpstate = new DumpstateDevice;
? ? configureRpcThreadpool(1, true /* will join */);
? ? if (dumpstate->registerAsService() != OK) {
? ? ? ? ALOGE("Could not register service.");
? ? ? ? return 1;
? ? }
? ? joinRpcThreadpool();
? ? ALOGE("Service exited!");
? ? return 1;
}
IDumpstateDevice::registerAsService
android::hardware::details::onRegistration(“android.hardware.dumpstate@1.0”, “IDumpstateDevice”, serviceName)?
tryShortenProcessName 設(shè)置當(dāng)前進(jìn)程的名字,長度最多為16怜珍。android.hardware.dumpstate@1.0-service
BpHwServiceManager::add?
ServiceManager::add @system/hwservicemanager/ServiceManager.cpp 注意和binder的區(qū)別端蛆。將當(dāng)前的service添加進(jìn)mInstanceMap。
收到HwBinder驅(qū)動的 BR_TRANSACTION 消息酥泛,然后執(zhí)行 BHwBinder::transact
BnHwDumpstateDevice::onTransact
joinRpcThreadpool(); 把當(dāng)前的通信加入HwBinder的線程池進(jìn)行循環(huán)欺税。
至此,registerAsService 創(chuàng)建HAL Service就完成了揭璃。
4.4 Binderized 模式 client和服務(wù)端的交互
服務(wù)注冊成功之后晚凿,客戶端就可以調(diào)用相關(guān)服務(wù)提供的功能。
以點(diǎn)擊屏幕為實(shí)例說明瘦馍,當(dāng)我們點(diǎn)擊屏幕的時(shí)候歼秽,會調(diào)用com_android_server_power_PowerManagerService.cpp的android_server_PowerManagerService_userActivity函數(shù),代碼如下:
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
? ? // Tell the power HAL when user activity occurs.
? ? gPowerHalMutex.lock();
? ? if (getPowerHal()) {
? ? ? ? Return ret = gPowerHal->powerHint(PowerHint::INTERACTION, 0);
? ? ? ? processReturn(ret, "powerHint");
? ? }
? ? // ...? ? }
}
// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
bool getPowerHal() {
? ? if (gPowerHalExists && gPowerHal == nullptr) {
? ? ? ? gPowerHal = IPower::getService();
? ? ? ? if (gPowerHal != nullptr) {
? ? ? ? ? ? ALOGI("Loaded power HAL service");
? ? ? ? } else {
? ? ? ? ? ? ALOGI("Couldn't load power HAL service");
? ? ? ? ? ? gPowerHalExists = false;
? ? ? ? }
? ? }
? ? return gPowerHal != nullptr;
}
在getPowerHal里面情组,通過IPower::getService();方法經(jīng)過HwBinder通信燥筷,獲取服務(wù)端的引用。主要包含如下步驟:
IPower::getService() 獲取IPower的服務(wù)院崇。返回遠(yuǎn)程服務(wù)的代理gPowerHal肆氓,最終返回的是BpHwPower。
IPower::getService(const std::string &serviceName, const bool getStub)@PowerApp.cpp底瓣。
BpHwServiceManager::getTransport 獲取當(dāng)前的傳輸類型谢揪,passthrough或者binderized。Power是binderized,返回對應(yīng)的服務(wù)代理。
sm->get(IPower::descriptor, serviceName) 從ServiceManager里面獲取描述是android.hardware.power@1.0::IPower拨扶,服務(wù)名是default的hidlservice的引用凳鬓。
IPower::castFrom(base, true /* emitError */)
android::hardware::details::castInterface 將hidlservice服務(wù)的引用轉(zhuǎn)換成Binder對象。
::android::hardware::IInterface::asBinder(static_cast)
4.4?pathrough 模式 client和服務(wù)端的交互
查詢manifest.xml可以發(fā)現(xiàn)患民。android.hardware.graphics.mapper是passthrough的模式缩举。
以hardware/interfaces/graphics/mapper/2.0/作為例子進(jìn)行分析。
@frameworks/native/libs/ui/Gralloc2.cpp
Mapper::Mapper()
{
? ? mMapper = IMapper::getService();? ? if (mMapper == nullptr || mMapper->isRemote())
?{
? ? ? ? LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
? ? }
}
// static?
::android::sp IMapper::getService(const std::string &serviceName, const bool getStub) {?
using ::android::hardware::defaultServiceManager;?
using ::android::hardware::details::waitForHwService;?
using ::android::hardware::getPassthroughServiceManager;?
using ::android::hardware::Return;?
using ::android::sp;?
using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;
sp iface = nullptr;
const sp<::android::hidl::manager::V1_0::IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
? ? ALOGE("getService: defaultServiceManager() is null");
? ? return nullptr;
}
Return transportRet = sm->getTransport(IMapper::descriptor, serviceName);
if (!transportRet.isOk()) {
? ? ALOGE("getService: defaultServiceManager()->getTransport returns %s", transportRet.description().c_str());
? ? return nullptr;
}
Transport transport = transportRet;
const bool vintfHwbinder = (transport == Transport::HWBINDER);
const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
// ...
if (getStub || vintfPassthru || vintfLegacy) {
? ? const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();
? ? if (pm != nullptr) {
? ? ? ? Return> ret =
? ? ? ? ? ? ? ? pm->get(IMapper::descriptor, serviceName);
? ? ? ? if (ret.isOk()) {
? ? ? ? ? ? sp<::android::hidl::base::V1_0::IBase> baseInterface = ret;
? ? ? ? ? ? if (baseInterface != nullptr) {
? ? ? ? ? ? ? ? iface = new BsMapper(IMapper::castFrom(baseInterface));
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
return iface;
步驟和前面的一致匹颤,由于是passthrough的模式仅孩,調(diào)用PassthroughServiceManager的get(const hidl_string& fqName, const hidl_string& name)函數(shù)?@ServiceManagement.cpp, 根據(jù)傳入的fqName=(android.hardware.graphics.mapper@2.0::IMapper"),獲取當(dāng)前的接口名IMapper,拼接出后面需要載入的函數(shù)名HIDL_FETCH_IMapper和庫名字android.hardware.graphics.mapper@2.0-impl印蓖,接著通過dlopen載入android.hardware.graphics.mapper@2.0-impl杠氢,然后通過dlsym載入HIDL_FETCH_IMapper函數(shù)。
這樣就實(shí)現(xiàn)了passthrough模式下的通信了另伍。
5?HAL 通信 (JAVA)
以hardware/interfaces/radio/1.0/作為例子:
當(dāng)我們編譯hardware/interfaces/radio/1.0/的時(shí)候鼻百,會編譯出:
android.hardware.radio-V1.0-java-static
out/target/common/gen/JAVA_LIBRARIES/android.hardware.radio-V1.0-java-static_intermediates/android/hardware/radio/V1_0/IRadio.java
接下來我們以
@frameworks/opt/telephony/Android.mk 最為例子,直接引用android.hardware.radio-V1.0-java-static摆尝,然后就可以使用里面的相關(guān)代碼温艇。
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
// ...LOCAL_JAVA_LIBRARIES := voip-common ims-commonLOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.0-java-static \
? ? android.hardware.radio.deprecated-V1.0-java-staticLOCAL_MODULE_TAGS := optionalLOCAL_MODULE := telephony-common
// ...
include $(BUILD_JAVA_LIBRARY)
接下來我們看一下使用的地方。
@RIL.java
try {
? ? ? ? ? ? mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
? ? ? ? ? ? if (mRadioProxy != null) {
? ? ? ? ? ? ? ? mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,
? ? ? ? ? ? ? ? ? ? ? ? mRadioProxyCookie.incrementAndGet());
? ? ? ? ? ? ? ? mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? riljLoge("getRadioProxy: mRadioProxy == null");
? ? ? ? ? ? }
? ? ? ? } catch (RemoteException | RuntimeException e) {
? ? ? ? ? ? mRadioProxy = null;
? ? ? ? ? ? riljLoge("RadioProxy getService/setResponseFunctions: " + e);
? ? ? ? }
首先會直接調(diào)用IRadio.getService來獲取相關(guān)服務(wù)堕汞。
@IRadio.java
public static IRadio getService(String serviceName) throws android.os.RemoteException?
{
? ? ? ? return? ? ?IRadio.asInterface(android.os.HwBinder.getService("android.hardware.radio@1.0::IRadio",serviceName));
? ? }
android.os.HwBinder.getService(“android.hardware.radio@1.0::IRadio”,serviceName)
JNI?
@frameworks/base/core/jni/android_os_HwBinder.cpp
static jobject JHwBinder_native_getService(
? ? ? ? JNIEnv *env,
? ? ? ? jclass /* clazzObj */,
? ? ? ? jstring ifaceNameObj,
? ? ? ? jstring serviceNameObj) {
? ? ///...? ? auto manager = hardware::defaultServiceManager();
? ? // ...? ? Return transportRet =? ? ? ? ? ? manager->getTransport(ifaceNameHStr, serviceNameHStr);
? ? if (!transportRet.isOk()) {
? ? ? ? signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
? ? ? ? return NULL;
? ? }
? ? IServiceManager::Transport transport = transportRet;
? ? // ... java 類型的傳輸模式必須是HwBinder? ? if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
? ? ? ? LOG(ERROR) << "service " << ifaceName << " declares transport method "? ? ? ? ? ? ? ? ? << toString(transport) << " but framework expects hwbinder.";
? ? ? ? signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
? ? ? ? return NULL;
? ? }
? ? // 獲取接口引用勺爱。? ? Return> ret = manager->get(ifaceNameHStr, serviceNameHStr);
? ? if (!ret.isOk()) {
? ? ? ? signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
? ? ? ? return NULL;
? ? }
? ? // 轉(zhuǎn)換成Binder接口? ? sp service = hardware::toBinder<? ? ? ? ? ? hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
? ? if (service == NULL) {
? ? ? ? signalExceptionForError(env, NAME_NOT_FOUND);
? ? ? ? return NULL;
? ? }
? ? LOG(INFO) << "Starting thread pool.";
? ? ::android::hardware::ProcessState::self()->startThreadPool();
? ? // 返回JHwRemoteBinder對象。? ? return JHwRemoteBinder::NewObject(env, service);
}
以上步驟和C++里面的獲取服務(wù)步驟類似讯检。通過IRadio.getService()獲取相關(guān)的服務(wù)琐鲁,進(jìn)入JNI的相關(guān)接口,獲取HwServiceManager服務(wù)人灼,然后獲取當(dāng)前HAL的類型(必須是Binderized)围段,接下來獲取服務(wù)對應(yīng)的接口引用,接著將當(dāng)前接口轉(zhuǎn)換成Ibinder引用投放,然后創(chuàng)建JHwRemoteBinder對象返回給java層奈泪。
IRadio.asInterface(android.os.HwBinder.getService("android.hardware.radio@1.0::IRadio",serviceName))
java層接著調(diào)用IRadio.asInterface將Hwbinder引用轉(zhuǎn)換成IRadio對象。
這樣就可以通過IRadio對象調(diào)用
6. Vendor Interface Object
6.1 manifest.xml 和 compatibility_matrix.xml
在system分區(qū)和vendor分區(qū)灸芳,分別存在manifest.xml和compatibility_matrix.xml涝桅。內(nèi)容大致如下:
分為兩類:
framework相關(guān)的,Google默認(rèn)定義完成烙样。
device相關(guān)冯遂,有設(shè)備廠商自定義。
device可以通過DEVICE_MANIFEST_FILE和DEVICE_MATRIX_FILE指定自己的manifest.xml文件谒获。如高通平臺的項(xiàng)目:
DEVICE_MANIFEST_FILE:= device/qcom/msm8937_64/manifest.xml
DEVICE_MATRIX_FILE:= device/qcom/common/compatibility_matrix.xml
默認(rèn)的framework manifest定義和兼容性文件定義如下:?
@build/core/config.mk
FRAMEWORK_MANIFEST_FILE:= system/libhidl/manifest.xml
FRAMEWORK_COMPATIBILITY_MATRIX_FILE:= hardware/interfaces/compatibility_matrix.xml
以上文件都是通過編譯生成到對應(yīng)的分區(qū)蛤肌,編譯腳本位于build/target/board/Android.mk壁却。
通過對比可以發(fā)現(xiàn),out下面生成的和源碼里面存在的文件寻定,并不是完全一致,在Android.mk里面可以發(fā)現(xiàn)精耐,這幾個(gè)文件都經(jīng)過了out/host/linux-x86/bin/assemble_vintf轉(zhuǎn)換狼速,assemble_vintf會判斷文件格式是否正確,并且會根據(jù)name按字母順序排列卦停。
以上兩個(gè)xml都是在向胡,在system/libvintf/parse_string.cpp里面進(jìn)行解析。
在前面的介紹中惊完,我們都講到了一個(gè)重要的方法僵芹,就是transport
在system/libvintf/include/vintf/Transport.h定義
static const std::array gTransportStrings = {
? ? {
? ? ? ? "",
? ? ? ? "passthrough",
? ? ? ? "hwbinder",
? ? }
};
我們獲取服務(wù)的時(shí)候,首先肯定要獲取當(dāng)前的HAL是什么類型小槐。
7其他技巧
mmm system/libvintf/
adb push out/target/product/(產(chǎn)品名)/system/bin/vintf /system/bin/vintf
adb shell vintf