Android应用耗电问题排查

Posted Vigibord

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android应用耗电问题排查相关的知识,希望对你有一定的参考价值。

1 耗电定位工具与方法

1-1 系统提供的battery信息

1-1-1 在android 4.4 KitKat 以前使用

adb shell dumpsys batteryinfo > d:/batterinfo.log
获取电量日志

1-1-2 在Android 4.4 KitKat 及以后使用

  • 获取日志

adb shell dumpsys batterystats > d:/batterstats.log

获取电量日志可以使用命令清除记录后重新记录

adb shell dumpsys batterystats --enable full-wake-history
adb shell dumpsys batterystats –reset

  • 分析

从Android4.4中获取的日志与Android5.0以上获取的日志有点不一样,但不影响获得主要信息;下面以Android5.0以上获取的日志为例分析:

Battery History
电量相关数据的时间序列:

0 (52) RESET:TIME: 2017-08-17-15-29-36
                    0 (2) 099 status=discharging health=good plug=none temp=350 volt=4218 +running +wake_lock +wifi_scan +screen phone_state=off brightness=dim +wifi_running +wifi wifi_signal_strength=4 wifi_suppl=completed proc=u0a501:"com.tencent.mm:push"
                    0 (2) 099 proc=u0a49:"com.huawei.android.remotecontrol"
                    0 (2) 099 proc=1000:"com.huawei.geofence"
                    0 (2) 099 proc=1000:"WebViewLoader-armeabi-v7a"
                    0 (2) 099 proc=u0a642:"com.wukongtv.wukongtv:Global"
                    0 (2) 099 proc=1000:"com.huawei.android.pushagent.PushService"
                    0 (2) 099 proc=1000:"WebViewLoader-arm64-v8a"
                    0 (2) 099 proc=u0a642:"com.wukong.daemon"
                    0 (2) 099 proc=1000:"com.huawei.powergenie"
                    0 (2) 099 proc=u0a45:"com.huawei.android.hwouc:hwbd"

Per-PID Stats
每一个进程执行了多长的时间

  PID 0 wake time: +21s516ms
  PID 3438 wake time: +10m38s598ms
  PID 4044 wake time: +2s286ms
  PID 4176 wake time: +2s682ms
  PID 4573 wake time: +3s825ms
  PID 8587 wake time: +3m49s32ms
  PID 4616 wake time: +12s392ms

Statistics since last charge
上次充电以来的数据记录

System starts: 0, currently on battery: false
  Time on battery: 6h 41m 34s 718ms (98.8%) realtime, 2h 39m 54s 65ms (39.3%) uptime
  Time on battery screen off: 4h 13m 47s 988ms (62.5%) realtime, 12m 7s 335ms (3.0%) uptime
  Total run time: 6h 46m 22s 139ms realtime, 2h 44m 41s 485ms uptime
  Start clock time: 2017-08-17-15-29-36
  Screen on: 2h 27m 46s 730ms (36.8%) 10x, Interactive: 2h 27m 46s 309ms (36.8%)

Estimated power use (mAh)
目前只能算比较粗略的估计,不能作为实际消耗数据,其他google更为精准的数据

Capacity: 3000, Computed drain: 1413, actual drain: 1110-1140
    Screen: 561
    Uid 1000: 282
    Uid u0a643: 240
    Uid u0a623: 196
    Uid 0: 69.3
    Idle: 12.7
Uid u0a642: 11.0

All partial wake locks
所有程序中wakelock,关注持续时间和数量

Wake lock 1000 ConnectivityService: 3m 20s 310ms (4 times) realtime
  Wake lock 1000 dispatcher: 1m 31s 411ms (19 times) realtime
  Wake lock u0a501 WakerLock:341975309: 54s 332ms (47 times) realtime
  Wake lock 1013 AudioMix: 33s 57ms (18 times) realtime
  Wake lock u0a623 PushManager: 21s 960ms (26 times) realtime
  Wake lock 1000 *alarm*: 7s 239ms (87 times) realtime
  Wake lock 1000 GpsLocationProvider: 7s 2ms (4 times) realtime
  Wake lock 1000 AudioMix: 3s 736ms (6 times) realtime

最后是每个应用的详细信息,包含了Wake lock、Proc 信息、Foreground时间、CPU消耗时间、Service信息等;分析某个应用的具体运行情况、是否异常,主要可以参考这项数据;

1001:
    Wake lock RILJ: 16ms partial (5 times) realtime
    Foreground activities: 1s 566ms realtime (2 times)
    Foreground for: 6h 41m 34s 718ms 
    Proc com.android.server.telecom:
      CPU: 60ms usr + 30ms krn ; 0ms fg
    Proc com.android.phone:
      CPU: 40s 960ms usr + 30s 250ms krn ; 430ms fg
    Apk com.android.phone.recorder:
      Service com.android.phone.recorder.RecorderServer:
        Created for: 0ms uptime
        Starts: 0, launches: 1

1-1-3 在Android 5.0以后使用

  • 获取日志

我们在开始的时候需要通过以下命令来打开电池数据的获取以及重置:
adb shell dumpsys batterystats --enable full-wake-history
shell dumpsys batterystats –reset

通过命令获得日志文件,获取时间较长,稍等片刻
adb bugreport > d:/bugreport.txt

  • 分析

A. 通过谷歌提供工具battery-historian来分析

得到batterstats.log日志后,这个时候使用我们的battery-historian来生成可视化的html报告,具体生成方式参考[http://blog.csdn.net/itfootball/article/details/44084159]

这里写图片描述

battery-historian工具也可以分析通过dumpsys batterystats方式获得的日志

B. Battery Historian 2.0

新版本带来了很多的改进:更清晰的报告,每个应用程序的摘要,更快的执行等等。
安装参考:[http://www.07net01.com/linux/2016/01/1207924.html]
提示:安装时用go命令无法从github下载的时候可以直接上github手动下载;使用时也需要翻墙才能分析报告;

这里写图片描述
通过可视化的报告可以更直观清晰的观测到手机的整体使用情况,各个时间段前台后台应用的使用、手机各项指标以及每个应用程序独立的报告;从报告可以观测出应用程序的运行情况、消耗、是否有异常行为等

1-2 显示CPU使用情况 CPU Usage data

在开发者选项中,打开显示CPU使用情况开关
如下图:

这里写图片描述

  • 在右边会显示当前运行的进程列表,排列顺序是按照CPU占用降序排列,越往上表示消耗CPU越多
  • 绿色表示 userspace占用cpu百分比,红色表示kernel 占用cpu百分比,蓝色表示 io interrupt 占用cpu百分比.
  • 第一行表示所有进程叠加的占用CPU百分比,从左到右三个数表示userspace,kernel,io interrupt

通过观测被测应用进程的cpu使用情况,可以判断出应用的运行是否合理,是否会出现耗电异常,理论情况在静置状态下,应用应该不消耗或者消耗极少的cpu;

1-3 使用Android Monitor监测具体进程

对于debug版的应用程序,使用Android Studio自带的Android Monitor工具可以观测该应用的某个进程,如图所示

这里写图片描述

通过检测某个进程的cpu,网络及gpu,可以看出静置状态下,该进程的行为是否异常;如果异常了,能观测出异常规律就能回到代码找出异常;

1-4 使用DDMS中的Traceview进行定位

Traceview工具是一个分析器,记录了应用程序中每个函数的执行时间;
打开DDMS,然后选择一个进程,接着点击上面的“Start Method Profiling”按钮(红色小点变为黑色即开始运行)。
打开我们怀疑的需要被测试的页面,静置片刻,然后点击开始按钮后,过一段时间后(时间根据自己需要定),再次点击该按钮停止记录,稍等片刻即可出现下图,如下:

这里写图片描述

整个界面包括上下两部分,上面是你测试的进程中每个线程运行的时间线,下面是每个方法(包含parent及child)执行的各个指标的值。通过上图的时间面板可以直观发现,哪些方法cpu消耗的多。当我们选择上面的一个线程后可以发现下面的性能面板很复杂,其实这才是TraceView的核心图表,它主要展示了线程中各个方法的调用信息(CPU使用时间、调用次数等),这些信息就是我们分析的核心关注点,所以我们先看几个重要的属性说明,如下:

属性名含义
name线程中调运的方法名
Incl CPU Time当前方法(包含内部调运的子方法)执行占用的CPU时间;
Excl CPU Time当前方法(不包含内部调运的子方法)执行占用的CPU时间;
Incl Real Time当前方法(包含内部调运的子方法)执行的真实时间,ms单位;
Excl Real Time当前方法(不包含内部调运的子方法)执行的真实时间,ms单位;
Calls+Recur Calls/Total当前方法被调运的次数及递归调运占总调运次数百分比;
CPU Time/Call当前方法调运CPU时间与调运次数比,即当前方法平均执行CPU耗时时间;
Real Time/Call当前方法调运真实时间与调运次数比,即当前方法平均执行真实耗时时间;(重点关注)

通过分析哪些方法消耗了多少cpu,这些方法是否属于正常消耗,我们就能排查出异常消耗的方法,这些被异常调用的方法也是耗电的源头;

一般Traceview可以定位两类问题:
方法调运一次需要耗费很长时间;
方法调运一次耗时不长,但被频繁调运导致累计时长多。

在定位耗电异常问题时,可以打开Traceview然后按照Cpu Time/Call或者Real Time/Call进行降序排列,然后打开可疑的方法及其child进行分析查看,然后再回到代码定位检查逻辑优化即可;

PS:Android Studio新版本除过DDMS以外在CPU视图的左侧已经集成了Traceview(start Method Tracing)功能

.trace文件如下:

这里写图片描述

1-5 基于代码的排查

排查循环方法

搜索代码里面的定时循环执行的方法,考量该方法的功耗;
包括:Timer、handler.Postdelayed、ScheduledFutureTask、JobService、Animation、AnimationDrawable等

写日志记录

A.在关键地方及可疑地方打上日志;
B.将日志按进程以及每小时一个分类存入本地文件中;
比如ProcessA-20161026090520.log、ProcessA-20161026100520.log

这样可以清楚的观测到哪些进程在哪些时间段有活动迹象;看看有没有循环日志,或者耗时方法,再回到代码里去查看

分模块屏蔽

分模块屏蔽,使用排除法来缩小范围,最终定位到问题所在

2 实际排查过程中的分析与定位

这里仅限于讨论应用被静置情况下的耗电分析,应用被操作时的性能优化请参考博文http://blog.csdn.net/yanbober/article/details/48394201
对于一个比较复杂的应用来说,会有多进程、后台程序、拉活、push等情况,需要分别从这些维度来分析:(启屏状态、灭屏状态),(手机静置、操作),(被测应用在前台、后台),(长时间、短时间)

2-1 灭屏状态-被测应用在后台-手机静置

环境:在手机屏幕处于关闭状态、被测应用在后台运行(使用被测应用后正常退出应用,可以将应用加白防止被系统杀进行测试,手机处于桌面状态)、手机静置状态下进行测试,可以测试短时间也可以把手机放置长时间后再取数据

使用Battery Historian 2.0 + 日志记录方法来定位

这里写图片描述

如上图从报告结果中查看被测应用详细信息,可以看到应用的基本信息、电量消耗、wake lock、Service、Process等,主要分析wake lock的次数是否合理、Service的启动次数、运行时长是否合理,有没有出现没有及时关闭的情况、process的运行时长,有没有及时关闭等;
结合日志记录,定位出具体运行的逻辑,判断这些逻辑是否在灭屏时未及时停止、评估逻辑的复杂度及是否耗电等

2-2 启屏状态-被测应用在后台

环境:在手机屏幕处于开启状态、被测应用在后台运行(使用被测应用后正常退出应用),可尝试正常使用手机玩其他应用或者停留在某个应用中静置

使用 显示CPU情况 + Traceview 来定位

打开显示CPU情况 开关,在使用手机的过程中,观察被测应用所有的进程是否存在cpu消耗的情况,有cpu消耗的会排在前面;如果某个进程频繁的排在前面,这个进程就是可疑的,这时可以使用Traceview对可疑进程进行追踪,查出哪些方法消耗cpu后进行优化;

2-3 启屏状态-被测应用在前台-静置

环境:在手机屏幕处于开启状态、使用被测应用、停留在某个页面后静置(尽量避开banner,保证页面静置),观测该页面(主要用于测试应用的各页面是否合理,静置状态下不应该有cpu消耗)

使用 Android Monitor + Traceview 来定位

打开Android Monitor,观察各个进程的cpu、network、内存、gpu曲线;从曲线中找出波峰规律(有没有循环操作)、判断曲线合理度(是不是合理的逻辑操作),不合理的地方使用Traceview对可疑进程进行追踪,查出哪些方法消耗cpu后进行优化;

被测应用前台静置界面的功耗问题主要考虑两个部分:

  • 跟当前界面相关的循环执行逻辑
  • 跟当前界面无关的循环执行逻辑(其他界面没有关掉的逻辑或者后台逻辑)

可考虑:

  • 可以先测试桌面状态下的静置耗电(后台进程耗电),把后台进程优化一遍再优化前台进程;
  • 确保某界面退出后,该界面内启用的循环逻辑关掉;
  • Timer、handler.Postdelayed、ScheduledFutureTask、JobService、Animation、AnimationDrawable等的开始结束要注意同步问题,保证循环能停止;
  • 实在没办法的情况下,终极杀招:分模块屏蔽功能、页面,使用排除法来定位问题;

ps:欢迎各位探讨,有其他好方法请@我

以上是关于Android应用耗电问题排查的主要内容,如果未能解决你的问题,请参考以下文章

Android应用耗电问题排查

最近排查android webview https的发热耗电和加载速度慢问题解决

安卓Alarm闹钟唤醒耗电问题的排查

如何用adb命令查看Android手机具体某个应用的耗电量?

Android应用耗电定位方案

有没有办法确定 JS 代码的哪一部分最耗电?