**系列目录
**:第一篇:电源管理架构全景图 | 第二篇:开机全链路---BootROM到Launcher | 第三篇:关机/重启全链路---ShutdownThread到kernel_power_off | 第四篇:休眠唤醒与开关机---核心差异深度对比 | 第五篇:休眠全链路---PMS到Kernel Suspend | 第六篇:唤醒全链路---Kernel Resume到屏幕点亮 | 第七篇:内核层---wakelock与autosleep机制 | 第八篇:内核层---Alarm定时唤醒与硬件唤醒源 | 第九篇:Native层---libsuspend与Power HAL | 第十篇:实战调试与问题排查
一、为什么要深入理解唤醒流程
你可能遇到过这些问题:
- 按电源键后屏幕亮了,但从按键到亮屏经历了多少层调用?为什么有时按了没反应?
- 闹钟能准时唤醒系统,这个"准时"是如何保证的?内核休眠时谁在计时?
- 唤醒后应用恢复运行,ART 虚拟机和 Activity 栈是如何"原地复活"的?
上一篇追踪了从 Java 层到内核 CPU 进入 deep sleep 的完整路径。现在系统处于静止状态------仅 RAM
自刷新供电,若干唤醒源处于监听状态。本篇追踪从唤醒信号触发到用户看到亮屏的完整恢复过程。
二、唤醒源全景 --- 谁能唤醒系统
唤醒是"被动的"------系统不会主动醒来,必须由外部事件触发。Android 支持的主要唤醒源:
| 唤醒源类型 | 具体来源 | 硬件层面 |
|---|---|---|
| GPIO 按键 | 电源键、音量键、Home 键 | GPIO 边沿触发中断 |
| RTC Alarm | 闹钟、定时任务、Doze 维护窗口 | RTC 定时器中断 |
| Modem 事件 | 来电、收到短信、网络切换 | Modem 的 IPC 中断 |
| USB 事件 | USB 插拔、充电器插入 | USB PHY 中断 |
| 其他外设 | 耳机插拔、SD 卡插拔等 | 对应硬件的 IRQ |
2.1 为什么这些中断能唤醒 CPU
在休眠前(suspend_enter() 阶段),内核通过 irq_set_irq_wake() 将这些中断源标记为"唤醒源":
源码路径 :kernel/msm-3.18/kernel/irq/manage.c
c
int irq_set_irq_wake(unsigned int irq, unsigned int on) {
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
int ret = 0;
if (!desc)
return -EINVAL;
if (on) {
if (desc->wake_depth++ == 0) {
ret = set_irq_wake_real(irq, on);
if (ret)
desc->wake_depth = 0; // 失败回滚
else
irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
}
} else {
// 对称的禁用逻辑...
}
irq_put_desc_busunlock(desc, flags);
return ret;
}
关键设计 :
irq_set_irq_wake(irq, 1)通过set_irq_wake_real()最终调用中断控制器芯片的
irq_set_wake回调,配置硬件让该 IRQ 在 deep sleep 时仍能触发唤醒。wake_depth支持多个驱动共享同一唤醒IRQ,且
set_irq_wake_real()失败时会回滚wake_depth,保证计数一致。
三、Kernel 层唤醒 --- 从中断到 thaw 进程
先来回顾一下系统休眠时Kernel层的调用链。
3.1 系统休眠时Kernel层的调用链。
state_store() [sysfs回调]
→ pm_suspend(state)
→ enter_state(state)
→ sys_sync() [文件系统同步]
→ suspend_prepare() [挂起前准备]
→ suspend_freeze_processes() [冻结进程]
→ freeze_processes() [冻结用户进程]
→ freeze_kernel_threads() [冻结内核线程]
→ suspend_devices_and_enter() [挂起设备并进入休眠]
→ platform_suspend_begin() [平台初始化]
→ suspend_console() [挂起控制台]
→ dpm_suspend_start() [挂起所有设备]
→ suspend_enter() [进入硬件休眠]
→ dpm_suspend_late() [设备晚期挂起]
→ dpm_suspend_noirq() [设备无中断挂起]
→ disable_nonboot_cpus() [禁用非启动CPU]
→ arch_suspend_disable_irqs() [禁用中断]
→ syscore_suspend() [挂起系统核心]
→ suspend_ops->enter() [平台相关: WFI指令,休眠就在这里]
→ CPU进入deep sleep
当唤醒源触发时,CPU 从中断唤醒,内核开始执行恢复流程。恢复顺序与休眠顺序严格相反。
3.2 系统唤醒时Kernel层的调用链
唤醒源触发
│ GPIO按键 / RTC Alarm / Modem事件 / USB事件
▼
中断控制器 → CPU退出WFI → 跳转到唤醒入口
│
▼
Kernel层 (逆序恢复)
//enter_state() 进入
//suspend_devices_and_enter() 进入
//suspend_enter() 进入
//suspend_ops->enter() [从这里被唤醒继续往下执行]
→ syscore_resume() [恢复non-boot CPU、时钟、中断控制器]
→ arch_suspend_enable_irqs() [重新开启中断]
→ enable_nonboot_cpus() [恢复非启动CPU]
→ platform_resume_noirq() [平台无中断恢复]
→ dpm_resume_noirq() [设备无中断恢复]
→ platform_resume_early() [平台早期恢复]
→ dpm_resume_early() [设备早期恢复]
→ platform_resume_finish(); [平台恢复结束]
//suspend_enter() 返回
→ dpm_resume_end() [恢复所有设备]
→ platform_resume_end() [平台收尾]
//suspend_devices_and_enter() 返回
→ suspend_finish()
→ suspend_thaw_processes() [解冻所有用户进程]
//enter_state() 返回
唤醒入口是平台相关的汇编代码,负责恢复 CPU 寄存器状态、MMU、缓存等,然后跳转到 C 语言的 resume 函数。
3.3 suspend_enter() --- 休眠与唤醒的核心枢纽
suspend_enter() 是整个休眠/唤醒流程的核心。休眠路径中,suspend_ops->enter(state) 让 CPU
进入休眠;唤醒后,代码从 enter() 的下一行继续执行,通过 goto 标签按逆序完成所有恢复操作:
源码路径 :kernel/msm-3.18/kernel/power/suspend.c
c
static int suspend_enter(suspend_state_t state, bool *wakeup) {
// === 休眠路径 ===
// ... 平台准备、设备晚期挂起、关闭 non-boot CPU、关中断 ...
error = syscore_suspend();
if (!error) {
*wakeup = pm_wakeup_pending();
if (!(suspend_test(TEST_CORE) || *wakeup)) {
// ⬆ CPU 在这里进入休眠(阻塞调用)
error = suspend_ops->enter(state);
// ⬇ CPU 被唤醒后从这里继续执行
events_check_enabled = false;
}
syscore_resume(); // 恢复系统核心(中断仍关闭、仅 CPU0 在线)
}
// === 唤醒路径(通过 goto 标签逆序恢复)===
arch_suspend_enable_irqs(); // 重新开启中断
Enable_cpus:
enable_nonboot_cpus(); // 恢复 non-boot CPU
Platform_wake:
platform_resume_noirq(state); // 平台无中断恢复
dpm_resume_noirq(PMSG_RESUME); // 设备无中断恢复
Platform_early_resume:
platform_resume_early(state); // 平台早期恢复
Devices_early_resume:
dpm_resume_early(PMSG_RESUME); // 设备早期恢复
Platform_finish:
platform_resume_finish(state); // 平台收尾
return error;
}
关键设计 :
suspend_ops->enter()是一个"阻塞调用"------CPU 休眠时执行流暂停在此,被唤醒后从这里继续执行。恢复操作全部通过
goto标签完成:syscore_resume→enable_irqs→enable_nonboot_cpus→platform_resume_noirq→
dpm_resume_noirq→platform_resume_early→dpm_resume_early→platform_resume_finish。goto标签同时也是错误处理的跳转目标:休眠过程中任何阶段失败,都会跳到对应的恢复标签,确保已执行的操作被正确回滚。
3.4 suspend_devices_and_enter() --- 设备层面的最终收尾
suspend_enter() 返回后,suspend_devices_and_enter() 完成设备层面的最终恢复:
源码路径 :kernel/msm-3.18/kernel/power/suspend.c
c
int suspend_devices_and_enter(suspend_state_t state) {
// === 休眠路径 ===
error = platform_suspend_begin(state);
// ... suspend_console(), dpm_suspend_start() ...
do {
error = suspend_enter(state, &wakeup); // ⬆ 休眠在此
} while (!error && !wakeup && platform_suspend_again(state));
Resume_devices:
// === 唤醒路径 ===
dpm_resume_end(PMSG_RESUME); // 恢复所有设备(与 dpm_suspend_start 对称)
resume_console(); // 恢复控制台
Close:
platform_resume_end(state); // 平台收尾
return error;
}
关键设计 :
dpm_resume_end()与休眠时的dpm_suspend_start()对称,负责恢复在suspend_enter()之前挂起的设备。
platform_suspend_again()支持平台在唤醒后判断是否需要再次进入休眠(如 Qualcomm的快速重休眠优化)。
3.5 enter_state() --- 唤醒的最终收尾
suspend_devices_and_enter() 返回后,enter_state() 完成最后的收尾工作:
源码路径 :kernel/msm-3.18/kernel/power/suspend.c
c
static int enter_state(suspend_state_t state) {
// === 休眠路径 ===
sys_sync(); // 同步文件系统
suspend_prepare(state); // 准备(含冻结进程)
suspend_devices_and_enter(state); // ⬆ 休眠在此
// === 唤醒路径 ===
suspend_finish(); // 收尾(含解冻进程)
Unlock:
mutex_unlock(&pm_mutex);
return error;
}
static void suspend_finish(void)
{
suspend_thaw_processes();
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
}
关键设计 :
suspend_finish()内部调用thaw_processes()解冻所有用户进程。至此,内核层的唤醒工作全部完成。
以上 3.2-3.5 按函数嵌套层次展示了唤醒的完整框架------从最内层的 suspend_enter() 到最外层的
enter_state()。但实际执行时,恢复操作是从内向外逐层展开的。下面按实际执行顺序,深入每个关键恢复步骤的细节。
3.6 syscore_resume() --- 恢复系统核心(最先执行)
CPU 被唤醒后,suspend_ops->enter() 返回,第一个 被调用的恢复函数就是 syscore_resume()
------此时中断仍然关闭、只有 CPU0 在线:
源码路径 :kernel/msm-3.18/drivers/base/syscore.c
c
void syscore_resume(void) {
struct syscore_ops *ops;
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled before system core resume.\n");
// 遍历注册的 syscore_ops,依次调用 resume 回调
list_for_each_entry(ops, &syscore_ops_list, node)
if (ops->resume) {
ops->resume();
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled after %pF\n", ops->resume);
}
}
关键设计 :
syscore_resume()在中断关闭 的状态下执行,恢复 non-boot CPU、系统时钟源(
timekeeping_resume())、中断控制器的非唤醒 IRQ 等核心基础设施。每个ops->resume()执行后都会检查中断是否仍然关闭。
3.7 suspend_thaw_processes() --- 解冻所有进程
源码路径 :kernel/msm-3.18/kernel/power/process.h
c
static inline void suspend_thaw_processes(void)
{
thaw_processes();
}
源码路径 :kernel/msm-3.18/kernel/power/process.c
c
void thaw_processes(void) {
struct task_struct *g, *p;
struct task_struct *curr = current;
if (pm_freezing)
atomic_dec(&system_freezing_cnt);
pm_freezing = false;
pm_nosig_freezing = false;
oom_killer_enable(); // 重新启用 OOM killer
__usermodehelper_set_disable_depth(UMH_FREEZING); // 设置用户态助手状态
thaw_workqueues(); // 恢复工作队列
read_lock(&tasklist_lock);
for_each_process_thread(g, p) {
__thaw_task(p); // 解冻每个任务
}
read_unlock(&tasklist_lock);
curr->flags &= ~PF_SUSPEND_TASK;
usermodehelper_enable(); // 启用用户态助手
schedule(); // 让被唤醒的进程运行
}
关键设计 :
thaw_processes()不只是简单唤醒------它还恢复工作队列、重启用 OOM killer、设置用户态助手状态。最后调用
schedule()让被解冻的进程立即获得 CPU 时间。
__thaw_task() 的实际实现在另一个文件中:
源码路径 :kernel/msm-3.18/kernel/freezer.c
c
void __thaw_task(struct task_struct *p) {
unsigned long flags;
spin_lock_irqsave(&freezer_lock, flags);
if (frozen(p))
wake_up_process(p);
spin_unlock_irqrestore(&freezer_lock, flags);
}
关键设计 :
__thaw_task()逻辑非常简洁------加锁、检查frozen(p)、调用wake_up_process(p)。注意它不是
static函数,而是全局导出的,供其他内核模块调用。
四、Native 层 --- libsuspend 的唤醒检测
先来回顾一下系统休眠时Kernel层的调用链。
4.0 系统休眠时Native层的调用链。
JNI层
nativeSetAutoSuspend(true)
→ autosuspend_enable()
Native层 (libsuspend)
autosuspend_enable()
→ autosuspend_init() 选择 wakeup_count 实现(autosleep 已被 #if 0 禁用)
→ autosuspend_wakeup_count_enable() 释放信号量
→ 休眠线程: read wakeup_count → write wakeup_count → write "mem" 到 /sys/power/state
在第五篇休眠全链路中,libsuspend 的休眠线程通过 write("/sys/power/state", "mem") 触发内核休眠。这个
write() 是阻塞调用 ------系统休眠时执行流暂停在此,内核唤醒后 write() 返回,线程继续执行。这就是
libsuspend "检测到唤醒"的机制。
具体流程:
- 休眠前 :libsuspend 线程调用
write(state_fd, "mem", 3),执行流阻塞在内核的state_store()中 - 内核休眠:CPU 进入 deep sleep,libsuspend 线程也随进程一起被冻结
- 内核唤醒 :内核恢复流程执行到
suspend_finish()→thaw_processes(),解冻所有用户进程 - write 返回 :libsuspend 线程被解冻后,
write()返回,线程继续执行回调通知上层
内核完成恢复后,用户空间的 libsuspend 检测到系统已唤醒,通知 Java 层开始亮屏流程。
4.1 wakeup_count 模式的唤醒处理
libsuspend 使用 wakeup_count 模式管理休眠唤醒。suspend_thread_func 线程在循环中先读取
wakeup_count,写入 /sys/power/state 触发休眠。write() 是阻塞调用------系统休眠时执行流暂停在此,被唤醒后返回:
源码路径 :system/core/libsuspend/autosuspend_wakeup_count.c
c
static void *suspend_thread_func(void *arg __attribute__((unused))) {
char buf[80];
char wakeup_count[20];
int wakeup_count_len;
int ret;
bool success;
while (1) {
usleep(100000);
// 1. 读取当前 wakeup_count
lseek(wakeup_count_fd, 0, SEEK_SET);
wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
sizeof(wakeup_count)));
// 2. 等待信号量(enable 时 post,disable 时 wait)
ret = sem_wait(&suspend_lockout);
// 3. 写入 wakeup_count(确保休眠期间无新唤醒事件)
success = true;
ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
if (ret < 0) {
success = false;
} else {
// 4. 写入 "mem" 到 /sys/power/state --- 阻塞直到唤醒
ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
if (ret < 0) {
success = false;
}
}
// 5. 唤醒后,调用回调通知上层
void (*func)(bool success) = wakeup_func;
if (func != NULL) {
(*func)(success);
}
sem_post(&suspend_lockout);
}
return NULL;
}
关键设计 :
write(state_fd, "mem", ...)是用户空间感知唤醒的核心机制------系统休眠时执行流阻塞在此,内核唤醒后
write()返回,线程随即调用wakeup_func回调通知上层。TEMP_FAILURE_RETRY宏用于处理EINTR中断,确保系统调用被完整执行。
4.2 JNI 回调
唤醒后,libsuspend 通过 JNI 通知 Java 层:
源码路径 :frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
cpp
// 当检测到系统唤醒时
nativeSetAutoSuspend(env, clazz, JNI_FALSE);
// → autosuspend_disable()
关键设计 :JNI 层只是一个简单的转发,真正的逻辑在
libsuspend库中实现。
五、Java 层 --- PMS.wakeUp() 的状态机
Native 层通知唤醒后,Java 层的 PowerManagerService 开始执行唤醒流程。与休眠流程对称:
wakeUpNoUpdateLocked() 修改标记,updatePowerStateLocked() 执行操作。
5.1 wakeUp() 入口
源码路径 :frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
// ...
private final Object mLock = new Object(); // PMS 内部锁
@Override // Binder call
public void wakeUp(long eventTime, String reason, String opPackageName) {
// ... 权限检查、获取 uid ...
final long ident = Binder.clearCallingIdentity();
try {
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void wakeUpInternal(long eventTime, String reason, int uid,
String opPackageName, int opUid) {
synchronized (mLock) {
if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
updatePowerStateLocked(); ←核心状态机
}
}
}
}
关键设计 :与休眠流程完全对称------
wakeUpNoUpdateLocked()只修改标记,updatePowerStateLocked()根据标记执行实际状态变更。
5.2 wakeUpNoUpdateLocked()
源码路径 :frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
java
public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
// ...
private int mWakefulness; // 当前唤醒状态
private int mDirty; // 状态变更标记位
private long mLastWakeTime; // 最近一次唤醒时间
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep (uid " + reasonUid + ")...");
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream (uid " + reasonUid + ")...");
break;
case WAKEFULNESS_DOZING:
Slog.i(TAG, "Waking up from dozing (uid " + reasonUid + ")...");
break;
}
mLastWakeTime = eventTime;
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
return true;
}
}
关键设计 :
wakeUpNoUpdateLocked()先做前置检查(时间合法性、是否已唤醒、系统是否就绪),然后通过
switch打印不同唤醒来源的日志,最后设置状态为 AWAKE 并通知 Notifier。参数中的reason/reasonUid和
opPackageName/opUid分别来自调用者和被调用的 App Ops。
5.3 updatePowerStateLocked() --- 唤醒的 Phase 处理
与休眠使用相同的 updatePowerStateLocked(),但 mDirty 标记导致不同的分支:
Phase 1: updateWakeLockSummaryLocked()
唤醒后,PMS 重新获取 SCREEN_BRIGHT_WAKE_LOCK,确保屏幕点亮期间系统不休眠回去。
Phase 2: updateUserActivitySummaryLocked()
重置用户活动计时器,根据 mScreenOffTimeout 设置下一次超时休眠的时间。
Phase 3: updateWakefulnessLocked()
状态已从 ASLEEP 跳转为 AWAKE,此阶段无需额外操作。
Phase 4: updateDisplayPowerStateLocked()
这是唤醒中最关键的一步------点亮屏幕。
5.4 DisplayPowerController --- 屏幕点亮时序
源码路径 :
frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
java
final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
// ...
private DisplayPowerState mDisplayPowerState; // 显示状态管理
private DisplayPowerRequest mPowerRequest; // 当前显示策略请求
private void updatePowerState() {
// 根据 mPowerRequest.policy 决定显示状态
int state;
switch (mPowerRequest.policy) {
case DisplayPowerRequest.POLICY_OFF:
state = Display.STATE_OFF;
break;
case DisplayPowerRequest.POLICY_DOZE:
state = Display.STATE_DOZE;
break;
case DisplayPowerRequest.POLICY_BRIGHT:
default:
state = Display.STATE_ON;
break;
}
// 更新显示状态(触发屏幕点亮/熄灭)
mDisplayPowerState.setState(state);
}
}
关键设计 :
DisplayPowerController根据mPowerRequest.policy决定显示状态,通过
DisplayPowerState.setState()向下传递到 SurfaceFlinger → Hardware Composer → 显示驱动。
屏幕点亮的硬件路径:
DisplayPowerController
→ DisplayManagerService
→ SurfaceFlinger (native)
→ Hardware Composer (HWC)
→ 显示驱动 → 实际物理屏幕通电、显示
5.5 updateSuspendBlockerLocked()
唤醒阶段,PMS 重新获取两个关键 suspend_blocker:
| suspend_blocker | 职责 | 获取时机 |
|---|---|---|
PowerManagerService.Display |
确保屏幕点亮期间不休眠 | 屏幕点亮前 |
PowerManagerService.WakeLocks |
汇总所有活跃应用 WakeLock | 应用持有 WakeLock 时 |
六、唤醒后的收尾 --- 锁屏与按键处理
屏幕点亮后,系统还需要处理一些收尾工作:分发按键事件、显示锁屏界面、发送唤醒广播。
6.1 按键事件分发
唤醒由按键触发时(如电源键),PhoneWindowManager 在休眠前拦截了按键事件。唤醒后,PhoneWindowManager
需要处理该事件------通常是显示锁屏界面。
源码路径 :frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
java
public class PhoneWindowManager implements WindowManagerPolicy {
// ...
private boolean mInteractive; // 屏幕是否处于交互状态
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
// ... 其他按键处理 ...
}
return result;
}
}
关键设计 :
PhoneWindowManager在按键事件分发链的最前端,通过policyFlags中的
FLAG_INTERACTIVE判断屏幕状态。电源键事件始终被拦截(result &= ~ACTION_PASS_TO_USER),不会传递给应用,而是由
interceptPowerKeyDown()处理唤醒/锁屏逻辑。
6.2 Keyguard(锁屏)显示
源码路径 :
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
唤醒后,KeyguardViewMediator 判断是否需要显示锁屏:
- 如果没有安全锁(PIN/图案/密码),直接显示滑动解锁
- 如果有安全锁,显示对应解锁界面
- 如果设置了 Smart Lock(信任设备/地点),自动解锁
6.3 Notifier 的唤醒广播
源码路径 :frameworks/base/services/core/java/com/android/server/power/Notifier.java
java
final class Notifier {
// ...
private final IActivityManagerInternal mActivityManagerInternal; // ActivityManager 内部接口
private boolean mInteractive; // 当前是否处于交互状态
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
// 通知 ActivityManager 唤醒状态变更
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});
// 如果交互状态发生变化,发送广播
if (mInteractive != interactive) {
// ... 发送交互状态变更广播 ...
}
}
}
关键设计 :
Notifier通过onWakefulnessChangeStarted()接收唤醒通知,先通过 Handler 异步通知
ActivityManagerInternal,再根据交互状态是否变化决定是否发送广播。整个通知流程异步执行,不阻塞唤醒主路径。
七、唤醒流程完整调用链
唤醒源触发
│ GPIO按键 / RTC Alarm / Modem事件 / USB事件
▼
中断控制器 → CPU退出WFI → 跳转到唤醒入口
│
▼
Kernel层 (逆序恢复)
suspend_enter() 返回
→ syscore_resume() [恢复non-boot CPU、时钟、中断控制器]
→ arch_suspend_enable_irqs() [重新开启中断]
→ enable_nonboot_cpus() [恢复非启动CPU]
suspend_devices_and_enter() 返回
→ platform_resume_noirq() [平台无中断恢复]
→ dpm_resume_noirq() [设备无中断恢复]
→ dpm_resume_early() [设备早期恢复]
enter_state() 继续
→ suspend_finish()
→ thaw_processes() [解冻所有用户进程]
│
▼
Native层
write("/sys/power/state", "mem") 返回 [wakeup_count模式]
→ wakeup_func回调
│
▼
JNI层
nativeSetAutoSuspend(false)
→ autosuspend_disable()
│
▼
Java层 (Framework)
PMS.wakeUp()
→ wakeUpInternal()
→ wakeUpNoUpdateLocked()
setWakefulnessLocked(WAKEFULNESS_AWAKE)
mDirty |= DIRTY_WAKEFULNESS | DIRTY_DISPLAY_POWER | DIRTY_WAKE_LOCKS
→ updatePowerStateLocked() [PMS核心状态机]
→ updateWakeLockSummaryLocked() [重新获取WakeLock]
→ updateUserActivitySummaryLocked() [重置超时计时器]
→ updateWakefulnessLocked() [状态确认]
→ updateDisplayPowerStateLocked() [点亮屏幕]
→ DisplayPowerController.setState()
→ SurfaceFlinger → HWC → 显示驱动 → 物理亮屏
→ updateScreenBrightnessLocked() [恢复亮度]
→ updateSuspendBlockerLocked() [重获suspend_blocker]
│
▼
PhoneWindowManager → 分发按键 / 显示锁屏
KeyguardViewMediator → 显示解锁界面
Notifier → 广播 SCREEN_ON / WAKEFULNESS_AWAKE
八、唤醒 vs 开机的核心区别
将唤醒流程与第二篇的开机流程对比,一目了然:
| 开机阶段 | 唤醒中对应的操作 |
|---|---|
| BootROM → BootLoader → Kernel 启动 | ❌ 跳过,内核一直保持运行 |
| init → 守护进程启动 | ❌ 跳过,进程仅解冻 |
| Zygote 预加载类 | ❌ 跳过,ART 堆内存保留 |
| SystemServer 三阶段启动服务 | ❌ 跳过,服务仅恢复调度 |
| Launcher 冷启动 | ❌ 跳过,Activity 栈保留 |
| --- | ✅ 从中断唤醒 CPU |
| --- | ✅ 恢复非 boot CPU |
| --- | ✅ 恢复设备驱动 |
| --- | ✅ 解冻进程 |
| --- | ✅ 点亮屏幕 |
唤醒跳过了开机的 所有初始化工作 ,只做了三件事:恢复 CPU → 恢复设备 → 解冻进程。这就是为什么唤醒能在亚秒级完成。
九、小结
唤醒全链路的核心路径:
- 唤醒源触发 → 中断控制器唤醒 CPU
- 内核恢复:syscore → devices → IRQ,逆序恢复
- thaw_processes():解冻而非重启所有进程
- libsuspend 检测:write() 返回,通知 Java 层
- PMS.wakeUp():状态机从 ASLEEP → AWAKE
- 亮屏:DisplayPowerController → HWC → 物理点屏
- 收尾:锁屏显示、按键处理、通知广播
整个过程在 1 秒内完成。与关机→开机的 30-60 秒相比,唤醒的速度优势来自"状态保持"的核心设计------所有数据都在
RAM 中原地等待,恢复仅是"解冻"。