传感器硬件抽象层 (HAL) 是 Android 传感器框架和设备传感器(例如加速度计或陀螺仪)之间的接口。 Sensors HAL 定义了必须实现的功能以允许框架控制传感器。
Sensors HAL 2.0 适用于 Android 10 及更高版本,适用于新设备和升级设备。 Sensors HAL 2.0 基于Sensors HAL 1.0 ,但有几个关键差异,使其无法向后兼容。传感器 HAL 2.0 使用快速消息队列 (FMQ)将传感器事件从 HAL 发送到 Android 传感器框架。
Sensors HAL 2.1 适用于 Android 11 及更高版本,适用于新设备和升级设备。 Sensors HAL 2.1 是 Sensors HAL 2.0 的迭代版本,它公开了HINGE_ANGLE传感器类型并更新了各种方法以接受HINGE_ANGLE
类型。
HAL 2.1 接口
Sensors HAL 2.1 的主要文档来源位于hardware/interfaces/sensors/2.1/ISensors.hal的 HAL 定义中。如果此页面与ISensors.hal
之间的要求有冲突,请使用ISensors.hal
中的要求。
HAL 2.0 接口
Sensors HAL 2.0 的主要文档来源位于hardware/interfaces/sensors/2.0/ISensors.hal的 HAL 定义中。如果此页面与ISensors.hal
之间的要求有冲突,请使用ISensors.hal
中的要求。
实现传感器 HAL 2.0 和 HAL 2.1
要实现 Sensors HAL 2.0 或 2.1,对象必须扩展ISensors
接口并实现2.0/ISensors.hal
或2.1/ISensors.hal
中定义的所有功能。
初始化 HAL
Sensors HAL 必须先由 Android 传感器框架初始化,然后才能使用。框架调用 HAL 2.0 的initialize()
initialize_2_1()
函数和 HAL 2.1 的 initialize_2_1() 函数,为 Sensors HAL 提供三个参数:两个 FMQ 描述符和一个指向ISensorsCallback
对象的指针。
HAL 使用第一个描述符创建用于将传感器事件写入框架的事件 FMQ。 HAL 使用第二个描述符创建唤醒锁 FMQ,用于在 HAL 为WAKE_UP
传感器事件释放唤醒锁时进行同步。 HAL 必须保存指向ISensorsCallback
对象的指针,以便可以调用任何必要的回调函数。
初始化 Sensors HAL 时, initialize()
或initialize_2_1()
函数必须是第一个调用的函数。
暴露可用的传感器
要获取设备中所有可用静态传感器的列表,请使用 HAL 2.0 上的getSensorsList()
getSensorsList_2_1()
函数和 HAL 2.1 上的 getSensorsList_2_1() 函数。此函数返回一个传感器列表,每个传感器都由其句柄唯一标识。当托管传感器 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()
重新配置,而不会丢失传感器数据。
采样期
根据所配置的传感器类型,采样周期具有不同的含义:
- 连续:传感器事件以连续速率生成。
- 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 HAL 2.0/2.1 支持事件 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()
函数允许框架配置传感器,以便框架可以将传感器数据注入传感器。这对于测试很有用,尤其是对于框架下存在的算法。
HAL 2.0 中的injectSensorData()
函数和 HAL 2.0 中的injectSensorsData_2_1()
函数通常用于将操作参数推送到 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 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 中, getSensorsList()
函数必须在单个设备启动期间返回相同的值,即使在 Sensors HAL 重新启动时也是如此。 getSensorsList()
函数的一个新要求是,它必须在单个设备引导期间返回相同的值,即使在 Sensors HAL 重新启动时也是如此。这允许框架在系统服务器重新启动时尝试重新建立传感器连接。 getSensorsList()
返回的值可以在设备执行重启后更改。
将传感器事件写入 FMQ
在 Sensors HAL 2.0 中,无需等待poll()
被调用,只要传感器事件可用,Sensors HAL 就必须主动将传感器事件写入事件 FMQ。 HAL 还负责将正确的位写入EventFlag
以在框架内进行 FMQ 读取。
WAKE_UP 事件
在 Sensors HAL 1.0 中,在WAKE_UP
发布到poll()
poll()
之后,HAL 能够在任何后续调用 poll() 时为任何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
模式。
多 HAL 支持
Sensors HAL 2.0 和 2.1 使用Sensors Multi-HAL 框架支持多 HAL。有关实现细节,请参阅从 Sensors HAL 1.0 移植。