原文:http://www.cnblogs.com/hyddd/p/4402621.html
前言
- 在 Android 统计 App 耗电量比较麻烦,直至 Android 4.4,它仍没公开 “电量统计” API 或文档……额,是的,仅没有公开,并不是没有。平时在手机 “设置- 电量” 看到的数据就是系统调用内部 API 的统计结果。
基础概念
- 手机由众多 “部件” 组成,所谓 “部件” 是指:CPU,WIFI,GPS....所以,Android App 消耗总电量为 App 运行过程中,涉及各部件的消耗电量的总和。
- 假设运行 App 导致 CPU 运行,时间:t,CPU 单位时间消耗电量:w,则 App 的 CPU 耗电量为:W = w*t,而有物理公式 W = U*I*t(U:电压值,I:电流值),在手机中,一般 U 恒定不变,所以,可以单独通过 Q(电容量,单位: mAh)= I * t 表示电量。
系统源码分析
- 核心源码:/packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageSummary.java
- 核心类:
- BatteryStatsImpl:提供 App 各部件运行时间。
- PowerProfile:提供部件电流数值。
- 问题:
- Android 怎样存储与读取 App 耗电量信息(即:BatteryStatsImpl 数据怎么来的?)
- Android 怎么存储部件电流数值(即:PowerProfile 数据怎么来的?)
- Android 具体耗电量计算方法
1. Android 怎样存储与读取 App 耗电量信息
- 先看下 PowerUsageSummary.java 如何获取 BatteryStatsImpl?



- 可见 BatteryStatsImpl 通过 系统服务 “batteryinfo” 获得。
- 系统服务 “batteryinfo” 是什么玩意呢?(见:BatteryStatsService.java)

- 系统服务 “batteryinfo” 其实就是 BatteryStatsService,而 BatteryStatsService“唯一的” 构造函数提供了一个很重要的信息:filename!
- BatteryStatsService 在哪里创建?filename 是什么?(见:ActivityManagerService.java)

- filename 文件是:/data/system/batterystats.bin,关于 batterystats.bin,之前民间很多文章说它用作电池校正,但 Android 工程师 Dianne Hackborn 在 google+ 上明确:

- betterystats.bin 文件仅仅是一个记录不同 app 使用电量的一个文件。
- 再看看 BatteryStatsImpl(String filename) 构造函数(见:BatteryStatsImpl.java)

- 这里只做了些基本的初始化。真正载入 betterystats.bin 数据是在(ActivityManagerService.java)mBatteryStatsService.getActiveStatistics().readLocked();


- 至此,Android 怎样存储与读取 App 耗电量信息分析结束。
ruby
总结:
(1)ActivityManagerService 创建并初始化 BatteryStatsService,并传入耗电量记录文件batterystats.bin;
(2)BatteryStatsService 在内部创建 BatteryStatsImpl 实例,并传入耗电量记录文件batterystats.bin;
(3)ActivityManagerService 执行 mBatteryStatsService.getActiveStatistics().readLocked();导致 BatteryStatsService 的 BatteryStatsImpl 加载batterystats.bin数据;
(4)在PowerUsageSummary计算App耗电量时,PowerUsageSummary从BatteryStatsService 中获取BatteryStatsImpl 实例,从而获得App的相关数据。
2. Android 怎么存储部件电流数值
3. Android 具体耗电量计算方法
- App 耗电量统计:processAppUsage()
- 硬件耗电量统计:processMiscUsage()
processAppUsage() 分析 ##
-
【1】processAppUsage 耗电量统计的 时间段 是?


- 关于统计的 时间段,BatteryStats 有 4 个选项:

- 可见,processAppUsage 是 上一次拔掉设备后 ~ 至今 的 App 耗电量统计。
-
【2】processAppUsage 的统计对象真的是 App?

- 具体的 统计流程 都在 for 循环里,额……所以 processAppUsage 真实统计粒度是 Uid。
- Uid 与 App 关系:2 个 App 签名和 sharedUserId 相同,则在运行时,他们拥有相同 Uid。就是说 processAppUsage 统计的可能是多个 App 的耗电量数据,对于普通 App,出现这种情况的几率较少,而对于 Android 系统应用则较为常见。
-
【3】耗电量计算公式 - 部分 1:计算 Uid 属下每个 Process 的耗电量数据,并求和。
- Uid_Power1 =(Process1_Power + … + ProcessN_Power);
- Process_Power =(CPUSpeed_Time * POWER_CPU_ACTIVE);

-
【4】耗电量计算公式 - 部分 2:计算 Uid 的 wake lock 耗电量
- 这里,Android 只计算了 partial wake lock 的耗电量。
- Uid_Power2 = PartialWakeLock_Time * POWER_CPU_WAKE

-
【5】耗电量计算公式 - 部分 3:计算 Uid 的数据流量(data traffic)耗电量
- Uid_Power3 = ( tcpBytesReceived + tcpBytesSent ) * averageCostPerByte


-
【6】耗电量计算公式 - 部分 4:计算 Uid WIFI 耗电量。
- Uid_Power4 = wifiRunningTimeMs * POWER_WIFI_ON

-
【7】耗电量计算公式 - 部分 5:计算 Uid 其他传感器耗电量。
- Uid_Power5 =(Sensor1_Power + … + SensorN_Power)
- Sensor_Power = Sensor_Time * Power_Sensor
- 至此,App 耗电量计算方法分析结束。硬件耗电量统计(processMiscUsage())亦类似。
ruby
总结App耗电量计算公式:
Uid_Power(App耗电量,单位:mAh) = Uid_Power1 + Uid_Power2 + Uid_Power3 + Uid_Power4 + Uid_Power5
Uid_Power1 = (Process1_Power + … + ProcessN_Power);
- Process_Power = (CPUSpeed_Time * POWER_CPU_ACTIVE);
Uid_Power2 = PartialWakeLock_Time * POWER_CPU_WAKE
Uid_Power3 = ( tcpBytesReceived + tcpBytesSent ) * averageCostPerByte
Uid_Power4 = wifiRunningTimeMs * POWER_WIFI_ON
Uid_Power5 = (Sensor1_Power + … + SensorN_Power)
- Sensor_Power = Sensor_Time * Power_Sensor
说这么多,来一发……不,来一个统计耗电量的 App 吧,其实,之前已有人把这段 Android 系统代码抠出来,做了一个 App,可以到 http://www.eoeandroid.com/thread-255696-1-1.html下载。
↙↙↙阅读原文可查看相关链接,并与作者交流