AI 技术博客
Android全栈8 分钟阅读3971

【全栈第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. 踩坑提醒

  1. 不分待机/使用就乱查:待机掉电查 wakelock/regulator;使用发烫查 CPU。混着查抓不到重点。
  2. regulator_summary 要 root + debugfs:/d/ 是 debugfs,量产机可能没挂或没权限。
  3. wakeup_sources 名字看不懂:名字是各驱动/服务自起的,要对照代码/文档找是谁。
  4. batterystats 要先 reset 再复现:dumpsys batterystats --reset 清零,再复现场景,数据才干净。
  5. suspend 漏关是隐性 bug:功能完全正常,只是待机费电,容易漏测;L18 写驱动 suspend 时就要想好关什么。

9. 常见问题分析与定位(功耗实战)

9.1 常见问题清单

  1. 待机一晚掉电很多
  2. 使用中发烫降频卡顿
  3. 某 App 装了之后特别耗电
  4. 充电慢/边充边掉
  5. 偶发功耗高(抓不到)

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. 小结

  1. 功耗三元凶:CPU 高频 / wakelock 不放 / 外设没下电(regulator)。
  2. 先分场景:待机掉电(查 wakelock+regulator)vs 使用发烫(查 CPU+温度)。
  3. 待机三步:suspend_stats(睡着没)→ wake_lock(谁不让睡)→ regulator_summary(谁漏电)。
  4. L18 suspend 漏关 regulator = 待机掉电隐性 bug,这里用 regulator_summary 查出来。
  5. 排查口诀:分场景;待机查 suspend_stats→wake_lock→regulator;发烫查 top→cpufreq→thermal;归因用 batterystats/Battery Historian。

下节预告

L26:毕业——外设完整 bring-up —— 把全部 26 课串成一张能独立交付的能力地图,一颗新外设从硬件到 App 的完整 checklist。

评论