battery-research
耗电提醒

耗电问题难点
缺乏现场,无法复现。
用户上传某个截图,你的应用耗电占比 30%。通过电量的详细使用情况,我们可能会有一些猜测。但是用户也无法给出更丰富的信息,以及具体是在什么场景发生的,可以说是毫无头绪。
信息不全,难以定位。
如果是开发人员或者厂商可以提供 bug report,利用 Battery Historian 可以得到非常全的耗电统计信息。但是 Battery Historian 缺失了最重要的堆栈信息,代码调用那么复杂,可能还有很多的第三方 SDK,我们根本不知道是哪一行代码申请了 WakeLock、使用了 Sensor、调用了网络等。
无法评估结果。
通过猜测,我们可能会尝试一些解决方案。但是从 Android 4.4 开始,我们无法拿到应用的耗电信息。尽管我们解决了某个耗电问题,也很难去评估它是否已经生效,以及对用户产生的价值有多大。
信息不全,难以定位
如果是开发人员或者厂商可以提供 bug report,利用 Battery Historian 可以得到非常全的耗电统计信息。但是 Battery Historian 缺失了最重要的堆栈信息,代码调用那么复杂,可能还有很多的第三方 SDK,我们根本不知道是哪一行代码申请了 WakeLock、使用了 Sensor、调用了网络等。
系统如何计算 App 电量
电量 = 功率 * 时间 = 电压 * 电流 * 时间
模块电量(mAh) = 模块电流(mA)* 模块耗时(h)
App电量 = SUM(模块功率 * 模块时间)
各模块的功率
BatteryStatusService:用来统计电量工作的,各模块的功率在 power_profile.xml 中,再加上各模块的使用耗时就能统计出电量了
功率:功率在 power_profile.xml 中
时长:StopWatch 用来计算 App 各硬件模块的使用时长,怎么计算 Wifi 使用了多久?
WifiManager.startScan() –> WifiscanningServiceImp –> BatteryStatsImpl.noteWifiScanStartedFromSource(mScanWorkSource);
埋点
- 计算:PowerCalculators ,每个硬件都有相应的命名对象, 主要用来计算电量
WifiPowerCalculator -> calculateApp
https://www.jianshu.com/p/672d008c4ad3
https://juejin.cn/post/6844904195523346439
系统限制
提醒情况
从 Android 9.0 开始,,Google 对电源管理引入了几个更加严格的限制。

应用分组
根据DeepMind调整应用待机分组,各个厂商可选择使用DeepMind的提供的模型.
Active : App基本不会受到后台限制。
Rare : Jobs和Alarms都会受到延迟,访问网络的频率也会受到限制。
Frequent rare : 发送过量的高优先级FCM message, 系统会把这些信息降级为 普通优先级.

后台限制

Android Vitals 的规则 : Android P 是通过 Android Vitals 监控后台耗电
https://developer.android.google.cn/topic/performance/vitals
Android Vitals 核心指标:
其他指标:
后台 Wi-Fi 扫描次数过多
后台网络使用量过高
应用启动时间
呈现速度缓慢
冻结的帧
权限遭拒
可参考规则
华为公开过他们后台资源使用的“红线”
例如长时间获取 WakeLock、WiFi 和蓝牙的扫描等。为什么说耗电优化第一个方向就是优化应用后台耗电,因为大部分厂商预装项目要求最严格的正是应用后台待机耗电。
虽然上面的标准可能随时会改变,但是可以看到,Android 系统目前比较关心后台 Alarm 唤醒、后台网络、后台 WiFi 扫描以及部分长时间 WakeLock 阻止系统后台休眠。
https://blog.dreamtobe.cn/2016/08/15/android_scheduler_and_battery/

后台操作原则
减少 : 减少后台运行
延迟 : 延迟到合适的时间,例如设备充上电
合并: 合并后台操作
WorkManager : 后台操作的首选
耗电优化方式
灭屏时停止动画
我们可以监听灭屏以及亮屏的广播,在灭屏的时候停止 surfaceView 的动画绘制。在亮屏的时候,恢复动画的绘制。
监听手机充电状态
这里我们就需要思考,根据具体的业务,考虑将一些不需要及时地和用户交互的操作放到充电 的时候去做。比如:360 手机助手,当充上电的时候,才会自动清理手机垃圾,自动备份上传图片、联系人 等到云端,从而避免当用户手机低电量时,任然继续进行耗电操作。
1
2
3
4
5
6IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);
//获取用户是否在充电的状态或者已经充满电了
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;Sync Adapter
用于同步服务端与本地设备中的数据。通常是用于同步较多的数据,如系统联系人信息、Dropbox等。
找到需求场景的替代方案
以推送为例,我们是否可以更多地利用厂商通道,或者定时的拉取最新消息这种模式。如果真是迫不得已,是不是可以使用 foreground service 或者引导用户加入白名单。后台任务的总体指导思想是减少、延迟和合并,可以参考微信一个小伙写的《Android 后台调度任务与省电》。在后台运行某个任务之前,我们都需要经过下面的思考:
插桩
写一个基础类,然后在统一的调用接口中增加监控逻辑。
以 WakeLock 为例:
1 |
|
电量监控工具
- Battery Historian
无法评估结果
Energy Profiler
XHook(爱奇艺), 拿到所有线程的 cpu 耗时时间 。
facebook Battery-Metrics
它监控的数据非常全,包括 Alarm、WakeLock、Camera、CPU、Network 等,而且也有收集电量充电状态、电量水平等信息。Battery-Metrics 只是提供了一系列的基础类,在实际使用中,接入者可能需要修改大量的源码。但对于一些第三方 SDK 或者后续增加的代码,我们可能就不太能保证可以监控到了。这些场景也就无法监控了,所以 Facebook 内部是使用插桩来动态替换。
Facebook 并没有开源它们内部的插桩具体实现方案,可以使用 ASM、Aspectj 这两种插桩方案了。
matrix BatteryCanary
ANR 内存使用 优化好了, 电量肯定没问题,
如果电量不行,程序有问题