系列目录:第一篇:电源管理架构全景图 | 第二篇:开机全链路—BootROM到Launcher | 第三篇:关机/重启全链路—ShutdownThread到kernel_power_off | 第四篇:休眠唤醒与开关机—核心差异深度对比 | 第五篇:休眠全链路—PMS到Kernel Suspend | 第六篇:唤醒全链路—Kernel Resume到屏幕点亮 | 第七篇:内核层—wakelock与autosleep机制 | 第八篇:内核层—Alarm定时唤醒与硬件唤醒源 | 第九篇:Native层—libsuspend与Power HAL | 第十篇:实战调试与问题排查
一、为什么要深入理解休眠流程
你可能遇到过这些问题:
- 按下电源键后屏幕黑了,但系统真的休眠了吗?为什么有时按电源键没反应?
- 应用持有 WakeLock 不释放,系统就无法休眠——这个"无法休眠"到底发生在哪一层?
- 从 Java 层的
goToSleep()到 CPU 执行 WFI 指令,中间经历了多少次状态跳转?
本篇从 PowerManagerService 一路下穿到内核的 pm_suspend(),完整追踪一次休眠操作的调用链。不讨论原理(原理见第四篇),只追踪代码。
二、休眠全链路概览
在进入细节之前,先建立全局视角。一次完整的休眠操作从 Java 层一路贯穿到内核层,经历以下层次:
Java层 (Framework)
PowerManager.goToSleep()
→ PMS.BinderService.goToSleep() [权限检查]
→ goToSleepInternal()
→ goToSleepNoUpdateLocked()
setWakefulnessLocked(WAKEFULNESS_DOZING, reason)
→ updatePowerStateLocked() [PMS 核心状态机]
→ updateWakeLockSummaryLocked() [汇总 WakeLock]
→ updateUserActivitySummaryLocked() [检测超时]
→ updateWakefulnessLocked() [判断 bedtime]
→ reallyGoToSleepNoUpdateLocked() [DOZING → ASLEEP]
→ updateDisplayPowerStateLocked() [关闭屏幕]
→ updateSuspendBlockerLocked() [释放 suspend_blocker]
→ nativeSetAutoSuspend(true)
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
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
下面按调用链顺序逐层拆解。
三、休眠触发入口
休眠有三种触发方式,但最终都汇聚到 goToSleepNoUpdateLocked()——修改唤醒状态标记的核心方法。区别在于进入方式:电源键和应用调用通过 Binder 入口 goToSleep() 进入,超时则通过状态机 updateWakefulnessLocked() 进入。
3.1 应用调用 PowerManager.goToSleep()
任何持有 android.permission.DEVICE_POWER 权限的应用都可以调用 PowerManager.goToSleep() 主动触发休眠:
源码路径:frameworks/base/core/java/android/os/PowerManager.java
public final class PowerManager {
// ...
final IPowerManager mService; // Binder 代理,指向 PowerManagerService
public void goToSleep(long time) {
goToSleep(time, GO_TO_SLEEP_REASON_APPLICATION, 0);
}
public void goToSleep(long time, int reason, int flags) {
try {
mService.goToSleep(time, reason, flags); // Binder 调用到 PMS
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
private final class BinderService extends IPowerManager.Stub {
@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {
goToSleepInternal(eventTime, reason, flags, uid);
}
}
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
protected void updatePowerStateLocked() {
updateSuspendBlockerLocked();
}
private void setHalAutoSuspendModeLocked(boolean enable) {
nativeSetAutoSuspend(enable);
}
}
关键设计:
PowerManager.goToSleep()只是一个 Binder 代理层——通过mService(IPowerManager)跨进程调用PowerManagerService,三种触发方式在此汇聚。
完整调用链:
应用调用 PowerManager.goToSleep()
→ mService.goToSleep(time, reason, flags) [Binder]
→ PowerManagerService.goToSleepInternal()
3.2 超时自动休眠
用户一段时间不操作屏幕,屏幕超时后自动进入休眠。这是最常见的休眠场景。
1. 定时器设置:updateUserActivitySummaryLocked() 根据用户最后活动时间计算下一次超时时间,并通过 Handler 发送延时消息:
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private int mUserActivitySummary; // 用户活动状态标志
private long mLastUserActivityTime; // 最后一次用户活动时间
private final PowerManagerHandler mHandler; // PMS 内部 Handler
private void updateUserActivitySummaryLocked(long now, int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); // 移除旧消息
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
// 计算屏幕变暗的时间点
nextTimeout = mLastUserActivityTime + screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
// 计算屏幕关闭的时间点
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
// 如果用户活动已超时,发送延时消息
if (mUserActivitySummary == 0) {
// ... 省略: 处理 sleepTimeout 和 dream 模式 ...
}
// 发送超时消息
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout); // 在 nextTimeout 时刻触发
}
}
}
}
}
关键设计:超时检测通过
Handler.sendMessageAtTime()实现精确定时。每次用户操作时调用userActivityNoUpdateLocked()更新mLastUserActivityTime,然后updateUserActivitySummaryLocked()重新计算超时时间并发送新消息。
2. 超时触发:消息超时后,handleUserActivityTimeout() 被调用:
public final class PowerManagerService extends SystemService {
// ...
private int mDirty; // 状态变更标记位
private int mWakefulness; // 当前唤醒状态
private void handleUserActivityTimeout() { // runs on handler thread
synchronized (mLock) {
mDirty |= DIRTY_USER_ACTIVITY; // 标记用户活动超时
updatePowerStateLocked(); // 触发状态机重新计算
}
}
protected void updatePowerStateLocked() {
updateWakefulnessLocked(dirtyPhase1);
}
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
// isItBedTimeYetLocked() 检查:
// - 所有 WakeLock 是否已释放
// - 用户活动是否已超时
// - 是否满足其他休眠条件
changed = goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
}
}
return changed;
}
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
}
}
关键设计:超时休眠的完整路径是:定时器超时 →
handleUserActivityTimeout()→updatePowerStateLocked()→updateWakefulnessLocked()→goToSleepNoUpdateLocked()→setWakefulnessLocked(WAKEFULNESS_DOZING)。状态先跳转到 DOZING(Doze 模式),Doze 结束后再由reallyGoToSleepNoUpdateLocked()跳转到 ASLEEP。
完整调用链:
用户操作超时
→ updateUserActivitySummaryLocked() 计算超时时间
→ mHandler.sendMessageAtTime(MSG_USER_ACTIVITY_TIMEOUT, nextTimeout)
→ [超时后] handleUserActivityTimeout()
→ mDirty |= DIRTY_USER_ACTIVITY
→ updatePowerStateLocked()
→ updateWakefulnessLocked()
→ goToSleepNoUpdateLocked()
3.3 电源键短按
用户短按电源键,屏幕立即关闭并进入休眠。
1. 按键拦截:PhoneWindowManager 在 interceptKeyBeforeQueueing() 中拦截电源键事件,清除 ACTION_PASS_TO_USER 标志,阻止事件传递给应用层:
源码路径:frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public class PhoneWindowManager implements WindowManagerPolicy {
// ...
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
// ...
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER; // 不向上传递给应用
isWakeKey = false;
if (down) {
interceptPowerKeyDown(event, interactive); // 按键按下
} else {
interceptPowerKeyUp(event, interactive, canceled); // 按键释放
}
break;
}
}
return result;
}
}
关键设计:电源键事件在
PhoneWindowManager被拦截,ACTION_PASS_TO_USER标志被清除,应用不会收到电源键事件。goToSleep()的调用不在按键按下时,而是在按键释放时。
2. 按键释放触发休眠:interceptPowerKeyUp() 在按键释放时调用 powerPress(),根据短按行为配置决定是否休眠:
public class PhoneWindowManager implements WindowManagerPolicy {
// ...
private int mPowerKeyPressCounter; // 按键计数(用于多击检测)
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled;
// ... 省略: 取消截图组合键等 ...
if (!handled) {
mPowerKeyPressCounter += 1;
final int maxCount = getMaxMultiPressPowerCount();
final long eventTime = event.getDownTime();
if (mPowerKeyPressCounter < maxCount) {
// 可能是多击,等待确认
Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
return;
}
// 确认是单次按键,立即处理
powerPress(eventTime, interactive, mPowerKeyPressCounter);
}
finishPowerKeyPress();
}
}
3. powerPress() 根据配置执行休眠:mShortPressOnPowerBehavior 决定短按行为,默认是 SHORT_PRESS_POWER_GO_TO_SLEEP:
public class PhoneWindowManager implements WindowManagerPolicy {
// ...
private int mShortPressOnPowerBehavior; // 短按电源键行为
private PowerManager mPowerManager; // 电源管理器
private void powerPress(long eventTime, boolean interactive, int count) {
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (interactive && !mBeganFromNonInteractive) {
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0); // 触发休眠
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); // 跳过 Doze 直接深度休眠
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
launchHomeFromHotKey(); // 休眠后回到桌面
break;
case SHORT_PRESS_POWER_GO_HOME:
// ... 省略: 回到桌面 ...
break;
}
}
}
}
关键设计:电源键休眠的完整路径是:按键释放 →
interceptPowerKeyUp()→powerPress()→mPowerManager.goToSleep()。mShortPressOnPowerBehavior配置决定短按行为:普通休眠、跳过 Doze 直接深度休眠、或休眠后回到桌面。
完整调用链:
KEYCODE_POWER 短按
→ interceptKeyBeforeQueueing() [拦截事件,不传递给应用]
→ [按下] interceptPowerKeyDown() [设置长按定时器、截图组合键检测等]
→ [释放] interceptPowerKeyUp()
→ powerPress(eventTime, interactive, count=1)
→ mShortPressOnPowerBehavior == SHORT_PRESS_POWER_GO_TO_SLEEP
→ mPowerManager.goToSleep(eventTime, GO_TO_SLEEP_REASON_POWER_BUTTON, 0)
→ BinderService.goToSleep()
→ PowerManagerService.goToSleepInternal()
四、PMS.goToSleep() — 休眠的 Java 层入口
所有休眠触发方式最终都汇聚到 PowerManagerService 的 goToSleepInternal()。这个方法是休眠的 Java 层入口。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private final Object mLock = new Object(); // PMS 内部锁
// Binder 回调内部类
private final class BinderService extends IPowerManager.Stub {
// ...
@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {
// 权限检查
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked(); // 核心状态机
}
}
}
}
关键设计:核心两步——
goToSleepNoUpdateLocked()修改状态标记,返回true时调用updatePowerStateLocked()执行实际状态变更。权限检查在 Binder 线程完成,状态操作在持锁后执行。
五、goToSleepNoUpdateLocked() — 状态标记修改
goToSleepNoUpdateLocked() 只修改标记,不做实际操作。这是 PMS 的典型设计模式:NoUpdateLocked 系列方法只负责状态计算,真正的副作用由 updatePowerStateLocked() 统一执行。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private int mWakefulness; // 当前唤醒状态
private int mDirty; // 状态变更标记位
private long mLastSleepTime; // 最近一次休眠时间
private boolean mSandmanSummoned; // 是否正在召唤 Doze
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
// 前置校验:时间异常或已处于休眠/Doze状态则跳过
if (eventTime < mLastWakeTime
|| mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
// ... 省略: 根据 reason 打印不同日志 ...
mLastSleepTime = eventTime;
mSandmanSummoned = true;
setWakefulnessLocked(WAKEFULNESS_DOZING, reason); // 状态跳转:AWAKE → DOZING
// ... 省略: 统计将被清除的 WakeLock 数量 ...
// 如果指定了 NO_DOZE 标志,跳过 Doze 直接进入深度休眠
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
return true;
}
}
关键设计:方法名中的
NoUpdateLocked表明它只修改标记、不触发副作用。核心操作是setWakefulnessLocked(WAKEFULNESS_DOZING, reason)将状态从 AWAKE 跳转到 DOZING(而非直接到 ASLEEP)。DOZING 是 Doze 模式的过渡状态,如果指定了NO_DOZE标志则跳过 Doze 直接调用reallyGoToSleepNoUpdateLocked()。
mWakefulness 的四个取值:
| 值 | 常量 | 含义 |
|---|---|---|
| 0 | WAKEFULNESS_AWAKE | 清醒(正在使用) |
| 1 | WAKEFULNESS_DREAMING | 屏保/互动屏保(Android 4.2+) |
| 2 | WAKEFULNESS_DOZING | 正在进入休眠(过渡状态) |
| 3 | WAKEFULNESS_ASLEEP | 已休眠 |
六、updatePowerStateLocked() — 状态机核心调度
updatePowerStateLocked() 是 PMS 最核心的函数。每当 mDirty 不为零时调用,根据标记位按 Phase 顺序执行相应的状态更新。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private boolean mSystemReady; // 系统是否就绪
private int mDirty; // 状态变更标记位
private boolean mDisplayReady; // 显示是否就绪
protected void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
// Phase 0: 基础状态更新
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: 更新唤醒状态(循环,因为 wakefulness 变化会影响 WakeLock 计算)
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: 更新显示电源状态(屏幕开关)
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 3: 更新 Dream 状态
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 4: 完成唤醒状态变更通知
finishWakefulnessChangeIfNeededLocked();
// Phase 5: 管理 suspend blocker(必须最后执行)
updateSuspendBlockerLocked();
}
}
关键设计:六个 Phase 按固定顺序执行。Phase 1 使用循环结构——因为唤醒状态的变化可能影响 WakeLock 和用户活动的计算,需要迭代直到稳定。Phase 5 必须最后执行,因为释放 suspend blocker 可能触发内核休眠。
当执行休眠路径时,各 Phase 行为如下:
6.1 updateWakeLockSummaryLocked() — 汇总 WakeLock
遍历所有活跃 WakeLock,将它们的类型汇总到 mWakeLockSummary 标志位中。休眠路径关心的是 WAKE_LOCK_CPU 标志——如果为 0,说明没有应用持有 CPU 唤醒锁。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private int mWakeLockSummary; // 活跃 WakeLock 聚合标志位
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
// 遍历所有 WakeLock,按类型汇总标志位
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_CPU;
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
break;
case PowerManager.DOZE_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DOZE;
break;
// ... 省略: 其他 WakeLock 类型 ...
}
}
// 根据当前状态裁剪无意义的标志位
if (mWakefulness != WAKEFULNESS_DOZING) {
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
if (mWakefulness == WAKEFULNESS_ASLEEP) {
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT | WAKE_LOCK_PROXIMITY_SCREEN_OFF);
}
}
}
}
关键设计:
mWakeLockSummary是所有活跃 WakeLock 的"或"聚合。休眠时如果WAKE_LOCK_CPU为 0,说明没有应用阻止休眠。注意裁剪逻辑:ASLEEP 状态下,屏幕相关的 WakeLock 标志会被清除,因为它们已经没有意义。
6.2 updateUserActivitySummaryLocked() — 超时检测
计算用户活动超时时间,通过 Handler 发送延时消息。超时后触发 DIRTY_USER_ACTIVITY 标记,驱动状态机进入休眠流程。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private int mUserActivitySummary; // 用户活动状态标志
private long mLastUserActivityTime; // 最后一次用户活动时间
private final PowerManagerHandler mHandler; // PMS 内部 Handler
private void updateUserActivitySummaryLocked(long now, int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
// 计算屏幕变暗的时间点
nextTimeout = mLastUserActivityTime + screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
// 计算屏幕关闭的时间点
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
// 发送超时消息
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
}
}
}
}
关键设计:超时检测分两个阶段:先
USER_ACTIVITY_SCREEN_BRIGHT(屏幕亮),再USER_ACTIVITY_SCREEN_DIM(屏幕暗),最后超时。每次用户操作时mLastUserActivityTime更新,定时器重新计算。
6.3 updateWakefulnessLocked() — 状态跳转
当 mDirty 包含休眠相关标记时,判断是否需要进入休眠。如果是 bedtime,调用 goToSleepNoUpdateLocked() 触发休眠流程:
public final class PowerManagerService extends SystemService {
// ...
private int mWakefulness; // 当前唤醒状态
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
// ... 省略: 判断是否应该进入 Dream 模式 ...
changed = goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
}
}
return changed;
}
}
关键设计:
updateWakefulnessLocked()不是直接设置 ASLEEP,而是再次调用goToSleepNoUpdateLocked()进入 DOZING 状态。真正的 DOZING → ASLEEP 跳转发生在 Doze 流程结束后,由reallyGoToSleepNoUpdateLocked()完成。
6.4 reallyGoToSleepNoUpdateLocked() — 最终休眠
Doze 流程结束后,调用此方法完成最终的状态跳转:
public final class PowerManagerService extends SystemService {
// ...
private int mWakefulness; // 当前唤醒状态
// Done dozing, drop everything and go to sleep.
private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
|| !mBootCompleted || !mSystemReady) {
return false;
}
Slog.i(TAG, "Sleeping (uid " + uid + ")...");
setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
return true;
}
}
关键设计:
reallyGoToSleepNoUpdateLocked()将状态从 DOZING 跳转到 ASLEEP,这是休眠流程中最后一次状态变更。方法注释 “Done dozing, drop everything and go to sleep” 清晰说明了它的职责。
6.5 updateDisplayPowerStateLocked() — 关闭屏幕
根据 mWakefulness 状态计算屏幕策略,调用 DisplayPowerController 调整屏幕亮度或关闭屏幕。屏幕关闭后设置 mDisplayReady = true。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private boolean mDisplayReady; // 显示是否就绪
private DisplayPowerRequest mDisplayPowerRequest; // 显示电源请求
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED)) != 0) {
// 根据 mWakefulness 计算屏幕策略
mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
// ... 省略: 计算屏幕亮度、自动亮度调整 ...
// 更新显示电源请求
mDisplayPowerRequest.screenBrightness = screenBrightness;
mDisplayPowerRequest.screenAutoBrightnessAdjustment =
screenAutoBrightnessAdjustment;
mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
// 调用 DisplayPowerController 应用请求
mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
}
// 检查显示是否就绪
mDisplayReady = !mDisplayManagerInternal.isProximityPositive()
|| !mDisplayPowerRequest.useProximitySensor;
return mDisplayReady && !oldDisplayReady;
}
// 根据 mWakefulness 计算屏幕策略
private int getDesiredScreenPolicyLocked() {
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
return DisplayPowerRequest.POLICY_OFF;
case WAKEFULNESS_DOZING:
return DisplayPowerRequest.POLICY_DOZE;
case WAKEFULNESS_AWAKE:
return DisplayPowerRequest.POLICY_BRIGHT;
case WAKEFULNESS_DREAMING:
return DisplayPowerRequest.POLICY_BRIGHT;
}
return DisplayPowerRequest.POLICY_BRIGHT;
}
}
关键设计:
getDesiredScreenPolicyLocked()根据mWakefulness决定屏幕策略:AWAKE/DREAMING → 亮屏,DOZING → Doze 模式(低亮度),ASLEEP → 关屏。mDisplayReady为 true 表示屏幕状态已稳定,可以进入下一阶段。
6.6 updateSuspendBlockerLocked() — 管理 suspend blocker
管理两个关键的 suspend_blocker,决定是否允许内核休眠。当两个 blocker 都释放后,调用 nativeSetAutoSuspend(true) 允许内核休眠。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private int mWakeLockSummary; // 活跃 WakeLock 聚合标志位
private boolean mHoldingWakeLockSuspendBlocker; // 是否持有 WakeLock blocker
private boolean mHoldingDisplaySuspendBlocker; // 是否持有 Display blocker
private final SuspendBlocker mWakeLockSuspendBlocker; // WakeLock blocker
private final SuspendBlocker mDisplaySuspendBlocker; // Display blocker
private void updateSuspendBlockerLocked() {
// 判断是否需要持有 blocker
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
// 先获取需要的 blocker
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
// 再释放不需要的 blocker
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
// 如果 Display blocker 不需要了,允许内核自动休眠
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true); // → nativeSetAutoSuspend(true)
}
}
// 判断是否需要 Display blocker
private boolean needDisplaySuspendBlockerLocked() {
if (!mDisplayReady) {
return true; // 显示未就绪,需要保持 blocker
}
if (mDisplayPowerRequest.isBrightOrDim()) {
// 屏幕亮或暗,需要保持 blocker
return true;
}
// 屏幕关闭或 Doze 模式,可以释放 blocker
return false;
}
private void setHalAutoSuspendModeLocked(boolean enable) {
if (enable != mHalAutoSuspendModeEnabled) {
mHalAutoSuspendModeEnabled = enable;
nativeSetAutoSuspend(enable); // 调用 JNI 层
}
}
}
关键设计:两个 blocker 的释放条件:
WakeLockSuspendBlocker在mWakeLockSummary & WAKE_LOCK_CPU == 0时释放(无 CPU 唤醒锁);DisplaySuspendBlocker在needDisplaySuspendBlockerLocked()返回 false 时释放(屏幕关闭且显示就绪)。两个 blocker 都释放后,调用nativeSetAutoSuspend(true)允许内核休眠。
七、nativeSetAutoSuspend() — JNI 跨越
当 PMS 的 updateSuspendBlockerLocked() 判断可以进入休眠后,调用setHalAutoSuspendModeLocked方法,该方法通过 JNI 调用 Native 层的 autosuspend_enable(),开始进入底层休眠流程。
源码路径:frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
if (enable) {
autosuspend_enable(); // 启用自动休眠
} else {
autosuspend_disable(); // 禁用自动休眠
}
}
关键设计:JNI 层只是一个简单的转发,真正的逻辑在
libsuspend库中实现。注意函数签名使用了JNIEnv* /* env */注释掉未使用参数——这是 JNI 代码的常见风格。
八、libsuspend — Native 层休眠触发
libsuspend 是 Android 提供的用户空间库,负责与内核的休眠机制交互。它支持两种方式:wakeup_count 和 autosleep。
8.1 autosuspend_init() — 选择具体实现
autosuspend_enable() 首次调用时执行 autosuspend_init(),按优先级选择具体实现:
源码路径:system/core/libsuspend/autosuspend.c
static struct autosuspend_ops *autosuspend_ops; // 具体实现的函数指针
static bool autosuspend_enabled;
static bool autosuspend_inited;
static int autosuspend_init(void) {
if (autosuspend_inited) return 0;
// 优先级 1: earlysuspend(旧版本,当前源码已移除)
autosuspend_ops = autosuspend_earlysuspend_init();
if (autosuspend_ops) goto out;
// 优先级 2: autosleep(当前被 #if 0 禁用)
#if 0
autosuspend_ops = autosuspend_autosleep_init();
if (autosuspend_ops) goto out;
#endif
// 优先级 3: wakeup_count(当前默认实现)
autosuspend_ops = autosuspend_wakeup_count_init();
if (autosuspend_ops) goto out;
out:
autosuspend_inited = true;
return 0;
}
int autosuspend_enable(void) {
autosuspend_init(); // 首次调用时初始化
if (autosuspend_enabled) return 0;
autosuspend_ops->enable(); // 调用选中实现的 enable
autosuspend_enabled = true;
return 0;
}
关键设计:
autosuspend_init()通过函数指针autosuspend_ops实现策略选择。当前源码中autosleep被#if 0禁用,最终选中wakeup_count。autosuspend_wakeup_count_init()在初始化时打开/sys/power/state和/sys/power/wakeup_count,创建休眠线程(初始被信号量阻塞),然后返回函数指针表。
8.2 wakeup_count 方式 — 从初始化到休眠线程执行
autosuspend_wakeup_count_init() 在初始化阶段创建休眠线程,但线程立即被信号量阻塞。当 autosuspend_enable() 调用 autosuspend_ops->enable() 时,信号量被释放,休眠线程才开始工作:
源码路径:system/core/libsuspend/autosuspend_wakeup_count.c
static int state_fd; // /sys/power/state 的文件描述符
static int wakeup_count_fd; // /sys/power/wakeup_count 的文件描述符
static pthread_t suspend_thread; // 休眠线程
static sem_t suspend_lockout; // 信号量:控制休眠线程是否运行
static const char *sleep_state = "mem";
// 初始化:创建休眠线程(初始被信号量阻塞)
struct autosuspend_ops *autosuspend_wakeup_count_init(void) {
state_fd = open("/sys/power/state", O_RDWR);
wakeup_count_fd = open("/sys/power/wakeup_count", O_RDWR);
sem_init(&suspend_lockout, 0, 0); // 初始值 0 → 线程阻塞
pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL);
return &autosuspend_wakeup_count_ops;
}
// enable: 释放信号量,唤醒休眠线程
static int autosuspend_wakeup_count_enable(void) {
sem_post(&suspend_lockout); // 线程被唤醒,开始工作
return 0;
}
// disable: 获取信号量,阻塞休眠线程
static int autosuspend_wakeup_count_disable(void) {
sem_wait(&suspend_lockout); // 线程被阻塞,停止休眠
return 0;
}
关键设计:信号量
suspend_lockout是控制休眠线程的核心——enable()通过sem_post()释放线程,disable()通过sem_wait()阻塞线程。线程创建后不会立即休眠,只有enable()被调用后才开始执行休眠流程。
8.3 休眠线程 — 实际触发内核休眠
休眠线程被信号量唤醒后,循环执行 read → write wakeup_count → write “mem” 流程:
源码路径:system/core/libsuspend/autosuspend_wakeup_count.c
// 休眠线程:循环执行 read → wait → write → write 流程
static void *suspend_thread_func(void *arg) {
while (1) {
usleep(100000);
// 1. 读取当前 wakeup_count
lseek(wakeup_count_fd, 0, SEEK_SET);
read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count));
// 2. 等待信号量(enable 时 post,disable 时 wait)
sem_wait(&suspend_lockout);
// 3. 写入 wakeup_count 确认无新唤醒事件
write(wakeup_count_fd, wakeup_count, wakeup_count_len);
// 4. 写入 "mem" 到 /sys/power/state 触发休眠
write(state_fd, sleep_state, strlen(sleep_state));
sem_post(&suspend_lockout);
}
}
关键设计:步骤 4 的
write()是阻塞调用——系统休眠时执行流暂停在此,内核唤醒后write()返回,线程随即调用wakeup_func回调通知上层。TEMP_FAILURE_RETRY宏用于处理EINTR中断,确保系统调用被完整执行。
8.4 autosleep 方式 — 内核自动管理(已被禁用)
除了 wakeup_count 方式外,libsuspend 还支持另一种实现:autosleep。在 8.1 节的 autosuspend_init() 中,autosleep 被 #if 0 禁用,但源码仍然保留。作为对比,了解 autosleep 的实现有助于理解两种方式的差异:
源码路径:system/core/libsuspend/autosuspend_autosleep.c
static int autosleep_fd; // /sys/power/autosleep 的文件描述符
static const char *sleep_state = "mem"; // 休眠状态
static const char *on_state = "off"; // 唤醒状态
static int autosuspend_autosleep_enable(void) {
// 写入 "mem" 到 /sys/power/autosleep
write(autosleep_fd, sleep_state, strlen(sleep_state));
return 0;
}
static int autosuspend_autosleep_disable(void) {
// 写入 "off" 到 /sys/power/autosleep
write(autosleep_fd, on_state, strlen(on_state));
return 0;
}
struct autosuspend_ops autosuspend_autosleep_ops = {
.enable = autosuspend_autosleep_enable,
.disable = autosuspend_autosleep_disable,
};
struct autosuspend_ops *autosuspend_autosleep_init(void)
{
autosleep_fd = open("/sys/power/autosleep", O_WRONLY);
autosuspend_autosleep_disable();
return &autosuspend_autosleep_ops;
}
关键设计:
autosleep方式比wakeup_count简单得多——只需写入/sys/power/autosleep,内核自己管理休眠时机。但注意在当前源码中,autosleep被#if 0禁用,实际默认使用wakeup_count方式。
九、内核层 — pm_suspend() 完整路径
当 /sys/power/state 被写入 "mem" 后,内核执行休眠。内核的休眠流程分为五个阶段:准备、冻结、挂起设备、进入休眠、恢复。
9.1 state_store() — sysfs 回调入口
源码路径:kernel/msm-3.18/kernel/power/main.c
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n) {
suspend_state_t state;
error = pm_suspend(state); ← 进入内核休眠主入口
return error ? error : n;
}
关键设计:
state_store()是 sysfs 的写回调,用户空间写入/sys/power/state时触发。
9.2 pm_suspend() 与 enter_state() — 休眠主入口
源码路径:kernel/msm-3.18/kernel/power/suspend.c
int pm_suspend(suspend_state_t state)
{
int error;
if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
return -EINVAL;
pm_suspend_marker("entry");
error = enter_state(state); // 进入具体休眠流程
if (error) {
suspend_stats.fail++;
dpm_save_failed_errno(error);
} else {
suspend_stats.success++;
}
pm_suspend_marker("exit");
return error;
}
static int enter_state(suspend_state_t state)
{
int error;
// 1. 同步文件系统
sys_sync();
// 2. 挂起前准备(冻结进程等)
error = suspend_prepare(state);
if (error)
goto Unlock;
// 3. 挂起设备并进入休眠(核心流程)
error = suspend_devices_and_enter(state);
// 4. 收尾清理(thaw进程等)
suspend_finish();
Unlock:
mutex_unlock(&pm_mutex);
return error;
}
关键设计:
enter_state()是休眠的主框架,但它本身不做设备挂起——而是委托给suspend_devices_and_enter()。注意函数名是suspend_devices_and_enter,不是某些文档中写的suspend_devices_and_irq。
suspend_devices_and_enter() 的内部流程:
int suspend_devices_and_enter(suspend_state_t state) {
// 1. 平台相关初始化
error = platform_suspend_begin(state);
// 2. 挂起控制台
suspend_console();
// 3. 挂起所有设备(第一阶段)
error = dpm_suspend_start(PMSG_SUSPEND);
// 4. 进入休眠(可能循环执行,支持 suspend_again)
do {
error = suspend_enter(state, &wakeup);
} while (!error && !wakeup && platform_suspend_again(state));
// 5. 恢复设备
dpm_resume_end(PMSG_RESUME);
resume_console();
return error;
}
关键设计:
suspend_devices_and_enter()先挂起所有设备,然后调用suspend_enter()进入休眠。注意do...while循环——某些平台支持suspend_again,即休眠后立即被某个事件唤醒但希望再次进入休眠。
9.3 freeze_processes() — 冻结所有用户进程
源码路径:kernel/msm-3.18/kernel/power/process.c
int freeze_processes(void) {
// 遍历所有用户进程
for_each_process_thread(g, p) {
freeze_task(p); ← 冻结单个进程
}
return 0;
}
bool freeze_task(struct task_struct *p) {
// 1. 设置 TIF_FREEZE 标志
set_tsk_thread_flag(p, TIF_FREEZE);
// 2. 发送伪信号唤醒进程
wake_up_process(p);
// 3. 进程在返回用户空间前检测 TIF_FREEZE,
// 调用 try_to_freeze() 进入 TASK_UNINTERRUPTIBLE 状态
}
关键设计:冻结机制的精妙之处在于不是直接挂起进程,而是在进程即将返回用户空间时拦截。内核线程需要主动调用
try_to_freeze()检查标志。
9.4 suspend_enter() — 进入硬件休眠
源码路径:kernel/msm-3.18/kernel/power/suspend.c
static int suspend_enter(suspend_state_t state, bool *wakeup) {
// 1. 平台相关准备
error = platform_suspend_prepare(state);
// 2. 挂起设备(late 阶段)
error = dpm_suspend_late(PMSG_SUSPEND);
error = platform_suspend_prepare_late(state);
// 3. 挂起设备(noirq 阶段,中断已禁用)
error = dpm_suspend_noirq(PMSG_SUSPEND);
error = platform_suspend_prepare_noirq(state);
// 4. 禁用非启动 CPU
error = disable_nonboot_cpus();
// 5. 禁用中断
arch_suspend_disable_irqs();
// 6. 挂起系统核心
error = syscore_suspend();
// 7. 调用平台相关的休眠代码 → CPU 进入 deep sleep
error = suspend_ops->enter(state);
// → 通常执行:
// ① 保存 CPU 寄存器状态
// ② 配置唤醒源
// ③ 执行 WFI (Wait For Interrupt) 指令
// ④ CPU 进入 low-power state
// === 被唤醒后,从这里继续执行 ===
// 8. 恢复系统核心
syscore_resume();
// 9. 重新启用中断
arch_suspend_enable_irqs();
// 10. 重新启用非启动 CPU
enable_nonboot_cpus();
return error;
}
关键设计:
suspend_enter()是休眠的最后阶段,在禁用中断后执行syscore_suspend()和suspend_ops->enter()。被唤醒后按相反顺序恢复:syscore_resume()→ 启用中断 → 启用 CPU。注意suspend_ops->enter()是平台相关的回调,由具体 SoC 实现,ARM 架构通常执行 WFI 指令让 CPU 进入低功耗状态。
十、休眠流程完整调用链
Java层 (Framework)
PowerManager.goToSleep()
→ PMS.BinderService.goToSleep() [权限检查]
→ goToSleepInternal()
→ goToSleepNoUpdateLocked()
setWakefulnessLocked(WAKEFULNESS_DOZING, reason)
→ updatePowerStateLocked() [PMS 核心状态机]
→ updateWakeLockSummaryLocked() [汇总 WakeLock]
→ updateUserActivitySummaryLocked() [检测超时]
→ updateWakefulnessLocked() [判断 bedtime]
→ reallyGoToSleepNoUpdateLocked() [DOZING → ASLEEP]
→ updateDisplayPowerStateLocked() [关闭屏幕]
→ updateSuspendBlockerLocked() [释放 suspend_blocker]
→ setHalAutoSuspendModeLocked
→ nativeSetAutoSuspend(true)
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
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
十一、休眠的两个关键动作 — 放行与广播
11.1 SuspendBlocker 的释放 — 谁在阻止内核休眠
休眠的前提是"没有人在阻止休眠"。在 PMS 中,阻止休眠的机制是 SuspendBlocker——只要有一个 SuspendBlocker 没释放,内核就不能进入休眠。
PMS 内部维护两个 SuspendBlocker:
| SuspendBlocker | 释放条件 | 谁在阻止它释放 |
|---|---|---|
mWakeLockSuspendBlocker | 没有应用持有 PARTIAL_WAKE_LOCK | 持有 CPU 唤醒锁的应用 |
mDisplaySuspendBlocker | 屏幕已关闭且显示就绪 | 屏幕还在亮着 |
休眠时,两个 SuspendBlocker 必须全部释放,才会调用 nativeSetAutoSuspend(true) 允许内核休眠。释放过程分三步,每步解决一个问题:
goToSleepNoUpdateLocked() updateWakeLockSummaryLocked() updateSuspendBlockerLocked()
│ │ │
① 标记"我要休眠了" ② 重新盘点:哪些 WakeLock ③ 根据盘点结果
状态 AWAKE → DOZING 还有效、哪些已失效 释放SuspendBlocker
→ nativeSetAutoSuspend(true)
① goToSleepNoUpdateLocked() — 标记"我要休眠了"
这个方法只做一件事:把 mWakefulness 从 AWAKE 改为 DOZING,并设置 mSandmanSummoned = true 触发 Doze 流程。它不释放任何 WakeLock——PMS 的设计模式是 goToSleepNoUpdateLocked 方法只修改标记,副作用由后续的 updatePowerStateLocked() 统一执行。
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private int mWakefulness; // 当前唤醒状态
private int mDirty; // 状态变更标记位
private boolean mSandmanSummoned; // 是否正在召唤 Doze
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
// ... 省略: 前置校验 ...
mLastSleepTime = eventTime;
mSandmanSummoned = true; // 触发 Doze 流程
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
// → mWakefulness = WAKEFULNESS_DOZING
// → mDirty |= DIRTY_WAKEFULNESS
return true;
}
private void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
mWakefulness = wakefulness;
mDirty |= DIRTY_WAKEFULNESS;
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
}
}
}
关键设计:状态先跳到 DOZING 而不是直接到 ASLEEP——因为 Doze 流程需要时间完成(比如屏幕渐暗、AOD 显示等)。Doze 完成后,
reallyGoToSleepNoUpdateLocked()才会把状态从 DOZING 改为 ASLEEP。
② updateWakeLockSummaryLocked() — 重新盘点:哪些 WakeLock 还有效
状态变更后,mDirty 驱动 updatePowerStateLocked() 重新执行。updateWakeLockSummaryLocked() 遍历所有活跃 WakeLock,按类型聚合到 mWakeLockSummary 标志位中,然后根据当前状态裁剪已失效的标志:
public final class PowerManagerService extends SystemService {
// ...
private int mWakefulness; // 当前唤醒状态
private int mWakeLockSummary; // 活跃 WakeLock 聚合标志位
private final ArrayList<WakeLock> mWakeLocks; // 所有活跃 WakeLock 列表
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
// 遍历所有活跃 WakeLock,按类型聚合标志位
for (int i = 0; i < mWakeLocks.size(); i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_CPU; // ← 阻止休眠的关键标志
break;
case PowerManager.DOZE_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DOZE; // ← Doze 期间保持
break;
// ... 省略: SCREEN_BRIGHT、SCREEN_DIM 等其他类型 ...
}
}
// 裁剪:ASLEEP 状态下,屏幕相关标志全部失效
if (mWakefulness == WAKEFULNESS_ASLEEP) {
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
}
// 裁剪:非 Doze 状态下,Doze 相关标志失效
if (mWakefulness != WAKEFULNESS_DOZING) {
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
}
}
}
关键设计:裁剪逻辑的核心问题是——即使某个应用还持有
SCREEN_BRIGHT_WAKE_LOCK,一旦进入 ASLEEP 状态,这个标志也会被裁剪掉,不再计入mWakeLockSummary。而WAKE_LOCK_CPU(来自PARTIAL_WAKE_LOCK)不会被裁剪——只要有任何应用持有它,系统就无法休眠。
③ updateSuspendBlockerLocked() — 根据盘点结果释放 SuspendBlocker
updateWakeLockSummaryLocked 盘点完毕后,updateSuspendBlockerLocked() 检查两个条件,决定是否释放 SuspendBlocker:
public final class PowerManagerService extends SystemService {
// ...
private int mWakeLockSummary; // 活跃 WakeLock 聚合标志位
private boolean mHoldingWakeLockSuspendBlocker; // 是否持有 WakeLock blocker
private boolean mHoldingDisplaySuspendBlocker; // 是否持有 Display blocker
private final SuspendBlocker mWakeLockSuspendBlocker; // WakeLock blocker
private final SuspendBlocker mDisplaySuspendBlocker; // Display blocker
private void updateSuspendBlockerLocked() {
// 条件一:还有应用持有 PARTIAL_WAKE_LOCK 吗?
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
// 条件二:屏幕还在亮着吗?
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
// 释放不再需要的 WakeLockSuspendBlocker
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release(); // ← 释放
mHoldingWakeLockSuspendBlocker = false;
}
// 释放不再需要的 DisplaySuspendBlocker
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release(); // ← 释放
mHoldingDisplaySuspendBlocker = false;
}
// Display blocker 不需要了 → 允许内核自动休眠
final boolean autoSuspend = !needDisplaySuspendBlocker;
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true); // → nativeSetAutoSuspend(true)
}
}
private boolean needDisplaySuspendBlockerLocked() {
if (!mDisplayReady) return true; // 显示未就绪 → 保持
if (mDisplayPowerRequest.isBrightOrDim()) return true; // 屏幕亮或暗 → 保持
return false; // 屏幕关闭 → 可释放
}
}
关键设计:
needDisplaySuspendBlockerLocked()的三层判断——显示未就绪、屏幕亮/暗时都保持 blocker,只有屏幕完全关闭且显示就绪后才释放。两个 blocker 全部释放后,setHalAutoSuspendModeLocked(true)调用 JNI → libsuspend → 写入/sys/power/state→ 内核开始休眠。
完整链路:
用户按下电源键
→ goToSleepNoUpdateLocked() 状态 AWAKE → DOZING,触发 Doze
→ updatePowerStateLocked() [PMS 核心状态机]
→ updateWakeLockSummaryLocked() [汇总 WakeLock]
→ updateDisplayPowerStateLocked() [关闭屏幕]
→ updateSuspendBlockerLocked() [释放 suspend_blocker]
→ setHalAutoSuspendModeLocked(true)
→ nativeSetAutoSuspend(true) → libsuspend → 内核休眠
→ [Doze 流程完成]
→ reallyGoToSleepNoUpdateLocked() 状态 DOZING → ASLEEP
→ updatePowerStateLocked() [再次驱动状态机]
→ updateWakeLockSummaryLocked() 裁剪屏幕相关标志
→ updateSuspendBlockerLocked() 释放 DisplaySuspendBlocker
→ setHalAutoSuspendModeLocked(true)
→ nativeSetAutoSuspend(true) → libsuspend → 内核休眠
11.2 Notifier 广播 — 状态变更如何通知全系统
在 updatePowerStateLocked() 执行过程中,setWakefulnessLocked() 内部调用 mNotifier.onWakefulnessChangeStarted() 向系统发送电源状态变更通知:
源码路径:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
public final class PowerManagerService extends SystemService {
// ...
private Notifier mNotifier; // 电源状态通知器
private void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
mNotifier.onWakefulnessChangeStarted(wakefulness, reason); // 广播状态变更
}
}
}
关键设计:Notifier 在状态变更时立即广播,而不是等到
updatePowerStateLocked()结束。onWakefulnessChangeStarted()会触发PhoneWindowManager、DreamManagerService等服务响应电源状态变化。
关键设计:Notifier 不直接发送广播,而是分两阶段通知:早期交互阶段(Early Interactive)在状态变更时立即执行,晚期交互阶段(Late Interactive)在状态变更完成后执行。
第一步:Notifier.onWakefulnessChangeStarted() — 入口,立即执行早期通知
源码路径:frameworks/base/services/core/java/com/android/server/power/Notifier.java
final class Notifier {
// ...
private final NotifierHandler mHandler; // Notifier 专用 Handler
private final WindowManagerPolicy mPolicy; // 窗口策略(PhoneWindowManager)
private final ActivityManagerInternal mActivityManagerInternal; // ActivityManager 内部接口
private final InputManagerInternal mInputManagerInternal; // 输入管理器
private boolean mInteractive; // 当前是否处于交互状态
private boolean mInteractiveChanging; // 是否正在切换交互状态
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
// 根据 wakefulness 判断是否进入交互状态
// AWAKE/DREAMING → 交互中,DOZING/ASLEEP → 非交互
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
// 通知 ActivityManager(通过 Handler 异步执行)
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});
// 如果交互状态发生变化,立即执行早期通知
if (mInteractive != interactive) {
// 如果上一次切换还没完成晚期通知,先补上
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
// 通知输入管理器
mInputManagerInternal.setInteractive(interactive);
// 立即执行早期交互变更
mInteractive = interactive;
mInteractiveChanging = true;
handleEarlyInteractiveChange();
}
}
}
关键设计:
onWakefulnessChangeStarted()在 PMS 持锁时调用,所以它不直接发送广播(广播会阻塞),而是立即执行handleEarlyInteractiveChange()通知PhoneWindowManager。晚期通知延迟到onWakefulnessChangeFinished()时执行。
第二步:handleEarlyInteractiveChange() — 通知 PhoneWindowManager,开始关屏流程
final class Notifier {
// ...
private final WindowManagerPolicy mPolicy; // 窗口策略
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// 唤醒路径:通知 PhoneWindowManager 屏幕即将亮起
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.startedWakingUp();
}
});
updatePendingBroadcastLocked();//发送休眠唤醒事件广播
} else {
// 休眠路径:通知 PhoneWindowManager 开始进入休眠
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.startedGoingToSleep(why); // ← 开始进入休眠
}
});
}
}
}
}
关键设计:
mPolicy.startedGoingToSleep()触发PhoneWindowManager执行锁屏准备、禁用传感器、停止手势检测等操作。注意这里调用的是startedGoingToSleep(),不是finishedGoingToSleep()——真正的完成通知在晚期阶段。
第三步:onWakefulnessChangeFinished() — 状态变更完成,执行晚期通知
final class Notifier {
// ...
private boolean mInteractiveChanging; // 是否正在切换交互状态
private boolean mPendingGoToSleepBroadcast; // 待发送的休眠广播标志
public void onWakefulnessChangeFinished() {
if (mInteractiveChanging) {
mInteractiveChanging = false;
handleLateInteractiveChange(); // ← 状态变更完成后执行
}
}
private void handleLateInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// 唤醒路径:通知 PhoneWindowManager 唤醒完成
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.finishedWakingUp();
}
});
} else {
// 休眠路径:通知 PhoneWindowManager 休眠完成
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.finishedGoingToSleep(why); // ← 休眠完成
}
});
updatePendingBroadcastLocked();//发送休眠唤醒事件广播
}
}
}
}
关键设计:
onWakefulnessChangeFinished()在updatePowerStateLocked()的最后一个 Phase(finishWakefulnessChangeIfNeededLocked())中被调用。此时状态机已完成所有状态变更,可以安全地通知PhoneWindowManager休眠完成。
第四步:sendNextBroadcast() — 发送系统广播,通知全系统
广播发送通过 MSG_BROADCAST 消息触发 sendNextBroadcast(),发送 ACTION_SCREEN_OFF 或 ACTION_SCREEN_ON:
final class Notifier {
// ...
private final Context mContext; // 系统上下文
private final Intent mScreenOffIntent; // 休眠广播 Intent
private final SuspendBlocker mSuspendBlocker; // 防止广播期间系统休眠
private boolean mBroadcastInProgress; // 广播是否正在进行
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState != mBroadcastedInteractiveState)) {
mBroadcastInProgress = true;
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
private final class NotifierHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BROADCAST:
sendNextBroadcast();
break;
}
}
}
private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
// ... 省略: 判断发送唤醒还是休眠广播 ...
powerState = mPendingInteractiveState;
mPendingInteractiveState = INTERACTIVE_STATE_UNKNOWN;
}
if (powerState == INTERACTIVE_STATE_AWAKE) {
// 唤醒路径:发送 ACTION_SCREEN_ON
sendScreenBroadcast(mScreenOnIntent);
} else {
// 休眠路径:发送 ACTION_SCREEN_OFF
sendScreenBroadcast(mScreenOffIntent);
}
}
private void sendScreenBroadcast(Intent intent) {
// 获取 SuspendBlocker 防止广播期间系统休眠
mSuspendBlocker.acquire();
// 发送有序广播
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, null);
}
}
关键设计:
ACTION_SCREEN_OFF是有序广播(sendOrderedBroadcastAsUser),接收方按优先级依次处理。广播发送前获取SuspendBlocker,防止广播还没发完系统就休眠了。广播完成后释放 blocker。
完整通知链路:
setWakefulnessLocked()
→ mNotifier.onWakefulnessChangeStarted(wakefulness, reason)
→ handleEarlyInteractiveChange()
→ mPolicy.startedGoingToSleep(why) [通知 PhoneWindowManager 开始休眠]
→ [updatePowerStateLocked() 继续执行其他 Phase]
→ finishWakefulnessChangeIfNeededLocked()
→ mNotifier.onWakefulnessChangeFinished()
→ handleLateInteractiveChange()
→ mPolicy.finishedGoingToSleep(why) [通知 PhoneWindowManager 休眠完成]
→ sendNextBroadcast()
→ mContext.sendBroadcast(ACTION_SCREEN_OFF) [广播通知全系统]
十二、关键源码文件索引
| 文件 | 职责 | 所在目录 |
|---|---|---|
PowerManagerService.java | PMS 核心状态机 | frameworks/.../power/ |
PowerManager.java | 应用层 API | frameworks/.../os/ |
PhoneWindowManager.java | 电源键拦截 | frameworks/.../policy/ |
Notifier.java | 电源状态广播 | frameworks/.../power/ |
...PowerManagerService.cpp | JNI 层 | frameworks/.../jni/ |
autosuspend.c | libsuspend 入口 | system/core/libsuspend/ |
autosuspend_wakeup_count.c | wakeup_count | system/core/libsuspend/ |
autosuspend_autosleep.c | autosleep | system/core/libsuspend/ |
suspend.c | 内核休眠主流程 | kernel/power/ |
main.c | sysfs 接口 | kernel/power/ |
process.c | 进程冻结 | kernel/power/ |
十三、小结
休眠全链路从 Java 层一气贯通到内核层,核心路径为:
- 触发:电源键/超时 → PMS.goToSleep()
- 标记:设置 mWakefulness 跳转和 mDirty 标记位
- 状态机:updatePowerStateLocked() 按 Phase 执行
- 释放 WakeLock:两个 suspend_blocker 全部释放
- Native:libsuspend 写入 /sys/power/state 或 /sys/power/autosleep
- 内核:freeze 进程 → 挂起设备 → CPU 进入 deep sleep
整个流程在 1 秒内完成,关键在于"冻结而非杀死"的设计——下一篇将分析唤醒流程,看系统如何从中断触发到点亮屏幕,以同样的速度恢复。
休眠全链路&spm=1001.2101.3001.5002&articleId=163267659&d=1&t=3&u=75a85d0d6afa44d99b14e8b2d746e441)
374

被折叠的 条评论
为什么被折叠?



