2、BatteryStats进阶:四大唤醒源深度剖析 深入剖析四大唤醒源WakeLock、Alarm、网络唤醒、JobScheduler。这四兄弟可以说是Android耗电的“四大天王”。我这些年处理过的线上功耗问题十有八九都能在这四个里找到根因。核心观点系统休眠就像深度睡眠每次被唤醒都要消耗大量能量。优化目标不是不让唤醒而是减少不必要的、过于频繁的唤醒。2.1 WakeLock 分析谁在阻止系统休眠WakeLock直译就是“唤醒锁”。它的作用很简单——告诉系统“嘿我现在有事儿别睡” 但问题就出在这里很多开发者用完忘了释放或者锁的时间过长。拿到一台有功耗问题的手机第一件事就是跑adb shell dumpsys batterystats --checkin | grep wake_lock这个命令会输出所有WakeLock的持有记录。但说实话原始数据太乱了。我会配合这个脚本# 提取WakeLock汇总信息 adb shell dumpsys batterystats | grep -A 100 WakeLock | grep -E Partial|Full|Screen我的经验重点关注Partial WakeLock。它是最容易出问题的——屏幕关了还在后台干活耗电大户。Full WakeLock通常和屏幕相关反而问题不大。举个例子我曾经遇到一个社交App用户反馈晚上待机掉电20%。一查WakeLock发现有个叫com.social.app:push_keepalive的锁每5分钟持锁一次每次持续30秒。你算算一晚上8小时它唤醒了96次怎么定位具体代码用这个命令看堆栈adb shell dumpsys batterystats --wakeup_info嗯这里要注意有些厂商的ROM可能不支持这个参数。如果不行就抓traceadb shell echo 1 /sys/kernel/debug/tracing/events/power/wake_lock/enable adb shell cat /sys/kernel/debug/tracing/trace_pipe2.2 Alarm 唤醒分析定时任务的陷阱Alarm机制说白了就是系统里的“闹钟”。App可以设定一个时间点到了就唤醒系统执行任务。但很多App设得太频繁了。查看Alarm唤醒情况adb shell dumpsys batterystats --alarms输出会按App分组显示每个App设置的Alarm次数和类型。我重点关注两个指标唤醒次数单位时间内触发了多少次实际唤醒时长每次唤醒后系统工作了多久有一次我发现某个天气App每小时唤醒4次。每次就更新一下温度耗时不到1秒。但问题是它用的是setExact精确到毫秒。这就导致系统无法合并唤醒CPU频繁进出休眠状态。避坑指南我曾经见过一个极端案例——某App用setExact每30秒唤醒一次就为了检查有没有新消息。这简直是“功耗杀手”。正确的做法是用setInexact或者setAndAllowWhileIdle让系统自己决定什么时候批量处理。优化建议能用setInexact就别用setExact多个Alarm尽量合并到同一个时间窗口非关键任务用setAndAllowWhileIdle允许系统延迟执行2.3 网络唤醒分析看不见的数据流网络唤醒指的是网络数据包到达时把系统从休眠中唤醒。通常和App的后台推送、心跳包有关。查看网络唤醒统计adb shell dumpsys batterystats --network这里有个关键字段叫wakeup表示该App导致网络唤醒的次数。我见过最夸张的是一个视频App后台每10秒发一次心跳包一晚上网络唤醒了4000多次。为什么会这样说白了很多App为了“保活”用长连接不断发心跳。但心跳间隔太短系统根本没法深度休眠。我的建议是心跳间隔至少拉到5分钟以上使用Google的Firebase Cloud MessagingFCM统一推送别自己搞长连接如果必须用长连接利用JobScheduler的setRequiredNetworkType来管理2.4 JobScheduler 分析被忽视的调度器JobScheduler 是Android 5.0引入的本意是让系统统一调度后台任务减少碎片化唤醒。但很多App用得并不好。查看JobScheduler状态adb shell dumpsys jobscheduler输出会列出所有注册的Job包括包名、Job ID、执行频率、上次执行时间等。关注这几个点指标说明危险值periodic周期性Job的执行间隔 15分钟last_run上次执行时间频繁更新num_failures执行失败次数高失败率我记得有一次一个电商App注册了3个周期性Job分别每10分钟、15分钟、20分钟执行一次。结果这三个Job的时间窗口完全错开导致系统每5分钟就被唤醒一次。优化方案很简单——把三个Job合并成一个设置setPeriodic(30 * 60 * 1000)然后内部统一处理。核心原则JobScheduler 的设计初衷就是“延迟执行、批量处理”。如果你用它来做高频任务那还不如直接用Handler。记住JobScheduler 的周期建议至少30分钟以上。3.5 实战四步定位法好了理论讲完了。我分享一个自己常用的四步定位法帮你快速找到问题第一步全局扫描——dumpsys batterystats看整体唤醒次数和时长第二步分类排查—— 分别看WakeLock、Alarm、网络、JobScheduler的详细数据第三步锁定App—— 找到唤醒次数最多的几个App重点关注第四步代码定位—— 用trace或日志找到具体的代码位置小技巧抓取一段长时间比如一整晚的batterystats数据对比“屏幕亮着”和“屏幕关闭”两个阶段的唤醒模式。很多App在屏幕关闭后反而更活跃——这明显不合理。