Android 8.1 Battery系列(三) PowerProfile和power_profil

2019-07-14 00:39发布

概述

Battery系列(二)中分析道,当实例化BatteryStatsImpl完毕后,给BSI对象设置了一个PowerProfile对象,这个对象的作用是什么呢? 在了解PowerProfile之前,需要了解下电源配置文件。电源配置文件定义了组件的电流消耗值以及该组件在一段时间内大概消耗的电量。
在Google给出的文档中指出:在电源配置文件中,功耗表示额定电压下的电流消耗量,单位为mA (mA),也可用微安 (uA) 表示,该值应代表电池上消耗的电流。 PowerProfile负责解析电源配置文件,获取功耗值,并将获取的值供给BatteryStatsService等类计算各个项的耗电量,因此,最终的电池使用信息是由BatteryStatsImpl中的统计时长和电源配置文件中的值的运算而来。 电源配置文件路径:/frameworksasecore es esxmlpower_profile.xml
Google规定,设备制造厂商必须提供自己的power_profile.xml文件,因此,一般在device/xxx/overlay/framework/base/core/res/res/xml目录下定义该文件。

解析power_profile.xml

下面开始从PowerProfile类的构造方法开始分析对电源配置文件的读取,其构造方法如下: static final HashMap<String, Object> sPowerMap = new HashMap<>(); public PowerProfile(Context context) { // Read the XML file for the given profile (normally only one per // device) synchronized (sLock) { //sPowerMap是一个static Map,保存解析内容({name,value}) if (sPowerMap.size() == 0) { //解析power_profile.xml文件 readPowerValuesFromXml(context); } //初始化cpu集群 initCpuClusters(); } } 在构造方法中,首先进行了解析xml文件,将解析后的值存储在一个Map中。在power_profile.xml中,存在两种类型的数据,分别是元素和元素,如: <item name="cpu.idle">3.5item> <item name="cpu.awake">37item> <array name="cpu.speeds.cluster1"> <value>1650000value> <value>1800000value> array> 在解析过程中,对于元素,则以name为键,电流值为值存储到sPowerMap中;对于元素,则以name为键,以Double[]为值存储到sPowerMap中,Double数组中则存储了该的解析值。 解析完毕后,调用initCpuClusters()方法初始化CPU集群: //每个cpu集群中cpu核数 private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores"; //cpu集群中各个核支持的cpu速率 private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster"; //每个cpu集群中处于激活状态的cpu耗电量 private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster"; private void initCpuClusters() { // 获取每个cpu集群的cpu核数 final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT); if (obj == null || !(obj instanceof Double[])) { // 如果存储的不是数组的话,默认为1核 mCpuClusters = new CpuClusterKey[1]; //实例化CpuClusterKey,代表cpu集群 mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1); } else { final Double[] array = (Double[]) obj; mCpuClusters = new CpuClusterKey[array.length]; //遍历每个集群 for (int cluster = 0; cluster < array.length; cluster++) { //一个cpu集群的核数 int numCpusInCluster = (int) Math.round(array[cluster]); //实例化CpuClusterKey,代表一个cpu集群,对应xml中的名称 mCpuClusters[cluster] = new CpuClusterKey( //cpu.speeds.cluster+index POWER_CPU_CLUSTER_SPEED_PREFIX + cluster, //cpu.active.cluster+index POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster, numCpusInCluster); } } } 在实例化CPU集群对象CpuClusterKey时,为了区分集群中激活的 CPU 耗电量和所支持的 CPU 速率耗电量,需要将集群编号附加到数组名称上。集群编号按照 CPU 核心在内核设备树中的顺序分配。
电源配置文件中对应的字段及值配置如下: <array name="cpu.clusters.cores"> <value>6value> <value>2value> array> <array name="cpu.speeds.cluster0"> <value>768000value> <value>900000value> <value>1000000value> <value>1100000value> <value>1250000value> <value>1350000value> array> <array name="cpu.speeds.cluster1"> <value>1650000value> <value>1800000value> array> <array name="cpu.active.cluster0"> <value>83value> <value>98value> <value>108value> <value>123value> <value>143value> <value>164value> array> <array name="cpu.active.cluster1"> <value>220value> <value>238value> array> 综上所述,在实例化PowerProfile对象时,就在其构造方法中进行了电源配置文件的解析,并保存在了PowerProfile中。

电源配置文件中各个参数含义

名称 说明 示例值 备注 none 无 0 screen.on 屏幕以最低亮度打开时消耗的额外电量。 200 mA 包括触摸控制器和显示屏背光。Android 的最低亮度并非是 0,而是倾向于设为 10% 或 20%。 screen.full 与处于最低亮度的屏幕相比,当屏幕处于最高亮度时消耗的额外电量。 100-300 mA 将此值的分数(基于屏幕亮度)添加到 screen.on 值,用来计算屏幕耗电量。 wifi.on 当 WLAN 打开,但未接收、发送信号或执行扫描时消耗的额外电量。 2 mA wifi.active 通过 WLAN 发送或接收信号时消耗的额外电量。 31 mA wifi.scan WLAN 正在扫描无线接入点时消耗的额外电量。 100 mA dsp.audio 当通过 DSP 进行音频解码/编码时消耗的额外电量。 14.1 mA 预留以供日后使用。 dsp.video 当通过 DSP 进行视频解码时消耗的额外电量。 54 mA 预留以供日后使用。 camera.avg 用于典型相机应用的相机子系统的平均电量消耗。 600 mA 预期将此值作为当应用运行预览且每分钟捕获大约 10 张全分辨率照片时的粗略估算值。 camera.flashlight 当摄像头闪光模块开启时消耗的平均电量。 200 mA gps.on GPS 获取信号时消耗的额外电量。 50 mA radio.active 蜂窝无线电发送/接收信号时消耗的额外电量。 100-300 mA radio.scanning 当移动网络无线装置寻呼发射塔时消耗的额外电量。 1.2 mA radio.on 当蜂窝无线电开启时消耗的额外电量。多值条目,每个信号强度(无信号、弱、良好、强)各有一个值。 1.2 mA 某些无线装置在搜索手机信号塔但未能检测到信号时会增加耗电量。随着信号强度的增加,这些值可能保持不变或变小。如果您只提供一个值,则所有强度都使用同一个值。如果您提供两个值,则第一个值在无信号时使用,第二个值用于所有其他信号强度,以此类推。 bluetooth.controller.idle 蓝牙控制器在空闲时的平均电流消耗量(mA)。 - 这些值并不是通过预估获得的,而是从控制器的数据表中提取出来的。如果有多种接收或发送状态,则采用这些状态的平均值。此外,系统将即时收集数据以用于低功耗(LE) 和蓝牙扫描。Android N 及更高版本不再将蓝牙电量值用于 bluetooth.active(通过蓝牙 A2DP 播放音频时使用)和bluetooth.on(在蓝牙打开但处于空闲状态时使用)。 bluetooth.controller.rx 蓝牙控制器在接收信号时的平均电流消耗量(mA)。 - bluetooth.controller.tx 蓝牙控制器在发送信号时的平均电流消耗量(mA)。 - bluetooth.controller.voltage 蓝牙控制器的平均工作电压(毫伏)。 - modem.controller.idle 调制解调控制器在空闲时的平均电流消耗量(mA)。 - 这些值并不是通过预估获得的,而是从控制器的数据表中提取出来的。如果有多种接收或发送状态,则采用这些状态的平均值。 modem.controller.rx 调制解调控制器在接收信号时的平均电流消耗量(mA)。 - modem.controller.tx 调制解调控制器在发送信号时的平均电流消耗量(mA)。 - modem.controller.voltage 调制解调控制器的平均工作电压(毫伏)。 - wifi.controller.idle WLAN 控制器在空闲时的平均电流消耗量(mA)。 - 这些值并不是通过预估获得的,而是从控制器的数据表中提取出来的。如果有多种接收或发送状态,则采用这些状态的平均值。 wifi.controller.rx WLAN 控制器在接收信号时的平均电流消耗量(mA)。 - wifi.controller.tx WLAN 控制器在发送信号时的平均电流消耗量(mA)。 - wifi.controller.voltage WLAN 控制器的平均工作电压(毫伏)。 - cpu.speeds 多值条目,以千赫(KHz)为单位列出每个 CPU 可能支持的速率。 125000 、250000、500000、1000000、1500000 条目的数量和顺序必须与 cpu.active中的mA条目相一致。 cpu.idle 当 CPU(和 SoC)处于系统挂起状态时,系统消耗的总电量。 3 mA cpu.awake 当CPU 处于未挂起状态但没有执行任务时消耗的电量(计算partial wakelock时使用此值) 50 mA 平台可能在不同的耗电水平上存在多种空闲状态;针对时间较长的调度空闲(几毫秒)可以选择一种有代表性的空闲状态。检查测量设备上的电量图,并选择 CPU 耗电量最低时的样本,丢弃当 CPU 退出空闲状态时的较高耗电量样本。 cpu.active CPU 以不同速度运行时消耗的额外电量。 100 mA、120 mA、140 mA、160 mA、200 mA 此值代表 CPU 供电通道以不同速率运行时消耗的电量。在内核中设定每个耗电量所允许的最大速率并限制 CPU 以该速率运行。条目的数量和顺序应与 cpu.speeds 中的条目的数量和顺序相一致。 cpu.clusters.cores 每个 CPU 集群所包含的核心数。 4、2 仅适用于具有异构 CPU 架构的设备。条目的数量和顺序应与适用于 cpu.active 和 cpu.speeds 的集群的条目的数量相一致。第一个条目表示 cluster0 中的 CPU 核心数,第二个条目表示 cluster1 中的 CPU 核心数,依此类推。 battery.capacity 总电池容量 (以mAh为单位)。 3000 mAh

参考资料

Android Open Source Project