系列目录 :第一篇:电源管理架构全景图 | 第二篇:开机全链路---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()
→ wakeup_count方式: 休眠线程 read → write wakeup_count → write "mem"
→ autosleep方式: 直接写入 "mem" 到 /sys/power/autosleep
Kernel层
state_store() [sysfs回调]
→ pm_suspend(state)
→ enter_state(state)
→ sys_sync() [文件系统同步]
→ suspend_prepare() [挂起前准备]
→ freeze_processes() [冻结所有用户进程]
→ suspend_devices_and_irq() [挂起设备、禁用IRQ]
→ suspend_enter()
→ 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
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
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
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() 被调用:
java
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
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(),根据短按行为配置决定是否休眠:
java
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:
java
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
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
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
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
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
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() 触发休眠流程:
java
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 流程结束后,调用此方法完成最终的状态跳转:
java
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
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
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
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_enable() --- 入口函数
源码路径 :system/core/libsuspend/autosuspend.c
c
static struct autosuspend_ops *autosuspend_ops; // 具体实现的函数指针
static bool autosuspend_enabled;
int autosuspend_enable(void) {
int ret;
ret = autosuspend_init(); // 首次调用时初始化,选择具体实现
if (ret) {
return ret;
}
if (autosuspend_enabled) {
return 0;
}
ret = autosuspend_ops->enable(); // 调用具体实现的 enable
if (ret) {
return ret;
}
autosuspend_enabled = true;
return 0;
}
关键设计 :
autosuspend_enable()首次调用时会执行autosuspend_init(),按优先级选择具体实现:先尝试earlysuspend,再尝试autosleep(当前被#if 0禁用),最后回退到wakeup_count。之后通过autosuspend_ops->enable()调用选中实现的 enable 函数。
8.2 wakeup_count 方式 --- 线程模型
源码路径 :system/core/libsuspend/autosuspend_wakeup_count.c
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";
// 休眠线程:循环执行 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);
}
}
static int autosuspend_wakeup_count_enable(void) {
// 释放信号量,让休眠线程开始工作
sem_post(&suspend_lockout);
return 0;
}
static int autosuspend_wakeup_count_disable(void) {
// 获取信号量,阻塞休眠线程
sem_wait(&suspend_lockout);
return 0;
}
关键设计 :
wakeup_count方式使用独立线程循环执行休眠逻辑。enable()只是sem_post()释放信号量让线程开始工作,disable()通过sem_wait()阻塞线程。休眠线程内部通过 read → write wakeup_count → write "mem" 三步完成休眠,信号量机制解决了竞态问题。
8.3 autosleep 方式 --- 内核自动管理
源码路径 :system/core/libsuspend/autosuspend_autosleep.c
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;
}
关键设计 :
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
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
c
int pm_suspend(suspend_state_t state) {
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) {
// 1. 同步文件系统
sys_sync();
// 2. 挂起前准备(冻结进程等)
error = suspend_prepare(state);
// 3. 挂起设备并进入休眠(核心流程)
error = suspend_devices_and_enter(state);
// 4. 收尾清理( thaw 进程等)
suspend_finish();
return error;
}
关键设计 :
enter_state()是休眠的主框架,但它本身不做设备挂起------而是委托给suspend_devices_and_enter()。注意函数名是suspend_devices_and_enter,不是某些文档中写的suspend_devices_and_irq。
suspend_devices_and_enter() 的内部流程:
c
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
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
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]
→ nativeSetAutoSuspend(true)
JNI层
nativeSetAutoSuspend(true)
→ autosuspend_enable()
Native层 (libsuspend)
autosuspend_enable()
→ wakeup_count方式: 休眠线程 read → write wakeup_count → write "mem"
→ autosleep方式: 直接写入 "mem" 到 /sys/power/autosleep
Kernel层
state_store() [sysfs回调]
→ pm_suspend(state)
→ enter_state(state)
→ sys_sync() [文件系统同步]
→ suspend_prepare() [挂起前准备]
→ freeze_processes() [冻结所有用户进程]
→ suspend_devices_and_irq() [挂起设备、禁用IRQ]
→ suspend_enter()
→ arch_suspend_disable_irqs() [禁用中断]
→ syscore_suspend() [挂起系统核心]
→ suspend_ops->enter() [平台相关: WFI指令]
→ CPU进入deep sleep
十一、休眠中的关键数据流
11.1 Screen WakeLock 的释放时机
休眠的前提是"没有人在阻止休眠"。在 PMS 中,阻止休眠的机制是 suspend blocker------只要有一个 blocker 没释放,内核就不能进入休眠。
PMS 内部维护两个 suspend blocker:
| Blocker | 释放条件 | 谁在阻止它释放 |
|---|---|---|
WakeLockSuspendBlocker |
没有应用持有 PARTIAL_WAKE_LOCK |
持有 CPU 唤醒锁的应用 |
DisplaySuspendBlocker |
屏幕已关闭且显示就绪 | 屏幕还在亮着 |
休眠时,两个 blocker 必须全部释放 ,才会调用 nativeSetAutoSuspend(true) 允许内核休眠。释放过程分三步,每步解决一个问题:
goToSleepNoUpdateLocked() updateWakeLockSummaryLocked() updateSuspendBlockerLocked()
│ │ │
① 标记"我要休眠了" ② 重新盘点:哪些 WakeLock ③ 根据盘点结果
状态 AWAKE → DOZING 还有效、哪些已失效 释放 blocker
→ nativeSetAutoSuspend(true)
① goToSleepNoUpdateLocked() --- 标记"我要休眠了"
这个方法只做一件事:把 mWakefulness 从 AWAKE 改为 DOZING,并设置 mSandmanSummoned = true 触发 Doze 流程。它不释放任何 WakeLock ------PMS 的设计模式是 NoUpdateLocked 方法只修改标记,副作用由后续的 updatePowerStateLocked() 统一执行。
源码路径 :frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
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 标志位中,然后根据当前状态裁剪已失效的标志:
java
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() --- 根据盘点结果释放 blocker
mWakeLockSummary 盘点完毕后,updateSuspendBlockerLocked() 检查两个条件,决定是否释放 blocker:
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() {
// 条件一:还有应用持有 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;
}
// 两个 blocker 都释放 → 允许内核自动休眠
if (!needDisplaySuspendBlocker) {
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
→ [Doze 流程完成]
→ reallyGoToSleepNoUpdateLocked() 状态 DOZING → ASLEEP
→ updateWakeLockSummaryLocked() 裁剪屏幕相关标志,mWakeLockSummary 只剩 WAKE_LOCK_CPU
→ updateSuspendBlockerLocked() 无应用持有 PARTIAL_WAKE_LOCK → 释放两个 blocker
→ nativeSetAutoSuspend(true) → libsuspend → 内核休眠
11.2 Notifier 的广播
在 updatePowerStateLocked() 执行过程中,setWakefulnessLocked() 内部调用 mNotifier.onWakefulnessChangeStarted() 向系统发送电源状态变更通知:
源码路径 :frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
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等服务响应电源状态变化。
十二、关键源码文件索引
| 文件 | 职责 | 所在目录 |
|---|---|---|
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 秒内完成,关键在于"冻结而非杀死"的设计------下一篇将分析唤醒流程,看系统如何从中断触发到点亮屏幕,以同样的速度恢复。