Wakelock 和 doze 模式

18
根据Android Marshmallow文档,在系统进入沉睡模式时,任何唤醒锁都会被忽略。然而,我不确定唤醒锁是否可以防止沉睡模式。

请查看这个答案 - Amit Vaghela
5个回答

18

基于某些测试,使用已安装最终版(?)的Android 6.0的Nexus 5:

  • 持有PARTIAL_WAKE_LOCK无法阻止Doze模式,即使您持有WakeLock正在进行常规工作(例如使用setExactAndAllowWhileIdle()每分钟获取控制权)。

  • 使用android:keepScreenOn(或Java等效代码)让屏幕保持亮屏状态足以阻止Doze模式。

  • 使用android:keepScreenOn(或Java等效代码)让屏幕保持黑屏状态(用户按下电源按钮)无法阻止Doze模式。

换句话说,在用户观看视频时不应影响视频播放器等,尽管播放器可能未移动或充电。但是,如果用户按下电源按钮,则会重新出现Doze风险。

我还没有尝试使用FULL_WAKE_LOCK(我预计其行为与android:keepScreenOn相同,但我远非确定)。


3
哇,那么一个在屏幕关闭时运行的应用程序不再可用了 :( 感谢您的回复。 - greywolf82
16
欢迎加入“后台处理战争”。 - CommonsWare
1
@CommonsWare:实际上我刚刚发现...AndAllowWhileIdle()确实会影响Doze模式。它在空闲时大约每15分钟触发一次。我通过这个发现,在Doze模式下许多功能似乎被阻塞了,包括GPS(我的测试)和显然是存储访问。您的日志没有显示...AndAllowWhileIdle()的触发,因为您写入了文件-我的测试使用了数据库并显示了它。就像GPS一样,当空闲时它就无法工作,尽管周围的唤醒锁可以-它以某种方式被阻止,就像您的存储访问一样。这是我的猜测。 - sec_aw
@sec_aw:“你的日志没有显示...AndAllowWhileIdle()的触发,因为你写入了文件——我的测试使用数据库工作,并且那个显示了它。”——数据库就是一个文件。话虽如此,我会尝试一些其他的测试。 - CommonsWare
@CommonsWare:很遗憾,我无法提供测试应用程序的源代码,因为它是我目前正在开发的应用程序,我暂时修改了它以测试Doze模式的行为。请查看我的答案中的实际日志和测试细节。 - sec_aw
显示剩余6条评论

10

有趣

Android 6.0中的Google自带闹钟应用程序能够完全阻止Doze模式:

  1. 在闹钟应用程序中设置一个时间< 60分钟的闹钟
  2. 关闭设备
  3. 在控制台中输入$ adb shell dumpsys battery unplug
  4. 在控制台中输入$ adb shell dumpsys deviceidle step

状态保持为“Stepped to: ACTIVE”

如果您设置的闹钟时间> 60分钟,它会正常工作(设备可能进入空闲状态)。但是一旦闹钟还有不到60分钟的时间,设备似乎会静默地从Doze空闲状态中唤醒,因为状态再次返回为“ACTIVE”(而不是“IDLE_MAINTENANCE”)。

我真的想知道他们是如何做到这一点的!

-编辑 -

它似乎是默认情况下由setAlarmClock()产生这种行为。这对某些用例可能有所帮助。


请参阅文档 https://developer.android.com/training/monitoring-device-state/doze-standby.html#restrictions 了解 setAlarmClock() 和待机模式之间的区别,以及页面下方关于白名单应用如何仍然使用部分唤醒锁的部分。这一点在JavaDocs中没有提到。 - Jerry101
3
是的:"系统会在这些闹钟响起前不久退出Doze," 如果 不久 意味着60分钟:-)。Doze模式的文档非常糟糕,许多行为实际上根本没有记录,例如前台服务进入Doze( https://dev59.com/RVwY5IYBdhLWcg3wF0he#33077301 ),在Doze中GPS等硬件功能不可用 (https://dev59.com/n1wY5IYBdhLWcg3wuZym#32521940),谁知道还有什么其他影响很多用例的相当复杂的行为。 - sec_aw
@sec_aw,setAlarmClock()似乎是让我们的良好行为的闹钟管理器意识到应用程序的明确方法。但是当大多数包括不良行为的闹钟管理器应用程序开始使用setAlarmClock(),并将API升级到21级或更高级别时,那么Google在Android 6.0中做出的(疯狂的)尝试将完全无用。我真的欢迎setAlarmClock()是一个解决方法,但无法理解Google的意图。 - Tomcat
天啊,真的,我也不理解谷歌对这些变化的尝试。此外,网络连接也不再工作了,这对于聊天应用来说是一个非常糟糕的事情。如果只有使用GCM可以保证没有限制地工作,那么这就像苹果一样的行为。如果可以通过setExactAndAllowWhileIdle()打破Doze模式或应用程序待机状态...那么这一切都没有意义,对开发人员来说是一场不必要的斗争... - Opiatefuchs
1
.android包可以访问这种类型的唤醒锁static final int DOZE_WAKE_LOCK = 0x00000040;只有内部包才能使用此唤醒锁,它需要此权限 *需要{@link android.Manifest.permission#DEVICE_POWER}权限。.. 这就是闹钟应用程序的工作原理,以及为什么它可以像魅力一样唤醒设备....感到对Android API平台失望 - Arthur Melo

6
作为前面评论讨论的回应,这不是对问题的回答,而是旨在澄清Doze模式下应用程序的行为。 在我的测试应用程序中,我尝试每2分钟获取一次GPS位置,GPS信号强度始终足够。
测试条件: - Nexus 9,Android M预览版,Build MPA44I - “忽略优化”开启 - setExactAndAllowWhileIdle()设置为2分钟间隔 - 每个操作具有1分钟的超时时间来获得GPS信号强度,并被部分唤醒锁包围 - 日志记录在SQLiteOpenHelper.getWritableDatabase()中
Doze模式下GPS测试日志:
1   2015-09-04 - 12:14  GPS ok (device left stationary unplugged)
2   2015-09-04 - 12:16  GPS ok
3   2015-09-04 - 12:18  GPS ok
4   2015-09-04 - 12:20  GPS ok
5   2015-09-04 - 12:22  GPS ok
6   2015-09-04 - 12:24  GPS ok
7   2015-09-04 - 12:26  GPS ok
8   2015-09-04 - 12:28  GPS ok
9   2015-09-04 - 12:30  GPS ok
10  2015-09-04 - 12:32  GPS ok
11  2015-09-04 - 12:34  GPS ok
...
31  2015-09-04 - 13:14  GPS ok
32  2015-09-04 - 13:16  GPS ok
33  2015-09-04 - 13:18  GPS ok
34  2015-09-04 - 13:20  GPS ok
35  2015-09-04 - 13:22  GPS ok
36  2015-09-04 - 13:24  GPS ok
37  2015-09-04 - 13:26  GPS ok (entering Doze mode some time after)
38  2015-09-04 - 13:42  GPS failed, active millis: 60174 (idle)
39  2015-09-04 - 13:57  GPS failed, active millis: 60128 (idle)
40  2015-09-04 - 14:12  GPS failed, active millis: 60122 (idle)
41  2015-09-04 - 14:16  GPS ok (idle maintenance)
42  2015-09-04 - 14:18  GPS ok (idle maintenance)
43  2015-09-04 - 14:20  GPS ok (idle maintenance)
44  2015-09-04 - 14:22  GPS ok (idle maintenance)
45  2015-09-04 - 14:38  GPS failed, active millis: 60143 (idle)
46  2015-09-04 - 14:53  GPS failed, active millis: 60122 (idle)
47  2015-09-04 - 15:08  GPS failed, active millis: 60068 (idle)
48  2015-09-04 - 15:23  GPS failed, active millis: 60138 (idle)
49  2015-09-04 - 15:38  GPS failed, active millis: 60140 (idle)
50  2015-09-04 - 15:53  GPS failed, active millis: 60131 (idle)
51  2015-09-04 - 16:08  GPS failed, active millis: 60185 (idle)
52  2015-09-04 - 16:12  GPS ok (ending Doze mode - power button on)

我重新查看了日志,发现了一个非常奇怪的行为:关闭“忽略优化”后进行的相同测试显示基本相同的结果(正如应该的那样),但大多数时候超时未按预期工作,我得到了范围在约330000(超时时间的5倍)或甚至是约580000(超时时间的10倍)之间的“活动豪秒”(active millis),而此时设备是空闲状态。 我无法解释这种奇怪的行为,但它似乎表明在Doze模式下,“忽略优化”设置确实会产生某些效果。
编辑:如今,上述“奇怪”行为已经被记录:只有在“忽略优化”开启时,你才能在Doze空闲模式下保持部分唤醒锁。

1
据我所了解,所有的唤醒锁(除了由目前前台服务应用程序持有的锁)都会在更深层次的待机模式开始时被释放。待机的整个意义在于让系统在“相关条件”出现时进入睡眠状态。因此,我想他们可能不太关心锁定。
在我看来,JobScheduler是未来安排、后台任务等方面的最佳选择。虽然这会剥夺开发人员的一些控制权,但这是为了电池寿命而做出的决策。它更像是“触发并希望事情能够按时发生”。
对于您的使用情况,JobScheduler具有onStopJob回调函数,以知道您的作业何时停止执行[出于任何原因-比如wifi被切换],您需要采取适当的措施,例如为下一个维护窗口重新安排作业。从文档中可以看到:

其中一个直接的结果是,系统将停止为您保持唤醒锁。


0

我在使用Google Pixel 7 Pro上的Android 13中发现,只要用户手动禁用应用程序的电池优化,setExactAndAllowWhileIdle()实际上是有效的。这可以在应用程序的电池使用设置中完成,如此处所述。

我无法在Huawei P20 Pro上的Android 10中找到如何做到这一点,但我没有尝试太努力。

因此,我的建议是首先尝试使用多种手机进行实验,以更好地了解各种Android版本和手机网络的工作原理。

然后更改您的应用程序以检查设置,并告知用户是否需要更改,并提供打开应用程序设置的选项。(请记住,通常不知道手机制造商或网络如何自定义手机,因此如果说明过于详细,则可能与现实不符。)

此外,在您的应用程序中,检查您的功能是否被调用晚了,如果是,请告诉用户联系您以进行故障排除。

我认为电池使用设置无法通过编程进行更改。即使在添加了我认为必要的权限后,我甚至无法打开相应的设置界面,只能打开通用设置页面,用户可以从那里导航。所以:

// Check doze setting
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean ignoring = pm.isIgnoringBatteryOptimizations(getPackageName());

// Show the app's setting window
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接