Doze相关知识
一、Doze 模式的定义
Doze 模式(打盹模式) 是从 Android 6.0(Marshmallow, API 23) 开始引入的系统省电机制。 它的核心目标是:
当设备长时间处于“静止 + 熄屏 + 未充电”状态时,系统自动进入深度休眠状态,暂停或推迟大多数后台任务与网络访问,以延长电池续航。
简单说:
“锁屏 → 放着不用 → 不在充电” → 系统判断设备在闲置,就进入 Doze。
二、Doze 与 锁屏 的关系
| 场景 | 系统状态 | Doze 状态说明 |
|---|---|---|
| 用户按电源键锁屏 | 屏幕关闭 | 尚未进入 Doze(只是 screen-off 状态) |
| 设备持续静止几分钟(通常 1 小时内) | 屏幕关闭、无充电、无显著运动 | 系统逐渐进入 Doze 模式 |
| 设备移动 / 唤醒 / 充电 | 活动状态 | 退出 Doze 模式 |
🔹 锁屏 ≠ Doze:锁屏只是前提之一,真正进入 Doze 还需要「设备静止 + 不充电 + 屏幕熄灭」。
三、Doze 模式的行为特征(系统层面)
当设备处于 Doze 模式时,系统会:
- 冻结后台 CPU 唤醒(除非使用
setAndAllowWhileIdle()、setExactAndAllowWhileIdle()的 Alarm) - 阻止网络访问(仅在 maintenance window 打开)
- 推迟 JobScheduler 与 SyncAdapter 任务
- 暂停标准 AlarmManager 定时任务
- 禁止 WakeLock 长时间持有
- 延迟 Firebase Cloud Messaging 普通消息传递
系统会周期性短暂“唤醒”设备执行积压任务,称为 maintenance window(维护窗口)。 每次维护窗口时间会随着静止时间逐步拉长。
🧠 四、锁屏相关的具体含义
在「锁屏场景」中提到的 Doze,其实指的是:
系统在设备锁屏后经过一段时间,自动进入的“深度休眠省电模式”,会限制应用在后台的行为。
也就是说:
- 刚锁屏:应用依然能执行后台任务(只是 screen-off 模式)
- 锁屏 + 静止 + 不充电:系统逐渐进入 Doze 模式,后台活动被大幅限制
💻 五、开发者层面的影响与应对
-
AlarmManager 限制
-
常规
setExact()、set()的闹钟在 Doze 下会被延迟。 -
若必须执行,可用:
alarmManager.setAndAllowWhileIdle() alarmManager.setExactAndAllowWhileIdle()
-
-
JobScheduler 延迟
- 任务会被系统推迟到 maintenance window。
-
网络请求被暂停
- 建议使用 Firebase Cloud Messaging(FCM 高优先级) 唤醒设备。
-
后台同步延迟
- 依赖 SyncAdapter 的同步会被推迟。
-
后台服务被系统暂停
- 若需要长期运行,请使用
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=+1m0s0msDoze的分析一般先看当前状态再看历史
当前状态
| 变量 | 取值示例 | 含义 |
|---|---|---|
mState | ACTIVE / INACTIVE / IDLE_PENDING / SENSING / LOCATING / IDLE / IDLE_MAINTENANCE | 深度 Doze 状态机 |
mLightState | ACTIVE / INACTIVE / IDLE / MAINTENANCE | 轻度 Doze 状态机 |
mCharging | true/false | 充电会阻止深度 Doze |
mScreenOn | true/false | 熄屏是前提之一 |
Idling history | light-idle / deep-idle / (charging)/(motion) | 进入/退出原因记录 |
mState 与 mLightState状态组合
| mState 深度Doze状态 | mLightState 轻度Doze状态 | 状态 | 其他 |
|---|---|---|---|
| ACTIVE | ACTIVE | 未进入Doze | |
IDLE(或 IDLE_MAINTENANCE 在维护窗口) | - | 深度 Doze | |
IDLE(或 LIGHT_MAINT/MAINTENANCE) | 轻度Doze | 中间态:INACTIVE → IDLE ↔ MAINTENANCE 循环 | |
分析历史
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 的下一次进入/预算信息,仅作参考。
想要马上验证/触发
- 先断电(不要充电),放在桌面静止一会儿,再反复查看:
adb shell dumpsys deviceidle直到看到:
mLightState=IDLE 或 MAINTENANCE再长时间静止可进入深度:
mState=IDLE 或 IDLE_MAINTENANCE- 开发调试可强制:
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→ 这是 ADBforce-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”
- 深度 Doze:
mState=IDLE(或IDLE_MAINTENANCE即维护窗口) - 轻度 Doze:
mLightState=IDLE(或MAINTENANCE) - 强制/调试态:
mForceIdle=true/mLightState=OVERRIDE