14、电源管理调试:dumpsys battery、wakelock分析、功耗曲线、Doze模式

电源管理,说白了就是让手机更省电。但省电和流畅之间,往往需要做很多权衡。我调试过不少功耗问题,有些是硬件底层的锅,但更多时候,是软件层面的“锁”没用好,导致系统睡不下去。

这一章,我们就来聊聊电源调试的几个核心工具和概念。你掌握了这些,基本就能定位大部分异常耗电问题了。

14.1 先看电池状态:dumpsys battery

我最常用的第一招,就是敲 adb shell dumpsys battery。它能告诉你当前电池的实时状态,是充电还是放电,电量多少,温度如何。

adb shell dumpsys battery
Current Battery Service state:
  AC powered: false
  USB powered: true
  Wireless powered: false
  Max charging current: 500000
  Max charging voltage: 5000000
  Charge counter: 2450000
  status: 2
  health: 2
  present: true
  level: 65
  scale: 100
  voltage: 3875
  temperature: 310
  technology: Li-ion

这里有几个关键字段:

  • level:当前电量百分比。65 就是 65%。
  • status:充电状态。2 表示正在充电,1 是未充电,5 是充满。
  • temperature:温度,单位是 0.1 摄氏度。310 就是 31.0°C。
  • voltage:电池电压,单位毫伏。
小技巧: 如果你想模拟一个低电量场景来测试省电逻辑,可以用 dumpsys battery set level 5 强制把电量设为 5%。测试完记得 dumpsys battery reset 恢复。

14.2 Wakelock 分析:谁在阻止系统休眠?

系统想睡,但有些 App 或服务不肯放手。它们通过申请 WakeLock 来阻止 CPU 进入深度睡眠。这就是耗电的元凶之一。

查看当前 WakeLock 持有情况:

adb shell dumpsys power | grep -A 10 "Wake Locks"
Wake Locks: size=3
  PARTIAL_WAKE_LOCK           'AudioMix'                (uid=1000, pid=1234, ws=null)
  PARTIAL_WAKE_LOCK           'LocationManagerService'  (uid=1000, pid=5678, ws=null)
  SCREEN_DIM_WAKE_LOCK        'WindowManager'           (uid=1000, pid=9012, ws=null)

每个 WakeLock 都有名字、持有者 UID 和 PID。你可以根据名字判断是哪个模块在搞鬼。

我个人习惯,先看 PARTIAL_WAKE_LOCK,因为它会让 CPU 保持运行,屏幕却可以关掉。这种锁如果长时间不释放,耗电会非常明显。

注意: 有些第三方 App 会滥用 WakeLock。我曾经遇到一个视频 App,退到后台后还一直持有 WakeLock 播放“无声广告”。用 dumpsys power 抓到后,直接反馈给厂商修复。

14.3 功耗曲线:用 BatteryHistorian 看全局

光看静态的 WakeLock 还不够。你需要知道 时间轴上的功耗变化。Google 提供了 BatteryHistorian 工具,可以把系统日志转成可视化的 HTML 报告。

生成步骤:

  1. 抓取 bugreport:adb bugreport bugreport.zip
  2. 上传到 https://bathist.ef.lc/ 或本地部署 BatteryHistorian
  3. 查看各条曲线:CPU 频率、网络活动、WakeLock 持有时间、屏幕状态等

你会看到类似这样的时间线:

BatteryHistorian 时间线示例 00:00 00:05 00:10 00:15 屏幕亮 屏幕灭 WakeLock: AudioMix CPU 高频率 CPU 低频率 网络传输 无网络 图例: 屏幕 WakeLock CPU 网络

从这张图里,你能直观看到:屏幕灭掉之后,WakeLock 还在持续,CPU 频率也降不下来。这就是典型的异常耗电场景。

14.4 Doze 模式:系统如何省电?

Android 6.0 引入了 Doze 模式。简单说,就是设备静止且屏幕关闭一段时间后,系统会进入“打盹”状态,限制网络访问和后台任务。

Doze 有几个阶段:

阶段 触发条件 行为
Light Doze 屏幕关闭,设备静止 限制网络访问,推迟 Job
Deep Doze 屏幕关闭超过 30 分钟 完全禁止网络,禁止 WakeLock
Maintenance Window 每 1-2 小时短暂退出 允许同步、Alarm、网络

你可以用 dumpsys deviceidle 查看当前 Doze 状态:

adb shell dumpsys deviceidle
  mState: IDLE
  mLightState: IDLE
  mIdleStartTime: +1h30m20s
  mLastIdleMaintenance: +1h28m15s

mState: IDLE 表示设备已经进入 Deep Doze。如果设备长时间无法进入 IDLE,说明有 App 在阻止休眠。

核心思路: 调试 Doze 时,我会先确认设备是否真的进入了 IDLE 状态。如果一直卡在 ACTIVE,那就用 dumpsys power 看 WakeLock,用 dumpsys alarm 看谁在频繁设置闹钟唤醒系统。

14.5 实战:定位一个异常耗电问题

我记得有一次,用户反馈手机待机一晚掉电 30%。我拿到设备后,按以下步骤排查:

  1. 看电池统计dumpsys batterystats 发现“蓝牙”耗电占比异常高。
  2. 看 WakeLockdumpsys power 发现一个叫 BluetoothWakeLock 的锁一直没释放。
  3. 看 Doze 状态dumpsys deviceidle 显示设备从未进入 IDLE。
  4. 抓取 bugreport:用 BatteryHistorian 分析,发现蓝牙每 10 秒唤醒一次系统。

最终定位到是蓝牙芯片的固件 bug,导致连接断开后没有释放 WakeLock。升级固件后问题解决。

避坑指南: 我曾经遇到一个情况,dumpsys battery 显示电量正常,但手机发热严重。后来发现是某个传感器驱动在后台一直轮询,没有进入休眠。所以,不要只看电池电量,还要看 CPU 频率和传感器活动

14.6 总结一下

电源调试,说白了就是回答三个问题:

  • 谁在耗电? —— 用 dumpsys batterystats 和 BatteryHistorian
  • 谁不让系统睡? —— 用 dumpsys power 看 WakeLock
  • 系统睡了没有? —— 用 dumpsys deviceidle 看 Doze 状态

你把这些工具用熟了,大部分功耗问题都能手到擒来。嗯,今天就聊到这里。


公众号:蓝海资料掘金营,微信 deep3321