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