17. 测试Doze模式:adb命令模拟、dumpsys battery_unsettling

Doze模式写好了,怎么测?这是个好问题。

你总不能真的把手机放那儿等半小时吧?我刚开始做这个功能的时候,就傻等过。结果发现,等来的不是Doze,是瞌睡。后来团队里的老司机告诉我,Android早就给我们准备了测试工具——adb命令模拟和dumpsys。

说白了,就是让系统“假装”进入了Doze。你不用真的等,一条命令就能把时间“快进”到目标状态。

17.1 为什么需要模拟测试?

真实场景下,Doze的触发条件很苛刻:

  • 设备静止不动(靠加速度计判断)
  • 屏幕关闭超过30分钟
  • 没有正在进行的运动活动

你想想看,每次测试都要等半小时,这谁受得了?而且你还要反复验证不同阶段的逻辑。所以,Google提供了两套模拟方案:

  1. adb shell dumpsys battery_unsettling —— 模拟设备静止
  2. 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 实战:完整的测试流程

我一般会按这个步骤来:

  1. 准备阶段:安装待测App,确保它在后台有定时任务或网络请求。
  2. 模拟静止:adb shell dumpsys battery_unsettling --unsettle false
  3. 关屏:adb shell input keyevent KEYCODE_POWER
  4. 强制Doze:adb shell dumpsys deviceidle force-idle
  5. 观察行为:查看App的日志,确认定时任务被延迟、网络被挂起。
  6. 退出Doze:adb shell dumpsys deviceidle unforce
  7. 恢复不安定: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模式测试的核心逻辑:

Doze模式测试流程 1. 模拟静止 battery_unsettling 2. 关屏 input keyevent POWER 3. 强制Doze deviceidle force-idle 4. 观察App行为 日志、网络、定时任务 5. 退出Doze deviceidle unforce 6. 恢复不安定 battery_unsettling true 查看状态 dumpsys deviceidle 整个流程可在1分钟内完成,无需等待真实Doze触发

17.7 常见问题与避坑

测试过程中,我遇到过不少奇怪的问题。挑几个典型的说说:

  • 命令执行后没反应:检查一下设备是否开启了“开发者选项”中的“不保留活动”。这个选项会影响Doze的行为。
  • force-idle后App还在跑:大概率是App有高优先级任务(如前台服务、闹钟)。Doze不会阻止这些。
  • 退出Doze后状态没恢复:记得执行 unforcebattery_unsettling --unsettle true,否则下次测试会不准。

嗯,差不多就这些了。测试Doze其实不难,关键是掌握好模拟工具。你只要把 battery_unsettlingdeviceidle 玩熟了,大部分场景都能覆盖到。