【全栈第25课】实战:功耗 / 发热定位
Android 全栈工程师进阶教程 第25课。实战:功耗 / 发热定位。基于公开 AOSP 知识整理,含原理、可编译示例、常见问题定位。
> 本文是《Android 全栈工程师进阶教程》系列第 25 课。完整 26 课见 GitHub 仓库。
【全栈第25课】实战:功耗 / 发热定位
0. 这节课你将搞懂什么
"待机一晚掉电很多 / 使用时发烫 / 续航差"——怎么揪出耗电的元凶。 学完你能回答:用户报"待机掉电快",我该查什么?发烫怎么定位?wakelock、CPU 频率、regulator 各怎么看?L18 学的 suspend 漏关外设,这里怎么查出来?
1. 背景:功耗是用户最敏感的指标之一
续航差、发烫是高频用户投诉。功耗问题难在:它是全系统的,任何一个 App/服务/驱动都可能偷电。要有系统的方法分类(待机 vs 使用)和归因(谁在耗电)。
2. 全局图:功耗三大元凶
功耗高
├─ CPU 频率高/不降频 → 算力浪费(某进程死循环/频繁唤醒)
├─ wakelock 不释放 → 系统睡不下去(待机掉电,L18/L19)
└─ 外设没下电(regulator/clock 常开) → 硬件漏电(suspend 漏关,L18)
分两个场景:
- 待机掉电快(息屏不动也掉电)→ 主要查 wakelock / 外设没下电
- 使用发烫(用着烫)→ 主要查 CPU 频率 / 谁吃 CPU
3. 各场景的定位手段
待机掉电快(系统睡不下去 / 漏电)
# 看谁持 wakelock 不放(最常见的待机掉电根因)
adb shell cat /sys/power/wake_lock
adb shell dumpsys power | grep -iE "wake|wakelock"
adb shell cat /d/wakeup_sources # 各 wakeup source 的活跃次数/时长(active_count/active_since)
# 看系统有没有真正进入 suspend
adb shell cat /sys/power/suspend_stats # success/fail 次数
adb shell dmesg | grep -iE "PM: suspend|PM: resume"
# 看哪些外设 regulator/clock 待机还开着(本该关的 = 漏电,L18)
adb shell cat /d/regulator/regulator_summary
adb shell cat /d/clk/clk_summary
使用发烫(算力/功耗大)
adb shell top -m 10 # 哪个进程吃 CPU
adb shell cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq # 各核当前频率
adb shell cat /sys/class/thermal/thermal_zone*/temp # 各温区温度
adb shell cat /sys/devices/system/cpu/cpu7/cpufreq/stats/time_in_state # 大核各频点停留时间
系统化归因(最实用)
adb shell dumpsys batterystats # 耗电历史归因(哪个 App/uid 耗多少)
adb bugreport bug.zip # 抓全,用 Battery Historian 图形化看耗电时间线
4. 前置准备
- 依赖 L18(电源管理)、L19(wakelock/cgroup)、L22(武器库/bugreport)。
- 本课是实战方法,产出功耗定位 SOP。
5. 动手:跟着查一个"待机掉电快"
第 1 步:确认系统有没有睡着
adb shell cat /sys/power/suspend_stats # 息屏一段时间后看 success 涨不涨
- success 不涨 / fail 多 → 系统根本没睡着(被 wakelock 拦着)→ 查 wakelock。
- success 在涨但还是掉电 → 睡是睡了,但睡眠中有外设漏电或频繁被唤醒 → 查 regulator + wakeup 唤醒次数。
第 2 步:找谁不让睡 / 谁频繁唤醒
adb shell cat /d/wakeup_sources | sort -k6 -n # 按活跃时长/次数排序,看谁最活跃
- 找到 active 时间最长/唤醒次数最多的 source(名字对照是哪个驱动/服务)。
- 示例项目 场景:某应用入口 / 某后台 App 持锁不放 → 待机掉电。
第 3 步:查外设漏电
adb shell cat /d/regulator/regulator_summary | grep -iE "enabled|on" # 待机时还 enable 的
- 息屏后某个 sensor/触控的 regulator 还 enable → 它的驱动 suspend 漏关了(L18)→ 找对应驱动补
regulator_disable。
6. 看底层:一次"掉电"是怎么发生的
息屏 → 系统尝试 suspend
├─ 有 wakelock 持着 → suspend 失败 → CPU 不睡 → 持续耗电(查 wake_lock)
└─ suspend 成功 → CPU 睡
├─ 但某 regulator 没关 → 那个外设一直耗电(查 regulator_summary,L18)
└─ 频繁被 wakeup source 唤醒(网络/定时器)→ 睡睡醒醒,平均功耗高(查 wakeup_sources 唤醒次数)
所以待机掉电 = "没睡着" 或 "睡了但漏电/频繁醒"。三个命令(suspend_stats / wake_lock / regulator_summary)就能定位到哪种。
7. 编译 & 运行(本课无编译产物)
见第 3、5 节命令。 > 验证状态(诚实):本课为功耗定位方法论,无编译产物;命令为标准功耗调试方式(debugfs 节点需 root)。
8. 踩坑提醒
- 不分待机/使用就乱查:待机掉电查 wakelock/regulator;使用发烫查 CPU。混着查抓不到重点。
- regulator_summary 要 root + debugfs:
/d/是 debugfs,量产机可能没挂或没权限。 - wakeup_sources 名字看不懂:名字是各驱动/服务自起的,要对照代码/文档找是谁。
- batterystats 要先 reset 再复现:
dumpsys batterystats --reset清零,再复现场景,数据才干净。 - suspend 漏关是隐性 bug:功能完全正常,只是待机费电,容易漏测;L18 写驱动 suspend 时就要想好关什么。
9. 常见问题分析与定位(功耗实战)
9.1 常见问题清单
- 待机一晚掉电很多
- 使用中发烫降频卡顿
- 某 App 装了之后特别耗电
- 充电慢/边充边掉
- 偶发功耗高(抓不到)
9.2 分析与定位
① 待机掉电 — 见第 5 节三步:suspend_stats(睡着没)→ wake_lock/wakeup_sources(谁不让睡)→ regulator_summary(谁漏电)。
② 使用发烫
adb shell top -m 10 # 谁吃 CPU
adb shell cat /sys/class/thermal/thermal_zone*/temp # 温度
- 某进程 CPU 100% → 死循环/频繁唤醒,看它在干嘛(perfetto/simpleperf,L22);大核长期高频 → 算力压力。
③ 某 App 耗电 — dumpsys batterystats 看该 uid 的耗电归因(CPU 时间、wakelock、网络、GPS);它持的 wakelock 在 wake_lock 里。
④ 边充边掉 — 充电电流 < 功耗。看 dumpsys battery 充电电流;同时功耗太大(发烫场景)。
⑤ 偶发 — 难抓。开 batterystats 长时间记录,用 Battery Historian 回看耗电时间线,找异常时段对应什么活动。
9.3 定位决策树
功耗/发热问题
├─ 先分场景:待机掉电 还是 使用发烫
├─ 待机掉电:
│ suspend_stats success 涨吗
│ ├─ 不涨 → 没睡着 → wake_lock/wakeup_sources 谁持锁(L19)
│ └─ 涨但掉电 → regulator_summary 谁漏电(L18 suspend 漏关)+ wakeup 唤醒次数
├─ 使用发烫:
│ top 谁吃 CPU + cpufreq 频率 + thermal 温度 → perfetto/simpleperf 看那进程干嘛
├─ 某 App 耗电 → dumpsys batterystats 该 uid 归因
└─ 偶发 → batterystats 长记录 + Battery Historian 回看时间线
10. 小结
- 功耗三元凶:CPU 高频 / wakelock 不放 / 外设没下电(regulator)。
- 先分场景:待机掉电(查 wakelock+regulator)vs 使用发烫(查 CPU+温度)。
- 待机三步:suspend_stats(睡着没)→ wake_lock(谁不让睡)→ regulator_summary(谁漏电)。
- L18 suspend 漏关 regulator = 待机掉电隐性 bug,这里用 regulator_summary 查出来。
- 排查口诀:分场景;待机查 suspend_stats→wake_lock→regulator;发烫查 top→cpufreq→thermal;归因用 batterystats/Battery Historian。
下节预告
L26:毕业——外设完整 bring-up —— 把全部 26 课串成一张能独立交付的能力地图,一颗新外设从硬件到 App 的完整 checklist。