系列目录:第一篇:电源管理架构全景图 | 第二篇:开机全链路—BootROM到Launcher | 第三篇:关机/重启全链路—ShutdownThread到kernel_power_off | 第四篇:休眠唤醒与开关机—核心差异深度对比 | 第五篇:休眠全链路—PMS到Kernel Suspend | 第六篇:唤醒全链路—Kernel Resume到屏幕点亮 | 第七篇:内核层—wakelock与autosleep机制 | 第八篇:内核层—Alarm定时唤醒与硬件唤醒源 | 第九篇:Native层—libsuspend与Power HAL | 第十篇:实战调试与问题排查
一、为什么要理解休眠唤醒
移动设备与 PC 在电源管理上有本质区别。PC 可以随时插电使用,而手机依赖电池供电,必须在"性能"和"续航"之间做精细平衡。Android 为此设计了一套从应用到内核、跨越四层软件栈的电源管理体系。
当你遇到以下问题时,答案都在这套体系之中:
- “为什么 App 申请了 WakeLock,设备还是会休眠?”——WakeLock 的 level 可能不够高,或者 PMS 的
mWakeLockSummary汇总时被覆盖了 - “为什么设备休眠后无法通过 Alarm 唤醒?”——Alarm 的 type 可能不是
RTC_WAKEUP或ELAPSED_REALTIME_WAKEUP - “为什么功耗测试显示设备从未进入 deep sleep?”——内核 wakelock 可能被某个驱动持锁,
/sys/power/wake_lock可以排查
这套体系的核心思想:当用户不使用设备时,让它尽可能深地睡眠;当用户需要使用设备时,让它在一秒之内恢复。
二、三种状态转移模型
Android 系统的电源状态可以抽象为三种粒度的转移:
2.1 宏观级别:关机 ↔ 开机
最彻底的状态切换。关机将操作系统完整卸载、硬件完全掉电;开机则从 BootROM 开始,经历 BootLoader → Kernel → init → Zygote → SystemServer → Launcher 的完整启动链。
| 维度 | 说明 |
|---|---|
| 耗时 | 开机 30-60 秒,关机 5-15 秒 |
| 状态保留 | 无。所有内存数据、进程状态、寄存器上下文全部丢失 |
| 功耗 | 关机后几乎为零(仅 RTC 时钟供电) |
2.2 中观级别:休眠 ↔ 唤醒
这是本系列的核心。休眠时 CPU 进入深度睡眠状态(deep idle / suspend),仅保留 RAM 自刷新供电和外设唤醒源。唤醒时,从中断触发到屏幕点亮通常在 1 秒以内完成。
| 维度 | 说明 |
|---|---|
| 耗时 | 休眠 < 1 秒,唤醒 < 1 秒 |
| 状态保留 | 完整。进程页表、ART 虚拟机堆、Activity 栈全部保留在 RAM 中 |
| 功耗 | 仅 RAM 自刷新 + RTC + 唤醒源监听,功耗极低 |
2.3 微观级别:亮屏 ↔ 暗屏
最轻量级的切换,仅涉及DisplayPowerController控制屏幕背光和显示层,不涉及 CPU 挂起。通常由用户操作(触摸屏幕、按下按键)或接近传感器触发。
三、Android 电源管理四层架构
Android 电源管理跨越四层软件栈,每层有明确的职责边界:
┌──────────────────────────────────────────────────────┐ │ 应用层 (Application Layer) │ │ PowerManager API / WakeLock 申请与释放 │ │ frameworks/base/core/java/android/os/PowerManager │ ├──────────────────────────────────────────────────────┤ │ 框架层 (Framework Layer) │ │ PowerManagerService / DisplayPowerController │ │ Notifier / ShutdownThread │ │ frameworks/base/services/core/java/com/android/ │ │ server/power/ │ ├──────────────────────────────────────────────────────┤ │ Native 层 (Native Layer) │ │ libsuspend / suspend_blocker / Power HAL │ │ system/core/libsuspend/ │ │ hardware/libhardware/include/hardware/power.h │ ├──────────────────────────────────────────────────────┤ │ 内核层 (Kernel Layer) │ │ wakelock / autosleep / alarmtimer │ │ kernel/power/ │ │ drivers/rtc/alarm-dev.c │ └──────────────────────────────────────────────────────┘3.1 应用层:PowerManager API
应用程序通过PowerManager.WakeLock通知系统"我正在做重要的事,不要休眠"。
源码路径:frameworks/base/core/java/android/os/PowerManager.java
publicfinalclassPowerManager{// WakeLock 级别(从低到高)publicstaticfinalintPARTIAL_WAKE_LOCK=0x00000001;// 仅保持 CPU 运行publicstaticfinalintSCREEN_DIM_WAKE_LOCK=0x00000006;// 保持 CPU + 暗屏publicstaticfinalintSCREEN_BRIGHT_WAKE_LOCK=0x0000000a;// 保持 CPU + 亮屏publicstaticfinalintFULL_WAKE_LOCK=0x0000001a;// 保持 CPU + 亮屏 + 键盘publicWakeLocknewWakeLock(intlevelAndFlags,Stringtag){returnnewWakeLock(levelAndFlags,tag,mContext.getOpPackageName());}publicfinalclassWakeLock{publicvoidacquire(){...}// 获取锁,阻止休眠publicvoidacquire(longtimeout){...}// 带超时的获取publicvoidrelease(){...}// 释放锁}}关键设计:
WakeLock默认非引用计数(setReferenceCounted(false)),多次acquire()只需一次release()即可释放。如果设为引用计数模式,则必须acquire()和release()次数匹配。
3.2 框架层:PowerManagerService
PowerManagerService(PMS)是休眠唤醒的"中枢大脑",运行在 SystemServer 进程中。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
publicfinalclassPowerManagerServiceextendsSystemService{// 唤醒状态机:四种状态privateintmWakefulness;// AWAKE → DREAMING → DOZING → ASLEEPprivatebooleanmWakefulnessChanging;// 状态迁移中标志// WakeLock 聚合状态:所有活跃 WakeLock 的位掩码汇总privateintmWakeLockSummary;// 每个 bit 代表一种 WakeLock 类型// 脏标记:指示哪部分电源状态需要更新protectedintmDirty;// 位掩码,驱动 updatePowerStateLocked() 的增量更新}关键设计:PMS 用
mDirty位掩码驱动增量更新——当某个条件变化时(如 WakeLock 变化、亮度变化),只设置对应的 dirty bit,updatePowerStateLocked()根据 dirty bits 分阶段处理,避免全量重算。
Wakefulness 状态机沿固定方向迁移:
AWAKE ──→ DREAMING ──→ DOZING ──→ ASLEEP ↑ ↑ ↑ │ │ │ │ │ └─────────┴───────────┴───────────┘ (用户交互 / 唤醒事件)- AWAKE:屏幕亮,设备完全可用
- DREAMING:屏幕变暗,可能进入屏保(Daydream)
- DOZING:Doze 模式,限制网络和后台任务
- ASLEEP:CPU 挂起,仅 RAM 自刷新
关键设计:状态迁移是单向的(AWAKE → ASLEEP),唤醒时直接跳回 AWAKE。
mWakefulnessChanging标志在状态迁移过程中置位,防止并发状态变更。
3.3 Native 层:libsuspend 与 Power HAL
libsuspend是用户空间与内核休眠机制的桥梁。两种实现方式:
源码路径:system/core/libsuspend/autosuspend_wakeup_count.c
- wakeup_count 方式:读取
/sys/power/wakeup_count获取当前值,写入/sys/power/state为 “mem” 触发休眠。如果在读取和写入之间产生了新的唤醒事件,wakeup_count 不匹配,内核拒绝休眠并返回错误。
源码路径:system/core/libsuspend/autosuspend_autosleep.c
- autosleep 方式:写入
/sys/power/autosleep为 “mem”,内核在 autosleep 工作线程中自动尝试休眠,无需用户空间持续轮询。
Power HAL 定义硬件抽象层接口:
源码路径:hardware/libhardware/include/hardware/power.h
关键接口:powerHint()— 向底层(cpufreq governor)传递电源提示;setInteractive()— 通知 HAL 交互模式变化。
3.4 内核层:wakelock 与 autosleep
Android 内核在 Linux 标准 suspend/resume 基础上,增加了 wakelock 和 autosleep 机制,确保在有活跃 wakelock 时不会错误休眠。
关键内核源码路径:
kernel/power/wakelock.c— wakelock 核心实现kernel/power/autosleep.c— autosleep 工作线程kernel/power/main.c— sysfs 节点注册(/sys/power/wake_lock、/sys/power/wake_unlock)kernel/power/suspend.c— suspend 主路径(pm_suspend)kernel/power/process.c— 进程 freeze/thaw
四、休眠唤醒与开关机:核心区分
理解这四种流程的关键在于状态保持 vs 状态重建:
关机→开机:状态完全重建 BootROM → BootLoader → Kernel → init → Zygote → SystemServer → Launcher 内核重载、进程全部冷启动、ART 堆清零重分配 休眠→唤醒:状态完全保持 内核仍在运行(仅 CPU 暂停) 进程被 freeze(冻结)而非 kill ART 虚拟机堆内存完整保留 Activity 栈原样保存 恢复时只需 thaw(解冻)→ 恢复外设 → 点亮屏幕关键:休眠唤醒的核心优势是"状态保持"——不需要重新加载内核、不需要重启进程、不需要重新初始化服务。这解释了为什么唤醒只需不到 1 秒,而开机需要 30-60 秒。
五、关键源码文件索引
| 层级 | 文件 | 本文涉及内容 |
|---|---|---|
| Framework | frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java | PMS 核心,Wakefulness 状态机、mDirty 增量更新 |
| Framework | frameworks/base/services/core/java/com/android/server/power/Notifier.java | 电源状态广播(SCREEN_ON/OFF) |
| Framework | frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java | 关机/重启调度 |
| Framework | frameworks/base/core/java/android/os/PowerManager.java | 应用层 WakeLock API |
| Native | system/core/libsuspend/autosuspend.c | 自动休眠核心实现 |
| Native | system/core/libsuspend/autosuspend_wakeup_count.c | wakeup_count 方式休眠 |
| Native | system/core/libsuspend/autosuspend_autosleep.c | autosleep 方式休眠 |
| HAL | hardware/libhardware/include/hardware/power.h | Power HAL 接口定义 |
| Kernel | kernel/power/wakelock.c | 内核 wakelock 实现 |
| Kernel | kernel/power/autosleep.c | 内核 autosleep 线程 |
| Kernel | kernel/power/suspend.c | Suspend 主路径 |
| Kernel | kernel/power/process.c | 进程 freeze/thaw |
六、系列阅读路线
第 1 篇(本篇)全景图 │ ├─→ 第 2 篇:开机全链路(建立"全量启动"的基准认知) │ │ │ └─→ 第 3 篇:关机/重启全链路(理解"全量销毁"的代价) │ │ │ └─→ 第 4 篇:休眠唤醒 vs 开关机 对比(核心交汇点) │ │ │ ┌───────────┼───────────┐ │ │ │ │ 第 5 篇:休眠全链路 第 6 篇:唤醒全链路 │ (Framework → Kernel) (Kernel → Framework) │ │ │ │ └───────────┬───────────┘ │ │ │ 第 7 篇:内核wakelock 第 8 篇:Alarm唤醒源 │ │ │ 第 9 篇:Native 层 & Power HAL │ │ └─────────── 第 10 篇:实战调试与问题排查- App 开发者:重点读第 1、4、5、6、10 篇,理解 WakeLock 的申请释放与功耗影响
- Framework 开发者:通读全系列,核心是第 2-6 篇
- 驱动/Kernel 开发者:重点关注第 4-8 篇,特别是第 5、6、7、8 篇
七、小结
本篇建立了 Android 电源管理的顶层认知:
| 概念 | 说明 |
|---|---|
| 三种状态转移 | 关机↔开机(全量重建)、休眠↔唤醒(状态保持)、亮屏↔暗屏(仅背光) |
| 四层架构 | 应用层(WakeLock API)→ 框架层(PMS 状态机)→ Native 层(libsuspend)→ 内核层(wakelock/autosleep) |
| 核心区分 | 状态保持(休眠唤醒)vs 状态重建(开关机) |
后续篇章将逐层深入——下一篇从"开机"开始,走完从 BootROM 到 Launcher 的完整启动链路,为理解"休眠唤醒跳过了什么"打下基础。