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

系列目录第一篇:电源管理架构全景图 | 第二篇:开机全链路—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 代理层——通过 mServiceIPowerManager)跨进程调用 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. 按键拦截PhoneWindowManagerinterceptKeyBeforeQueueing() 中拦截电源键事件,清除 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 层入口

所有休眠触发方式最终都汇聚到 PowerManagerServicegoToSleepInternal()。这个方法是休眠的 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 的四个取值:

常量含义
0WAKEFULNESS_AWAKE清醒(正在使用)
1WAKEFULNESS_DREAMING屏保/互动屏保(Android 4.2+)
2WAKEFULNESS_DOZING正在进入休眠(过渡状态)
3WAKEFULNESS_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 的释放条件:WakeLockSuspendBlockermWakeLockSummary & WAKE_LOCK_CPU == 0 时释放(无 CPU 唤醒锁);DisplaySuspendBlockerneedDisplaySuspendBlockerLocked() 返回 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_countautosleep

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_countautosuspend_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() 会触发 PhoneWindowManagerDreamManagerService 等服务响应电源状态变化。

关键设计: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_OFFACTION_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.javaPMS 核心状态机frameworks/.../power/
PowerManager.java应用层 APIframeworks/.../os/
PhoneWindowManager.java电源键拦截frameworks/.../policy/
Notifier.java电源状态广播frameworks/.../power/
...PowerManagerService.cppJNI 层frameworks/.../jni/
autosuspend.clibsuspend 入口system/core/libsuspend/
autosuspend_wakeup_count.cwakeup_countsystem/core/libsuspend/
autosuspend_autosleep.cautosleepsystem/core/libsuspend/
suspend.c内核休眠主流程kernel/power/
main.csysfs 接口kernel/power/
process.c进程冻结kernel/power/

十三、小结

休眠全链路从 Java 层一气贯通到内核层,核心路径为:

  1. 触发:电源键/超时 → PMS.goToSleep()
  2. 标记:设置 mWakefulness 跳转和 mDirty 标记位
  3. 状态机:updatePowerStateLocked() 按 Phase 执行
  4. 释放 WakeLock:两个 suspend_blocker 全部释放
  5. Native:libsuspend 写入 /sys/power/state 或 /sys/power/autosleep
  6. 内核:freeze 进程 → 挂起设备 → CPU 进入 deep sleep

整个流程在 1 秒内完成,关键在于"冻结而非杀死"的设计——下一篇将分析唤醒流程,看系统如何从中断触发到点亮屏幕,以同样的速度恢复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值