17. 测试Doze模式:adb命令模拟、dumpsys battery_unsettling
Doze模式写好了,怎么测?这是个好问题。
你总不能真的把手机放那儿等半小时吧?我刚开始做这个功能的时候,就傻等过。结果发现,等来的不是Doze,是瞌睡。后来团队里的老司机告诉我,Android早就给我们准备了测试工具——adb命令模拟和dumpsys。
说白了,就是让系统“假装”进入了Doze。你不用真的等,一条命令就能把时间“快进”到目标状态。
17.1 为什么需要模拟测试?
真实场景下,Doze的触发条件很苛刻:
- 设备静止不动(靠加速度计判断)
- 屏幕关闭超过30分钟
- 没有正在进行的运动活动
你想想看,每次测试都要等半小时,这谁受得了?而且你还要反复验证不同阶段的逻辑。所以,Google提供了两套模拟方案:
- adb shell dumpsys battery_unsettling —— 模拟设备静止
- adb shell dumpsys deviceidle —— 直接控制Doze状态机
我个人习惯把这两者结合着用。先模拟静止,再手动触发状态切换,这样最接近真实行为。
17.2 模拟设备静止:battery_unsettling
Doze的第一个门槛就是“设备静止”。系统内部有个叫 battery_unsettling 的机制,它记录设备是否处于“不安定”状态。
如果设备一直在动,系统就不会进入Doze。所以我们要先“骗”过它。
核心命令:
# 模拟设备静止(清除不安定状态)
adb shell dumpsys battery_unsettling --unsettle false
# 查看当前状态
adb shell dumpsys battery_unsettling
执行完第一条命令后,系统会认为设备已经静止了。这时候你再配合Doze的强制命令,就能直接进入深度休眠。
我曾经踩过一个坑:只模拟了静止,但没关屏幕。结果Doze死活不触发。后来才发现,Doze要求屏幕关闭超过30分钟。所以测试前,记得先按电源键关屏。
小技巧:
如果你不想每次都手动关屏,可以用这条命令:
adb shell input keyevent KEYCODE_POWER
配合脚本一起用,效率翻倍。
17.3 直接控制Doze状态机:deviceidle
如果说 battery_unsettling 是“敲门砖”,那 deviceidle 就是“万能钥匙”。它可以直接把Doze状态机推到任意阶段。
常用的命令有这些:
| 命令 | 作用 |
|---|---|
adb shell dumpsys deviceidle enable |
开启Doze模式(有些设备默认关闭) |
adb shell dumpsys deviceidle step |
手动推进一个状态(IDLE→IDLE_MAINTENANCE→IDLE) |
adb shell dumpsys deviceidle force-idle |
强制进入深度Doze |
adb shell dumpsys deviceidle unforce |
退出强制Doze |
adb shell dumpsys deviceidle disable |
关闭Doze模式(测试完记得关) |
嗯,这里要注意:force-idle 虽然方便,但它跳过了正常的“预休眠”流程。有些依赖 onIdleOn 回调的逻辑可能不会被触发。所以,我建议你两种方式都测一下。
17.4 实战:完整的测试流程
我一般会按这个步骤来:
- 准备阶段:安装待测App,确保它在后台有定时任务或网络请求。
- 模拟静止:
adb shell dumpsys battery_unsettling --unsettle false - 关屏:
adb shell input keyevent KEYCODE_POWER - 强制Doze:
adb shell dumpsys deviceidle force-idle - 观察行为:查看App的日志,确认定时任务被延迟、网络被挂起。
- 退出Doze:
adb shell dumpsys deviceidle unforce - 恢复不安定:
adb shell dumpsys battery_unsettling --unsettle true
你看,整个过程不到1分钟。比起傻等半小时,效率提升太多了。
17.5 查看Doze状态:dumpsys deviceidle
测试过程中,你肯定想知道当前到底在哪个状态。用这条命令就能看到:
adb shell dumpsys deviceidle
输出内容很多,我重点看这几个字段:
- mState:当前状态(ACTIVE、IDLE、IDLE_MAINTENANCE等)
- mIdle:是否处于Doze模式(true/false)
- mScreenOn:屏幕是否亮着
- mCharging:是否在充电(充电时不会Doze)
注意:
有些厂商的定制ROM会修改Doze逻辑。比如小米的“神隐模式”、华为的“智能省电”。在这些设备上,dumpsys deviceidle 的输出可能不准。我遇到过一台设备,明明显示IDLE,但App的网络请求还是照发不误。后来发现是厂商在底层做了“白名单”。
所以,测试时尽量用原生系统或AOSP模拟器。如果只能用厂商设备,记得先确认它的Doze行为是否标准。
17.6 知识体系图
下面这张图总结了Doze模式测试的核心逻辑:
17.7 常见问题与避坑
测试过程中,我遇到过不少奇怪的问题。挑几个典型的说说:
- 命令执行后没反应:检查一下设备是否开启了“开发者选项”中的“不保留活动”。这个选项会影响Doze的行为。
- force-idle后App还在跑:大概率是App有高优先级任务(如前台服务、闹钟)。Doze不会阻止这些。
- 退出Doze后状态没恢复:记得执行
unforce和battery_unsettling --unsettle true,否则下次测试会不准。
嗯,差不多就这些了。测试Doze其实不难,关键是掌握好模拟工具。你只要把 battery_unsettling 和 deviceidle 玩熟了,大部分场景都能覆盖到。