传感器 Multi-HAL

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/。以下是指向一些资源的指针。

实现

本部分将介绍如何在以下情况下实现 Sensors Multi-HAL:

搭配使用 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,请按以下步骤操作:

  1. 按照 SubHal.h 中的说明实现 ISensorsSubHal 接口。
  2. SubHal.h 中实现 sensorsHalGetSubHal_2_1 方法。
  3. 添加 cc_library_shared 目标,以构建新实现的子 HAL。添加目标时,请注意以下事项:

    1. 确保将目标推送到设备 vendor 分区上的某个位置。
    2. 在位于 /vendor/etc/sensors/hals.conf 的配置文件中,另起一行添加指向库的路径。如有必要,请创建 hals.conf 文件。

    如需查看用于构建子 HAL 库的示例 Android.bp 条目,请参阅 hardware/interfaces/sensors/common/default/2.X/multihal/tests/Android.bp

  4. manifest.xml 文件中移除所有 android.hardware.sensors 条目,该文件包含设备中受支持 HAL 的列表。

  5. device.mk 文件中移除所有 android.hardware.sensors 服务和 service.rc 文件,然后将 android.hardware.sensors@2.1-service.multihalandroid.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.0 SubHal 接口中的回调
  • 子 HAL 必须实现 getSensorsList_2_1injectSensorData_2_1,而不是 getSensorsListinjectSensorData,因为这些方法使用的是在 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 中的 onDynamicSensorsConnectedonDynamicSensorsDisconnected。这些回调作为 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 中的 onDynamicSensorsConnectedonDynamicSensorsDisconnected。这些回调作为 IHalProxyCallback 指针(通过 initialize() 函数提供)的一部分提供。

从 Sensors Multi-HAL 1.0 移植

如需从 Sensors Multi-HAL1.0 移植现有实现,请按以下步骤操作。

  1. 确保 sensors HAL 配置位于 /vendor/etc/sensors/hals.conf,这可能需要移动位于 /system/etc/sensors/hals.conf 的文件。
  2. 移除对 hardware/hardware.hhardware/sensors.h 的所有引用,因为 HAL 2.0 不支持这些引用。
  3. 移植子 HAL(如从 Sensors HAL 1.0 移植中所述)。
  4. 按照实现 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 并将其推送到设备,请执行以下步骤:

  1. 运行以下命令以构建三个不同的虚构子 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
    
  2. 使用虚构子 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
    
  3. 重启 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 接口的一部分。