Doze相关知识

一、Doze 模式的定义

Doze 模式(打盹模式) 是从 Android 6.0(Marshmallow, API 23) 开始引入的系统省电机制。 它的核心目标是:

当设备长时间处于“静止 + 熄屏 + 未充电”状态时,系统自动进入深度休眠状态,暂停或推迟大多数后台任务与网络访问,以延长电池续航。

简单说:

“锁屏 → 放着不用 → 不在充电” → 系统判断设备在闲置,就进入 Doze

二、Doze 与 锁屏 的关系

场景系统状态Doze 状态说明
用户按电源键锁屏屏幕关闭尚未进入 Doze(只是 screen-off 状态)
设备持续静止几分钟(通常 1 小时内)屏幕关闭、无充电、无显著运动系统逐渐进入 Doze 模式
设备移动 / 唤醒 / 充电活动状态退出 Doze 模式

🔹 锁屏 ≠ Doze:锁屏只是前提之一,真正进入 Doze 还需要「设备静止 + 不充电 + 屏幕熄灭」。

三、Doze 模式的行为特征(系统层面)

当设备处于 Doze 模式时,系统会:

  1. 冻结后台 CPU 唤醒(除非使用 setAndAllowWhileIdle()setExactAndAllowWhileIdle() 的 Alarm)
  2. 阻止网络访问(仅在 maintenance window 打开)
  3. 推迟 JobScheduler 与 SyncAdapter 任务
  4. 暂停标准 AlarmManager 定时任务
  5. 禁止 WakeLock 长时间持有
  6. 延迟 Firebase Cloud Messaging 普通消息传递

系统会周期性短暂“唤醒”设备执行积压任务,称为 maintenance window(维护窗口)。 每次维护窗口时间会随着静止时间逐步拉长。


🧠 四、锁屏相关的具体含义

在「锁屏场景」中提到的 Doze,其实指的是:

系统在设备锁屏后经过一段时间,自动进入的“深度休眠省电模式”,会限制应用在后台的行为。

也就是说:

  • 刚锁屏:应用依然能执行后台任务(只是 screen-off 模式)
  • 锁屏 + 静止 + 不充电:系统逐渐进入 Doze 模式,后台活动被大幅限制

💻 五、开发者层面的影响与应对

  1. AlarmManager 限制

    • 常规 setExact()set() 的闹钟在 Doze 下会被延迟。

    • 若必须执行,可用:

      alarmManager.setAndAllowWhileIdle()
      alarmManager.setExactAndAllowWhileIdle()
  2. JobScheduler 延迟

    • 任务会被系统推迟到 maintenance window。
  3. 网络请求被暂停

    • 建议使用 Firebase Cloud Messaging(FCM 高优先级) 唤醒设备。
  4. 后台同步延迟

    • 依赖 SyncAdapter 的同步会被推迟。
  5. 后台服务被系统暂停

    • 若需要长期运行,请使用 Foreground Service(带通知栏常驻)。

🧭 六、与 App Standby / Battery Saver 区别

模式触发条件限制点主要影响
Doze设备长时间静止且未充电所有应用全局后台任务、网络被推迟
App Standby用户长时间未使用某个 App单个应用限制后台同步、Job 执行
Battery Saver用户主动开启省电模式全局CPU 降频、网络/动画受限

🧰 七、验证和调试 Doze

开发者可以通过 adb 手动模拟 Doze:

bash复制编辑adb shell dumpsys deviceidle force-idle    # 强制进入 Doze
adb shell dumpsys deviceidle step          # 模拟进入下一个阶段
adb shell dumpsys deviceidle unforce       # 退出 Doze
adb shell dumpsys deviceidle disable       # 关闭 Doze 模式

查看状态:

adb shell dumpsys deviceidle

八、各种模式演示

一台息屏的手机,直接执行 adb shell dumpsys deviceidle 获取运行状态

adb shell dumpsys deviceidle
  Flags:
    com.android.server.deviceidle.use_cpu_time_for_temp_allowlist=true
    com.android.server.deviceidle.remove_idle_location=true
 
  Settings:
    flex_time_short=+1m0s0ms
    light_after_inactive_to=+4m0s0ms
    light_idle_to=+5m0s0ms
    light_idle_to_initial_flex=+1m0s0ms
    light_max_idle_to_flex=+15m0s0ms
    light_idle_factor=2.0
    light_idle_increase_linearly=true
    light_idle_linear_increase_factor_ms=300000
    light_idle_flex_linear_increase_factor_ms=60000
    light_max_idle_to=+30m0s0ms
    light_idle_maintenance_min_budget=+1m0s0ms
    light_idle_maintenance_max_budget=+5m0s0ms
    min_light_maintenance_time=+5s0ms
    min_deep_maintenance_time=+30s0ms
    inactive_to=+15s0ms
    sensing_to=+15s0ms
    locating_to=+5s0ms
    location_accuracy=20.0m
    motion_inactive_to=+30s0ms
    motion_inactive_to_flex=+1m0s0ms
    idle_after_inactive_to=+15s0ms
    idle_pending_to=+5m0s0ms
    max_idle_pending_to=+10m0s0ms
    idle_pending_factor=2.0
    quick_doze_delay_to=+1m0s0ms
    idle_to=+1h0m0s0ms
    max_idle_to=+6h0m0s0ms
    idle_factor=2.0
    min_time_to_alarm=+10m0s0ms
    max_temp_app_allowlist_duration_ms=+3m0s0ms
    mms_temp_app_allowlist_duration_ms=+1m0s0ms
    sms_temp_app_allowlist_duration_ms=+20s0ms
    notification_allowlist_duration_ms=+30s0ms
    wait_for_unlock=true
    use_window_alarms=true
    use_mode_manager=false
  Idling history: # 这里会打印系统Doze历史状态,相关解释在下面
      deep-idle: -1d18h31m5s448ms
     deep-maint: -1d17h31m4s136ms
      deep-idle: -1d17h30m34s91ms
     deep-maint: -1d15h30m33s23ms
      deep-idle: -1d15h30m2s997ms
         
         normal: -1d14h18m21s312ms (alarm)# 进入normal状态,因为alarm充电
     light-idle: -1d14h13m20s314ms
      deep-idle: -1d14h6m1s871ms
     deep-maint: -1d13h6m0s370ms
      deep-idle: -1d13h5m30s341ms
     deep-maint: -1d11h5m28s408ms
      deep-idle: -1d11h4m58s368ms
     deep-maint: -1d7h4m57s553ms
      deep-idle: -1d7h4m27s522ms
         normal: -1d5h13m47s208ms (motion)# 进入motion状态,因为charging充电
     light-idle: -1d5h8m46s619ms
    light-maint: -1d4h52m12s639ms
     light-idle: -1d4h50m21s618ms
    light-maint: -1d4h32m7s168ms
     light-idle: -1d4h32m2s118ms
      deep-idle: -1d4h17m36s286ms
         normal: -1d3h39m44s649ms (charging) # 进入normal状态,因为charging充电
  Whitelist (except idle) system apps:  # 可以对应用进行加白
    com.android.providers.calendar
    com.android.updater
    com.qualcomm.qti.uceShimService
    com.android.providers.downloads
    com.qualcomm.qti.telephonyservice
    com.android.vending
    com.android.mms
    com.qualcomm.qcrilmsgtunnel
    com.android.rkpdapp
    com.android.cellbroadcastreceiver
    com.google.android.gms
    com.android.proxyhandler
    com.qualcomm.qti.workloadclassifier
    com.android.imsserviceentitlement
    com.qualcomm.qti.ims
    com.qualcomm.location
    com.miui.powerinsight
    com.android.shell
    com.android.emergency
    com.qualcomm.atfwd
    com.android.providers.contacts
    com.android.devicelockcontroller
    com.miui.core
  Whitelist system apps:
    com.android.providers.calendar
    com.android.updater
    com.qualcomm.qti.uceShimService
    com.android.providers.downloads
    com.qualcomm.qti.telephonyservice
    com.android.mms
    com.qualcomm.qcrilmsgtunnel
    com.android.rkpdapp
    com.android.cellbroadcastreceiver
    com.google.android.gms
    com.qualcomm.qti.workloadclassifier
    com.qualcomm.qti.ims
    com.qualcomm.location
    com.miui.powerinsight
    com.android.shell
    com.android.emergency
    com.qualcomm.atfwd
    com.android.devicelockcontroller
    com.miui.core
  Whitelist user apps:
    com.unionpay.tsmservice.mi
    com.milink.service
    com.xiaomi.account
    com.xiaomi.gamecenter.sdk.service
    com.miui.gallery
    com.miui.systemAdSolution
    com.baidu.input_mi
    com.miui.micloudsync
    com.miui.player
    com.miui.cloudbackup
    com.xiaomi.aicr
    com.xiaomi.xmsf
    com.iflytek.inputmethod.miui
    com.xiaomi.market
    com.miui.cloudservice
    com.sohu.inputmethod.sogou.xiaomi
    com.xiaomi.metoknlp
    com.miui.analytics
    com.miui.weather2
    com.android.email
    com.miui.voiceassist
    com.miui.greenguard
    com.android.deskclock
    com.lbe.security.miui
    com.eg.android.AlipayGphone
    com.miui.home
  Whitelist (except idle) all app ids:
    1001
    2000
    6102
    10086
    10088
    10093
    10099
    10129
    10130
    10133
    10134
    10135
    10141
    10144
    10146
    10149
    10151
    10156
    10169
    10176
    10177
    10178
    10179
    10182
    10193
    10195
    10202
    10208
    10213
    10216
    10218
    10220
    10225
    10236
    10255
    10257
    10275
    10279
    10287
    10293
    10294
    10296
    10303
    10310
    10316
    10331
  Whitelist user app ids:
    10133
    10135
    10141
    10144
    10149
    10151
    10169
    10176
    10177
    10178
    10179
    10182
    10193
    10195
    10208
    10213
    10220
    10287
    10293
    10294
    10296
    10303
    10310
    10316
    10331
  Whitelist all app ids:
    1001
    2000
    6102
    10088
    10093
    10133
    10134
    10135
    10141
    10144
    10146
    10149
    10151
    10156
    10169
    10176
    10177
    10178
    10179
    10182
    10193
    10195
    10202
    10208
    10213
    10216
    10218
    10220
    10225
    10236
    10255
    10257
    10275
    10279
    10287
    10293
    10294
    10296
    10303
    10310
    10316
    10331
  mLightEnabled=true  mDeepEnabled=true
  mForceIdle=false
  mUseMotionSensor=true mMotionSensor={Sensor name="sns_smd  Wakeup", vendor="QTI", version=1, type=17, maxRange=1.0, resolution=1.0, power=0.025, minDelay=-1}
  # 当前是灭屏状态
  mScreenOn=false
  # 当前是锁屏状态
  mScreenLocked=true
  # 联网中
  mNetworkConnected=true
  # 在充电
  mCharging=true
  activeEmergencyCall=false
  mMotionActive=false
  mNotMoving=true
  mMotionListener.activatedTimeElapsed=81400957
  mLastMotionEventElapsed=81310919
  0 stationary listeners registered
  Location prefetching disabled
  # mState是Doze状态,见拆解
  mState=ACTIVE mLightState=ACTIVE
  mInactiveTimeout=+15s0ms
  mNextLightIdleDelay=+5m0s0ms (flex=+1m0s0ms)
  mCurLightIdleBudget=+1m0s0ms

Doze的分析一般先看当前状态再看历史

当前状态

变量取值示例含义
mStateACTIVE / INACTIVE / IDLE_PENDING / SENSING / LOCATING / IDLE / IDLE_MAINTENANCE深度 Doze 状态机
mLightStateACTIVE / INACTIVE / IDLE / MAINTENANCE轻度 Doze 状态机
mChargingtrue/false充电会阻止深度 Doze
mScreenOntrue/false熄屏是前提之一
Idling historylight-idle / deep-idle / (charging)/(motion)进入/退出原因记录

mState 与 mLightState状态组合

mState
深度Doze状态
mLightState
轻度Doze状态
状态其他
ACTIVEACTIVE未进入Doze
IDLE(或 IDLE_MAINTENANCE 在维护窗口)-深度 Doze
IDLE(或 LIGHT_MAINT/MAINTENANCE轻度Doze中间态:INACTIVEIDLEMAINTENANCE 循环

分析历史

Idling history: 列出了最近的状态切换,时间是“距离现在多久之前”:

  • deep-idle … / deep-maint … / light-idle … → 说明过去确实进入过轻/深 Doze。
  • 你这里最后一条是:normal: … (charging),表明当时因充电而退出了 Doze。

其他会影响进入 Doze 的线索

  • mCharging=true充电会阻止进入深度 Doze。
  • mMotionActive=false mNotMoving=true:静止有利于进入。
  • mScreenOn=false:熄屏是前提之一。
  • mLightEnabled=true mDeepEnabled=true:两个机制都开启(但未必触发)。
  • mNextLightIdleDelay / mCurLightIdleBudget:轻度 Doze 的下一次进入/预算信息,仅作参考。

想要马上验证/触发

  1. 先断电(不要充电),放在桌面静止一会儿,再反复查看:
adb shell dumpsys deviceidle

直到看到:

mLightState=IDLE 或 MAINTENANCE

再长时间静止可进入深度:

mState=IDLE 或 IDLE_MAINTENANCE
  1. 开发调试可强制
adb shell dumpsys deviceidle force-idle      # 直接拉进深度 Doze
adb shell dumpsys deviceidle step            # 逐步推进阶段
adb shell dumpsys deviceidle unforce         # 解除强制
adb shell dumpsys deviceidle                 # 再看状态

执行 adb shell dumpsys deviceidle force-idle

adb shell dumpsys deviceidle
  Flags:
    com.android.server.deviceidle.use_cpu_time_for_temp_allowlist=true
    com.android.server.deviceidle.remove_idle_location=true
 
  Settings:
    flex_time_short=+1m0s0ms
    light_after_inactive_to=+4m0s0ms
    light_idle_to=+5m0s0ms
    light_idle_to_initial_flex=+1m0s0ms
    light_max_idle_to_flex=+15m0s0ms
    light_idle_factor=2.0
    light_idle_increase_linearly=true
    light_idle_linear_increase_factor_ms=300000
    light_idle_flex_linear_increase_factor_ms=60000
    light_max_idle_to=+30m0s0ms
    light_idle_maintenance_min_budget=+1m0s0ms
    light_idle_maintenance_max_budget=+5m0s0ms
    min_light_maintenance_time=+5s0ms
    min_deep_maintenance_time=+30s0ms
    inactive_to=+15s0ms
    sensing_to=+15s0ms
    locating_to=+5s0ms
    location_accuracy=20.0m
    motion_inactive_to=+30s0ms
    motion_inactive_to_flex=+1m0s0ms
    idle_after_inactive_to=+15s0ms
    idle_pending_to=+5m0s0ms
    max_idle_pending_to=+10m0s0ms
    idle_pending_factor=2.0
    quick_doze_delay_to=+1m0s0ms
    idle_to=+1h0m0s0ms
    max_idle_to=+6h0m0s0ms
    idle_factor=2.0
    min_time_to_alarm=+10m0s0ms
    max_temp_app_allowlist_duration_ms=+3m0s0ms
    mms_temp_app_allowlist_duration_ms=+1m0s0ms
    sms_temp_app_allowlist_duration_ms=+20s0ms
    notification_allowlist_duration_ms=+30s0ms
    wait_for_unlock=true
    use_window_alarms=true
    use_mode_manager=false
  Idling history:
      deep-idle: -1d18h34m39s629ms
     deep-maint: -1d17h34m38s317ms
      deep-idle: -1d17h34m8s272ms
     deep-maint: -1d15h34m7s204ms
      deep-idle: -1d15h33m37s178ms
         normal: -1d14h21m55s493ms (alarm)
     light-idle: -1d14h16m54s495ms
      deep-idle: -1d14h9m36s52ms
     deep-maint: -1d13h9m34s551ms
      deep-idle: -1d13h9m4s522ms
     deep-maint: -1d11h9m2s589ms
      deep-idle: -1d11h8m32s549ms
     deep-maint: -1d7h8m31s734ms
      deep-idle: -1d7h8m1s703ms
         normal: -1d5h17m21s389ms (motion)
     light-idle: -1d5h12m20s800ms
    light-maint: -1d4h55m46s820ms
     light-idle: -1d4h53m55s799ms
    light-maint: -1d4h35m41s349ms
     light-idle: -1d4h35m36s299ms
      deep-idle: -1d4h21m10s467ms
         normal: -1d3h43m18s830ms (charging)
      deep-idle: -6s454ms
  Whitelist (except idle) system apps:
    com.android.providers.calendar
    com.android.updater
    com.qualcomm.qti.uceShimService
    com.android.providers.downloads
    com.qualcomm.qti.telephonyservice
    com.android.vending
    com.android.mms
    com.qualcomm.qcrilmsgtunnel
    com.android.rkpdapp
    com.android.cellbroadcastreceiver
    com.google.android.gms
    com.android.proxyhandler
    com.qualcomm.qti.workloadclassifier
    com.android.imsserviceentitlement
    com.qualcomm.qti.ims
    com.qualcomm.location
    com.miui.powerinsight
    com.android.shell
    com.android.emergency
    com.qualcomm.atfwd
    com.android.providers.contacts
    com.android.devicelockcontroller
    com.miui.core
  Whitelist system apps:
    com.android.providers.calendar
    com.android.updater
    com.qualcomm.qti.uceShimService
    com.android.providers.downloads
    com.qualcomm.qti.telephonyservice
    com.android.mms
    com.qualcomm.qcrilmsgtunnel
    com.android.rkpdapp
    com.android.cellbroadcastreceiver
    com.google.android.gms
    com.qualcomm.qti.workloadclassifier
    com.qualcomm.qti.ims
    com.qualcomm.location
    com.miui.powerinsight
    com.android.shell
    com.android.emergency
    com.qualcomm.atfwd
    com.android.devicelockcontroller
    com.miui.core
  Whitelist user apps:
    com.unionpay.tsmservice.mi
    com.milink.service
    com.xiaomi.account
    com.xiaomi.gamecenter.sdk.service
    com.miui.gallery
    com.miui.systemAdSolution
    com.baidu.input_mi
    com.miui.micloudsync
    com.miui.player
    com.miui.cloudbackup
    com.xiaomi.aicr
    com.xiaomi.xmsf
    com.iflytek.inputmethod.miui
    com.xiaomi.market
    com.miui.cloudservice
    com.sohu.inputmethod.sogou.xiaomi
    com.xiaomi.metoknlp
    com.miui.analytics
    com.miui.weather2
    com.android.email
    com.miui.voiceassist
    com.miui.greenguard
    com.android.deskclock
    com.lbe.security.miui
    com.eg.android.AlipayGphone
    com.miui.home
  Whitelist (except idle) all app ids:
    1001
    2000
    6102
    10086
    10088
    10093
    10099
    10129
    10130
    10133
    10134
    10135
    10141
    10144
    10146
    10149
    10151
    10156
    10169
    10176
    10177
    10178
    10179
    10182
    10193
    10195
    10202
    10208
    10213
    10216
    10218
    10220
    10225
    10236
    10255
    10257
    10275
    10279
    10287
    10293
    10294
    10296
    10303
    10310
    10316
    10331
  Whitelist user app ids:
    10133
    10135
    10141
    10144
    10149
    10151
    10169
    10176
    10177
    10178
    10179
    10182
    10193
    10195
    10208
    10213
    10220
    10287
    10293
    10294
    10296
    10303
    10310
    10316
    10331
  Whitelist all app ids:
    1001
    2000
    6102
    10088
    10093
    10133
    10134
    10135
    10141
    10144
    10146
    10149
    10151
    10156
    10169
    10176
    10177
    10178
    10179
    10182
    10193
    10195
    10202
    10208
    10213
    10216
    10218
    10220
    10225
    10236
    10255
    10257
    10275
    10279
    10287
    10293
    10294
    10296
    10303
    10310
    10316
    10331
  mLightEnabled=true  mDeepEnabled=true
  mForceIdle=true
  mUseMotionSensor=true mMotionSensor={Sensor name="sns_smd  Wakeup", vendor="QTI", version=1, type=17, maxRange=1.0, resolution=1.0, power=0.025, minDelay=-1}
  mScreenOn=false
  mScreenLocked=true
  mNetworkConnected=true
  mCharging=true
  activeEmergencyCall=false
  mMotionActive=true
  mNotMoving=false
  mMotionListener.activatedTimeElapsed=183549434
  mLastMotionEventElapsed=81310919
  0 stationary listeners registered
  Location prefetching disabled
  mState=IDLE mLightState=OVERRIDE
  mInactiveTimeout=+15s0ms
  mNextAlarmTime=+59m53s543ms
  mNextIdlePendingDelay=+5m0s0ms
  mNextIdleDelay=+2h0m0s0ms
  mNextLightIdleDelay=+5m0s0ms (flex=+1m0s0ms)
  mCurLightIdleBudget=+1m0s0ms

结论:现在已经在深度 Doze,而且是你用 ADB 强制进的。

关键行读法——看你这段的几个信号:

  • mState=IDLE深度 Doze(device idle)已生效
  • mLightState=OVERRIDE → 轻度 Doze 状态机被强制覆盖(因为你开启了强制空闲)。
  • mForceIdle=true → 这是 ADB force-idle 造成的强制 Doze,不是自然进入。
  • Idling history 最后一条 deep-idle: -6s… → 刚在 6 秒前进入 deep-idle
  • mCharging=true → 正常情况“充电会阻止进入深度 Doze”,但这里仍然进了,是因为 被强制
  • mMotionActive=true / mNotMoving=false → 设备有运动迹象;自然 Doze 会被运动打断,但在 强制模式下仍保持 IDLE
  • mNextAlarmTime=+59m…mNextIdlePendingDelay=+5m…mNextIdleDelay=+2h…mCurLightIdleBudget=+1m… → 这些是接下来维护/调度窗口与预算的时间参考(强制模式下主要看 mState 即可)。

小抄:如何判断是否“在 Doze”

  1. 深度 DozemState=IDLE(或 IDLE_MAINTENANCE 即维护窗口)
  2. 轻度 DozemLightState=IDLE(或 MAINTENANCE
  3. 强制/调试态mForceIdle=true / mLightState=OVERRIDE