应用商店中关于电池管理的应用做的极其绚烂,可耗电应用排行、剩余时间计算、关闭耗电程序以节省电量等功能是如何实现的,遇到功耗高的问题从哪些方面入手分析和定位,这里简要总结如下。
一. 电量值的获取和计算
首先解释下各软硬件耗电量的计算。假设设备(如WIFI)单位时间内消耗的电量为w,运行时间为t,则其在这段时间内的耗电量为W=w*t。根据物理学中的知识,电功率(即所谓电量)计算公式为W=UIt,其中U为电压值,I为电流值,t为运行时间。由于在一部机器中,电压值U是恒定不变的(一般如此),因此可以忽略掉参数U,单独通过电流及时间即可表示电量(比如电池容量为2000mA、2500mA等,以mA为单位进行恒量)。根据以上描述,只要我们获得了某程序或某设备运行的时间,以及其运行时所需要电流值,则可以计算出其消耗的电量(以上理论会在代码中体现)。
某程序或硬件设备的运行时间可以分别通过BatteryStats.Uid.Proc和BatteryStatsImpl中的相关接口获得,这里主要讲下电流值(即单位时间消耗电量)的获取。
a. PowerProfile.java ./frameworks/base/core/java/com/android/internal/os/PowerProfile.java
代码中定义了几十种不同设备的耗电类型:
/** * No power consumption, or accounted for elsewhere. */
public static final String POWER_NONE = "none;
/** * Power consumption when CPU is in power collapse mode. */
public static final String POWER_CPU_IDLE = "cpu.idle";
public static final String POWER_CPU_AWAKE = "cpu.awake";
/** * Power consumption when CPU is in power collapse mode. */
@Deprecated public static final String POWER_CPU_ACTIVE = "cpu.active";
public static final String POWER_WIFI_SCAN = "wifi.scan";
public static final String POWER_WIFI_ON = "wifi.on";
public static final String POWER_WIFI_ACTIVE = "wifi.active";
public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx";
public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx";
public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
"bluetooth.controller.voltage";
public static final String POWER_GPS_ON = "gps.on";
public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
public static final String POWER_SCREEN_ON = "screen.on";
public static final String POWER_RADIO_ON = "radio.on";
public static final String POWER_RADIO_SCANNING = "radio.scanning";
public static final String POWER_RADIO_ACTIVE = "radio.active";
public static final String POWER_SCREEN_FULL = "screen.full";
public static final String POWER_AUDIO = "dsp.audio";
public static final String POWER_VIDEO = "dsp.video";
public static final String POWER_FLASHLIGHT = "camera.flashlight";
public static final String POWER_CAMERA = "camera.avg";
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan";
public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
(1)public double getAveragePower(String type)
此方法返回在type子系统下消耗的电流值,单位为mA。type可取PowerProfile中定义的常量值,包括POWER_CPU_IDLE(CPU空闲时),POWER_CPU_ACTIVE(CPU处于活动时),POWER_WIFI_ON(WIFI开启时)等各种状态。例如,如下调用getAveragePower(POWER_CPU_ACTIVE)将返回CPU处于活动时的电流值;getAveragePower(POWER_WIFI_ON)将返回维持WIFI启动状态所需的电流值。结合之前的描述,假设WIFI开启的时间为t(假设此段时间未使用WIFI传输数据,因为WIFI传输数据需要额外的电能消耗),那么在此段时间内WIFI所消耗的电量为W=t*getAveragePower(POWER_WIFI_ON)。
(2) public double getAveragePower(String type, int level)
相比于方法(1),此接口需要传入参数level,现在来解释下level的含义。我们知道,android系统中CPU可以以多种速度运行(假设分别为600MHz,800MHz,1GHZ等),速度不同时CPU消耗的电量也不同,参数level即代表不同的运行频率,显然,方法getAveragePower(String type, int level)将返回type子系统在CPU运行速度级别为level时单位时间内所消耗的电量(即电流值)。
(3)public double getBatteryCapacity() 获取电池总电量。
(4)public int getNumSpeedStepsInCpuCluster(int index) 获取CPU可以以几种速度运行。
b. powe