理解Android的休眠与唤醒流程,需要从应用层 、框架层 一直深入到内核驱动层。为了帮你直观地看清这个复杂的协作过程,下图展示了完整的架构与核心流程:
请求休眠/持有WakeLock ioctl/系统调用 中断/事件 广播/回调 Linux内核层 Wakeup Source
唤醒源跟踪 Suspend/Resume流程
及状态机 系统服务层 PowerManagerService
核心协调器 Native空间
JNI桥接 应用框架层 PowerManager 应用/WakeLock/Alarm
上图揭示了各层级的关键角色:应用层发起请求,PowerManagerService作为"总指挥",而内核层则负责硬件层面的最终执行。
🔍 核心流程详解与代码日志分析
下面我们结合你提供的日志片段,对休眠和唤醒这两个主要流程进行拆解。
1. 休眠流程:从应用到内核的层层关停
完整的休眠是一个由应用触发、最终由内核执行的"关停"过程:
-
应用层请求 :当需要休眠时(如超时、按电源键),会调用
PowerManager.goToSleep()。拥有系统权限的应用才能调用此方法。 -
框架层协调 :
PowerManagerService收到请求后,会先检查是否有唤醒锁 阻止休眠。这是关键检查点,可以参考一个早期但原理一致的代码逻辑:c// kernel/power/wakelock.c (简化示例,说明机制) static long has_wake_lock_locked(int type) { struct wake_lock *lock; list_for_each_entry(lock, &active_wake_locks[type], link) { if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE)) { printk("lockname = %s,lockflag = 0x%x\n", lock->name, lock->flags); return -1; // 返回-1,表示有非自动释放的锁阻止休眠 } } return 0; // 返回0,表示没有锁阻止,可以休眠 }代码注释 :这个函数遍历活跃的唤醒锁列表。如果存在
WAKE_LOCK_AUTO_EXPIRE(非自动释放)类型的锁,系统就无法进入休眠。 -
内核层执行 :如果没有唤醒锁阻止,
PowerManagerService会通过 JNI 和 sysfs 接口,向内核写入mem或standby等状态,触发内核的全局休眠流程 。这包括:- 冻结用户进程 :日志中出现的
Freezing user space processes ... (elapsed 0.017 seconds) done.就是这个阶段。 - 挂起外围设备 :内核会依次调用各设备驱动的
suspend回调函数。在你之前的日志中,[TP]ILITEK: ilitek_spi_suspend、mtk-msdc ... suspend就是触屏、存储等设备进入低功耗状态。 - 系统核心挂起:最后,CPU进入特定的低功耗状态。
- 冻结用户进程 :日志中出现的
2. 唤醒流程:从硬件中断到应用响应
唤醒通常由硬件中断发起,是一个"启动"过程:
-
硬件中断 :唤醒源(如电源键、网络中断、RTC闹钟)产生硬件中断。你日志中的
Resume caused by IRQ 138, wlan0明确指示了唤醒源头是Wi-Fi中断。 -
内核响应与日志记录 :Linux内核的
wakeup_reason基础设施会记录导致唤醒的中断号(IRQ)或唤醒源(wakeup_source) 。这就是你日志开头部分记录的由来。其核心实现逻辑简化如下:c// drivers/base/power/wakeup.c (相关逻辑) void pm_system_irq_wakeup(unsigned int irq_number) { if (pm_wakeup_irq == 0) { log_irq_wakeup_reason(irq_number); // 记录唤醒原因 pm_wakeup_irq = irq_number; pm_system_wakeup(); // 触发系统唤醒 } }代码注释 :当中断触发唤醒时,
pm_system_irq_wakeup被调用。log_irq_wakeup_reason(irq_number)会将这个中断号记录下来,最终可以通过/sys/power/last_wakeup_reason读取。 -
恢复系统与设备 :内核沿着休眠的逆序恢复:CPU核心 -> 系统总线 -> 设备驱动 (调用
resume函数)-> 解冻进程。 -
框架层与应用层通知 :
PowerManagerService被通知后,会更新系统状态,并发送ACTION_SCREEN_ON等广播。应用可以接收这些广播来执行恢复操作。
💎 总结与问题回顾
综上所述,Android的休眠唤醒是一个涉及软硬件多层级的状态机协作。其核心在于 PowerManagerService 作为中央协调器,基于唤醒锁 策略和硬件唤醒源事件,指挥内核完成状态切换。
回顾你最初日志中遇到的 "eMMC访问违例"问题 ,其根源正是在这个精密的协作流程中出现了时序竞争 :系统在休眠流程中已经开始挂起eMMC控制器(释放时钟/电源),但此时安全子系统(TEE)的RPMB操作仍在进行,导致非法访问。这通常需要在驱动或系统层面增加同步机制,确保关键操作在器件下电前完成。
如果你想进一步探讨,我们可以深入某个具体环节,例如:
- 唤醒锁的具体类型和应用场景(如保持CPU唤醒或屏幕唤醒)。
- Android Doze模式等更深度的电源优化策略。
- 如何利用
/sys/power/wakeup_sources或dumpsys power命令进行实际的功耗问题调试。
欢迎你提出更具体的方向。