电池使用情况信息根据电池使用情况统计信息和电源配置文件中的值计算得出。
电池使用情况统计信息
框架可通过跟踪设备组件在不同状态下维持的时间来自动确定电池使用情况统计信息。当组件(WLAN 芯片组、手机无线装置、蓝牙、GPS、显示屏和 CPU)状态发生改变(开/关、空闲/全功耗、低/高亮度等)时,控制服务会向框架中的 BatteryStats 服务报告状态改变信息。BatteryStats 会不断地收集信息,并存储这些信息以供在设备重新启动后继续使用。该服务不会直接跟踪电池中消耗的电流,而是通过收集计时信息来估算不同组件所消耗的电量。
该框架使用以下方法收集统计信息:
- 推送:服务察觉到组件状态发生变化后,会将状态变化推送到 BatteryStats 服务中。
- 拉取:对于应用使用的 CPU 等组件,框架会在转换点(例如启动 Activity 或停止 Activity)自动拉取数据以截取快照。
资源的消耗会关联到使用资源的应用。当多个应用同时使用某项资源(例如防止系统挂起的唤醒锁)时,框架会将资源消耗量分摊到这些应用上,但不一定会均分。
为了避免由于关机事件而丢失电池使用情况统计信息(这些统计信息可能表明存在电池功耗问题,比如由于电池电量耗尽而关机),框架大约每 30 分钟会将统计信息写入存储设备一次。
电池使用情况统计信息完全由框架处理,不需要原始设备制造商 (OEM) 做任何修改。
电源配置文件中的值
注意:设备制造商必须提供组件的电源配置文件,该配置文件定义了组件的电流消耗值以及该组件在一段时间内大概消耗的电量。有关此配置文件的定义,请查看 platform/frameworks/base/core/res/res/xml/power_profile.xml。要获得与这些设置相关的指导,请参阅电源值。
在电源配置文件中,功耗以额定电压下的电流消耗量(毫安 [mA])来表示,也可用微安 (uA) 分数值来表示。该值应代表电池上消耗的电流,而非与电池消耗的电流不对应的某个电源轨的值。
例如,显示屏电源配置文件列出了当显示屏开启状态下保持最低亮度和最高亮度时需消耗的电流量 (mA)。为了确定显示屏常亮时所需的电源成本(即由显示屏组件所消耗的电池量),框架会跟踪在各个亮度级别下维持的时间,然后将这些时间间隔乘以通过插值算法计算出的显示亮度成本。
该框架还会将每个应用的 CPU 时间乘以在特定速度运行 CPU 所需的毫安量。通过该计算方法,您可以创建一个应用电池消耗量(执行 CPU 代码的消耗)的相对排名(应用在前台运行的时间和包含应用后台活动时间的总时间将分开进行报告)。
测量组件功耗
bookmark_border
您可以通过比较当组件处于期望状态(开启、活跃和扫描等)和关闭状态时设备消耗的电流来确定单个组件的功耗。在额定电压下使用外部电源监控器(如台式电源或 Monsoon Solution Inc. 的电源监控器和电源工具软件等专用电池监控工具)测量设备消耗的平均瞬时电流。
制造商通常都会提供有关单个组件所耗电流的信息。如果这些信息准确地反映了实际操作时设备电池消耗的电流,您便可以利用这些信息。不过,在采用制造商提供的设备电源配置文件中的值之前,请先对它们进行验证。
控制功耗
进行测量时,请确保设备未连接到外部电源,例如运行 Android 调试桥 (adb) 时与开发主机之间通过 USB 连接。因为被测设备可能会使用来自主机的电流,从而导致电池的测量值偏低。避免使用 USB On-The-Go (OTG) 连接,因为 OTG 设备可能消耗被测设备的电流。
除被测量的组件外,系统应以恒定的功耗水平运行,以避免由于其他组件的功耗变化而影响测量的准确性。以下系统活动可能会给功率测量带来不必要的更改:
- 通过移动网络、Wi-Fi 和蓝牙进行的接收、传输或扫描活动。当未测量手机无线装置功率时,请将设备设置为飞行模式,并根据实际情况启用 Wi-Fi 或蓝牙。
- 屏幕开启/关闭。屏幕开启时屏幕上显示的色彩可能会影响某些屏幕技术的功耗。测量非屏幕组件的功耗值时请关闭屏幕。
- 系统挂起/恢复。当屏幕处于关闭状态时会触发系统进入挂起状态,使部分设备部件处于低功耗运行或关闭状态。这可能会影响被测组件的功耗,并在系统定期恢复以发送警报等情况下引入较大的功率读数差异。如需了解详情,请参阅控制系统挂起。
- CPU 变速以及进入/退出低功耗调度程序空闲状态。在正常运行期间,系统会频繁地调整 CPU 速率、在线 CPU 内核数量以及其他系统内核状态,例如内存总线速率以及与 CPU 和内存关联的电源轨电压。在测试期间,这些调整会影响功耗测量:
- CPU 速率调节操作可能会减少内存总线和其他系统核心组件的时钟和电压缩放量。
- 调度活动可能会影响 CPU 保持在低功耗空闲状态的时间所占的百分比。如需详细了解如何防止测试期间发生此类调整,请参阅控制 CPU 速率。
例如,Joe Droid 想要计算某个设备的 screen.on
值。他在设备上启用飞行模式,在恒定电流状态下运行设备,保持 CPU 速率恒定,并使用部分唤醒锁来防止系统进入挂起状态。随后,Joe 关闭设备屏幕并测量电流 (200mA)。接着他开启设备屏幕,将亮度调到最低,然后再次进行测量 (300mA)。screen.on
值为 100mA (300 - 200)。
注意:如果组件在活跃状态(如移动无线装置或 Wi-Fi)下测得的消耗电流波形不平,请使用功耗监控工具测量一段时间内的平均电流。
当使用外部电源代替设备电池时,系统可能会因为电池热敏电阻或集成的电量计引脚未连接而出现问题(即当电池温度或电池剩余电量读数无效时,内核或 Android 系统可能会关闭)。假冒电池可以提供模仿正常系统温度和充电读数状态的热敏电阻或电量计引脚信号,并且还可以提供外部电源引线以方便连接。或者您也可以修改系统,以便忽略由于缺失电池产生的无效数据。
控制系统挂起
本节介绍了当您不希望系统挂起状态干扰其他测量时应如何避免系统进入挂起状态,以及当您希望测量系统在挂起状态下的功耗时该如何操作。
防止系统挂起
系统挂起可能会给功率测量造成不必要的误差,并使系统组件处于低功耗状态,而在这种状态下不适合测量活跃状态的功耗。要防止系统在屏幕关闭时进入挂起状态,请暂时使用部分唤醒锁。使用 USB 电缆将设备连接到开发主机,然后发出以下命令:
adb shell "echo temporary > /sys/power/wake_lock"
当使用 wake_lock
时,屏幕进入关闭状态不会触发系统挂起。(请记得在测量功耗之前先断开 USB 电缆与设备的连接。)
如需移除唤醒锁,请使用以下命令:
adb shell "echo temporary > /sys/power/wake_unlock"
测量系统挂起状态下的功耗
如需测量系统挂起状态下的功耗,您可以测量电源配置文件中 cpu.idle
的值。测量前,请进行以下操作:
- 移除现有的唤醒锁(如上所述)。
- 将设备设置成飞行模式,以避免移动网络无线装置的并发活动。移动网络无线装置可能在独立于 SoC 部分(受系统挂起状态控制)的处理器上运行。
- 通过执行以下操作确保系统处于挂起状态:
- 确认电流读数稳定保持在某个值。读数应在预期范围内,即 SoC 挂起状态的功耗加上保持供电的系统组件(如 USB PHY)功耗之和。
- 检查系统控制台输出。
- 观察可指示系统状态的外部标示(如系统未挂起时 LED 关闭)。
控制 CPU 速率
活跃的 CPU 可以处于联机或脱机状态,改变其时钟速率和相关电压(也可能影响内存总线速率和其他系统内核的电源状态),并在内核空闲循环时进入较低功耗的空闲状态。在测量不同 CPU 的功耗状态来验证电源配置文件中的值时,请避免在测量其他参数时导致功耗发生变化。电源配置文件假设所有 CPU 的可用速率和功率特性都相同。
在测量 CPU 功率或者在保持恒定 CPU 功率以进行其他测量时,请保持在线 CPU 的数量恒定(例如一个 CPU 在线,其余处于离线状态/以热插拔方式拔出)。留下一个 CPU,并将其余的所有 CPU 处于调度空闲状态,这样可能有助于获得令人信服的结果。使用 adb shell stop
停止 Android 框架可以减少系统调度活动。
您必须在电源配置文件的 cpu.speeds
条目中指定设备的可用 CPU 速率。如需获取可用 CPU 速率列表,请运行以下命令:
adb shell cat /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state
这些速率与 cpu.active
值中对应的功率测量值相匹配。
如果某个平台的在线内核数量对功耗有很大的影响,您可能需要修改该平台的 cpufreq 驱动程序或调节器。大多数平台支持使用用户空间 cpufreq 调节器控制 CPU 速率以及使用 sysfs 接口来设置速率。例如,如需在只有 1 个 CPU 的系统上或者所有 CPU 共享一个公共 cpufreq 策略的系统上将速率设置为 200MHz,请使用系统控制台或 adb shell 运行以下命令:
echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
注意:确切的命令可能因平台实施的 cpufreq 不同而有所差异。
这些命令可确保新的速率不超出允许的范围,并设置新的速率,然后输出 CPU 实际运行的速率(用于验证)。如果执行前的当前最小速率高于 200000,则可能需要交换前两行的顺序,或者再次执行第一行,以在设置最大速率之前降低最小速率。
如需测量 CPU 在不同速率下运行时所消耗的电流,请使用以下命令通过系统控制台将 CPU 置于 CPU 限制循环中:
# while true; do true; done
请在执行循环时进行测量。
如果某些设备因测量温度值过高(即持续高速运行 CPU 一段时间后)需执行温控调频,则可能会限制最大 CPU 速率。您可以通过两种方式观察是否存在此类限制:一是在测量时使用系统控制台输出,二是在测量后检查内核日志。
对于 cpu.awake
值,您可以测量系统未挂起且不执行任务时的功耗。CPU 应处于低功耗调度程序空闲循环中(可能是正在执行 ARM 等待事件指令)或特定的 SoC 低功耗状态(适用于空闲状态下使用的快速退出延迟)。
对于 cpu.active
值,您可以测量系统未处于挂起模式且不执行任务时的功率。一个 CPU(通常是主 CPU)应运行任务,而所有其他 CPU 都应处于空闲状态。
测量屏幕功率
当测量屏幕功率时,请确保在启用屏幕时通常会一并开启的其他设备也处于开启状态。例如,如果触摸屏和显示屏背光通常在屏幕打开时亮起,请确保在测量时这些设备也处于打开状态,以获得屏幕功耗的实际示例。
一些显示屏技术因所显示颜色的不同而造成功耗上的差异,从而导致功率测量值随测量时屏幕上显示的内容而出现很大差异。测量时,请确保屏幕显示的是具有真实屏幕功率特性的内容。尽量确保屏幕处于全黑屏幕(某些技术在此状态下功耗最低)和全白屏幕两个极限状态之间。通常的做法是使用日历应用中的日程表视图,因为它混合了白色背景和非白色元素。
测量显示屏/背光亮度最低和最高时的屏幕功率。设置最低亮度的方法:
- 使用 Android 界面(不推荐)。依次转到“设置”>“显示屏亮度”,将相应滑块设为最低显示亮度。然而,Android UI 支持的最低亮度为面板/背光亮度的 10-20%,并且不支持将亮度设置到难以看清屏幕的程度。
- 使用 sysfs 文件(推荐)。如果有可用的 sysfs 文件,请使用该文件来控制面板亮度,最低可降至硬件支持的最低亮度。
此外,如果平台 sysfs 文件可以开启和关闭 LCD 面板、背光和触摸屏,请使用该文件在屏幕开启和关闭的状态下进行测量。或者您可以设置部分唤醒锁防止系统进入挂起状态,然后使用电源按钮开启和关闭屏幕。
测量 Wi-Fi 功耗
在活动较少的网络上执行 Wi-Fi 测量。避免引入与被测活动无关的其他工作(处理大量广播流量)。
wifi.on
值用于测量 Wi-Fi 在启用但未主动发送或接收数据的状态下的功耗。该值通常是测量系统挂起(休眠)状态下启用/禁用 Wi-Fi 之间产生的电流增量。
wifi.scan
值会测量 Wi-Fi 接入点扫描过程中的功耗。应用可以使用 WifiManager 类 startScan() API 触发 Wi-Fi 扫描。您也可以依次打开“设置”>“WLAN”,这样会每隔几秒钟执行一次接入点扫描,在扫描过程中功耗看起来会明显上升,但您必须从这些测量值中减去屏幕的功耗。
测量设备电耗
bookmark_border
对于配有 Summit SMB347 或 Maxim MAX17050(许多 Nexus 设备均有提供)等电池电量计的 Android 设备,您可以确定设备耗电量。如果没有外部测量设备,或将外部测量设备连接到设备较麻烦(如在移动使用中),可使用系统内置电量计。
测量结果可包括瞬时电流、剩余电量、测试开始和结束时的电量,以及其他测量结果(取决于设备支持的属性,见下文)。为获得最佳效果,请在长时间运行的 A/B 测试中进行设备电量测量,且该测试应使用具有相同电量计和相同电流感应电阻的同类型设备。确保每台设备的起始电量相同,以避免电量计在电池放电曲线的不同点出现不同的行为。
即使处在相同的测试环境下,也不能保证测量结果具有绝对的高精确度。然而,在各次测试运行中,特定于电量计和感应电阻的大部分误差都会保持一致,这样使得相同设备之间的比较变得有意义。我们建议采用不同的配置进行多次测试,以确定各配置间的显著差异和相对耗电量。
读取耗电量
要读取耗电量数据,请在测试代码中插入对相关 API 的调用。
import android.os.BatteryManager; import android.content.Context; BatteryManager mBatteryManager = (BatteryManager)Context.getSystemService(Context.BATTERY_SERVICE); Long energy = mBatteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER); Slog.i(TAG, "Remaining energy = " + energy + "nWh");
可用属性
Android 支持以下电池电量计属性:
BATTERY_PROPERTY_CHARGE_COUNTER Remaining battery capacity in microampere-hours BATTERY_PROPERTY_CURRENT_NOW Instantaneous battery current in microamperes BATTERY_PROPERTY_CURRENT_AVERAGE Average battery current in microamperes BATTERY_PROPERTY_CAPACITY Remaining battery capacity as an integer percentage BATTERY_PROPERTY_ENERGY_COUNTER Remaining energy in nanowatt-hours
大多数属性都是从具有类似名称的内核 power_supply 子系统属性中读取的。但是,特定设备的确切属性、属性值解析度和更新频率取决于:
- 电量计硬件,如 Summit SMB347 或 Maxim MAX17050。
- 电量计与系统的连接,如外部电流感应电阻的值。
- 电量计芯片的软件配置,如为内核驱动程序中的平均电流计算间隔所选的值。
有关详情,请参阅 Nexus 设备的可用属性。
Maxim 电量计
在确定电池在长时间内的荷电状态时,Maxim 电量计(MAX17050,BC15)可校正库仑计数器的偏移测量结果。对于在短时间内进行的测量(如耗电量计量测试),该电量计不会进行校正,因此当电流测量值过小时,偏移会成为主要误差源(尽管任何时长都无法完全消除偏移误差)。
对于典型的 10 毫欧感应电阻设计,电流偏移量应小于 1.5 毫安,这意味着任何测量结果误差均为 +/- 1.5 毫安(电路板布局也会对该误差产生影响)。例如,当测量强电流(200 毫安)时,您将会获得以下结果:
- 2 毫安(200 毫安的 1% 增益误差,由电量计增益误差导致)
- +2 毫安(200 毫安的 1% 增益误差,由感应电阻误差导致)
- +1.5 毫安(电流感应偏移误差,由电量计导致)
总误差为 5.5 毫安 (2.75%)。将该误差与中等电流(50 毫安)进行比较(相同误差百分比得出的总误差为 7%),或与小电流(15 毫安)进行比较(+/-1.5 毫安误差得出的总误差为 10%)。
为获得最佳效果,我们建议测量大于 20 毫安的电流。增益测量误差是可重复的系统误差,使您能够在多种模式下测试设备,并获得纯粹的相对测量结果(1.5 毫安偏移量除外)。
对于 +/-100 微安的相对测量结果,所需测量时间取决于:
- ADC 采样噪声。具有正常出厂配置的 MAX17050 由于噪声而产生 +/-1.5 毫安的样本变差,每 175.8 毫秒输出一个样本。对于 1 分钟的测试窗口,您将会获得大约 +/-100 微安的噪声,对于 6 分钟的测试窗口,您将会获得小于 100 微安、3-sigma 的纯粹噪声(或 33 微安、1-sigma 的噪声)。
- 由负载变化引起的样本混叠。差异会放大误差,因此对于具有负载固有差异的样本,请考虑采用较长的测试窗口。
支持的 Nexus 设备
Nexus 5
型号 | Nexus 5 |
---|---|
电量计 | Maxim MAX17048 电量计(ModelGauge™,无库仑计数器) |
属性 | BATTERY_PROPERTY_CAPACITY |
测量结果 | 电量计不支持除电池荷电状态达到 %/256(占满格电池电量的百分之一的 256 分之一)解析度之外的任何测量结果。 |
Nexus 6
型号 | Nexus 6 |
---|---|
电量计 | Maxim MAX17050 电量计(带有 Maxim ModelGauge™ 调节功能的库仑计数器)和 10 毫欧电流感应电阻。 |
属性 | BATTERY_PROPERTY_CAPACITY BATTERY_PROPERTY_CURRENT_NOW BATTERY_PROPERTY_CURRENT_AVERAGE BATTERY_PROPERTY_CHARGE_COUNTER BATTERY_PROPERTY_ENERGY_COUNTER |
测量结果 | CURRENT_NOW 解析度为 156.25 微安,更新周期为 175.8 毫秒。 CURRENT_AVERAGE 解析度为 156.25 微安,更新周期可在 0.7 秒到 6.4 小时范围内配置,默认为 11.25 秒。 CHARGE_COUNTER(累计电流,不可扩展精度)解析度为 500 微安时(未经电量计针对库仑计数器偏移量进行调整的原始库仑计数器读数,加上来自 ModelGauge m3 算法的输入值,其中包括空值补偿)。 CHARGE_COUNTER_EXT(内核扩展精度)解析度为 8 纳安时。 当额定电压为 3.7 伏时,ENERGY_COUNTER 为 CHARGE_COUNTER_EXT。 |
Nexus 9
型号 | Nexus 9 |
---|---|
电量计 | Maxim MAX17050 电量计(带有 Maxim ModelGauge™ 调节功能的库仑计数器)和 10 毫欧电流感应电阻。 |
属性 | BATTERY_PROPERTY_CAPACITY BATTERY_PROPERTY_CURRENT_NOW BATTERY_PROPERTY_CURRENT_AVERAGE BATTERY_PROPERTY_CHARGE_COUNTER BATTERY_PROPERTY_ENERGY_COUNTER |
测量结果 | CURRENT_NOW 解析度为 156.25 微安,更新周期为 175.8 毫秒。 CURRENT_AVERAGE 解析度为 156.25 微安,更新周期可在 0.7 秒到 6.4 小时范围内配置,默认为 11.25 秒。 CHARGE_COUNTER(累计电流,不可扩展精度)解析度为 500 微安时。 CHARGE_COUNTER_EXT(内核扩展精度)解析度为 8 纳安时。 当额定电压为 3.7 伏时,ENERGY_COUNTER 为 CHARGE_COUNTER_EXT。 累计电流更新周期为 175.8 毫秒。 当经过 175 毫秒的量化时进行 ADC 采样,采样周期为 4 毫秒。可以调整占空比。 |
Nexus 10
型号 | Nexus 10 |
---|---|
电量计 | Dallas Semiconductor DS2784 电量计(库仑计数器),带 10 毫欧电流感应电阻。 |
属性 | BATTERY_PROPERTY_CAPACITY BATTERY_PROPERTY_CURRENT_NOW BATTERY_PROPERTY_CURRENT_AVERAGE BATTERY_PROPERTY_CHARGE_COUNTER BATTERY_PROPERTY_ENERGY_COUNTER |
测量结果 | 电流测量(瞬时电流和平均电流)解析度为 156.3 微安。 CURRENT_NOW 瞬时电流更新周期为 3.5 秒。 CURRENT_AVERAGE 更新周期为 28 秒(不可配置)。 CHARGE_COUNTER(累计电流,不可扩展精度)解析度为 625 微安时。 CHARGE_COUNTER_EXT(内核扩展精度)解析度为 144 纳安时。 当额定电压为 3.7 伏时,ENERGY_COUNTER 为 CHARGE_COUNTER_EXT。 更新周期全部为 3.5 秒。 |
测量电量值
bookmark_border
设备制造商必须在 /frameworks/base/core/res/res/xml/power_profile.xml
中提供组件的电源配置文件。
如需确定电源配置文件的有关数值,请使用测量设备耗电量的硬件,并执行需要其耗电量信息的各种操作。测量执行这些操作时的电量使用情况并计算各项值(在适当情况下与其他基准操作的电量消耗做对比所得的差异值)。
电源配置文件的目的在于适当地估算电量消耗情况,电源配置文件的有关数值以电流(安培)表示。Android 框架用电流乘以子系统处于激活状态的时间,并计算毫安时值,然后将此值用于评估应用/子系统消耗的电池电量。
运行 Android 7.0 及更高版本且配备蓝牙、调制解调器和 Wi-Fi 控制器的设备可以提供从芯片组数据获得的更多电量值。
采用异构 CPU 的设备
如果设备具有异构架构的 CPU 核心,则其电源配置文件必须包含以下额外字段:
- 每个集群的 CPU 总数(以 cpu.clusters.cores 表示)。
- 每个集群支持的 CPU 速率。
- 每个集群处于激活状态时的 CPU 耗电情况。
为了区分集群激活时的 CPU 耗电量和所支持的 CPU 速率耗电量,您需要将集群编号附加到数组名称上。集群编号按照 CPU 核心在内核设备树中的顺序分配。例如,在具备两 (2) 个集群,每个集群拥有四 (4) 个核心的异构架构中:
- cluster0 由 cpu0-3 组成
- cluster1 由 cpu4-7 组成
当 Android 框架从位于 /sys/devices/system/cpu/cpu<number>/cpufreq/stats
中的 sysfs
文件读取统计信息时,将使用以上 CPU 核心编号。
集群中的 CPU 以及速率示例:
<array name="cpu.active.cluster0"> <value>200</value> <value>300</value> <value>400</value> </array> <array name="cpu.speeds.cluster0"> <value>600000</value> <value>800000</value> <value>1200000</value> </array> <array name="cpu.active.cluster1"> <value>400</value> <value>500</value> <value>600</value> </array> <array name="cpu.speeds.cluster1"> <value>800000</value> <value>1200000</value> <value>1400000</value> </array>
电量值
下表列出可供使用的电量值设置。要查看 AOSP 中的示例文件,请参阅 power_profile.xml。
名称 | 说明 | 示例值 | 备注 |
---|---|---|---|
ambient.on | 屏幕在低电耗/微光/始终开启模式(而非关闭模式)下消耗的额外电量。 | 大约 100 毫安 | - |
screen.on | 屏幕以最低亮度开启时消耗的额外电量。 | 200 毫安 | 包括触摸控制器和显示屏背光。亮度为 0,而非 Android 通常所设的最低值 10% 或 20%。 |
screen.full | 与处于最低亮度的屏幕相比,当屏幕处于最高亮度时消耗的额外电量。 | 100-300 毫安 | 将此值乘以一定比例(基于屏幕亮度)后与 screen.on 值相加,用来计算屏幕耗电量。 |
wifi.on | 当 WLAN 打开,但未接收、发送信号或执行扫描时消耗的额外电量。 | 2 毫安 | - |
wifi.active | 通过 WLAN 发送或接收信号时消耗的额外电量。 | 31 毫安 | - |
wifi.scan | WLAN 正在扫描无线接入点时消耗的额外电量。 | 100 毫安 | - |
audio | 通过 DSP 进行音频解码/编码时消耗的额外电量。 | 大约 10 毫安 | 用于 DSP 音频。 |
video | 通过 DSP 进行视频解码时消耗的额外电量。 | 大约 50 毫安 | 用于 DSP 视频。 |
camera.avg | 针对典型相机应用,相机子系统的平均电量消耗。 | 600 毫安 | 当应用运行预览且每分钟捕获大约 10 张全分辨率照片时的粗略估算值。 |
camera.flashlight | 相机闪光灯模块开启时消耗的平均电量。 | 200 毫安 | - |
gps.signalqualitybased | GPS 消耗的额外电量(具体取决于信号强度)。这是一个多值条目,每个信号强度(从最弱到最强)各有一个值。 | 30 毫安、10 毫安 | - |
gps.on | GPS 获取信号时消耗的额外电量。 | 50 毫安 | - |
radio.active | 蜂窝无线电发送/接收信号时消耗的额外电量。 | 100-300 毫安 | - |
radio.scanning | 移动网络无线装置寻呼发射塔时消耗的额外电量。 | 1.2 毫安 | - |
radio.on | 蜂窝无线电开启时消耗的额外电量。多值条目,每个信号强度(无信号、弱、良好、强)各有一个值。 | 1.2 毫安 | 某些无线装置在搜索手机信号塔但未能检测到信号时会增加耗电量。随着信号强度的增加,这些值可能保持不变或变小。如果您只提供一个值,则所有强度都使用同一个值。如果您提供两个值,则第一个值在无信号时使用,第二个值用于所有其他信号强度,以此类推。 |
bluetooth.controller.idle | 蓝牙控制器在空闲时的平均电流消耗量(毫安)。 | - | 这些值并不是估算值,而是从控制器的数据表中提取出来的。如果有多种接收或发送状态,则采用这些状态的平均值。此外,系统现在将收集低功耗 (LE) 和蓝牙扫描的数据。 Android 7.0 及更高版本不再将蓝牙电量值用于 bluetooth.active(通过蓝牙 A2DP 播放音频时使用)和 bluetooth.on(在蓝牙开启但处于空闲状态时使用)。 |
bluetooth.controller.rx | 蓝牙控制器在接收信号时的平均电流消耗量(毫安)。 | - | |
bluetooth.controller.tx | 蓝牙控制器在发送信号时的平均电流消耗量(毫安)。 | - | |
bluetooth.controller.voltage | 蓝牙控制器的平均工作电压(毫伏)。 | - | |
modem.controller.sleep | 调制解调控制器在休眠时的平均电流消耗量(毫安)。 | 0 毫安 | 这些值并不是估算值,而是从控制器的数据表中提取出来的。如果有多种接收状态,则采用这些状态的平均值。如果有多种发送状态,则从 Android 9 开始支持为每种发送状态指定一个值。 |
modem.controller.idle | 调制解调控制器在空闲时的平均电流消耗量(毫安)。 | - | |
modem.controller.rx | 调制解调控制器在接收信号时的平均电流消耗量(毫安)。 | - | |
modem.controller.tx | 调制解调控制器在以不同的 RF 发送信号时的平均电流消耗量(毫安)。这是一个多值条目,每个发射能级有一个值。 | 100 毫安、200 毫安、300 毫安、400 毫安、500 毫安 | |
modem.controller.voltage | 调制解调控制器的平均工作电压(毫伏)。 | - | |
wifi.controller.idle | Wi-Fi 控制器在空闲时的平均电流消耗量(毫安)。 | - | 这些值并不是估算值,而是从控制器的数据表中提取出来的。如果有多种接收或发送状态,则采用这些状态的平均值。 |
wifi.controller.rx | Wi-Fi 控制器在接收信号时的平均电流消耗量(毫安)。 | - | |
wifi.controller.tx | Wi-Fi 控制器在发送信号时的平均电流消耗量(毫安)。 | - | |
wifi.controller.voltage | Wi-Fi 控制器的平均工作电压(毫伏)。 | - | |
cpu.speeds | 这是一个多值条目,以千赫 (KHz) 为单位列出 CPU 可能支持的每个速率。 | 125000 千赫、250000 千赫、500000 千赫、1000000 千赫、1500000 千赫 | 条目的数量和顺序必须与 cpu.active 中的毫安条目相一致。 |
cpu.idle | CPU(和 SoC)处于系统挂起状态时系统消耗的总电量。 | 3 毫安 | - |
cpu.awake | CPU 处于调度空闲状态(内核空闲循环)时消耗的额外电量;系统没有处于系统挂起状态。 | 50 毫安 | 您的平台可能在不同的耗电水平上存在多种空闲状态;针对时间较长的调度空闲(几毫秒)可以选择一种有代表性的空闲状态。检查您的测量设备上的电量图,并选择 CPU 耗电量最低时的样本,丢弃当 CPU 退出空闲状态时的较高耗电量样本。 |
cpu.active | CPU 以不同速度运行时消耗的额外电量。 | 100 毫安、120 毫安、140 毫安、160 毫安、200 毫安 | 此值代表 CPU 供电通道以不同速率运行时消耗的电量。在内核中设定每个耗电量所允许的最大速率并限制 CPU 以该速率运行。条目的数量和顺序应与 cpu.speeds 中的条目的数量和顺序相一致。 |
cpu.clusters.cores | 每个 CPU 集群所包含的核心数。 | 4、2 | 仅适用于具有异构 CPU 架构的设备。条目的数量和顺序应与适用于 cpu.active 和 cpu.speeds 的集群的条目的数量相一致。第一个条目表示 cluster0 中的 CPU 核心数,第二个条目表示 cluster1 中的 CPU 核心数,依此类推。 |
battery.capacity | 总电池容量(以毫安时为单位)。 | 3,000 毫安时 | - |
低功耗 (LE) 和蓝牙扫描
对于运行 Android 7.0 的设备,系统为低功耗 (LE) 扫描和蓝牙网络流量(例如:RFCOMM 和 L2CAP)收集数据并将这些活动与初始化应用相关联。蓝牙扫描与初始化扫描的应用有关,但批量扫描与后者无关(而是与蓝牙应用有关)。对于扫描 N 毫秒的应用,扫描耗时为 N 毫秒接收时间和 N 毫秒发射时间;所有剩余的控制器时间被分配至网络流量或蓝牙应用。
SystemSuspend 服务
bookmark_border
在 Android 9 及更低版本中,libsuspend 中有一个负责发起系统挂起的线程。Android 10 在 SystemSuspend HIDL 服务中引入了等效功能。此服务位于系统映像中,由 Android 平台提供。 libsuspend
的逻辑基本保持不变,以下情况除外:阻止系统挂起的每个用户空间进程都需要与 SystemSuspend 进行通信。
libsuspend 和 libpower
在 Android 10 中,SystemSuspend 服务取代了 libsuspend
。libpower
经过重新实现,目前依赖于 SystemSuspend 服务(而不是 /sys/power/wake[un]lock
),且不必更改 C API。
下面的伪代码显示了如何实现 acquire_wake_lock
和 release_wake_lock
。
static std::unordered_map<std::string, sp<IWakeLock>> gWakeLockMap;
int acquire_wake_lock(int, const char* id) {
...
if (!gWakeLockMap[id]) {
gWakeLockMap[id] = suspendService->acquireWakeLock(WakeLockType::PARTIAL, id);
}
...
return 0;
}
int release_wake_lock(const char* id) {
...
if (gWakeLockMap[id]) {
auto ret = gWakeLockMap[id]->release();
gWakeLockMap[id].clear();
return 0;
}
...
return -1;
}
执行线程
SystemSuspend 服务使用挂起计数器跟踪发出的唤醒锁数量。它有两个执行线程:
- 主线程响应 binder 调用。
- 挂起线程控制系统挂起。
主线程
主线程响应来自客户端的请求以分配新的唤醒锁,从而递增/递减挂起计数器。
挂起线程
挂起线程循环执行以下操作:
- 从
/sys/power/wakeup_count
读取。 - 获取互斥量。这可确保挂起线程在主线程尝试递增或递减挂起计数器时不会触发挂起计数器。如果挂起计数器达到零,并且挂起线程尝试运行,则系统会在发出或移除唤醒锁定时阻止主线程。
- 等到计数器等于零。
- 将从
/sys/power /wakeup_count
(第 1 步中)读取的值写入此文件。 如果写入失败,则返回到循环的开头。 - 通过将
mem
写入/sys/power/state
来发起系统挂起。 - 释放互斥量。
成功返回唤醒锁定的请求后,挂起线程会被阻止。
图 1. 挂起线程循环
注意:互斥量始终在循环迭代结束时释放。
SystemSuspend API
SystemSuspend API 包含两个接口。HIDL 接口由原生进程用于获取唤醒锁,而 AIDL 接口则用于在 SystemServer 和 SystemSuspend 之间通信。
ISystemSuspend HIDL 接口
enum WakeLockType : uint32_t {
PARTIAL,
FULL
};
interface IWakeLock {
oneway release();
};
interface ISystemSuspend {
acquireWakeLock(WakeLockType type, string debugName)
generates (IWakeLock lock);
};
请求唤醒锁定的每个客户端都会收到唯一的 IWakeLock
实例。这与 /sys/power/wake_lock
不同,后者允许多个客户端使用相同名称的唤醒锁定。如果拥有 IWakeLock
实例的客户端终止,则 binder 驱动程序和 SystemSuspend 服务会将其清除。
ISuspendControlService AIDL 接口
ISuspendControlService 仅供 SystemServer 使用。
interface ISuspendCallback {
void notifyWakeup(boolean success);
}
interface ISuspendControlService {
boolean enableAutosuspend();
boolean registerCallback(ISuspendCallback callback);
boolean forceSuspend();
}
利用 Android HIDL 可带来以下好处:
- 如果挂起阻止进程终止,则可以通知 SystemSuspend。
- 可以为负责系统挂起的线程提供回调。