传感器硬件抽象层 (HAL) 是 Android 传感器框架与设备传感器(例如加速度计或陀螺仪)之间的接口。传感器 HAL 定义了必须实现的功能,以允许框架控制传感器。
Android 10 及更高版本中为新设备和升级设备提供了 Sensors HAL 2.0。Sensors HAL 2.0 基于 Sensors HAL 1.0,但有几个主要区别,这使其无法向后兼容。Sensors HAL 2.0 使用快速消息队列 (FMQ),以将传感器事件从 HAL 发送到 Android 传感器框架。
Android 11 及更高版本中为新设备和升级设备提供了 Sensors HAL 2.1。Sensors HAL 2.1 是 Sensors HAL 2.0 的迭代版本,它公开了 HINGE_ANGLE
传感器类型,并更新了各种方法以接受 HINGE_ANGLE
类型。
HAL 2.1 接口
Sensors HAL 2.1 的主要文档来源位于 HAL 定义中,网址为 hardware/interfaces/sensors/2.1/ISensors.hal。如果此页面与 ISensors.hal
的要求发生冲突,请使用 ISensors.hal
中的要求。
HAL 2.0 接口
Sensors HAL 2.0 的主要文档来源位于 HAL 定义中,网址为 hardware/interfaces/sensors/2.0/ISensors.hal。如果此页面与 ISensors.hal
的要求发生冲突,请使用 ISensors.hal
中的要求。
实现 Sensors HAL 2.0 和 HAL 2.1
要实现 Sensors HAL 2.0 或 2.1,对象必须扩展 ISensors
接口并实现 2.0/ISensors.hal
或 2.1/ISensors.hal
中定义的所有函数。
初始化 HAL
传感器框架必须先初始化 Sensors HAL,然后才能使用它。框架调用 HAL 2.0 的 initialize()
函数和 HAL 2.1 的 initialize_2_1()
函数,以向 Sensors HAL 提供三个参数:两个 FMQ 描述符和一个指向 ISensorsCallback
对象的指针。
HAL 使用第一个描述符来创建 Event FMQ,用于将传感器事件写入框架。HAL 使用第二个描述符来创建 Wake Lock FMQ,用于同步 HAL 何时为 WAKE_UP
传感器事件释放唤醒锁定。HAL 必须保存指向 ISensorsCallback
对象的指针,以便可以调用任何必要的回调函数。
initialize()
或 initialize_2_1()
函数必须是在初始化 Sensors HAL 时调用的第一个函数。
公开可用传感器
要获取设备中所有可用静态传感器的列表,请在 HAL 2.0 上使用 getSensorsList()
函数,在 HAL 2.1 上使用 getSensorsList_2_1()
函数。此函数返回传感器列表,每个传感器都由其句柄唯一标识。当托管 Sensors HAL 的进程重启时,给定传感器的句柄不得更改。句柄可能会在设备重启和系统服务器重启后发生更改。
如果多个传感器共享相同的传感器类型和唤醒属性,则列表中的第一个传感器称为默认传感器,并返回给使用 getDefaultSensor(int sensorType, bool wakeUp)
函数的应用。
传感器列表的稳定性
在 Sensors HAL 重启后,如果 getSensorsList()
或 getSensorsList_2_1()
返回的数据表明与重启前检索到的传感器列表相比发生了重大更改,则框架会触发 Android 运行时重启。传感器列表的重大更改包括具有给定句柄的传感器丢失或属性发生更改,或者引入了新传感器的情况。虽然重启 Android 运行时会对用户造成干扰,但这是必需的,因为 Android 框架无法再满足静态(非动态)传感器在应用的生命周期内不会更改的 Android API 约定。这也可能会阻止框架重新建立应用发出的活动传感器请求。因此,建议 HAL 供应商防止可避免的传感器列表更改。
为了确保传感器句柄的稳定性,HAL 必须确定性地将设备中的给定物理传感器映射到其句柄。虽然 Sensors HAL 接口未强制要求任何特定实现,但开发人员有许多选项可用来满足此要求。
例如,可以使用每个传感器的固定属性(例如供应商、型号和传感器类型)的组合对传感器列表进行排序。另一种选择依赖于设备的一组静态传感器在硬件中是固定的这一事实,因此 HAL 需要知道何时所有预期的传感器都已完成初始化,然后才能从 getSensorsList()
或 getSensorsList_2_1()
返回。此预期传感器列表可以编译到 HAL 二进制文件中,也可以存储在文件系统中的配置文件中,并且可以使用外观顺序来派生稳定的句柄。虽然最佳解决方案取决于您的 HAL 的具体实现细节,但关键要求是传感器句柄在 HAL 重启后不会更改。
配置传感器
在激活传感器之前,必须使用 batch()
函数配置传感器的采样周期和最大报告延迟。
必须能够随时使用 batch()
重新配置传感器,而不会丢失传感器数据。
采样周期
采样周期根据配置的传感器类型而具有不同的含义
- 连续:以连续速率生成传感器事件。
- OnChange:事件的生成速度不快于采样周期,如果测量值未更改,则事件的生成速度可能会慢于采样周期。
- One-shot:采样周期被忽略。
- 特殊:如需了解详情,请参阅传感器类型。
要了解采样周期与传感器的报告模式之间的交互,请参阅报告模式。
最大报告延迟
最大报告延迟设置了事件可以延迟并在硬件 FIFO 中存储的最长时间(以纳秒为单位),然后再在 SoC 处于唤醒状态时通过 HAL 写入 Event FMQ。
值为零表示事件必须在测量后立即报告,要么完全跳过 FIFO,要么在 FIFO 中存在来自传感器的某个事件时立即清空 FIFO。
例如,当 SoC 处于唤醒状态时,以 50 赫兹激活且最大报告延迟为零的加速度计每秒触发 50 次中断。
当最大报告延迟大于零时,不需要在检测到传感器事件后立即报告。事件可以临时存储在硬件 FIFO 中并批量报告,只要任何事件的延迟不超过最大报告延迟即可。自上一批次以来的所有事件都会被记录并一次性返回。这减少了发送到 SoC 的中断次数,并允许 SoC 在传感器捕获和批量处理数据时切换到较低功耗模式。
每个事件都有一个与其关联的时间戳。延迟报告事件的时间不得影响事件时间戳。时间戳必须准确,并且与事件实际发生的时间(而不是报告时间)相对应。
有关使用非零最大报告延迟报告传感器事件的其他信息和要求,请参阅批量处理。
激活传感器
框架使用 activate()
函数启用和停用传感器。在激活传感器之前,框架必须首先使用 batch()
配置传感器。
停用传感器后,不得将来自该传感器的其他传感器事件写入 Event FMQ。
刷新传感器
如果传感器配置为批量处理传感器数据,则框架可以通过调用 flush()
强制立即刷新批量处理的传感器事件。这会导致批量处理的指定传感器句柄的传感器事件立即写入 Event FMQ。Sensors HAL 必须将刷新完成事件附加到因调用 flush()
而写入的传感器事件的末尾。
刷新是异步发生的(即,此函数必须立即返回)。如果实现对多个传感器使用单个 FIFO,则会刷新该 FIFO,并且仅为指定的传感器添加刷新完成事件。
如果指定的传感器没有 FIFO(无法进行缓冲),或者如果在调用时 FIFO 为空,则 flush()
仍必须成功并为该传感器发送刷新完成事件。这适用于除一次性传感器以外的所有传感器。
如果为一次性传感器调用 flush()
,则 flush()
必须返回 BAD_VALUE
,并且不生成刷新完成事件。
将传感器事件写入 FMQ
Sensors HAL 使用 Event FMQ 将传感器事件推送到 Android 传感器框架中。
Event FMQ 是一个同步 FMQ,这意味着任何尝试向 FMQ 写入比可用空间允许的事件更多的事件都会导致写入失败。在这种情况下,HAL 应确定是将当前事件集写入为两个较小的事件组,还是在有足够的空间可用时将所有事件一起写入。
当 Sensors HAL 将所需数量的传感器事件写入 Event FMQ 后,Sensors HAL 必须通过将 EventQueueFlagBits::READ_AND_PROCESS
位写入 Event FMQ 的 EventFlag::wake
函数来通知框架事件已准备就绪。可以使用 EventFlag::createEventFlag
和 Event FMQ 的 getEventFlagWord()
函数从 Event FMQ 创建 EventFlag。
Sensors HAL 2.0/2.1 在 Event FMQ 上同时支持 write
和 writeBlocking
。默认实现提供了使用 write
的参考。如果使用 writeBlocking
函数,则 readNotification
标志必须设置为 EventQueueFlagBits::EVENTS_READ
,这是框架在从 Event FMQ 读取事件时设置的。写入通知标志必须设置为 EventQueueFlagBits::READ_AND_PROCESS
,它会通知框架事件已写入 Event FMQ。
WAKE_UP 事件
WAKE_UP
事件是导致应用处理器 (AP) 唤醒并立即处理事件的传感器事件。每当 WAKE_UP
事件写入 Event FMQ 时,Sensors HAL 必须获得唤醒锁定,以确保系统保持唤醒状态,直到框架可以处理该事件。收到 WAKE_UP
事件后,框架会获得自己的唤醒锁定,从而允许 Sensors HAL 释放其唤醒锁定。要同步 Sensors HAL 何时释放其唤醒锁定,请使用 Wake Lock FMQ。
Sensors HAL 必须读取 Wake Lock FMQ 以确定框架已处理的 WAKE_UP
事件的数量。仅当未处理的 WAKE_UP
事件总数为零时,HAL 才应释放其 WAKE_UP
事件的唤醒锁定。在处理传感器事件后,框架会计算标记为 WAKE_UP
事件的事件数,并将此数字写回 Wake Lock FMQ。
每当框架将数据写入 Wake Lock FMQ 时,框架都会在 Wake Lock FMQ 上设置 WakeLockQueueFlagBits::DATA_WRITTEN
写入通知。
动态传感器
动态传感器是指并非物理上属于设备但可以用作设备输入的传感器,例如带有加速度计的游戏手柄。
当动态传感器连接时,必须从 Sensors HAL 调用 ISensorsCallback
中的 onDynamicSensorConnected
函数。这会通知框架新的动态传感器,并允许通过框架控制该传感器,并让客户端使用该传感器的事件。
同样,当动态传感器断开连接时,必须调用 ISensorsCallback
中的 onDynamicSensorDisconnected
函数,以便框架可以移除任何不再可用的传感器。
直接通道
直接通道是一种操作方法,其中传感器事件被写入特定内存而不是 Event FMQ,从而绕过 Android 传感器框架。注册直接通道的客户端必须直接从用于创建直接通道的内存中读取传感器事件,并且不会通过框架接收传感器事件。configDirectReport()
函数类似于正常操作的 batch()
,并配置直接报告通道。
registerDirectChannel()
和 unregisterDirectChannel()
函数创建或销毁新的直接通道。
操作模式
setOperationMode()
函数允许框架配置传感器,以便框架可以将传感器数据注入到传感器中。这对于测试非常有用,尤其对于框架下存在的算法。
HAL 2.0 中的 injectSensorData()
函数和 HAL 2.0 中的 injectSensorsData_2_1()
函数通常用于将操作参数推送到 Sensors HAL 中。该函数还可用于将传感器事件注入到特定传感器中。
验证
要验证 Sensors HAL 的实现,请运行传感器 CTS 和 VTS 测试。
CTS 测试
传感器 CTS 测试存在于自动化 CTS 测试和手动 CTS Verifier 应用中。
自动化测试位于 cts/tests/sensor/src/android/hardware/cts。这些测试验证传感器的标准功能,例如激活传感器、批量处理和传感器事件速率。
CTS Verifier 测试位于 cts/apps/CtsVerifier/src/com/android/cts/verifier/sensors。这些测试需要测试操作员手动输入,并确保传感器报告准确的值。
通过 CTS 测试对于确保被测设备满足所有 CDD 要求至关重要。
VTS 测试
Sensors HAL 2.0 的 VTS 测试位于 hardware/interfaces/sensors/2.0/vts。Sensors HAL 2.1 的 VTS 测试位于 hardware/interfaces/sensors/2.1/vts。这些测试确保 Sensors HAL 已正确实现,并且 ISensors.hal
和 ISensorsCallback.hal
中的所有要求都已正确满足。
从 2.0 升级到 Sensors HAL 2.1
从 2.0 升级到 Sensors HAL 2.1 时,您的 HAL 实现必须包含 initialize_2_1()
、getSensorsList_2_1()
和 injectSensorsData_2_1()
方法以及 HAL 2.1 类型。这些方法必须满足上面针对 HAL 2.0 概述的相同要求。
由于次要版本 HAL 必须支持以前的 HAL 中的所有函数,因此 2.1 HAL 必须支持初始化为 2.0 HAL。为了避免支持两个 HAL 版本的复杂性,强烈建议使用 Multi-HAL 2.1。
有关如何实现您自己的 Sensors 2.1 HAL 的示例,请参阅 Sensors.h。
从 1.0 升级到 Sensors HAL 2.0
从 1.0 升级到 Sensors HAL 2.0 时,请确保您的 HAL 实现满足以下要求。
初始化 HAL
必须支持 initialize()
函数,以在框架和 HAL 之间建立 FMQ。
公开可用传感器
在 Sensors HAL 2.0 中,即使在 Sensors HAL 重启后,getSensorsList()
函数也必须在单个设备启动期间返回相同的值。getSensorsList()
函数的新要求是,即使在 Sensors HAL 重启后,它也必须在单个设备启动期间返回相同的值。这允许框架在系统服务器重启时尝试重新建立传感器连接。getSensorsList()
返回的值可能会在设备执行重启后发生更改。
将传感器事件写入 FMQ
在 Sensors HAL 2.0 中,Sensors HAL 必须在传感器事件可用时主动将传感器事件写入 Event FMQ,而不是等待调用 poll()
。HAL 还负责将正确的位写入 EventFlag
,以导致框架内发生 FMQ 读取。
WAKE_UP 事件
在 Sensors HAL 1.0 中,对于发布到 poll()
的 WAKE_UP
之后的任何后续 poll()
调用,HAL 都可以释放其所有 WAKE_UP
事件的唤醒锁定,因为这表明框架已处理所有传感器事件并已获得唤醒锁定(如果需要)。由于在 Sensors HAL 2.0 中,HAL 不再知道框架何时处理了写入 FMQ 的事件,因此 Wake Lock FMQ 允许框架在处理 WAKE_UP
事件时与 HAL 通信。
在 Sensors HAL 2.0 中,Sensors HAL 为 WAKE_UP
事件获得的唤醒锁定必须以 SensorsHAL_WAKEUP
开头。
动态传感器
动态传感器是使用 Sensors HAL 1.0 中的 poll()
函数返回的。Sensors HAL 2.0 要求在动态传感器连接发生更改时,调用 ISensorsCallback
中的 onDynamicSensorsConnected
和 onDynamicSensorsDisconnected
。这些回调作为通过 initialize()
函数提供的 ISensorsCallback
指针的一部分提供。
操作模式
Sensors HAL 2.0 中必须支持 WAKE_UP
传感器的 DATA_INJECTION
模式。
Multi-HAL 支持
Sensors HAL 2.0 和 2.1 使用 Sensors Multi-HAL 框架支持 Multi-HAL。有关实现详情,请参阅从 Sensors HAL 1.0 移植。