Sensors Multi-HAL 是一个框架,可让 Sensors HAL 与其他传感器 HAL 一起运行。Sensors Multi-HAL 会动态加载在 vendor 分区中存储为动态库的传感器子 HAL,并为这些子 HAL 提供一个回调对象,以便处理发布事件以及获取和释放唤醒锁。 传感器子 HAL 是一种 Sensors HAL,它内置在 vendor 分区中的共享对象中,由 Multi-HAL 框架使用。这些子 HAL 互不依赖,也不依赖于包含该进程的主函数的 Multi-HAL 代码。
Sensors Multi-HAL 2.1(适用于搭载 Android 11 或更高版本的设备)是 Sensors Multi-HAL 2.0 的迭代升级版本,支持加载可以公开铰链角度传感器类型的子 HAL。如需支持此传感器类型,子 HAL 必须使用 2.1 子 HAL 头文件中定义的子 HAL API。
对于搭载 Android 13 或更高版本且使用 Sensors AIDL HAL 的设备,您可以使用 Multi-HAL shim 层来允许 Multi-HAL 功能。如需了解实现详情,请参阅搭配使用 Sensors Multi-HAL 与 Sensors AIDL HAL。
Sensors Multi-HAL 2 和 Sensors HAL 2 之间的区别
Sensors Multi-HAL 2(适用于搭载 Android 10 或更高版本的设备)在 Sensors HAL 2 的基础上引入了多个抽象化功能,以便更轻松地与 HAL API 交互。Sensors Multi-HAL 2 引入了 HalProxy 类,用于处理 Sensors HAL 2 接口和 V2_1/SubHal(或 V2_0/SubHal)接口的实现,以允许 HalProxy 与子 HAL 进行交互。
ISensorsSubHal 接口在以下几个方面与 2.1/ISensors.hal(或 2.0/ISensors.hal)接口存在差异:
- 初始化方法会传递
IHalProxyCallback类,而不是两个 FMQ 和ISensorsCallback。 - 子 HAL 必须实现一个调试函数,以在 bug 报告中提供调试信息。
- 子 HAL 必须实现一个名称函数,以使加载的子 HAL 能够与其他子 HAL 区分开。
Sensors Multi-HAL 2 和 Sensors HAL 2 的主要区别在于初始化函数。IHalProxyCallback 接口不提供 FMQ,而是提供了两种方法,一种方法用于将传感器事件发布到传感器框架,另一种方法用于创建唤醒锁。从本质上讲,Sensors Multi-HAL 管理与 FMQ 的所有交互,以确保及时为所有子 HAL 提供传感器事件。强烈建议子 HAL 使用 createScopedWakelock 方法将要超时的唤醒锁的处理作业委派给 Sensors Multi-HAL,并将唤醒锁的使用集中到一个对整个 Sensors Multi-HAL 通用的唤醒锁,从而最大限度地减少锁定和解锁调用次数。
Sensors Multi-HAL 2 还具有一些内置安全功能。它可处理传感器 FMQ 已满或 Android 传感器框架重启且需要重置传感器状态等情况。此外,当事件发布到 HalProxy 类但传感器框架无法立即接受这些事件时,Sensors Multi-HAL 可以将这些事件移到后台线程,以便在等待事件发布时,让所有子 HAL 中的工作继续进行。
源代码和参考实现
所有 Sensors Multi-HAL 代码都保存在 hardware/interfaces/sensors/common/default/2.X/multihal/。以下是指向一些资源的指针。
HalProxy.h:HalProxy对象已由 Sensors multi-HAL 实例化,可处理从子 HAL 到传感器框架的数据传递操作。HalProxy.cpp:HalProxy的实现包含子 HAL 与传感器框架之间的多路复用通信所需的所有逻辑。SubHal.h:ISensorsSubHal接口定义了子 HAL 为与HalProxy兼容而必须遵循的接口。子 HAL 实现了初始化方法,以便将HalProxyCallback对象用于postEvents和createScopedWakelock。对于 Multi-HAL 2.0 实现,请使用 2.0 版
SubHal.h。hardware/interfaces/sensors/common/default/2.X/multihal/tests/:这些单元测试用于验证HalProxy实现。hardware/interfaces/sensors/common/default/2.X/multihal/tests/fake_subhal/:此示例子 HAL 实现使用虚构传感器生成虚假数据。可用于测试多个子 HAL 如何在设备中交互。
实现
本部分将介绍如何在以下情况下实现 Sensors Multi-HAL:
- 搭配使用 Sensors Multi-HAL 与 Sensors AIDL HAL
- 实现 Sensors Multi-HAL 2.1
- 从 Sensors Multi-HAL 2.0 移植到 Multi-HAL 2.1
- 从 Sensors HAL 2.0 移植
- 从 Sensors HAL 1.0 移植
- 从 Sensors Multi-HAL 1.0 移植
搭配使用 Sensors Multi-HAL 与 Sensors AIDL HAL
如需配合使用 Sensors AIDL HAL 和 Multi-HAL 功能,请导入 AIDL Multi-HAL shim 层模块(位于:hardware/interfaces/sensors/aidl/default/multihal/)。该模块可处理 AIDL 和 HIDL 传感器 HAL 定义类型之间的转换,并定义一个围绕 Multi-HAL 接口的封装容器,如实现 Sensors Multi-HAL 2.1 中所述。AIDL Multi-HAL shim 层与实现 Sensors Multi-HAL 2.1 的设备兼容。
借助 AIDL Multi-HAL shim 层,您可以在 Sensors AIDL HAL 中公开头部跟踪器和受限轴 IMU 传感器类型。如需使用由 AIDL HAL 接口定义的这些传感器类型,请在 getSensorsList_2_1() 实现中的 SensorInfo 结构体中设置 type 字段。这是安全的,因为 AIDL 和 HIDL 传感器 HAL 由整数支持的传感器类型字段不重叠。
实现 Sensors Multi-HAL 2.1
如需在新设备上实现 Sensors Multi-HAL 2.1,请按以下步骤操作:
- 按照
SubHal.h中的说明实现ISensorsSubHal接口。 - 在
SubHal.h中实现sensorsHalGetSubHal_2_1方法。 添加
cc_library_shared目标,以构建新实现的子 HAL。添加目标时,请注意以下事项:- 确保将目标推送到设备 vendor 分区上的某个位置。
- 在位于
/vendor/etc/sensors/hals.conf的配置文件中,另起一行添加指向库的路径。如有必要,请创建hals.conf文件。
如需查看用于构建子 HAL 库的示例
Android.bp条目,请参阅hardware/interfaces/sensors/common/default/2.X/multihal/tests/Android.bp。从
manifest.xml文件中移除所有android.hardware.sensors条目,该文件包含设备中受支持 HAL 的列表。从
device.mk文件中移除所有android.hardware.sensors服务和service.rc文件,然后将android.hardware.sensors@2.1-service.multihal和android.hardware.sensors@2.1-service.multihal.rc添加到PRODUCT_PACKAGES。
在启动时,HalProxy 开始运行,查找新实现的子 HAL,并通过调用 sensorsHalGetSubHal_2_1 对其进行初始化。
从 Sensors Multi-HAL 2.0 移植到 Multi-HAL 2.1
如需从 Multi-HAL 2.0 移植到 Multi-HAL 2.1,请实现 SubHal 接口并重新编译子 HAL。
下面是 2.0 和 2.1 SubHal 接口之间的区别:
IHalProxyCallback使用在 2.1 版ISensors.hal规范中创建的类型。initialize()函数传递新的IHalProxyCallback,而不是 2.0SubHal接口中的回调- 子 HAL 必须实现
getSensorsList_2_1和injectSensorData_2_1,而不是getSensorsList和injectSensorData,因为这些方法使用的是在 2.1 版ISensors.hal规范中添加的新类型。 - 子 HAL 必须公开
sensorsHalGetSubHal_2_1而不是sensorsHalGetSubHal,这样 Multi-HAL 才会将它们视作 2.1 版子 HAL。
从 Sensors HAL 2.0 移植
从 Sensors HAL 2.0 升级到 Sensors Multi-HAL 2.0 时,请确保 HAL 实现满足以下要求。
初始化 HAL
Sensors HAL 2.0 具有一个初始化函数,使传感器服务可以传递 FMQ 和动态传感器回调。在 Sensors Multi-HAL 2.0 中,initialize() 函数会传递一个回调,必须使用该回调来发布传感器事件、获取唤醒锁,以及通知动态传感器连接和断开连接情况。
将传感器事件发布到 Multi-HAL 实现
当传感器事件可用时,子 HAL 必须将传感器事件写入 IHalProxyCallback,而不是通过 FMQ 发布传感器事件。
WAKE_UP 事件
在 Sensors HAL 2.0 中,HAL 可以管理针对其实现的唤醒锁定。在 Sensors Multi-HAL 2.0 中,子 HAL 允许 Multi-HAL 实现管理唤醒锁,并且可以通过调用 createScopedWakelock 请求获取唤醒锁。
在将唤醒事件发布到 Multi-HAL 实现时,必须获取已锁定且限定作用域的唤醒锁,并将其传递给 postEvents。
动态传感器
Sensors Multi-HAL 2.0 要求,每次动态传感器连接发生变化时,都必须调用 IHalProxyCallback 中的 onDynamicSensorsConnected 和 onDynamicSensorsDisconnected。这些回调作为 IHalProxyCallback 指针(通过 initialize() 函数提供)的一部分提供。
从 Sensors HAL 1.0 移植
从 Sensors HAL 1.0 升级到 Sensors Multi-HAL 2.0 时,请确保 HAL 实现满足以下要求。
初始化 HAL
为了在子 HAL 和 Multi-HAL 实现之间建立回调,必须支持 initialize() 函数。
公开可用的传感器
在 Sensors Multi-HAL 2.0 中,getSensorsList() 函数在单次设备启动期间必须返回相同的值,即使 sensors HAL 在此期间进行了重启也是如此。这样一来,框架就可以在系统服务器重启时尝试重建传感器连接。在设备重新启动后,getSensorsList() 返回的值可以更改。
将传感器事件发布到 Multi-HAL 实现
在 Sensors HAL 2.0 中,子 HAL 必须在有可用的传感器事件时主动将传感器事件写入 IHalProxyCallback,而不是等待调用 poll()。
WAKE_UP 事件
在 Sensors HAL 1.0 中,HAL 可以管理针对其实现的唤醒锁定。在 Sensors Multi-HAL 2.0 中,子 HAL 允许 Multi-HAL 实现管理唤醒锁,并且可以通过调用 createScopedWakelock 请求获取唤醒锁。
在将唤醒事件发布到 Multi-HAL 实现时,必须获取已锁定且限定作用域的唤醒锁,并将其传递给 postEvents。
动态传感器
在 Sensors HAL 1.0 中,动态传感器通过 poll() 函数返回。Sensors Multi-HAL 2.0 要求,每次动态传感器连接发生变化时,都必须调用 IHalProxyCallback 中的 onDynamicSensorsConnected 和 onDynamicSensorsDisconnected。这些回调作为 IHalProxyCallback 指针(通过 initialize() 函数提供)的一部分提供。
从 Sensors Multi-HAL 1.0 移植
如需从 Sensors Multi-HAL1.0 移植现有实现,请按以下步骤操作。
- 确保 sensors HAL 配置位于
/vendor/etc/sensors/hals.conf,这可能需要移动位于/system/etc/sensors/hals.conf的文件。 - 移除对
hardware/hardware.h和hardware/sensors.h的所有引用,因为 HAL 2.0 不支持这些引用。 - 移植子 HAL(如从 Sensors HAL 1.0 移植中所述)。
- 按照实现 Sensors Multi-HAL 2.0 部分中的第 3 步和第 4 步,将 Sensors Mutli-HAL 2.0 设置为指定 HAL。
验证
运行 VTS
将一个或多个子 HAL 与 Sensors Multi-HAL 2.1 集成后,请使用供应商测试套件 (VTS) 确保您的子 HAL 实现满足 Sensors HAL 接口设置的所有要求。
如需仅在宿主机上设置 VTS 时运行传感器 VTS 测试,请执行以下命令:
vts-tradefed run commandAndExit vts \
--skip-all-system-status-check \
--primary-abi-only \
--skip-preconditions \
--module VtsHalSensorsV2_0Target && \
vts-tradefed run commandAndExit vts \
--skip-all-system-status-check \
--primary-abi-only \
--skip-preconditions \
--module VtsHalSensorsV2_1Target
如果您运行的是 AIDL Multi-HAL shim 层,请运行 VtsAidlHalSensorsTargetTest。
vts-tradefed run commandAndExit vts \
--skip-all-system-status-check \
--primary-abi-only \
--skip-preconditions \
--module VtsAidlHalSensorsTargetTest
运行单元测试
HalProxy_test.cpp 中的单元测试使用虚构的子 HAL(在单元测试中实例化,但未动态加载)对 HalProxy 进行测试。在创建新的子 HAL 时,这些测试应作为指导,指导用户添加单元测试,以验证新的子 HAL 是否已正确实现。
如需运行测试,请执行以下命令:
cd $ANDROID_BUILD_TOP/hardware/interfaces/sensors/common/default/2.X/multihal/testsatest
使用虚构 sub-HAL 进行测试
虚构子 HAL 是 ISensorsSubHal 接口的虚拟实现。
这些子 HAL 公开了不同的传感器列表。传感器启用后,它们会根据指定传感器请求中指定的时间间隔,将生成的传感器事件定期自动发布到 HalProxy。
这些虚构子 HAL 可用于测试完整的 Multi-HAL 代码如何与加载到系统中的其他子 HAL 兼容,从而强调 Sensors Multi-HAL 代码的各个方面。
hardware/interfaces/sensors/common/default/2.X/multihal/tests/fake_subhal/ 提供两个虚构子 HAL。
如需构建虚构子 HAL 并将其推送到设备,请执行以下步骤:
运行以下命令以构建三个不同的虚构子 HAL 并将其推送到设备:
$ANDROID_BUILD_TOP/hardware/interfaces/sensors/common/default/2.X/multihal/tests/mmaadb push \ $ANDROID_BUILD_TOP/out/target/product/<device>/symbols/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config1.so \ /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config1.soadb push \ $ANDROID_BUILD_TOP/out/target/product/<device>/symbols/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config2.so \ /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config2.soadb push \ $ANDROID_BUILD_TOP/out/target/product/<device>/symbols/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config3.so \ /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config3.so使用虚构子 HAL 的路径更新
/vendor/etc/sensors/hals.conf中的 Sensors HAL 配置。/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config1.so /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config2.so /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config3.so重启
HalProxy并加载配置中列出的新子 HAL。adb shell stopadb shell start
调试
开发者可使用 lshal 命令调试框架。如需请求 Sensors HAL 的调试输出,请运行以下命令:
adb rootadb shell lshal debug android.hardware.sensors@2.1::ISensors/default
然后,系统会将 HalProxy 及其子 HAL 的当前状态信息输出到终端。下面是 HalProxy 对象和虚构子 HAL 的命令输出示例。
Internal values:
Threads are running: true
Wakelock timeout start time: 200 ms ago
Wakelock timeout reset time: 73208 ms ago
Wakelock ref count: 0
# of events on pending write queue: 0
# of non-dynamic sensors across all subhals: 8
# of dynamic sensors across all subhals: 0
SubHals (2):
Name: FakeSubHal-OnChange
Debug dump:
Available sensors:
Name: Ambient Temp Sensor
Min delay: 40000
Flags: 2
Name: Light Sensor
Min delay: 200000
Flags: 2
Name: Proximity Sensor
Min delay: 200000
Flags: 3
Name: Relative Humidity Sensor
Min delay: 40000
Flags: 2
Name: FakeSubHal-OnChange
Debug dump:
Available sensors:
Name: Ambient Temp Sensor
Min delay: 40000
Flags: 2
Name: Light Sensor
Min delay: 200000
Flags: 2
Name: Proximity Sensor
Min delay: 200000
Flags: 3
Name: Relative Humidity Sensor
Min delay: 40000
Flags: 2
如果为 # of events on pending write queue 指定的数字很大(1000 或更大),则表示有许多待写入传感器框架的事件。这表示传感器服务已死锁或已崩溃,并且未在处理传感器事件,或者最近通过子 HAL 发布了大量传感器事件。
如果唤醒锁引用计数大于 0,表示 HalProxy 已获取唤醒锁。只有在 ScopedWakelock 被有意保留或唤醒事件已发送到 HalProxy 且未被传感器框架处理时,该值才应大于 0。
传递到 HalProxy 的调试方法的文件描述符会传递到每个子 HAL,因此开发者必须将调试方法实现为 ISensorsSubHal 接口的一部分。