移动测试基础 深入浅出 Android App 耗电量统计

匿名 · 2015年04月08日 · 最后由 朱光精 回复于 2017年11月05日 · 3376 次阅读
本帖已被设为精华帖!

原文:http://www.cnblogs.com/hyddd/p/4402621.html

前言

  • 在 Android 统计 App 耗电量比较麻烦,直至 Android 4.4,它仍没公开 “电量统计” API 或文档……额,是的,仅没有公开,并不是没有。平时在手机 “设置- 电量” 看到的数据就是系统调用内部 API 的统计结果。

基础概念

  1. 手机由众多 “部件” 组成,所谓 “部件” 是指:CPU,WIFI,GPS....所以,Android App 消耗总电量为 App 运行过程中,涉及各部件的消耗电量的总和。
  2. 假设运行 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 怎么存储部件电流数值

  • 比较简单,见 PowerProfile.java

    • PowerProfile 读取资源 com.android.internal.R.xml.power_profile,并把数据加载到 sPowerMap。
  • com.android.internal.R.xml.power_profile 在哪里?

    • 在官方文档《Power Profiles for Android》明确了 power_profile.xml 位置: device///frameworks/base/core/res/res/xml/power_profile.xml。
    • 下面是一个 samsung 的 power_profile.xml:
    • 字段含义见《Power Profiles for Android》。
  • 每个 OEM 厂商有自己独立的 power_profile.xml 配置

    • 官方文档表明:OEM 厂商应该有自己的 power_profile.xml,因为部件(如:cpu, wifi…)耗电量应与具体硬件相关,这个只有 OEM 厂商清楚……
  • PowerProfile 关键 API:

    • public double getAveragePower(String type):返回 type 的电流值(mA),type 表示 power_profile.xml 中的某关键字(如:gps.on)。
    • public double getAveragePower(String type, int level) :返回 type 的电流值(mA),level 表示 xml 中 array 的第几个 value。
    • 至此,Android 怎么存储部件电流数值分析结束。 ruby 总结: (1)Android部件电流信息存于:power_profile.xml (2)每个OEM厂商有私有power_profile.xml (2)PowerProfile读取power_profile.xml,并提供API访问部件电流数值。

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下载。

共收到 13 条回复 时间 点赞
codeskyblue 通过电池电量评测安卓 App 的耗电水平 中提及了此贴 12月09日 19:39
codeskyblue [该话题已被删除] 中提及了此贴 12月09日 16:17
易寒 详解 Android 耗电量 API 中提及了此贴 12月21日 17:43

楼主文章刚开始提到:"在手机中,一般 U 恒定不变" U 恒定不变么? 大部分手机锂电池充满电,电池电压是 4.3V,随着手机耗电电压最低会降到 3.75V,怎么会是恒定不变的捏?

参考http://www.eoeandroid.com/thread-254484-1-1.html?_dsign=8fce3273jar 包,导入了 编译出错了,你知道是啥原因吗
Error:Execution failed for task ':mobile:transformClassesWithDexForDebug'.

com.android.build.api.transform.TransformException: java.lang.RuntimeException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '/Applications/Android Studio2.2.app/Contents/jre/jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

易寒 [该话题已被删除] 中提及了此贴 10月09日 19:20

最近结合你这篇文章在做电量测试,还不错。

功耗仪也可以自动化的获取,另外精确度比软件高

匿名 #7 · 2015年04月10日

#6 楼 @walkwall 嘿嘿,终于有人提到这个问题了.....我现在还没看,但从其他地方的表现看(dumpsys),应该是 android 把服务名换了,batteryinfo 换成了 batterystats....要兼容 4.4+ 应该还是有办法的。这个文章主要是想说明 “如何 区分 各个应用的功耗!"用功耗仪是为了更好的解决什么问题?

感谢楼主分享,很详尽。不过方案仅支持 4.1-4.3,算是个微弱的限制。
我们项目中,这种软件的方法已经有了,最近在琢磨要不要上功耗仪。大家在项目中,有使用到功耗仪来测试的吗?功耗仪的价格和方案不是问题,就是对效果心存疑虑。有试过水的没?

好文, 感谢转发。 目前好像可以精准统计 app 耗电量的云服务还没有

来,上功耗仪 Orz

感觉即使耗电严重,用户也只会抱怨手机电池太次~然后换一个手机~嘿嘿嘿!

添加头像

匿名 #1 · 2015年04月08日

格式转换不好玩...

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册