4. Doze 模式深度阶段:静止进入深休眠、维护窗口、定期退出

核心概念

当设备进入轻度 Doze 后,如果继续保持屏幕关闭且完全静止状态超过一定时间(通常为 30 分钟至 1 小时不等,取决于设备策略与电量水平),系统会进一步收紧限制,进入深度 Doze(Deep Doze / IDLE)阶段。此阶段被视为 Android 节电策略的最终防线,意在最大化延长待机时间。

  • 网络彻底切断: 所有应用的网络访问权限被冻结,包括前台通知推送和后台数据同步。
  • Wakelock 失效: 应用持有的部分 Wakelock 将被系统忽略,强制 CPU 进入深度睡眠。
  • Alarm 延迟: 应用设置的普通闹钟被统一延迟,直到下一个维护窗口到达。
  • Job/同步挂起: JobScheduler 和 SyncAdapter 任务完全暂停。
⚠️ 重点提示: 深度 Doze 不会杀死应用进程或强制回收内存。它只是冻结应用获取资源的能力(网络、CPU锁、高精度定时器)。应用进程本身仍然驻留在内存中,一旦退出 Doze 即可恢复运行。

类比说明:冬眠的棕熊

想象一头棕熊在冬季进入树洞深眠(深度 Doze)。它几乎不消耗能量,不外出觅食,对外界刺激反应极低。但为了维持基本生命体征,它每隔一段时间会短暂苏醒(维护窗口),调整姿势、检查环境,然后继续沉睡。如果有人用力敲打树洞(高优先级推送 / 闹钟),它也可能被迫提前退出休眠。

  • 轻度 Doze 相当于打盹: 耳朵还在动,稍有动静就能醒来。
  • 深度 Doze 相当于深睡: 呼吸和心跳极慢,不到万不得已不会醒来。
  • 维护窗口相当于伸懒腰: 短暂恢复机能,处理积压任务,然后继续睡。

原理图解:深度 Doze 状态机

下图呈现了从轻度 Doze 转入深度 Doze,以及维护窗口与退出的完整闭环流程。

深度 Doze 状态转换图 轻度 Doze 有限制但可唤醒 深度 Doze(休眠) 无网络 / 无 WakeLock 维护窗口 执行积压任务(约 1%) 触发退出 移动检测 setAlarmClock 闹钟 静止超时 维护窗口到期 维护结束 / 继续休眠 突发退出条件 退出后重新评估 📌 关键指标 深度 Doze 下,Google Play 服务仍可通过高优先级 FCM 触发退出;非白名单应用的精准闹钟(setExact)会被蜕变为近似闹钟。

常见误区辨析

误区 真相
深度 Doze 会杀死后台应用 不会。深度 Doze 只冻结资源(网络、定时器),应用进程仍在后台运行,只是无法执行实际操作。
所有闹钟在深度 Doze 下都被延迟 部分闹钟可绕过:setAlarmClock() 触发的闹钟会强制退出 Doze;高优先级 FCM 推送也可以唤醒设备。
只要连接 Wi-Fi 就不会进入深度 Doze Wi-Fi 连接本身不会阻止进入深度 Doze。保持屏幕关闭且静止才是关键条件。Wi-Fi 在深度 Doze 下也会被限制扫描。

练习题

  1. (选择题) 以下哪种场景会强制设备退出深度 Doze?
    A. 应用发起普通 HTTP 请求
    B. 应用通过 AlarmManager.setExact() 设置闹钟
    C. 系统检测到用户拿起手机(显著移动)
    D. 蓝牙一直连接中
  2. (简答题) 为什么维护窗口的时间窗口仅有 1% 左右?这样设计的目的是什么?
  3. (Bug 修复) 用户反馈步数记录 App 在夜间深度 Doze 期间完全不记步,即使申请了 PARTIAL_WAKE_LOCK 也无用。请从深度 Doze 的原理角度分析原因。
  4. (代码分析) 以下代码在深度 Doze 期间执行会返回什么?
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    boolean isIdle = pm.isDeviceIdleMode();
    // 此时 isIdle 的值是?
    Log.d("PowerTest", "Device is idle: " + isIdle);

应用边界

  • 白名单机制: 系统内置 config_ignoreBatteryOptimizationWhitelist 名单(如 GMS、Launcher、输入法),这些应用在深度 Doze 下保留受限的网络访问能力。
  • FCM 高优先级: 服务器推送时需要设置 "priority": "high",客户端才能在深度 Doze 下收到唤醒广播(仍存在一定延迟,受 sync_delay 影响)。
  • JobScheduler 约束: 即使应用被白名单,JobScheduler 在深度 Doze 期间也不会严格按照 deadline 执行,必须等待维护窗口或退出 Doze。
  • Debug 命令(仅供开发测试):
# 强制进入深度 Doze(需要 root 或调试权限)
adb shell dumpsys deviceidle force-idle

# 设置空闲超时时间(单位毫秒)
adb shell dumpsys deviceidle step

# 查看当前 Doze 状态
adb shell dumpsys deviceidle enabled