Android耗电优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq980106800/article/details/87811924

什么是耗电优化

有些同学可能会疑惑,所谓的耗电优化不就是减少应用的耗电,增加用户的续航时间吗?但是落到实践中,如果我们的应用需要播放视频、需要获取 GPS 信息、需要拍照,这些耗电看起来是无法避免的。

如何判断哪些耗电是可以避免,或者是需要去优化的呢?你可以看下面这张图,当用户去看耗电排行榜的时候,发现“王者荣耀”使用了 7 个多小时,这时用户对“王者荣耀”的耗电是有预期的。

假设这个时候发现某个应用他根本没怎么使用(前台时间很少),但是耗电却非常多。这种情况会跟用户的预期差别很大,他可能就会想去投诉。

所以耗电优化的第一个方向是优化应用的后台耗电。

知道了系统是如何计算耗电的,那反过来看,我们也就可以知道应用在后台不应该做什么,例如长时间获取 WakeLock、WiFi 和蓝牙的扫描等。为什么说耗电优化第一个方向就是优化应用后台耗电,因为大部分厂商预装项目要求最严格的正是应用后台待机耗电。

当然前台耗电我们不会完全不管,但是标准会放松很多。你再来看看下面这张图,如果系统对你的应用弹出这个对话框,可能对于微信来说,用户还可以忍受,但是对其他大多数的应用来说,可能很多用户就直接把你加入到后台限制的名单中了

耗电优化的第二个方向是符合系统的规则,让系统认为你耗电是正常的。

而 Android P 是通过 Android Vitals 监控后台耗电,所以我们需要符合 Android Vitals 的规则,目前它的具体规则如下:

虽然上面的标准可能随时会改变,但是可以看到,Android 系统目前比较关心后台 Alarm 唤醒、后台网络、后台 WiFi 扫描以及部分长时间 WakeLock 阻止系统后台休眠。

1.耗电监控

对于耗电监控也是如此,我们首先需要抽象出具体的规则,然后收集尽量多的辅助信息,帮助问题的排查。

1. Android Vitals

我们先复习一下Android Vitals 的几个关于电量的监控方案与规则。

  • Alarm Manager wakeup 唤醒过多
  • 频繁使用局部唤醒锁
  • 后台网络使用量过高
  • 后台 WiFi scans 过多

在使用了一段时间之后,我发现它并不是那么好用。以 Alarm wakeup 为例,Vitals 以每小时超过 10 次作为规则。由于这个规则无法做修改,很多时候我们可能希望针对不同的系统版本做更加细致的区分。

其次跟 Battery Historian 一样,我们只能拿到 wakeup 的标记的组件,拿不到申请的堆栈,也拿不到当时手机是否在充电、剩余电量等信息。

对于网络、WiFi scans 以及 WakeLock 也是如此。虽然 Vitals 帮助我们缩小了排查的范围,但是依然需要在茫茫的代码中寻找对应的可疑代码。

2. 耗电监控都监控什么

Android Vitals并不是那么好用,而且对于国内的应用来说其实也根本无法使用。不管怎样,我们还是需要搭建自己的耗电监控系统。

那我们的耗电监控系统应该监控哪些内容,怎么样才能比 Android Vitals 做得更好呢?

  • 监控信息。简单来说系统关心什么,我们就监控什么,而且应该以后台耗电监控为主。类似 Alarm wakeup、WakeLock、WiFi scans、Network 都是必须的,其他的可以根据应用的实际情况。如果是地图应用,后台获取 GPS 是被允许的;如果是计步器应用,后台获取 Sensor 也没有太大问题。
  • 现场信息。监控系统希望可以获得完整的堆栈信息,比如哪一行代码发起了 WiFi scans、哪一行代码申请了 WakeLock 等。还有当时手机是否在充电、手机的电量水平、应用前台和后台时间、CPU 状态等一些信息也可以帮助我们排查某些问题。
  • 提炼规则。最后我们需要将监控的内容抽象成规则,当然不同应用监控的事项或者参数都不太一样。 由于每个应用的具体情况都不太一样,下面是一些可以用来参考的简单规则。

在安卓绿色联盟的会议中,华为公开过他们后台资源使用的“红线”,你也可以参考里面的一些规则:

3. 如何监控耗电

明确了我们需要监控什么以及具体的规则之后,终于可以来到实现这个环节了。跟 I/O 监控、网络监控一样,我首先想到的还是 Hook 方案。

Java Hook

Hook 方案的好处在于使用者接入非常简单,不需要去修改自己的代码。下面我以几个比较常用的规则为例,看看如果使用 Java Hook 达到监控的目的。

  • WakeLock。WakeLock 用来阻止 CPU、屏幕甚至是键盘的休眠。类似 Alarm、JobService 也会申请 WakeLock 来完成后台 CPU 操作。WakeLock 的核心控制代码都在PowerManagerService中,实现的方法非常简单。
// 代理 PowerManagerService
ProxyHook().proxyHook(context.getSystemService(Context.POWER_SERVICE), "mService", this);@Override
public void beforeInvoke(Method method, Object[] args) {// 申请 Wakelockif (method.getName().equals("acquireWakeLock")) {if (isAppBackground()) {// 应用后台逻辑,获取应用堆栈等等     } else {// 应用前台逻辑,获取应用堆栈等等}// 释放 Wakelock} else if (method.getName().equals("releaseWakeLock")) {// 释放的逻辑    }
}
  • Alarm。Alarm 用来做一些定时的重复任务,它一共有四个类型,其中ELAPSED_REALTIME_WAKEUP和RTC_WAKEUP类型都会唤醒设备。同样,Alarm 的核心控制逻辑都在AlarmManagerService中,实现如下:
// 代理 AlarmManagerService
new ProxyHook().proxyHook(context.getSystemService
(Context.ALARM_SERVICE), "mService", this);public void beforeInvoke(Method method, Object[] args) {// 设置 Alarmif (method.getName().equals("set")) {// 不同版本参数类型的适配,获取应用堆栈等等// 清除 Alarm} else if (method.getName().equals("remove")) {// 清除的逻辑}
}
  • 其他。对于后台 CPU,我们可以使用卡顿监控相关的方法。对于后台网络,同样我们可以通过网络监控相关的方法。对于 GPS 监控,我们可以通过 Hook 代理LOCATION_SERVICE。对于 Sensor,我们通过 Hook SENSOR_SERVICE中的“mSensorListeners”,可以拿到部分信息。

通过 Hook,我们可以在申请资源的时候将堆栈信息保存起来。当我们触发某个规则上报问题的时候,可以将收集到的堆栈信息、电池是否充电、CPU 信息、应用前后台时间等辅助信息也一起带上。

插桩

虽然使用 Hook 非常简单,但是某些规则可能不太容易找到合适的 Hook 点。而且在 Android P 之后,很多的 Hook 点都不支持了。

出于兼容性考虑,我首先想到的是写一个基础类,然后在统一的调用接口中增加监控逻辑。以 WakeLock 为例:

public class WakelockMetrics {// Wakelock 申请public void acquire(PowerManager.WakeLock wakelock) {wakeLock.acquire();// 在这里增加 Wakelock 申请监控逻辑}// Wakelock 释放public void release(PowerManager.WakeLock wakelock, int flags) {wakelock.release();// 在这里增加 Wakelock 释放监控逻辑}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Facebook 也有一个耗电监控的开源库Battery-Metrics,它监控的数据非常全,包括 Alarm、WakeLock、Camera、CPU、Network 等,而且也有收集电量充电状态、电量水平等信息。

Battery-Metrics 只是提供了一系列的基础类,在实际使用中,接入者可能需要修改大量的源码。但对于一些第三方 SDK 或者后续增加的代码,我们可能就不太能保证可以监控到了。这些场景也就无法监控了,所以 Facebook 内部是使用插桩来动态替换。

遗憾的是,Facebook 并没有开源它们内部的插桩具体实现方案。不过这实现起来其实并不困难,事实上在我们前面的 Sample 中,已经使用过 ASM、Aspectj 这两种插桩方案了。后面我也安排单独一期内容来讲不同插桩方案的实现。

插桩方案使用起来兼容性非常好,并且使用者也没有太大的接入成本。但是它并不是完美无缺的,对于系统的代码插桩方案是无法替换的,例如 JobService 申请 PARTIAL_WAKE_LOCK 的场景。

总结

从 Android 系统计算耗电的方法,我们知道了需要关注哪些模块的耗电。从 Android 耗电优化的演进历程,我们知道了 Android 在耗电优化的一些方向以及在意的点。从 Android Vitals 的耗电监控,我们知道了耗电优化的监控方式。

但是系统的方法不一定可以完全适合我们的应用,还是需要通过进一步阅读源码、思考,沉淀出一套我们自己的优化实践方案。这也是我的性能优化方法论,在其他的领域也是如此。

Android耗电优化相关推荐

  1. 19 | 耗电优化(下):耗电的优化方法与线上监控

    相比启动.卡顿.内存和网络的优化来说,可能大多数应用对耗电优化的关注不是太多.当然并不是我们不想做耗电优化,更多时候是感觉有些无从下手. 不同于启动时间.卡顿率,耗电在线上一直缺乏一个可以量化的指标. ...

  2. 18 | 耗电优化(上):从电量优化的演进看耗电分析

    曾经有一句笑话说的是"用 Android 手机的男人一定是个好男人,因为他每天必须回家充电,有时候还得 1 天 2 次". 我们现在工作和生活都离不开手机,但是却很难找到一款可以完 ...

  3. Android 系统(102)---Android APP耗电优化

    Android APP耗电优化 可能造成耗电的一些原因 网络请求耗电,而且手机数据网络进行http请求比无线网进行http请求更加耗电,因为数据网络调用到一些底层的硬件模块,就如GPS一样,当手机打开 ...

  4. 耗电优化(上):Android App 耗电分析

    这里写目录标题 1. 电量和硬件 1.1 App 通过使用硬件模块消耗相应的电能 1.2 资源调度机制是厂商功耗优化最重要的手段 2. 电量和应用程序 2.1 评估不同应用程序的耗电情况 结论:把电量 ...

  5. 你是否了解APP耗电问题?深入探索 Android 电量优化,flutter插件推荐

    3).最后,把电量输送给电池,而整个降压的过程中会产生热能. 分类 1).高压低电流快充方案:在充电过程中提升充电电压(7-20V)来提升充电功率. 2).低压大电流快充方案:在电压一定情况下,增加电 ...

  6. Android 性能优化(62)---存检测、卡顿优化、耗电优化、APK瘦身——详解篇

    Android 性能优化,内存检测.卡顿优化.耗电优化.APK瘦身--详解篇 自2008年智能时代开始,Android操作系统一路高歌,10年智能机发展之路,如今 Android 9.0 代号P  都 ...

  7. Android高手笔记 - 耗电优化

    耗电的背景知识 电池技术:电池容量,充电时间,寿命,安全性: 电量和硬件:应用程序不会直接去消耗电池,而是通过使用硬件模块消耗相应的电能:CPU.屏幕.WiFi 和数据网络.GPS 以及音视频通话都是 ...

  8. Android性能优化(一)闪退治理、卡顿优化、耗电优化、APK瘦身

    系列推荐: Android 性能优化(二)Handler运行机制原理,源码分析 Android 性能优化(三)认识错误Error和异常Exception及栈轨迹StackTrace Android 性 ...

  9. 你是否了解APP耗电问题?深入探索 Android 电量优化,醍醐灌顶

    batterystats 所记录的电量统计数据源自于 BatteryStatsService-电量统计服务,其实现类为 BatteryStatsImpl,内部正是使用的 PowerProfile . ...

最新文章

  1. python3 ThreadPoolExecutor 线程池大小设置
  2. hbase java api 两种方式
  3. python爬虫反爬 对方是如何丧心病狂的通过css_如何应对网站反爬虫策略?如何高效地爬大量数据?...
  4. 第5章 初识JQuery
  5. html试题及答案,HTML试题及答案
  6. [Leedcode][JAVA][第445题][链表][栈]
  7. 天池 在线编程 两句话中的不常见单词(哈希计数)
  8. html 经常会用到的英语名词
  9. 关于进程资源限制的getrlimit和setrlimit函数(epoll、服务器经常用)
  10. 深度学习的实用层面 —— 1.14 关于梯度检验实现的标记
  11. STM8S——8位基本定时器(TIM4)
  12. 杭电OJ分类题目(1)
  13. bootstrap拖动div_BootStrap modal实现拖拽功能
  14. 微信OpenIdUnionID
  15. 再忆年少,再见年少——青春路上的我们
  16. 电脑 桌面图标上多了一个白色的文档图标 怎么去掉?
  17. AVG神作是如何炼成的? 《逆转裁判》成步堂三部曲解析
  18. 解决微信浏览器缓存问题
  19. 弘辽科技:数字化衍生菜篮子工程,电商巨头纷纷布局
  20. CSS小技巧之替换图片(content)

热门文章

  1. 18.QThread线程创建
  2. [读书笔记] - 《深度探索C++对象模型》第5章 构造、解构、拷贝语意学
  3. 源码分析Dubbo前置篇-寻找注册中心、服务提供者、服务消费者功能入口
  4. DP(三)——简单的完全背包
  5. .net backend return json string , used by frontend
  6. 最简单OGG配置方式
  7. 锅巴文件共享软件地址和说明
  8. [ActiveRecord] 之ActiveRecordMediator
  9. ASCII码对照表(参考用)
  10. 怎样快速提高新站权重收录