AndroidT(13)--支持MultiHal 的 SensorHal启动--HIDL(四)

1.概览

  The Sensors Multi-HAL is a framework that allows sensors HALs to run alongside other sensor HALs. The Sensors Multi-HAL dynamically loads sensors sub-HALs stored as dynamic libraries on the vendor partition and gives them a callback object that can handle posting events and acquiring and releasing the wake lock. A sensors sub-HAL is a sensors HAL that is built into a shared object on the vendor partition and is used by the multi-HAL framework. These sub-HALs don’t depend on one another or on the multi-HAL code that contains the main function for the process.
  关于MutiHal更详细的说明可以参考Android的官方文档,其中包括和普通sensorhal的不同点以及如何适配multiHal等主要的说明。官方文档 sensors-multihal
  另外本章不涉及HIDL接口的编写及使用说明,读者只要将其理解为和c++/java中的接口对等即可,只不过HIDL支持跨进程的方式调用。

2.SensorHal的编译

  SensorHal是以独立的进程进行的,下面看看AndroidT中是如何对其进行编译的。

//hardware/interfaces/sensors/2.0/multihal/Android.bp
cc_binary {
    name: "android.hardware.sensors@2.0-service.multihal",
    ...
    vendor: true,
    relative_install_path: "hw",
    srcs: [
        "service.cpp",
    ],
    init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
    ...
    header_libs: [
        "android.hardware.sensors@2.X-shared-utils",
    ],
    shared_libs: [
        "android.hardware.sensors@2.0",
        "android.hardware.sensors@2.1",
        ...
    ],
}

  根据字段name、vendor以及relative_install_path可知,最终编译出的可执行程序名为 android.hardware.sensors@2.0-service.multihal 且位于/vendor/bin/hw下。
  init_rc中的文件描述在init阶段,SensorHal的启动特性,例如进程的名字、所在组、优先级等。

//hardware/interfaces/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
    class hal
    user system
    group system wakelock context_hub
    task_profiles ServiceCapacityLow
    capabilities BLOCK_SUSPEND
    rlimit rtprio 10 10

  srcs字段描述可执行程序的源码组成。至于其它字段可以参考文档

out/soong/docs/cc.html

3.SensorHal的启动

  SensorHal的进程由init根据其给定的rc文件来启动,下面是部分定义

service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal

  不难看出是以service的形式来启动它的,即没有指定oneshot的情况下,在 vendor.sensors-hal-2-0-multihal 退出后,init进程会再次启动它。Sensor Hal的源文件就一个,即service.cpp,下面看看其启动流程

//hardware/interfaces/sensors/2.0/multihal
int main(int /* argc */, char** /* argv */) {
    android::sp<ISensors> halProxy = new HalProxyV2_0();
    halProxy->registerAsService()
    joinRpcThreadpool();
    return 1;  // joinRpcThreadpool shouldn't exit
}

  程序启动后只做两件事
    1)为接口 ISensors 实例化一个它的子类,即实现类。
    2)将HalProxyV2_0注册到 hwservicemanager 中去,如此才能支持跨进程的方式调用。HIDL接口的registerAsService则是用于此。至于其实现会在HIDL的实现系列文章中进行说明。读者目前只要知道,在其他进程中如何使用即可,下面是一个简单的例子

//client.cpp
int main(){

    android::sp<ISensors> sensorHal = ISensors::getService();
}

  在注册完实例后,当然就是等待用户请求了,所以进程是不能退出并且要能处理用户发来的请求的,此处joinRpcThreadpool方法就是用于此,下面给出调用流程,

//system/libhidl/transport/HidlBinderSupport.cpp
joinRpcThreadpool
    joinBinderRpcThreadpool() {
        IPCThreadState::self()->joinThreadPool();
            do{
                // now get the next command to be processed, waiting if necessary
                result = getAndExecuteCommand();
                    result = talkWithDriver();
                        ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
                    result = executeCommand(cmd);
            } while (result != -ECONNREFUSED && result != -EBADF);

4.HalProxy2_0 的初始化

  HalProxy2_0 是接口ISensor的实现类,所以以后客户端通过ISensor接口的调用,实际上就是调用HalProxy2_0内部的实现。下面看下它的类图
在这里插入图片描述

  引入IHalProxy是因为较新的HAL不能伪装成较旧的HAL,引入IHalProxy后允许在编译阶段选择HAL 2.0或HAL 2.1作为HalProxy的实现。所以不论是使用V2_1::ISensor还是V2_0::ISensor,最终都是需要实例化HalProxy的,下面看下它的实例化

//hardware\interfaces\sensors\common\default\2.x\multihal\HalProxy.cpp
HalProxy::HalProxy() {
    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
    init();
        initializeSensorList();  
}

  kMultiHalConfigFile指向的文件中存放子SensorHal的动态库。

4.1 加载动态库–initializeSubHalListFromConfigFile

  为了更好的查看它的意图,精简下它的代码

//hardware\interfaces\sensors\common\default\2.x\multihal\HalProxy.cpp
void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
    while (subHalConfigStream >> subHalLibraryFile) {
        //code 1
        void* handle = getHandleForSubHalSharedObject(subHalLibraryFile);
        //code 2
        SensorsHalGetSubHalV2_1Func* getSubHalV2_1Ptr =
                (SensorsHalGetSubHalV2_1Func*)dlsym(handle, "sensorsHalGetSubHal_2_1");
        std::function<SensorsHalGetSubHalV2_1Func> sensorsHalGetSubHal_2_1 =
                *getSubHalV2_1Ptr;

        ISensorsSubHalV2_1* subHal = sensorsHalGetSubHal_2_1(&version);
        //code 3
        if (version == SUB_HAL_2_1_VERSION)
            mSubHalList.push_back(std::make_unique<SubHalWrapperV2_1>(subHal))
    }
}
4.1.1 获取动态库的句柄–code1

    在知道了各个动态库的路径后,那就准备加载他们了

//hardware\interfaces\sensors\common\default\2.x\multihal\HalProxy.cpp
void* HalProxy::getHandleForSubHalSharedObject(const std::string& filename) {
    static const std::string kSubHalShareObjectLocations[] = {
            "",  // Default locations will be searched
    #ifdef __LP64__
            "/vendor/lib64/hw/", "/odm/lib64/hw/"
    #else
            "/vendor/lib/hw/", "/odm/lib/hw/"
    #endif
        for (const std::string& dir : kSubHalShareObjectLocations) {
            void* handle = dlopen((dir + filename).c_str(), RTLD_NOW);
            if (handle != nullptr) {
                return handle;
            }
        }
    }
}

  从kSubHalShareObjectLocations中可以看出,配置文件中除了支持绝对路径的精准查外,还支持在lib目录下根据给定动态库名字的方式进行查找。对于按动态库名的方式查找的,如果是以64bit方式编译SensorHal的话,就到 /vendor/lib64/hw/ 下查找动态库。只要找到符合的动态库就调用dlopen打开并返回它的handle。后面通过操作handle就可以使用动态库中提供的各种资源了。

4.1.2 调用动态库中的方法sensorsHalGetSubHal_2_1–code2

  所有的子SensorHal内部是需要实现特定的接口的,在V2_1版本中则需要实现接口sensorsHalGetSubHal_2_1,其定义如下

::android::hardware::sensors::V2_1::implementation::ISensorsSubHal* sensorsHalGetSubHal_2_1( uint32_t* version);

  必须返回以ISensorsSubHal为父类的子类的实例,后续ProxyHal调用子SensorHal都是通过该接口。下面看下其类图
在这里插入图片描述

  SensorsHalGetSubHalV2_1Func的定义如下

//hardware/interfaces/sensors/common/default/2.X/multihal/HalProxy.cpp
typedef V2_1::implementation::ISensorsSubHal*(SensorsHalGetSubHalV2_1Func)(uint32_t*);
4.1.3 校验动态库版本–code3

  基于不同版本的HIDL接口实现的HalProxy则需要不同的ISensorsSubHal接口实现来调用子类,所以ProxyHal中调用的版本要和子类实现的HIDL 版本匹配才行。
  在版本校验通过后,就需要将子SensorHal返回的示例指针存储下来供下次使用,这里是使用mSubHalList来存储的,它的定义如下

class HalProxy{
private:
    std::vector<std::shared_ptr<ISubHalWrapperBase>> mSubHalList;
}

  存储的时候则用类SubHalWrapperV2_1对子SensorHal返回的实例再次封装,并用 SubHalWrapperBase::mSubHalList 私有成员指向它

mSubHalList.push_back(std::make_unique<SubHalWrapperV2_1>(subHal));

  SubHalWrapperV2_1 的类图如下
在这里插入图片描述

4.2 获取Sensor信息–initializeSensorList

  这一步用于调用子SensorHal中的接口getSensorsList来获取具体的sensor信息,并且进行存储供后面使用。

//hardware/interfaces/sensors/common/default/2.X/multihal/HalProxy.cpp
void HalProxy::initializeSensorList() {
    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
        auto result = mSubHalList[subHalIndex]->getSensorsList([&](const auto& list) {
            for (SensorInfo sensor : list) {
                sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
                setDirectChannelFlags(&sensor, mSubHalList[subHalIndex]);
                mSensors[sensor.sensorHandle] = sensor;
            }
        });
    }
}

  通过遍历mSubHalList,也就是每一个子SensorHal,然后再调用 getSensorsList接口获取其内部所支持的sensor信息。最后将sensor信息存到mSensors中去。

//hardware/interfaces/sensors/common/default/2.X/multihal/HalProxy.cpp
class HalProxy{
private:
    std::map<int32_t, SensorInfo> mSensors;
};

  下面看下各个sensor再map中存储的索引是如何生成的

//hardware\interfaces\sensors\common\default\2.x\multihal\HalProxy.cpp
static constexpr int32_t kBitsAfterSubHalIndex = 24;
for (SensorInfo sensor : list) {
    sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
        return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
    mSensors[sensor.sensorHandle] = sensor;
}

  低24bit用于存储各个sensor在子SensorHal中的handle,高8bit则用于区分他们所来自的子SensorHal。

|----------8bit------------|---------24bit---------|
    number of subSsensorHal       sensor.handle

5.流程图

在这里插入图片描述

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值