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