Skip to content

11 电源体系:wakelock、Doze 与 suspend 的三道闸门 ​

本页导读:Android 省电的本质是「让 CPU 和屏幕尽可能睡下去」,而 framework 的全部电源设计就是三道闸门的管理学:wakelock 决定「谁说不许睡」、PowerManagerService 决定「屏幕和系统的清醒状态」、Doze/待机策略决定「App 什么时候被断网断闹钟」。本页把 PowerManagerService、wakelock 家族、Doze 分级、内核 autosuspend 串成一条链,并给出「谁偷电」的取证方法。基线 Android 16(API 36)。


读完本页你要能回答:屏灭一晚掉电 10% 该先查哪三段读数?Doze 之后应用到底还剩什么权利?framework 和内核各握着哪张否决票?

一、清醒状态机:PowerManagerService ​

PowerManagerService(PMS,frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java)维护系统电源状态机(状态名以 AOSP 为准,大致为):

状态含义屏幕CPU
ON正常亮屏亮正常
DIM超时前调暗暗正常
DREAMDaydream/屏保运行亮(低亮)正常
DOZE / DOZE_SUSPEND环境显示(AOD)/ AOD 且允许挂起部分像素低
OFF屏灭灭可 suspend

两个设计要点:

  1. 状态 = f(亮度请求, wakelock, 用户活动):任何组件都不直接「关灯」,而是提交投票,PMS 仲裁——这保证了策略集中、账目可审计;
  2. Android 13 起多显示(折叠/外接)由 PowerGroup 分组仲裁(power/ 包内 PowerGroup 类,每屏独立状态机,主组联动从组,以 AOSP 为准)。

二、wakelock 家族:谁说不许睡 ​

类型作用现状
PARTIAL_WAKE_LOCK保 CPU 运行,不管屏唯一仍推荐给系统级场景的锁
SCREEN_BRIGHT / SCREEN_DIM / FULL亮屏类早废弃(用 window flag/直接亮屏 API)
PROXIMITY 类通话距感废弃(HAL 层策略接管)
DOZE / DOZE_SUSPENDAOD 场景专用系统内部(AOD 服务)
NOTIFICATION / FOUL_WAKE_LOCK 等 flag行为修饰(超时、强制唤醒)部分随版本退役,以 AOSP 为准

三层事实要钉牢:

  • wakelock 拿的是 WAKE_LOCK 权限下的引用计数;dumpsys power 的 wakelock 段列出当前持有者与统计(含 unattended);
  • 应用侧 wakelock 在 Doze 面前无效:进入 Doze 后闹钟/网络/job 被折叠,partial lock 也不让 CPU 常醒(非白名单);
  • framework 内部还有一层 SuspendBlocker(native 挂起票,对应内核 wakelock):system_server/SF 在关键路径短暂持票防「睡在半路」,普通应用接触不到——dumpsys power 的 suspend blockers 段可见;
  • 排查入口:dumpsys power 顶部即列出活动 wakelock 与最近释放者统计;Android 13+ 提供「禁用指定应用 wakelock」的调试开关(PowerManager 侧接口名以 AOSP 为准),验证「这货是不是元凶」最快;
  • wakelock 计数≠耗电:10s 内高频取放(如传感器轮询)比单次长锁更耗电,看 batterystats 的 count 与 actual time 两列要一起看。

应用侧 API 骨架(类型常量见 frameworks/base/core/java/android/os/PowerManager.java):

java
// 示意:唯一仍常用的 PARTIAL 锁正确用法骨架
PowerManager pm = context.getSystemService(PowerManager.class);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Tag:WhatFor");
wl.setReferenceCounted(true);          // 默认即引用计数
wl.acquire(timeoutMillis);             // 永远带超时兜底
// ... 必须成对 release;tag 会出现在 dumpsys 里,写清楚用途是职业操守

三、亮灭屏的完整链路 ​

text
电源键/活动事件 → PowerManager(use-case 投票)
  → PMS 状态迁移(wakeUp/goToSleep 语义)
  → DisplayManager 亮度/模式(联动第 10 页刷新率降档)
  → 屏 OFF 后:所有 PARTIAL/DOZE 锁释放 → 用户态可睡
  → 内核 autosuspend:延迟窗口(默认量级数百 ms,以配置为准)无新唤醒 → suspend

屏灭 ≠ 立刻 suspend:中间隔着「用户态 wakelock 清零 + autosuspend 延迟」两小节——「灭屏后待机一晚上掉电 10%」的凶手九成在第一小节(某个 App 灭屏后仍持锁)。

四、Doze:应用侧的断舍离 ​

DeviceIdleController(frameworks/base/services/core/java/com/android/server/deviceidle/DeviceIdleController.java,目录以 AOSP 当前为准)实现 Android 6 引入的 Doze,状态机(名称以 AOSP 为准,语义稳定):

  • ACTIVE:在用;INACTIVE:静止但轻约束;IDLE 家族:深度限制(Doze)、维护窗口周期性放行;
  • 触发前提:设备静止+灭屏(屏幕关闭、非充电或低电),时间常数以设备配置(config_ 系列 overlay)为准;
  • IDLE 的限制内容:网络访问被挂(netd 按 uid 置 idle 状态,第 03 页网络底座)、Wake Lock 被忽略、闹钟折叠到维护窗口、sync/job 推迟;
  • Light Doze(轻度档)先收紧网络与 sync,Full Doze 上全量限制——两档在 Android 7 定型;
  • 维护窗口不是固定闹钟:进 IDLE 前会有一次短窗,IDLE 内按指数退避排长窗;「Doze 后任务偶尔集中跑一波」正是维护窗的体感;
  • 亮屏/移动/插电即退出 Doze 回到 ACTIVE,所有被折叠的闹钟/作业在出口处统一结算。
  • 白名单(电池优化豁免 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 与 OEM/运营商预置白名单)是唯一的合法旁路,OEM 省电激进程度差异也主要体现在 Doze 参数上。

调试三板斧(需 root/eng 或白名单身份):cmd deviceidle force-idle 强制进 Doze 复现;dumpsys deviceidle whitelist +<pkg> 临时加白;dumpsys deviceidle 直接看状态机与剩余时间常数。

应用侧的「正统姿势」变迁:wakelock 后台干活 → JobScheduler/FirebaseJobDispatcher(Doze 自动调度窗口)→ WorkManager(Android 架构组件推荐)——链的终点是「你描述需求,系统挑时间」。

五、应用待机分桶与功耗配额 ​

Android 9 起 UsageStats 驱动 App Standby Buckets(RESTRICTED/ACTIVE/WORKING_SET/FREQUENT/RARE/NEVER,常量名以 UsageStatsManager 为准):按使用频度给 App 定档,后台执行/网络/Job 配额随之收紧;Android 12+ 耗电大户(高功耗后台行为)还会被系统弹窗建议限制。

  • 查看:dumpsys usagestats 的分桶与 dumpsys deviceidle;
  • 省电与稳定性的接口在这里第一次「双向」:framework 省电配额反过来成为第三方 App 后台存活率的主要变量,国内 OEM 的「自启动/后台管理」都是这套机制上的加严策略;
  • 配额的具体形态:低桶的 App 后台网络被限时、Job 频次受限、高省电模式(PowerSave 开启)还会再压一层临时配额;
  • 观察面:dumpsys usagestats 看桶位变迁,dumpsys battery power save(子命令随版本,以设备帮助为准)看省电模式开关对系统的降级动作。

六、亮度、dim 与灭屏通道 ​

亮屏段的电量大头是屏本身,framework 的控制面:

  • 亮度链路:自动亮度(ALS 传感器 + 厂商算法)、热限亮(ThermalManager 压制上限)、低亮度省电策略,最终都落到 DisplayManager→显示 HAL(第 10/12 页);
  • DIM 态是超时前的「礼貌劝退」:PMS 先进 DIM 再 OFF,动画期间用户一动即回 ON;
  • 应用「挽留」屏的合法姿势只有 FLAG_KEEP_SCREEN_ON(第 07 页转交 PMS)与导航/通话等场景的系统级 use-case,而不是自己 new 一个亮屏 wakelock;
  • 灭屏超时是用户设置值(Settings screen_off_timeout),OEM 可改默认;「调试时总是很快灭屏」改这个值而不是在代码里抢锁。

七、CPU 调速器、cluster 与电量归因 ​

framework 不直接管频率(那是内核 schedutil/walt 与厂商 EAS 的事),但留了三个抓手:

  • PowerManager 的 SCHED_BOOST hint 类通路(历史 API 多已废弃,现代走 PowerHint HAL(AIDL android.hardware.power,第 12 页)由厂商实现语义);
  • ThermalManager(services/core/java/com/android/server/power/thermal/ThermalManager.java)聚合热缓解等级(THERMAL_STATUS_*),应用可用 getCurrentThermalStatus/注册监听 主动降载;
  • 电量归因:BatteryStatsService(core 阶段启动,第 03 页)按 uid/组件记账(wakelock、cpu、sensor、camera、kernel wakelock……),dumpsys batterystats + bugreport 的 Battery Usage 段即「谁偷电」的最终答案。

八、内核侧:autosuspend 与 last wake ​

  • 所有用户态票清零后,内核走 autosuspend(现代走 delay 机制,/sys/power/... 节点名以内核版本为准)进入 suspend(suspend-to-idle/deep,厂商配置);
  • 唤醒源统计:/sys/kernel/debug/wakeup_sources、/proc/last_kmsg/pstore、/sys/power/suspend_stats——「睡不下去」先看哪个 wakeup source 活跃;
  • SELinux 与 debugfs 限制下很多节点普通 shell 不可读,量产机常需 eng 版或 OEM dump 工具(以设备策略为准);
  • 厂商深睡策略(DoD/智能待机)都在这一层做手脚,framework 的 Doze 只是第一道闸门。

九、实战:抓一个偷电贼 ​

bash
adb shell dumpsys batterystats -u0 --checkin > bs.txt   # 取原始账本
 # 关注段:
 #   "Wake lock"     —— App wakelock 累计时长/次数 Top
 #   "Kernel wakelock"—— 内核态票据(驱动嫌疑)
 #   "Network" / "Jobs" / "Syncs"
adb shell dumpsys deviceidle          # Doze 状态机与白名单
adb shell dumpsys power               # wakelock 现值 + suspend blocker
adb shell dumpsys usagestats -b        # 分桶结果

判读三步:先看 screen on time vs on time 确认问题在灭屏段还是亮屏段;灭屏段查 wakelock Top 与 kernel wakelock;亮屏段查刷新率/亮度与 CPU 频率曲线(perfdump/厂商工具)。

补充两个趁手工具:dumpsys batterystats -bh(battery history 逐事件流,含 wakelock/unplug/plug,子命令以版本为准)适合「昨晚到底发生了什么」类问题;bugreport 自带的 Battery Usage 汇总段则适合交给不写代码的同事看。

十、省电对外 API 一览(framework 的接口面) ​

  • PowerManager:newWakeLock(受限使用)、isInteractive、getThermalHeadroom(Android 13+)、user activity(Android 15+ 的 getUserActivityEvent 类接口,命名以 AOSP 为准);
  • BatteryManager/BatteryEx(Android 15+ Mainline 化)、EnergyStatsManager(Android 12 引入、16 起稳定 AIDL 接口):App 查自身能耗;
  • 亮度/刷新率偏好走 WindowManager.LayoutParams 与显示投票 API(第 10 页);
  • 省电策略「被管」侧:JobScheduler/AlarmManager/WorkManager 的 deadline、exact 权限(Android 12+ exact alarm 需 SCHEDULE_EXACT_ALARM 特殊权限)都是电源策略在应用 API 上的投影。

十一、判例清单 ​

症状高概率机制取证
一晚待机掉电两位数灭屏后 App wakelock 或驱动 wakeupbatterystats wakelock 段 + wakeup_sources
息屏播放音乐中断未持 PARTIAL 锁的「伪后台播放」dumpsys media.session/audio 与 wakelock
闹钟不准时Doze 折叠非 exact 闹钟deviceidle 状态 + alarm 账本
Job 迟迟不跑分桶档位低/约束未满足dumpsys jobscheduler 与 usagestats 桶
一插电就醒charger 唤醒源正常,但唤醒后 App 借机干活batterystats 充电段事件流
AOD 耗电异常厂商 AOD 实现未走 DOZE_SUSPENDdumpsys power 状态分布

十二、自测清单 ​

  • 能画出「屏灭→suspend」的完整闸门序列;
  • 能区分 wakelock、SuspendBlocker、kernel wakeup 三层票据;
  • 能说出 Doze 两档各限制什么、维护窗口放行什么;
  • 能用 batterystats 三段式在 5 分钟内指认偷电大户;
  • 能解释为什么 Doze 白名单申请在商店合规与用户口碑上都是高成本操作。

十三、版本注记 ​

  • Android 6(API 23):Doze 与电池优化白名单登场。
  • Android 7(API 24):Light Doze、implicit broadcast 大削减(省电组合拳)。
  • Android 9(API 28):App Standby Buckets;SuspendControlService HAL 化(AOSP 统一 suspend 入口)。
  • Android 11(API 30):PowerManager 热缓解 API 扩展;isLightDevice 轻量设备策略。
  • Android 12(API 31):EnergyStats 登场;exact alarm 收紧;AdaptiveConnectivity 类省电。
  • Android 13(API 33):PowerGroup 多屏电源仲裁;AOD/DOZE 族语义细化。
  • Android 15~16(API 35~36):BatteryEx/能耗稳定接口、user activity 类新面;Doze 骨架十年未动,变的是配额与白名单治理。

本页小结 ​

本页小结:三道闸门记清楚:wakelock 是「否决票」,PMS 状态机是「仲裁庭」,Doze/桶是「配额局」;屏灭之后还要过 suspend blocker 清零与内核 autosuspend 才真睡。查偷电永远 dumpsys batterystats 三段式(App wakelock/kernel wakelock/屏幕段),写后台任务永远优先 Job/Work 而不是「持锁硬扛」。

最后连一次网:wakelock 的引用计数走的是 system_server 单点(第 03 页),Doze 的静止判定依赖传感器(第 09 页),刷新率降档归图形(第 10 页),HAL 语义归 Treble(第 12 页)——电源从来不是一个模块,是全系统的一张网。

参考 ​

  • 省电官方指南:developer.android.com/topic/performance/power-features
  • DeviceIdleController 源码:cs.android.com/android/platform/frameworks/base/+/main/services/core/java/com/android/server/deviceidle/DeviceIdleController.java
  • PowerManagerService 源码:cs.android.com/android/platform/frameworks/base/+/main/services/core/java/com/android/server/power/PowerManagerService.java
  • Doze 与 App Standby:developer.android.com/training/monitoring/manage-device-usage

基于 Android 16 / API 36 · 内容为原创整理,转载请注明出处