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

更多相关文章

  1. Android入门教程(四)之------Android工程目录结构介绍
  2. android的文件系统结构及其引导过程的初步理解
  3. 如何在Android中使用OpenCV
  4. Android文件系统的提取方法(一)
  5. [Android][Android(安卓)Studio] *.jar 与 *.aar 的生成与*.aar
  6. Android发送邮件附带文件
  7. Android的init过程(二):初始化语言(init.rc)解析
  8. NPM 和webpack 的基础使用
  9. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程

随机推荐

  1. Android在应用中固定屏幕方向
  2. Android应用程序的权限列表
  3. android ExpandableListView简单例子
  4. android 去ListView滑动阴影
  5. 修改ZXing for Android为竖屏模式
  6. android的四大组件及其生命周期
  7. Android(安卓)布局中 如何使控件居中
  8. Android中RelativeLayout的字符水平(垂直
  9. Android开发前奏
  10. 【Android工场】Android(安卓)Input Syst