设备子系统的功耗通常是在实验室环境中针对各种稳态条件进行测量和记录的,例如当屏幕开启时,或设备处于闲置电源状态时。这对于具有恒定功耗的子系统,或在实验室环境中容易测量的条件下是可行的,但对于某些用例(如当屏幕显示视频时)就不适用。
IPower.hal 1.0
提供了一个接口,用于传递电量提示并报告子系统休眠状态指标的累积数据。在 Android 10 及更高版本中,累积统计信息报告函数位于 IPowerStats.hal
电源统计信息收集 API 中,并提供了检索设备耗电量数据的一种方式。这取代了 IPower.hal
接口的累积统计信息收集部分,实现了更明确的功能分离。
IPowerStats
服务的判读不是定期进行。它们发生在关键时刻,例如当电池电量下降 1% 时。当耗电量较低时,判读频率较低;当耗电量较高时,判读频率较高。数据可能会发回服务器,也可能会在 bug 报告中用到以进行分析和分类。这有助于持续降低功耗并延长电池续航时间。
IPower.hal 和 IPowerStats.hal
IPower.hal
和
IPowerStats.hal
接口在 Android 10 中均可用,但 IPower.hal
统计信息收集功能仅在 IPowerStats.hal
接口中可用。IPowerStats.hal
功能中包含的 API 可用于获取和使用在受支持的设备上通过功耗测量而收集到的数据:
- 为低频 (
getRailInfo
) 和高频 (streamEnergyData
) 客户端执行轨道级功耗测量,并报告自启动以来的耗电量。 - 报告与每个受支持的
PowerEntity
(如果有数据可用)相关的信息。每个PowerEntity
都是一个影响设备总功耗的平台子系统、外围设备或电源域。 - 报告由指定电源实体提供驻留数据的实体状态集 (
getPowerEntityStateInfo
),然后报告每个指定PowerEntity
的累积数据。
以下客户端会使用 IPowerStats.hal
API:
Statsd
,目的是收集每条轨道的功耗指标。Perfetto
,目的是将功耗与 CPU 活动相关联。Batterystats
,目的是使用测得的数据优化电耗归因,而不是通过power_profile.xml.
中的预定义常量来估计耗电量。
对于 Android 10 及更高版本,设备制造商可以在 IPower.hal
和 IPowerStats.hal
函数之间进行选择,但如果未实现 IPowerStats.hal
,所有客户端必须回退到 IPower.hal
。
IPowerStats.hal 实现选项
在 Android 7 到 Android 9 上,只有 IPower.hal
函数可用。升级到 Android 10 的设备必须有一个硬件功耗监控子系统,或者可以通过其他方式来监控和记录功耗统计信息。有些 SoC 会为您收集耗电量统计数据,或者您可以通过软件获取电源实体状态驻留信息。只有在支持 getRailInfo()
、getEnergyData()
和 streamEnergyData()
时才需要使用功耗监控硬件。
如果您在没有功耗监控硬件的情况下实现 IPowerStats.hal
,getRailInfo(), getEnergyData()
和 streamEnergyData()
会返回 NOT_SUPPORTED
。同样地,在这种情况下,getPowerEntityInfo(), getPowerEntityStateInfo()
和 getPowerEntityStateResidencyData()
也可能会返回 NOT_SUPPORTED
。
轨道监控 API 返回的数据示例包括:
- 屏幕的电源轨道使用了 X 微瓦 (μW)。
- 调制解调器的电源轨道使用了 Y 微瓦 (μW)。
子系统休眠状态 API 返回的数据示例包括:
- 调制解调器休眠了 X 毫秒 (ms)。
- SoC 处于掉电模式达 Y 毫秒 (ms)。
- GPU 处于挂起状态达 Z 毫秒 (ms)。
使用硬件电源监控子系统
如果您的设备设计有一个硬件功耗监控子系统,可通过创建单个 sysfs 节点(PowerStats.hal
可以从该节点解析数据)来实现 IPowerStats.hal
,或者通过进行一系列 ioctl 类型的系统调用来实现。
您必须以不会造成累加器溢出的方式实现内核驱动程序。所使用的算法取决于您独特的硬件功耗监控子系统设计,它必须同时提供瞬时和平均总线电压以及电流测量值。内核驱动程序必须以不清空功耗累加器的方式采集这些数据,并且必须以 64 位变量的形式来维护自启动以来每个子轨的累积功耗数据;该变量会随着每次累加器查询的能耗读数而递增。
某个给定组件(或者多个组件)的统计信息必须在单个节点中。虽然这并不是 sysfs 的常规用法(通常将每个节点限制为单个值),但可确保所有数据的一致性。
设计方案指导意见
- 从 sysfs 节点判读数据或进行系统调用时,保持较低的延迟(不超过 1msec)。
- 确保支持统计信息功能不会明显增加耗电量:
- 请勿通过增加接入点 (AP) 和/或子系统的唤醒次数来跟踪处于休眠模式的时间等参数。
- 如有可能,随同其他流量在应用处理器和固件之间适时地传输统计信息。
- 如有必要,子系统可以使用以下驱动程序函数:
- 在内部缓存数据,以略微降低数据时效性为代价来避免出现延迟/唤醒。
- 在子系统处于休眠状态时执行推断,以便在不唤醒子系统的情况下提供最新的休眠时间信息。
选择组件、子系统和统计信息
在选择要从哪些组件或子系统收集 IPowerStats.hal
数据时,请选择设备上会使用大量电流(5mA 或更多)或支持多种功耗模式的组件或子系统,示例如下:
- 各个 SoC 子系统。
- 部分或完全位于 SoC 之外的子系统,如 Wi-Fi、图像处理器或安全处理器。
- 外围设备,如大功率 LED 和相机。
- 使用不同模式的电源域,如整个 SoC 的电源域。
自定义
这个可选功能可进行自定义。您可以设计用例并自定义您的使用方式:
- 决定要测量哪些轨道,以及测量频率。
- 决定何时判读数据以及如何解读这些数据。
- 决定根据您的数据要执行的操作以及执行时间。
验证
VTS 测试可确保设备符合 Android 要求。IPowerStats.hal
中的注释用于验证设备是否合规。
例如,如果您调用 getRailInfo()
但它没有返回任何内容,则表示 VTS 测试失败了,原因在于您没有收到关于所监控轨道的信息,也没有收到 SUCCESS
这一返回状态。同样,如果您收到轨道信息,但随它一起返回的还有 NON_SUPPORTED
或 FILE_SYSTEM_ERROR
响应,那也表示测试失败了。VTS 会按照 IPower.hal 和 IPowerStats.hal 注释中的要求,验证是否符合 HAL 文件中的设备制造商规范。VTS 测试中使用的注释示例如下:
/** * Rail information: * Reports information related to the rails being monitored. * * @return rails Information about monitored rails. * @return status SUCCESS on success or NOT_SUPPORTED if * feature is not enabled or FILESYSTEM_ERROR on filesystem nodes * access error. */ getRailInfo() generates(vec<e;RailInfo>e; rails, Status status);