Sensors AIDL HAL

传感器硬件抽象层 (HAL) 是 Android 传感器框架和设备传感器(例如加速度计或陀螺仪)之间的接口。传感器 HAL 定义了框架控制传感器必须实现的功能。

传感器 AIDL HAL 在 Android 13 及更高版本中适用于新设备和升级设备。 Sensors AIDL HAL 基于Sensors HAL 2.1 ,使用AIDL HAL 接口并公开头部跟踪器和限轴 IMU 传感器类型。

AIDL HAL接口

传感器 AIDL HAL 的主要文档来源位于hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl 的HAL 定义中。

实施传感器 AIDL HAL

要实现传感器 AIDL HAL,对象必须扩展ISensors接口并实现hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl中定义的所有函数。

初始化 HAL

Sensors HAL 必须由 Android 传感器框架初始化才能使用。框架调用initialize()函数向传感器HAL 提供三个参数:两个FMQ 描述符和一个指向ISensorsCallback对象的指针。

HAL 使用第一个描述符创建事件 FMQ,用于将传感器事件写入框架。 HAL 使用第二个描述符创建唤醒锁 FMQ,用于在 HAL 释放WAKE_UP传感器事件的唤醒锁时进行同步。 HAL 必须保存指向ISensorsCallback对象的指针,以便可以调用任何必要的回调函数。

初始化传感器 HAL 时, initialize()函数必须是第一个调用的函数。

公开可用的传感器

要获取设备中所有可用静态传感器的列表,请使用getSensorsList()函数。该函数返回一个传感器列表,每个传感器都由其句柄唯一标识。当托管传感器 HAL 的进程重新启动时,给定传感器的句柄不得更改。句柄可能会在设备重新启动和系统服务器重新启动时发生变化。

如果多个传感器共享相同的传感器类型和唤醒属性,则列表中的第一个传感器称为默认传感器,并返回到使用getDefaultSensor(int sensorType, bool wakeUp)函数的应用程序。

传感器列表稳定性

Sensors HAL 重新启动后,如果getSensorsList()返回的数据表明与重新启动之前检索到的传感器列表相比发生了重大变化,则框架会触发 Android 运行时的重新启动。对传感器列表的重大更改包括具有给定句柄的传感器丢失或属性已更改,或者引入新传感器的情况。尽管重新启动 Android 运行时会对用户造成干扰,但这是必需的,因为 Android 框架无法再满足静态(非动态)传感器在应用程序的生命周期内不会更改的 Android API 约定。这也可能会阻止框架重新建立应用程序发出的活动传感器请求。因此,建议 HAL 供应商防止可避免的传感器列表更改。

为了确保稳定的传感器句柄,HAL 必须确定地将设备中给定的物理传感器映射到其句柄。尽管传感器 HAL 接口没有强制要求具体实现,但开发人员可以使用多种选项来满足此要求。

例如,可以使用每个传感器的固定属性(例如供应商、型号和传感器类型)的组合来对传感器列表进行排序。另一种选择依赖于设备的静态传感器集在硬件中固定的事实,因此 HAL 需要知道所有预期传感器何时完成初始化,然后再从getSensorsList()返回。该预期传感器列表可以编译到 HAL 二进制文件中或存储在文件系统中的配置文件中,并且出现的顺序可用于派生稳定句柄。尽管最佳解决方案取决于 HAL 的具体实现细节,但关键要求是传感器句柄不会在 HAL 重新启动时发生变化。

配置传感器

在激活传感器之前,必须使用batch()函数为传感器配置采样周期和最大报告延迟。

传感器必须能够随时使用batch()重新配置,而不会丢失传感器数据。

采样周期

根据所配置的传感器类型,采样周期具有不同的含义:

  • 连续:传感器事件以连续速率生成。
  • 变化时:事件的生成速度不会快于采样周期,如果测量值不发生变化,事件的生成速度可能会慢于采样周期。
  • 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

传感器 HAL 使用事件 FMQ 将传感器事件推送到 Android 传感器框架中。

事件 FMQ 是同步 FMQ,这意味着任何向 FMQ 写入超出可用空间允许的事件的尝试都会导致写入失败。在这种情况下,HAL 应确定是将当前事件集写入两个较小的事件组,还是在有足够空间可用时将所有事件写入在一起。

当传感器 HAL 将所需数量的传感器事件写入事件 FMQ 时,传感器 HAL 必须通过将EventQueueFlagBits::READ_AND_PROCESS位写入事件 FMQ 的EventFlag::wake函数来通知框架事件已准备就绪。可以使用EventFlag::createEventFlag和事件 FMQ 的getEventFlagWord()函数从事件 FMQ 创建 EventFlag。

传感器 AIDL HAL 支持事件 FMQ 上的writewriteBlocking 。默认实现提供了使用write的参考。如果使用writeBlocking函数,则readNotification标志必须设置为EventQueueFlagBits::EVENTS_READ ,该标志由框架在从 Event FMQ 读取事件时设置。写入通知标志必须设置为EventQueueFlagBits::READ_AND_PROCESS ,它通知框架事件已写入事件 FMQ。

WAKE_UP 事件

WAKE_UP事件是导致应用处理器 (AP) 唤醒并立即处理该事件的传感器事件。每当WAKE_UP事件写入事件 FMQ 时,传感器 HAL 必须确保唤醒锁,以确保系统保持唤醒状态,直到框架可以处理该事件。收到WAKE_UP事件后,框架会保护自己的唤醒锁,从而允许传感器 HAL 释放其唤醒锁。要在传感器 HAL 释放其唤醒锁时进行同步,请使用唤醒锁 FMQ。

传感器 HAL 必须读取唤醒锁 FMQ 以确定框架已处理的WAKE_UP事件的数量。仅当未处理的WAKE_UP事件总数为零时,HAL 才应释放WAKE_UP事件的唤醒锁。处理传感器事件后,框架会计算标记为WAKE_UP事件的事件数量,并将该数字写回唤醒锁 FMQ。

每当框架将数据写入唤醒锁 FMQ 时,框架都会在唤醒锁 FMQ 上设置WakeLockQueueFlagBits::DATA_WRITTEN写入通知。

动态传感器

动态传感器是物理上不属于设备一部分但可用作设备输入的传感器,例如带有加速计的游戏手柄。

连接动态传感器时,必须从传感器 HAL 调用ISensorsCallback中的onDynamicSensorConnected函数。这会向框架通知新的动态传感器,并允许通过框架控制传感器并使客户端使用传感器的事件。

同样,当动态传感器断开连接时,必须调用ISensorsCallback中的onDynamicSensorDisconnected函数,以便框架可以删除不再可用的任何传感器。

直接渠道

直接通道是一种操作方法,其中传感器事件被写入特定内存,而不是绕过 Android 传感器框架写入事件 FMQ。注册直接通道的客户端必须直接从用于创建直接通道的内存读取传感器事件,并且不会通过框架接收传感器事件。 configDirectReport()函数与正常操作的batch()类似,配置直接报告通道。

registerDirectChannel()unregisterDirectChannel()函数创建或销毁新的直接通道。

操作模式

setOperationMode()函数允许框架配置传感器,以便框架可以将传感器数据注入传感器。这对于测试很有用,特别是对于框架下方存在的算法。

injectSensorData()函数通常用于将操作参数推送到传感器 HAL 中。该函数还可用于将传感器事件注入特定传感器。

验证

要验证传感器 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 测试

传感器 AIDL HAL 的 VTS 测试位于hardware/interfaces/sensors/aidl/vts/中。这些测试可确保传感器 HAL 正确实现,并且ISensors.aidlISensorsCallback.aidl中的所有要求均得到正确满足。

初始化 HAL

必须支持initialize()函数才能在框架和HAL之间建立FMQ。

公开可用的传感器

在 Sensors AIDL HAL 中, getSensorsList()函数必须在单个设备启动期间返回相同的值,即使在 Sensors HAL 重新启动期间也是如此。 getSensorsList()函数的一个新要求是,它必须在单个设备启动期间返回相同的值,即使传感器 HAL 重新启动也是如此。这允许框架在系统服务器重新启动时尝试重新建立传感器连接。设备重新启动后, getSensorsList()返回的值可能会发生变化。

将传感器事件写入 FMQ

在传感器 AIDL HAL 中,传感器 HAL 必须在传感器事件可用时主动将传感器事件写入事件 FMQ,而不是等待调用poll() 。 HAL 还负责将正确的位写入EventFlag以引发框架内的 FMQ 读取。

WAKE_UP 事件

在传感器 HAL 1.0 中,在将WAKE_UP发布到poll()后,HAL 能够在任何后续调用poll()时释放其对任何WAKE_UP事件的唤醒锁,因为这表明框架已处理所有传感器事件并已获得唤醒锁(如有必要)。因为在 Sensors AIDL HAL 中,当框架处理完写入 FMQ 的事件时不再通知 HAL,所以唤醒锁 FMQ 允许框架在处理WAKE_UP事件时与 HAL 进行通信。

在传感器 AIDL HAL 中,传感器 HAL 为WAKE_UP事件保护的唤醒锁必须以SensorsHAL_WAKEUP开头。

动态传感器

使用 Sensors HAL 1.0 中的poll()函数返回动态传感器。传感器 AIDL HAL 要求每当动态传感器连接发生变化时就调用ISensorsCallback中的onDynamicSensorsConnectedonDynamicSensorsDisconnected 。这些回调可作为通过initialize()函数提供的ISensorsCallback指针的一部分来使用。

操作模式

必须支持WAKE_UP传感器的DATA_INJECTION模式。

多 HAL 支持

Sensors AIDL HAL 使用Sensors Multi-HAL 框架支持多 HAL。有关实现详细信息,请参阅从传感器 HAL 2.1 移植