传感器多 HAL

传感器多 HAL 是一个框架,允许传感器 HAL 与其他传感器 HAL 并行运行。传感器多 HAL 动态加载存储为供应商分区上动态库的传感器子 HAL,并为它们提供一个可以处理发布事件以及获取和释放唤醒锁的回调对象。传感器子 HAL 是一种传感器 HAL,它内置在供应商分区上的共享对象中,并由多 HAL 框架使用。这些子 HAL 彼此之间或与包含进程主函数的多 HAL 代码之间互不依赖。

传感器多 HAL 2.1(在搭载 Android 11 或更高版本的设备上可用)是传感器多 HAL 2.0 的迭代版本,它支持加载可以公开铰链角度传感器类型的子 HAL。为了支持这种传感器类型,子 HAL 必须使用 2.1 SubHal 标头中定义的子 HAL API。

对于运行 Android 13 或更高版本且使用传感器 AIDL HAL的设备,您可以使用多 HAL 垫片层来实现多 HAL 功能。如需了解实现详情,请参阅将传感器多 HAL 与传感器 AIDL HAL 结合使用

传感器多 HAL 2 和传感器 HAL 2 之间的区别

传感器多 HAL 2(在搭载 Android 10 或更高版本的设备上可用)在传感器 HAL 2之上引入了多个抽象层,以便更轻松地与 HAL API 交互。传感器多 HAL 2 引入了 HalProxy 类来处理传感器 HAL 2 接口的实现,并引入了 V2_1/SubHal(或 V2_0/SubHal)接口,以允许 HalProxy 与子 HAL 交互。

ISensorsSubHal 接口与 2.1/ISensors.hal(或 2.0/ISensors.hal)接口的不同之处在于以下几点:

  • initialize 方法传递 IHalProxyCallback 类,而不是两个 FMQ 和 ISensorsCallback
  • 子 HAL 必须实现调试函数,以便在错误报告中提供调试信息。
  • 子 HAL 必须实现名称函数,以便可以将加载的子 HAL 与其他子 HAL 区分开来。

传感器多 HAL 2 和传感器 HAL 2 之间的主要区别在于 initialize 函数。与提供 FMQ 不同,IHalProxyCallback 接口提供了两种方法:一种方法是将传感器事件发布到传感器框架,另一种方法是创建唤醒锁。在底层,传感器多 HAL 管理与 FMQ 的所有交互,以确保及时交付所有子 HAL 的传感器事件。强烈建议子 HAL 使用 createScopedWakelock 方法,将唤醒锁超时的负担委托给传感器多 HAL,并将唤醒锁的使用集中到整个传感器多 HAL 的一个通用唤醒锁,从而最大限度地减少锁定和解锁调用。

传感器多 HAL 2 还具有一些内置的安全功能。它可以处理传感器 FMQ 已满或 Android 传感器框架重启且传感器状态需要重置的情况。此外,当事件发布到 HalProxy 类,但传感器框架无法立即接受事件时,传感器多 HAL 可以将事件移动到后台线程,以便在等待事件发布时,所有子 HAL 上的工作都可以继续进行。

源代码和参考实现

所有传感器多 HAL 代码都可在 hardware/interfaces/sensors/common/default/2.X/multihal/ 中找到。以下是指向一些资源的指针。

实现

本部分介绍如何在以下情况下实现传感器多 HAL:

将传感器多 HAL 与传感器 AIDL HAL 结合使用

为了使用传感器 AIDL HAL 实现多 HAL 功能,请导入 AIDL 多 HAL 垫片层模块,该模块位于 hardware/interfaces/sensors/aidl/default/multihal/。该模块处理 AIDL 和 HIDL 传感器 HAL 定义类型之间的转换,并定义了 实现传感器多 HAL 2.1中描述的多 HAL 接口的封装容器。AIDL 多 HAL 垫片层与实现传感器多 HAL 2.1 的设备兼容。

借助 AIDL 多 HAL 垫片层,您可以在传感器 AIDL HAL 中公开头部追踪器和有限轴 IMU 传感器类型。要使用 AIDL HAL 接口定义的这些传感器类型,请在 getSensorsList_2_1() 实现中设置 SensorInfo 结构中的 type 字段。这是安全的,因为 AIDL 和 HIDL 传感器 HAL 的整数支持的传感器类型字段不重叠。

实现传感器多 HAL 2.1

要在新设备上实现传感器多 HAL 2.1,请按照以下步骤操作:

  1. 按照 SubHal.h 中的描述实现 ISensorsSubHal 接口。
  2. SubHal.h 中实现 sensorsHalGetSubHal_2_1 方法。
  3. 添加 cc_library_shared 目标以构建新实现的子 HAL。添加目标时:

    1. 确保将目标推送到设备供应商分区上的某个位置。
    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 文件(其中包含设备上支持的 HAL 列表)中移除所有 android.hardware.sensors 条目。

  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 对其进行初始化。

从传感器多 HAL 2.0 移植到多 HAL 2.1

要从多 HAL 2.0 移植到多 HAL 2.1,请实现 SubHal 接口并重新编译子 HAL。

以下是 2.0 和 2.1 SubHal 接口之间的区别:

  • IHalProxyCallback 使用在 ISensors.hal 规范的 2.1 版本中创建的类型。
  • initialize() 函数传递新的 IHalProxyCallback,而不是来自 2.0 SubHal 接口的 IHalProxyCallback
  • 子 HAL 必须实现 getSensorsList_2_1injectSensorData_2_1,而不是 getSensorsListinjectSensorData,因为这些方法使用在 ISensors.hal 规范的 2.1 版本中添加的新类型。
  • 子 HAL 必须公开 sensorsHalGetSubHal_2_1,而不是 sensorsHalGetSubHal,以便多 HAL 将它们视为 2.1 版本的子 HAL。

从传感器 HAL 2.0 移植

传感器 HAL 2.0升级到传感器多 HAL 2.0 时,请确保 HAL 实现满足以下要求。

初始化 HAL

传感器 HAL 2.0 具有一个 initialize 函数,允许传感器服务传递 FMQ 和动态传感器回调。在传感器多 HAL 2.0 中,initialize() 函数传递单个回调,该回调必须用于发布传感器事件、获取唤醒锁以及通知动态传感器连接和断开连接。

将传感器事件发布到多 HAL 实现

子 HAL 必须将传感器事件写入 IHalProxyCallback,而不是通过 FMQ 发布传感器事件,以便在传感器事件可用时发布。

WAKE_UP 事件

在传感器 HAL 2.0 中,HAL 可以管理其实现的唤醒锁。在传感器多 HAL 2.0 中,子 HAL 允许多 HAL 实现管理唤醒锁,并且可以通过调用 createScopedWakelock 来请求获取唤醒锁。在向多 HAL 实现发布唤醒事件时,必须获取锁定的作用域唤醒锁并将其传递给 postEvents

动态传感器

传感器多 HAL 2.0 要求,每当动态传感器连接发生变化时,都必须调用 IHalProxyCallback 中的 onDynamicSensorsConnectedonDynamicSensorsDisconnected。这些回调作为通过 initialize() 函数提供的 IHalProxyCallback 指针的一部分提供。

从传感器 HAL 1.0 移植

传感器 HAL 1.0升级到传感器多 HAL 2.0 时,请确保 HAL 实现满足以下要求。

初始化 HAL

必须支持 initialize() 函数,以建立子 HAL 和多 HAL 实现之间的回调。

公开可用的传感器

在传感器多 HAL 2.0 中,getSensorsList() 函数必须在单个设备启动期间返回相同的值,即使在传感器 HAL 重启后也是如此。这允许框架在系统服务器重启时尝试重新建立传感器连接。getSensorsList() 返回的值可以在设备执行重启后更改。

将传感器事件发布到多 HAL 实现

在传感器 HAL 2.0 中,子 HAL 必须在传感器事件可用时主动将传感器事件写入 IHalProxyCallback,而不是等待调用 poll()

WAKE_UP 事件

在传感器 HAL 1.0 中,HAL 可以管理其实现的唤醒锁。在传感器多 HAL 2.0 中,子 HAL 允许多 HAL 实现管理唤醒锁,并且可以通过调用 createScopedWakelock 来请求获取唤醒锁。在向多 HAL 实现发布唤醒事件时,必须获取锁定的作用域唤醒锁并将其传递给 postEvents

动态传感器

在传感器 HAL 1.0 中,动态传感器通过 poll() 函数返回。传感器多 HAL 2.0 要求,每当动态传感器连接发生变化时,都必须调用 IHalProxyCallback 中的 onDynamicSensorsConnectedonDynamicSensorsDisconnected。这些回调作为通过 initialize() 函数提供的 IHalProxyCallback 指针的一部分提供。

从传感器多 HAL 1.0 移植

要从 传感器多 HAL 1.0 移植现有实现,请按照以下步骤操作。

  1. 确保传感器 HAL 配置位于 /vendor/etc/sensors/hals.conf。这可能涉及到移动位于 /system/etc/sensors/hals.conf 的文件。
  2. 移除对 hardware/hardware.hhardware/sensors.h 的任何引用,因为 HAL 2.0 不支持这些引用。
  3. 按照从传感器 Hal 1.0 移植中的描述移植子 HAL。
  4. 通过执行实现传感器多 HAL 2.0部分中的步骤 3 和 4,将传感器多 HAL 2.0 设置为指定的 HAL。

验证

运行 VTS

当您将一个或多个子 HAL 与传感器多 HAL 2.1 集成后,请使用 供应商测试套件 (VTS) 来确保您的子 HAL 实现满足传感器 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 多 HAL 垫片层,请运行 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

使用虚假子 HAL 进行测试

虚假子 HAL 是 ISensorsSubHal 接口的虚拟实现。子 HAL 公开不同的传感器列表。当传感器激活时,它们会根据给定传感器请求中指定的间隔,定期将自动生成的传感器事件发布到 HalProxy

虚假子 HAL 可用于测试完整的传感器多 HAL 代码如何与加载到系统中的其他子 HAL 协同工作,以及用于强调传感器多 HAL 代码的各个方面。

两个虚假子 HAL 在 hardware/interfaces/sensors/common/default/2.X/multihal/tests/fake_subhal/ 中提供。

要构建虚假子 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 中的传感器 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 命令调试框架。要请求传感器 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 接口的一部分。