Android 系統(tǒng)開發(fā)(2)--Android Treble詳細(xì)分析

?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其他技巧

打印當(dāng)前的manifest信息

mmm system/libvintf/

adb push out/target/product/(產(chǎn)品名)/system/bin/vintf /system/bin/vintf

adb shell vintf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拇派,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子凿跳,更是在濱河造成了極大的恐慌件豌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件控嗜,死亡現(xiàn)場離奇詭異茧彤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)疆栏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門曾掂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人壁顶,你說我怎么就攤上這事珠洗。” “怎么了若专?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵险污,是天一觀的道長。 經(jīng)常有香客問我富岳,道長蛔糯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任窖式,我火速辦了婚禮蚁飒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘萝喘。我一直安慰自己淮逻,他們只是感情好产喉,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布漫谷。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪罐旗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天腮考,我揣著相機(jī)與錄音忘巧,去河邊找鬼。 笑死桨啃,一個(gè)胖子當(dāng)著我的面吹牛车胡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播照瘾,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼匈棘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了析命?” 一聲冷哼從身側(cè)響起主卫,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鹃愤,沒想到半個(gè)月后队秩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昼浦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年馍资,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片关噪。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸟蟹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出使兔,到底是詐尸還是另有隱情建钥,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布虐沥,位于F島的核電站熊经,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏欲险。R本人自食惡果不足惜镐依,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望天试。 院中可真熱鬧槐壳,春花似錦、人聲如沸喜每。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至枫笛,卻和暖如春吨灭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刑巧。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工喧兄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人海诲。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓繁莹,卻偏偏與公主長得像檩互,于是被迫代替她去往敵國和親特幔。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345