Android 7系统休眠唤醒(六)唤醒全链路

**系列目录

**:第一篇:电源管理架构全景图 | 第二篇:开机全链路---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_resumeenable_irqsenable_nonboot_cpusplatform_resume_noirq

dpm_resume_noirqplatform_resume_earlydpm_resume_earlyplatform_resume_finishgoto

标签同时也是错误处理的跳转目标:休眠过程中任何阶段失败,都会跳到对应的恢复标签,确保已执行的操作被正确回滚。

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 "检测到唤醒"的机制。

具体流程:

  1. 休眠前 :libsuspend 线程调用 write(state_fd, "mem", 3),执行流阻塞在内核的 state_store()
  2. 内核休眠:CPU 进入 deep sleep,libsuspend 线程也随进程一起被冻结
  3. 内核唤醒 :内核恢复流程执行到 suspend_finish()thaw_processes(),解冻所有用户进程
  4. 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 → 恢复设备 → 解冻进程。这就是为什么唤醒能在亚秒级完成。


九、小结

唤醒全链路的核心路径:

  1. 唤醒源触发 → 中断控制器唤醒 CPU
  2. 内核恢复:syscore → devices → IRQ,逆序恢复
  3. thaw_processes():解冻而非重启所有进程
  4. libsuspend 检测:write() 返回,通知 Java 层
  5. PMS.wakeUp():状态机从 ASLEEP → AWAKE
  6. 亮屏:DisplayPowerController → HWC → 物理点屏
  7. 收尾:锁屏显示、按键处理、通知广播

整个过程在 1 秒内完成。与关机→开机的 30-60 秒相比,唤醒的速度优势来自"状态保持"的核心设计------所有数据都在

RAM 中原地等待,恢复仅是"解冻"。

相关推荐
雨白2 小时前
深入理解 Kotlin 协程 (九):互通有无,解构 Channel 缓冲策略与底层无锁机制
android·kotlin
灯塔@kuaidao4 小时前
平台交叉编译名词解释与基础流程
android
__Witheart__4 小时前
3568 Android otg模式下adb热拔插不识别
android·adb·rockchip
明天…ling6 小时前
Upload-Labs (Pass1-Pass21) 完整通关思路与源码分析
android·网络安全·渗透测试·burpsuite·upload-labs·文件上传绕过·靶场复现
__Witheart__6 小时前
3568 Android ntp校时使用
android·rockchip
wddptwd287 小时前
android studio 报错怎么处理 java.lang.NullPointerException
android·java·android studio
美狐美颜SDK开放平台8 小时前
直播APP开发,美颜SDK和相机SDK有什么区别?
android·深度学习·数码相机·ios·直播美颜sdk·视频美颜sdk
唐诺9 小时前
Android Open Accessory (AOA) 协议完全解析
android·usb·aoa
我命由我1234511 小时前
Android 开发 - 广播组件(标准广播、有序广播、静态注册广播、分钟到达广播、网络变更广播...)
android·java·开发语言·网络·java-ee·android studio·android-studio