1 Android Treble

Android 8.0 版本的一项新元素是 Project Treble。这是 Android 操作系统框架在架构方面的一项重大改变,旨在让制造商以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。Project Treble 适用于搭载 Android 8.0 及后续版本的所有新设备(这种新的架构已经在 Pixel 手机的开发者预览版中投入使用)。

2 关于 Android8.0 更新

利用新的供应商接口,Project Treble 将供应商实现(由芯片制造商编写的设备专属底层软件)与 Android 操作系统框架分离开来。

Android 7.x 及更早版本中没有正式的供应商接口,因此设备制造商必须更新大量 Android 代码才能将设备更新到新版 Android 系统:

图 1. Treble 推出前的 Android 更新环境

Treble 提供了一个稳定的新供应商接口,供设备制造商访问 Android 代码中特定于硬件的部分,这样一来,设备制造商只需更新 Android 操作系统框架,即可跳过芯片制造商直接提供新的 Android 版本:

图 2. Treble 推出后的 Android 更新环境

3 对Android Treble 进行测试

为了确保供应商实现的前向兼容性,新的供应商接口会由供应商测试套件 (VTS) 进行验证,该套件类似于兼容性测试套件 (CTS)。您可以使用 VTS 在推出 Treble 前的环境和 Treble 环境中自动执行 HAL 和操作系统内核测试。

4 Android Treble 资源

要详细了解新的 Treble 架构,请参阅以下部分:

HAL 类型:提供了关于绑定式 HAL、直通 HAL、Same-Process (SP) HAL 和旧版 HAL 的说明。

HIDL(一般信息):包含关于 HAL 接口定义语言(简称 HIDL,发音为“hide-l”)的一般信息;HIDL 是用于指定 HAL 和其用户之间接口的接口描述语言 (IDL)。

HIDL (C++):包含关于为 HIDL 接口创建 C++ 实现的详情。

HIDL (Java):包含关于 HIDL 接口的 Java 前端的详情。

ConfigStore HAL:提供了关于 ConfigStore HAL 的说明;该 HAL 提供了一组 API,可供访问用于配置 Android 框架的只读配置项。

设备树叠加层:提供了关于在 Android 中使用设备树叠加层 (DTO) 的详情。

供应商原生开发套件 (VNDK):提供了关于 VNDK(专门用来让供应商实现其 HAL 的一组库)的说明。

供应商接口对象 (VINTF):VINTF 对象整合了关于设备的相关信息,并让这类信息可通过可查询 API 提供。

SELinux for Android 8.0:提供了关于 SELinux 变更和自定义的详情。

1 Android  Treble  HAL

为了更好的了解Treble 架构里面的HAL,首先了解一下Android的经典架构。

在Android O之前,HAL是一个个的.so库,通过dlopen来进行打开,库和framework位于同一个进程。如图所示:

2 Treble 架构

为了能够让Android O之前的版本升级到Android O,Android设计了Passthrough模式,经过转换,可以方便的使用已经存在代码,不需要重新编写相关的HAL。HIDL分为两种模式:Passthrough和Binderized。

Binderized: Google官方翻译成绑定试HAL。

Passthrough:Google官方翻译成直通式HAL。

大致框架图如下,对于Android O之前的设备,对应图1,对于从之前的设备升级到O的版本,对应图2、图3. 对于直接基于Android O开发的设备,对应图4。

新的架构之下,framework和hal运行于不同的进程,所有的HAL采用新的HIDL技术来完成。

3 HIDL 深入理解

HIDL是一种接口定义语言,描述了HAL和它的用户之间的接口。接下来深入分析一下HIDL相关实现。

3.1 hidl-gen工具

在Treble架构中,经常会提到HIDL,首先介绍和HIDL相关的一个工具hidl-gen,系统定义的所有的.hal接口,都是通过hidl-gen工具转换成对应的代码。比如hardware/interfaces/power/1.0/IPower.hal,会通过hidl-gen转换成out/soong/.intermediates/hardware/interfaces/power/1.0/android.hardware.power@1.0_genc++/gen/android/hardware/power/1.0/PowerAll.cpp文件,为了深入了解,介绍相关原理,首先分析hidl-gen。

hidl-gen源码路径:system/tools/hidl,是在ubuntu上可执行的二进制文件。

使用方法: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

参数含义:

-L: 语言类型,包括c++, c++-headers, c++-sources, export-header, c++-impl, java, java-constants, vts, makefile, androidbp, androidbp-impl, hash等。hidl-gen可根据传入的语言类型产生不同的文件。

fqname:

完全限定名称的输入文件。比如本例中android.hardware.power@1.0,要求在源码目录下必须有hardware/interfaces/power/1.0/目录。

对于单个文件来说,格式如下:package@version::fileName,比如android.hardware.power@1.0::types.Feature。

对于目录来说。格式如下package@version,比如android.hardware.power@1.0。

-r:

格式package:path,可选,对fqname对应的文件来说,用来指定包名和文件所在的目录到Android系统源码根目录的路径。如果没有制定,前缀默认是:android.hardware,目录是Android源码的根目录。

-o :

存放hidl-gen产生的中间文件的路径。我们查看hardware/interfaces/power/1.0/Android.bp,可以看到,-o参数都是写的$(genDir),一般都是在out/soong/.intermediates/hardware/interfaces/power/1.0/下面,根据-L的不同,后面产生的路径

可能不太一样,比如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。

对于实例来说,fqname是:android.hardware.power@1.0,包名是android.hardware,文件所在的目录是hardware/interfaces。例子中的命令会在out/soong/.intermediates/hardware/interfaces/power/1.0/下面产生对应的c++文件。

2.2 生成子hal的Android.mk和Android.bp文件

正如我们所知,所有的HIDL Interface 都是通过一个.hal文件来描述,为了方便编译生成每一个子hal。Google在系统默认提供了一个脚本update-makefiles.sh,位于hardware/interfaces/、frameworks/hardware/interfaces/、system/hardware/interfaces/、system/libhidl/。以hardware/interfaces/里面的代码为实例做介绍。

#!/bin/bash

source system/tools/hidl/update-makefiles-helper.sh

do_makefiles_update \

"android.hardware:hardware/interfaces" \

"android.hidl:system/libhidl/transport"

这个脚本的主要作用:根据hal文件生成Android.mk(makefile)和Android.bp(blueprint)文件。在hardware/interfaces的子目录里面,存在.hal文件的目录,都会产生Android.bp和Android.mk文件。详细分析如下:

a. source system/tools下面的update-makefiles-helper.sh,然后执行do_makefiles_update

b. 解析传入进去的参数。参数android.hardware:hardware/interfaces:

android.hardware: android.hardware表示包名。

hardware/interfaces:表示相对于根目录的文件路径。

会输出如下LOG:

Updating makefiles for android.hardware in hardware/interfaces.

Updating ….

c. 获取所有的包名。通过function get_packages()函数,获取hardware/interfaces路径下面的所有hal文件所在的目录路径,比如子目录power里面的hal文件的路径是power/1.0,加上当前的参数包名hardware/interfaces,通过点的方式连接,将nfc/1.0+hardware/interfaces里面的斜线转换成点,最终获取的包名就是 android.hardware.power@1.0,依次类推获取所有的包名。

d. 执行hidl-gen命令.将c步骤里面获取的参数和包名还有类名传入hidl-gen命令,在hardware/interfaces/power/1.0目录下产生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

关于hidl-gen,后续章节会介绍。

e. 在hardware/interfaces的每个子目录下面产生Android.bp文件,文件内容主要是subdirs的初始化,存放当前目录需要包含的子目录。比如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",

]

意思就是说,编译的时候,需要编译hardware/interfaces/power目录下面的三个子目录。

经过以上步骤,就会在对应的子目录产生Android.mk和Android.bp文件。这样以后我们就可以执行正常的编译命令进行编译了。比如mmm hardware/interfaces/power/,默认情况下,在源码中,Android.mk和Android.bp文件已经存在。

2.3 转换.hal 文件为代码

如前面所示,每个接口都是定义在.hal文件里面,比如hardware/interfaces/power/1.0/IPower.hal,通过hidl-gen生成的android.bp文件里面会定义

可以看到在Android.bp里面,通过hidl-gen在out下面产生了types.cpp和PowerAll.cpp. 实际例子很多,不做详细介绍。

对于生成的PowerAll.cpp来说,我们可以看到,除了IPower.hal里面定义的函数之外,还生成了很多其他的方法,这个是hidl-gen默认产生,为了能够支持binder通信。在IPower.hal里面定义的setInteractive(bool interactive);,在PowerAll.cpp里面对应的是BpHwPower::setInteractive(bool interactive)。通过命名就可以知道,这个和Binder机制里面的命名一致。代码如下:

经过以上步骤,.hal文件就转换成了对应的代码,而且具备了Binder通信的能力。

HIDL整个流程如图所示:

3 HAL 层的通信机制

在Treble架构中,framework/vendor之间的通信通过HIDL接口和dev/hwbinder的IPC域来完成。而且HIDL接口有两种通信模式Passthrough和Binderized。接下来我们介绍两种模式下的交互原理。创建HAL服务器有两种模式:

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;

}

接下来我们分别介绍两种类型的详细过程。

4.1 defaultPassthroughServiceImplementation

首先介绍Passthrough模式的HIDL实现机制。以hardware/interfaces/power/1.0作为例子。当编译hardware/interfaces/power/1.0的时候,会生成:

1)中间文件PowerAll.cpp

2)/vendor/bin/hw/android.hardware.power@1.0-service的可执行文件

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文件的内容如下:

service power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service

class hal

user system    group system

接下来我们就一步步分析,power Server是如何初始化的。

5)对于init的解析机制,本文不做描述,在开机过程的某一个阶段,系统会启动class是hal的服务,会执行/vendor/bin/hw/android.hardware.power@1.0-service,从而调用hardware/interfaces/power/1.0/default/service.cpp的main方法。代码如下:

int main()

{

return defaultPassthroughServiceImplementation();

}

接下来会调用

@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;

}

// 获取当前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);

// 返回当前的接口类    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里面获取注册的服务。默认情况下是没有注册这个服务的。

defaultServiceManager @system/libhidl/transport/ServiceManagement.cpp 打开/dev/hwbinder,通过binder通信,获取HwServiceManager服务端。

sm->getTransport 基本就是按照Binder通信的机制来实现相关的流程。通过HwBinder调用服务端的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 根据framework hal和device hal配置的manifest.xml里面的定义,来判断当前的传输类型是HwBinder还是Passthrough模式。在vendor/manifest.xml里面,power配置的是hwbinder,所以最终就是hwBinder模式。(后续会讲解manifest.xml的原理)

由于我们采取的是defaultPassthroughServiceImplementation();进行注册,所以getStub=true.所以会走到const sp<::android::hidl::manager::V1_0::IServiceManager> pm = getPassthroughServiceManager();

- getPassthroughServiceManager @ PowerAll.cpp 获取passthrough服务管理。

- 调用PassthroughServiceManager的get(const hidl_string& fqName, const hidl_string& name)函数 @ServiceManagement.cpp, 根据传入的fqName=(android.hardware.power@1.0::IPower"),获取当前的接口名IPower,拼接出后面需要载入的函数名HIDL_FETCH_IPower和库名字android.hardware.power@1.0-impl,接着通过dlopen载入/vendor/lib/hw/android.hardware.power@1.0-impl.so,然后通过dlsym载入HIDL_FETCH_IPower函数。 代码如下:

@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复用原有hal的原理,测试用的是模拟器,所以最终获取的库文件是/system/lib/hw/power.ranchu.so,后续所有的和Power有关的接口调用,最终都是通过power.ranchu.so来实现功能。

接下来会调用registerReference("android.hardware.power@1.0::IPower","default"),接着调用BpHwServiceManager::registerPassthroughClient将fqName和服务名,注册进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实例。

new BsPower:首先会通过interfaceChain判断当前的interface是否支持转换,然后传入包名和接口名"android.hardware.power@1.0", "IPower"构造出一个new BsPower的实例。

IPower::registerAsService 接下来,调用status_t status = service->registerAsService(name),首先会创建BnHwPower对象,然后将当前的service 添加进hwservicemanager里面。初始化BnHwPower的过程中, _hidl_mImpl实际上就是BsPower的引用。代码如下。 。

返回android::hidl::base::V1_0::IBase实例。

new BsPower:首先会通过interfaceChain判断当前的interface是否支持转换,然后传入包名和接口名"android.hardware.power@1.0", "IPower"构造出一个new BsPower的实例。

IPower::registerAsService 接下来,调用status_t status = service->registerAsService(name),首先会创建BnHwPower对象,然后将当前的service 添加进hwservicemanager里面。初始化BnHwPower的过程中, _hidl_mImpl实际上就是BsPower的引用。代码如下。 。

返回android::hidl::base::V1_0::IBase实例。

new BsPower:首先会通过interfaceChain判断当前的interface是否支持转换,然后传入包名和接口名"android.hardware.power@1.0", "IPower"构造出一个new BsPower的实例。

IPower::registerAsService 接下来,调用status_t status = service->registerAsService(name),首先会创建BnHwPower对象,然后将当前的service 添加进hwservicemanager里面。初始化BnHwPower的过程中, _hidl_mImpl实际上就是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;

}

然后调用如下步骤,将当前通信加入IPC Binder的线程池进行循环。

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服务就启动成功了,可以响应客户端的请求了。

总结,通过defaultPassthroughServiceImplementation把当前的服务注册进HwServiceManager,每个服务都是一个HidlService。然后就可以等待客户端的调用。

4.2 registerAsService 创建HAL

根据Android源码网站介绍,android.hardware.dumpstate@1.0是属于绑定式HAL。接下来我们分析dumpstate服务初始化的流程。代码位于: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 设置当前进程的名字,长度最多为16。android.hardware.dumpstate@1.0-service

BpHwServiceManager::add

ServiceManager::add @system/hwservicemanager/ServiceManager.cpp 注意和binder的区别。将当前的service添加进mInstanceMap。

收到HwBinder驱动的 BR_TRANSACTION 消息,然后执行 BHwBinder::transact

BnHwDumpstateDevice::onTransact

joinRpcThreadpool(); 把当前的通信加入HwBinder的线程池进行循环。

至此,registerAsService 创建HAL Service就完成了。

4.4 Binderized 模式 client和服务端的交互

服务注册成功之后,客户端就可以调用相关服务提供的功能。

以点击屏幕为实例说明,当我们点击屏幕的时候,会调用com_android_server_power_PowerManagerService.cpp的android_server_PowerManagerService_userActivity函数,代码如下:

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();方法经过HwBinder通信,获取服务端的引用。主要包含如下步骤:

IPower::getService() 获取IPower的服务。返回远程服务的代理gPowerHal,最终返回的是BpHwPower。

IPower::getService(const std::string &serviceName, const bool getStub)@PowerApp.cpp。

BpHwServiceManager::getTransport 获取当前的传输类型,passthrough或者binderized。Power是binderized,返回对应的服务代理。

sm->get(IPower::descriptor, serviceName) 从ServiceManager里面获取描述是android.hardware.power@1.0::IPower,服务名是default的hidlservice的引用。

IPower::castFrom(base, true /* emitError */)

android::hardware::details::castInterface 将hidlservice服务的引用转换成Binder对象。

::android::hardware::IInterface::asBinder(static_cast)

4.4 pathrough 模式 client和服务端的交互

查询manifest.xml可以发现。android.hardware.graphics.mapper是passthrough的模式。

以hardware/interfaces/graphics/mapper/2.0/作为例子进行分析。

@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的模式,调用PassthroughServiceManager的get(const hidl_string& fqName, const hidl_string& name)函数 @ServiceManagement.cpp, 根据传入的fqName=(android.hardware.graphics.mapper@2.0::IMapper"),获取当前的接口名IMapper,拼接出后面需要载入的函数名HIDL_FETCH_IMapper和库名字android.hardware.graphics.mapper@2.0-impl,接着通过dlopen载入android.hardware.graphics.mapper@2.0-impl,然后通过dlsym载入HIDL_FETCH_IMapper函数。

这样就实现了passthrough模式下的通信了。

5 HAL 通信 (JAVA)

以hardware/interfaces/radio/1.0/作为例子:

当我们编译hardware/interfaces/radio/1.0/的时候,会编译出:

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,然后就可以使用里面的相关代码。

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);

}

首先会直接调用IRadio.getService来获取相关服务。

@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;

}

// 转换成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++里面的获取服务步骤类似。通过IRadio.getService()获取相关的服务,进入JNI的相关接口,获取HwServiceManager服务,然后获取当前HAL的类型(必须是Binderized),接下来获取服务对应的接口引用,接着将当前接口转换成Ibinder引用,然后创建JHwRemoteBinder对象返回给java层。

IRadio.asInterface(android.os.HwBinder.getService("android.hardware.radio@1.0::IRadio",serviceName))

java层接着调用IRadio.asInterface将Hwbinder引用转换成IRadio对象。

这样就可以通过IRadio对象调用

6. Vendor Interface Object

6.1 manifest.xml 和 compatibility_matrix.xml

在system分区和vendor分区,分别存在manifest.xml和compatibility_matrix.xml。内容大致如下:

分为两类:

framework相关的,Google默认定义完成。

device相关,有设备厂商自定义。

device可以通过DEVICE_MANIFEST_FILE和DEVICE_MATRIX_FILE指定自己的manifest.xml文件。如高通平台的项目:

DEVICE_MANIFEST_FILE:= device/qcom/msm8937_64/manifest.xml

DEVICE_MATRIX_FILE:= device/qcom/common/compatibility_matrix.xml

默认的framework manifest定义和兼容性文件定义如下:

@build/core/config.mk

FRAMEWORK_MANIFEST_FILE:= system/libhidl/manifest.xml

FRAMEWORK_COMPATIBILITY_MATRIX_FILE:= hardware/interfaces/compatibility_matrix.xml

以上文件都是通过编译生成到对应的分区,编译脚本位于build/target/board/Android.mk。

通过对比可以发现,out下面生成的和源码里面存在的文件,并不是完全一致,在Android.mk里面可以发现,这几个文件都经过了out/host/linux-x86/bin/assemble_vintf转换,assemble_vintf会判断文件格式是否正确,并且会根据name按字母顺序排列。

以上两个xml都是在,在system/libvintf/parse_string.cpp里面进行解析。

在前面的介绍中,我们都讲到了一个重要的方法,就是transport

在system/libvintf/include/vintf/Transport.h定义

static const std::array gTransportStrings = {

{

"",

"passthrough",

"hwbinder",

}

};

我们获取服务的时候,首先肯定要获取当前的HAL是什么类型。

7其他技巧

打印当前的manifest信息

mmm system/libvintf/

adb push out/target/product/(产品名)/system/bin/vintf /system/bin/vintf

adb shell vintf

作者:做机人
链接:https://www.jianshu.com/p/56bd1ea66aed
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Android Treble详细分析相关推荐

  1. Android 内存详细分析

    转载地址:http://blog.csdn.net/hnulwt/article/details/44900811 最近在网上看了不少Android内存管理方面的博文,但是文章大多都是就单个方面去介绍 ...

  2. [2021.10.14][Android P]OpenCamera详细分析(Camera2+Hal3)

    因为工作涉及到Android Camera系统的问题,本文整理了在Android P上讲解OpenCamera比较详细的文章,结合Andriod P源码,以架构图.UML顺序图.UML类图和关键代码走 ...

  3. android 串口开发_详细分析Esp8266上电信息打印的数据,如何做到串口通讯上电不乱码打印...

    01 写在前面: 上篇关于如何在内置仅1M的Esp8285做到 OTA 升级的同步到微信公众号,竟然被安信可的某些运维人员看到了,想要转载,我很欣慰,竟然自己的笔记可以被这么大型的公司员工认可! 我是 ...

  4. Android system server之PackageManagerService详细分析

    概要 本篇主要分析了系统启动阶段包管理服务的启动流程,其中的几个接口在 apk 安装时也会被调用.包管理服务启动时主要做的工作大致有如下几方面: 1. 建立 java 层的 installer 与 c ...

  5. android jni fork()子进程不运行_安卓系统最重要的进程之一:system_server详细分析...

    1 概述 SystemServer是android系统的系统服务进程.属于系统级别,其它服务进程都是应用级别.它也是android系统的唯一一个系统服务进程. SystemServer进程的名字是sy ...

  6. android ListView 九大重要属性详细分析

    2019独角兽企业重金招聘Python工程师标准>>> android ListView 九大重要属性详细分析 1.android ListView 一些重要属性详解,兄弟朋友可以参 ...

  7. 详细分析Android中的引用机制Reference(WeakReference、SoftReference、PhantomReference)

    目录 1.前言 2.四种引用 3.java.lang.ref 4.Reference 5.ReferenceQueue.enqueue(Reference) 6.ReferenceQueue.isEn ...

  8. [免费专栏] Android安全之Android so文件分析「详细版」

    也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 Android安全付费专栏长期更新,本篇最新内容请前往: [ ...

  9. 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)

    [SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...

最新文章

  1. Windows7关闭休眠
  2. 华为天才少年榜单遭受嘲讽:感觉水平一般,有点哗众取宠!
  3. 网站SEO优化之如何建设外链提升网站权重?
  4. 你必须具有权限才能读取此对象_win10中随心所欲设置文件/文件夹访问权限,可以轻松做到,并不难...
  5. html移动端怎么做城市选择,移动端页面单位的选择(px, em, rem, vw)
  6. .Net学习笔记----2015-06-30(超市收银系统01-仓库类)
  7. Knative Eventing 中如何实现 Registry 事件注册机制
  8. 在gns3中搭建VTP演示实验
  9. 改变Linux的DNS解析顺序(DNS到hosts)
  10. 在linux下运行锐捷客户端,锐捷Linux客户端使用方法(基于ubuntu16.04)
  11. dtw算法 c语言实现,dtw算法 - WELEN
  12. 国内主要OTT平台背后的那些CDN服务商
  13. php cms下载地址,让PHPCMS下载内容页显示链接真实地址
  14. 使用graphviz画树
  15. Enigma密码机初级解析
  16. Java对List集合中的对象的某个中文字段按照拼音首字母进行排序
  17. 真 · 神经网络发明人福岛邦彦获奖,Schmidhuber、李飞飞点赞
  18. HTML圆和圆角柜形的制作,圆角柜是典型的明式家具,详细解析圆角柜的智慧法则...
  19. java发邮件(简单)
  20. 366. 斐波纳契数列

热门文章

  1. 对标yaahp的python工具包
  2. FPGA 视频拼接器底图的实现
  3. 如何解决vscode使用ajax获取本地文件报错问题
  4. Vue.js 源码目录设计
  5. java64 压缩包,qq64位下载-rar 64位 v5.21 免费版
  6. Normal Distribution(正态分布)
  7. STC8H1K08 - IDLE - 空闲模式
  8. Flink(十六)—— Flink parallelism 和 Slot 介绍
  9. 流媒体协议HLS解析
  10. 软件测试行业未来职业规划是什么