Android M中引入的两个重要的功能是Doze和Appstandby,目的是延长设备的电池寿命。
根据文档,实现前台服务的应用程序可以被App Standby豁免,但是没有关于Doze的类似说法。
M发布几个月后,很快就推出了大量设备,我们开始通过我们的客户支持获得一些“怪异”的抱怨:
我有三星Galaxy s6,刚刚更新到android 6.0.1。
我几乎每天都使用Spreaker收听我最喜欢的播客,直到现在还没有问题。
自从三天前Android更新后,app随机停止播放。
而且根据一些用户的说法,这也发生在他们口袋里的手机上(不是静止的)这就非常奇怪了。
所以我再次开始使用Doze和App Standby进行实验,多次阅读文档,使用我们拥有的可以运行M的所有设备进行手动测试,我没有发现任何意外情况。显然强制设备进入Doze导致了他们报告的问题,同样适用于App Standby但是:
- 由于有前台服务,我们的应用程序应该被App Standby豁免
- 这些手机不是静止的,所以Doze不应该启动
仍然很奇怪。
这持续了几个月,直到几个星期前,当我决定对这些东西进行另一轮测试时,看看我是否能够找到新的东西。直到我偶然发现了这个Google+帖子,我开始阅读评论,直到我发现这个评论:
Apps that have been running foreground services (with the associated notification) are not restricted by doze. This covers a large number of these kinds of use cases.
WTF?我不知道这一点,它不在文档中,而且我们所做的所有手动测试都证明了完全相反!当我们的应用播放音频时,我关闭了屏幕,运行命令强制Doze:
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
并且应用程序立即开始报告网络问题,这意味着Doze起作用了,让我们继续阅读那篇文章的评论:
- 该应用程序是从网络流式传输音频,您关闭屏幕并强制Doze =网络访问中断,应用程序停止流式传输
- 该应用程序是从网络流式传输音频,您通过按HOME按钮把活动送入后台,然后关闭屏幕并强制Doze =网络访问仍然有效,应用程序继续流式传输
幸运的是,dumpsys工具可以提供一些额外的信息。让我们看看它的行为。
手机处于活动状态时:
$ adb shell dumpsys power | grep spreaker_player
PARTIAL_WAKE_LOCK 'spreaker_player' (uid=10309, pid=31020, ws=null) (elapsedTime=4524)
当关闭屏幕进入Doze之前,我们的Activity处于前台:
$ adb shell dumpsys power | grep spreaker_player
PARTIAL_WAKE_LOCK'spreaker_player'DISABLED(uid = 10309,pid = 31020,ws = null)(elapsedTime = 20218)
当关闭屏幕进入Doze之前,我们的Activity处于后台:
$ adb shell dumpsys power | grep spreaker_player
PARTIAL_WAKE_LOCK'spreaker_player'(uid = 10309,pid = 31020,ws = null)(elapsedTime = 64626)
通过最后一个实验我们得出的结论:
- 如果应用程序实现前台服务,则App Standby和Doze都可以豁免
- 由于6.x版本中存在BUG,如果您的应用活动在手机屏幕关闭时位于前台,则会使上述豁免条件无效
- 此错误已在Nougat中修复。目前尚不清楚该修复程序是否会被移植到6.x分支,但此时Nougat已经放出,我认为不会。