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/tests
atest
使用虚构 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/
mma
adb 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.so
adb 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.so
adb 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 stop
adb shell start
调试
开发者可使用 lshal
命令调试框架。如需请求 Sensors HAL 的调试输出,请运行以下命令:
adb root
adb 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
接口的一部分。