系列目录 :第一篇:电源管理架构全景图 | 第二篇:开机全链路---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
java
public final class PowerManager {
// WakeLock 级别(从低到高)
public static final int PARTIAL_WAKE_LOCK = 0x00000001; // 仅保持 CPU 运行
public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006; // 保持 CPU + 暗屏
public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a; // 保持 CPU + 亮屏
public static final int FULL_WAKE_LOCK = 0x0000001a; // 保持 CPU + 亮屏 + 键盘
public WakeLock newWakeLock(int levelAndFlags, String tag) {
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
public final class WakeLock {
public void acquire() { ... } // 获取锁,阻止休眠
public void acquire(long timeout) { ... } // 带超时的获取
public void release() { ... } // 释放锁
}
}
关键设计 :
WakeLock默认非引用计数(setReferenceCounted(false)),多次acquire()只需一次release()即可释放。如果设为引用计数模式,则必须acquire()和release()次数匹配。
3.2 框架层:PowerManagerService
PowerManagerService(PMS)是休眠唤醒的"中枢大脑",运行在 SystemServer 进程中。
源码路径 :frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
java
public final class PowerManagerService extends SystemService {
// 唤醒状态机:四种状态
private int mWakefulness; // AWAKE → DREAMING → DOZING → ASLEEP
private boolean mWakefulnessChanging; // 状态迁移中标志
// WakeLock 聚合状态:所有活跃 WakeLock 的位掩码汇总
private int mWakeLockSummary; // 每个 bit 代表一种 WakeLock 类型
// 脏标记:指示哪部分电源状态需要更新
protected int mDirty; // 位掩码,驱动 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 的完整启动链路,为理解"休眠唤醒跳过了什么"打下基础。