〇. 序
当我们手机屏幕电量的时候,我们或在游戏,或在看视频,或在上网,屏幕是一个很耗电的组件,在电量消耗方面,他跟设备上的大多数硬件都不是一个数量级的。
当手机在口袋里的时候。因为屏幕关闭,用户并没有真正的在使用手机。此时的功耗会被CPU ,Network,后台作业等占用。
通常我们在写代码的时候。会注册很多隐式广播来监听一些手机中状态变化,然后在后台开启一个任务。这看起来不经意的行为,其实是对电池电量和用户体验都产生了实质的影响。所以Google在Android的一些新版本中逐步增加了对于后台的优化和限制。就是为了提升电量的续航能力。
后台优化的核心宗旨就是:Reduce(减少), Defer(延迟), Coalesce(合并)
这个结果应该没有让大家失望吧。
一. 了解低电耗模式
1.1 低耗电模式:
如果用户设备未插接电源、处于静止状态一段时间且屏幕关闭,设备会进入低电耗模式。 在低电耗模式下,系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电量。 这还可以阻止应用访问网络并推迟其作业、同步和标准闹铃。
系统会定期退出低电耗模式一会儿,好让应用完成其已推迟的任务。在此维护时段内,系统会运行所有待定同步、作业和闹铃并允许应用访问网络。
在每个维护时段结束后,系统会再次进入低电耗模式,暂停网络访问并推迟作业、同步和闹铃。 随着时间的推移,系统安排维护时段的次数越来越少,这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低电池消耗。
一旦用户通过移动设备、打开屏幕或连接到充电器唤醒设备,系统就会立即退出低电耗模式,并且所有应用都将返回到正常 Activity。
总结一下:
- 原来的问题:每个App会通过监听不同广播和安排时钟会在后台做一些周期性的同步,以及网络请求。因为每个app的周期各不相同,唤醒周期和频率很多,当然,如我们所知,不同的后台任务会唤醒不同的硬件,所以会有耗电问题。
- 瞌睡(doze)模式:会有一定的doze周期,在这个瞌睡周期过后,提供一个”维护窗口”,通知所有任务,这是一个执行后台任务的时机。那么各家APP各显神通,做网络请求,同步数据等等。当然这周维护窗口的周期不是固定的。会估计系统休眠状态的切换。逐步扩大,这个后面会有介绍(简单的说就是系统任务设备不活跃的时候,比如晚上睡觉了,这个维护窗口可能周期会从1min->5min->1h->2h,这个时间只是个象征,不代表实际的系统原理,后面会扩展说。)
1.2 低耗电模式下的一些限制
- 暂停访问网络。
- 系统将忽略 wake locks。
- 标准 AlarmManager 闹铃(包括 setExact() 和 setWindow())推迟到下一维护时段。
- 如果您需要设置在低电耗模式下触发的闹铃,请使用 setAndAllowWhileIdle() 或 - setExactAndAllowWhileIdle()。
- 一般情况下,使用 setAlarmClock() 设置的闹铃将继续触发 — 但系统会在这些闹铃触发之前不久退出低电耗模式。
- 系统不执行 Wi-Fi 扫描。
- 系统不允许运行同步适配器。
- 系统不允许运行 JobScheduler。
二. 在设备空闲时使用 GCM 与您的应用交互
Google Cloud Messaging (GCM) 是一项云端至设备的服务,允许您支持在后端服务与 Android 设备上的应用之间实时进行下游消息传递。GCM 提供了单一持久的云连接;所有需要实时传递消息的应用均可共享此连接。此共享连接使多个应用无需消耗电池即可维持自身单独的持久连接,避免快速耗尽电池,从而显著优化电池消耗。 因此,如果应用需要与后端服务进行消息传递集成,我们强烈建议您尽量使用 GCM,而非维持自身持久的网络连接。
GCM 经过优化,可通过高优先级 GCM 消息用于低电耗模式和应用待机模式。GCM 高优先级消息允许您可靠地唤醒应用访问网络,即使用户设备处于低电耗模式或应用处于应用待机模式也不例外。 在低电耗模式或应用待机模式下,系统将传递消息并允许应用临时访问网络服务和部分唤醒锁,然后将设备或应用恢复到空闲状态。
高优先级 GCM 消息不会影响低电耗模式,也不会影响任何其他应用的状态。这意味着您的应用可以使用这些消息进行有效的通信,同时尽可能减少对整个系统和设备的电池影响。
作为一项常规最佳做法,如果您的应用需要下游消息传递,则应使用 GCM。如果您的服务器和客户端已经使用 GCM,请确保服务对关键消息使用高优先级消息,因为即使设备处于低电耗模式,这也会可靠地唤醒应用。
三.Dozen模式下的状态变化
当screenoff 且non-charging时,进入
STATE_INACTIVE
。此时会设置INACTIVE_TIMEOUT,默认为30min当INACTIVE_TIMEOUT时,进入
STATE_IDLE_PENDING
,此时会开启SignificantMotion,并设置IDLE_AFTER_INACTIVE_TIMEOUT,默认为30min.当IDLE_AFTER_INACTIVE_TIMEOUT时,进入
STATE_SENSING
,此时启动AnyMotionDetetor当AnyMoTionDetetor检测为静止时,进入
STATE_LOCATING
,并设置LOCATING_TIMEOUT,默认为30s,并请求当前的Location状态。当Location状态显示当前位置达到设定的精确标准时,直接进入
STATE_IDLE
,否则等到LOCATING_TIMEOUT,进入STATE_IDLE.此时停止AnyMotionDetetor,通过AlarmManager.setIdleUntil 通知AlarmManager进入IDLE,直到指定的alarm到来(这里设置的alarm默认为60min);通知PowerManager/NetworkPolicy/BatteryStas 进入IDLE状态。并发送broadcast: ACTION_DEVICE_IDLE_MODE_CHANGED.当(5)中设置的alarm唤醒时,进入
STATE_IDLE_MAINTAINTENCE
,此时设置一个默认为5min的timeout,同时通知PowerManager/NetworkPolicy/BatteryStas退出IDLE状态当(6)设置的timeout 到时,再次进入
STATE_IDLE
在状态
STATE_SENSING
和STATE_LOCATING
,可能会因为AnyMotionDetetor监测到移动或者SignificantMotion检测到有动作而重新进入STATE_INACTIVE
在状态
STATE_IDLE_PENDING
,可能会因为SignificantMotion检测到有动作而重新进入STATE_INACTIVE
当screenon 或者 charging 都会重新进入
STATE_ACTIVE
四. 在低电耗模式和应用待机模式下进行测试
为了确保用户获得极佳体验,您应在低电耗模式和应用待机模式下全面测试您的应用。
在低电耗模式下测试您的应用,您可按以下步骤测试低电耗模式:
- 使用 Android 6.0(API 级别 23)或更高版本的系统映像配置硬件设备或虚拟设备。
- 将设备连接到开发计算机并安装应用
- 运行应用并使其保持活动状态
- 关闭设备屏幕。(应用保持活动状态。)
- 通过运行以下命令强制系统在低电耗模式之间循环切换:
- $ adb shell dumpsys battery unplug
- $ adb shell dumpsys deviceidle step
您可能需要多次运行第二个命令。不断地重复,直到设备变为空闲状态。
前几次调用都是ACTIVE
,为什么呢?因为没有息屏。>.<
后面可以看到就是系统从活跃到低功耗模式的逐步切换。
最后也可以在彻底进入IDLE模式
之后。不停地切换到维修窗口
,来看看我们安排的JOB能否正常工作。
五. 为了减轻这个问题,Android 7(API级别24)进一步增加了限制:
- App Target API升级到24之后,将不在接受静态注册(声明在Manifest文件中)的
CONNECTIVITY_ACTION
广播(网络状态切换),当然如果是在运行时用context注册的动态广播,仍然生效。 - App 不能发送或者接收
ACTION_NEW_PICTURE
,ACTION_NEW_VIDEO
两个事件的广播。这个优化将影响所有应用。而不仅仅是针对Target 24以上的用户了。
如果我们的app仍然在使用这些intent,我们应该尽快移除这些,以便可以支持target 24以上的版本,Android Framework提供了多种方式来替换这些隐式广播。例如JobScheduler
和WorkManager
。
六. 替代方案
当然Google不是那么绝情的,还提供了几种替代方案。
- 前台服务:这个是在瞌睡模式的豁免名单中的,比如用户在听音乐的时候,即使app进入了瞌睡模式,前台服务依然可以获取wakelock和network.
- 闹钟:闹钟可以设置(RTC,RTC_WAKE_UP)当设置成RTC_WAKE_UP时,将无视休眠模式,随时唤醒。当然Google也希望你的“闹钟”能够准时叫醒你。
- 白名单,这只是针对非常具体的、有限的、可接受的情况。用户可以手动在设置中添加app到白名单,也可以在运行时同意这样的行为,并且经过GP review,是可以加入豁免白名单的。
结束
当然Google也为我们提供了电池分析的工具 Battery Historian 有兴趣的同学可以了解一下,后续有空,我也会体验一番,再来分享。先附上Google传送门,请大家科学上网。Analyze power use with Battery Historian
附赠一枚截图: