Android R PowerManagerService模块(4) 灭屏流程

4,605 阅读7分钟

Android R PowerManagerService模块(3)亮屏流程中分析了PMS部分的亮屏流程。PMS模块中也提供了灭屏接口goTosleep(),方法给其他组件或应用来关闭屏幕,这里将对PMS部分涉及到的灭屏流程进行分析。

1.非自动灭屏流程

当系统其他组件发起灭屏时,将调用PowerManager#goTosleep()方法:

/**
 * time: 开始灭屏时间
 * reason: 灭屏原因
 * flags: 灭屏可选标记值
 */
public void goToSleep(long time, int reason, int flags) {
    try {
        mService.goToSleep(time, reason, flags);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

PowerManager中直接调用到PMS中,并在进行权限检查后,调用goToSleepInternal()进入PMS模块内部:

private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
    synchronized (mLock) {
        // 灭屏成功返回true
        if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
            updatePowerStateLocked();
        }
    }
}

首先将会调用goToSleepNoUpdateLocked()方法,并在该方法返回true后,调用updatePowerStateLocked()开始更新全局状态,完成整个灭屏流程。

1.1.goToSleepNoUpdateLocked()更新验证和灭屏状态更新


    private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
        ......
        try {
            // 表示需要召唤"睡眠精灵",即请求进入Dreamland模式
            mSandmanSummoned = true;
            // 表示处于Doze过程中
            mDozeStartInProgress = true;
            // 设置唤醒状态为Dozing
            setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);

            // 灭屏后屏幕相关WakeLock锁将失去意义,所以统计下清除锁的个数
            int numWakeLocksCleared = 0;
            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.FULL_WAKE_LOCK:
                    case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                    case PowerManager.SCREEN_DIM_WAKE_LOCK:
                        numWakeLocksCleared += 1;
                        break;
                }
            }
            // 如果带有GO_TO_SLEEP_FLAG_NO_DOZE标记,则不会经过Doze直接进入Asleep状态
            if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
                reallyGoToSleepNoUpdateLocked(eventTime, uid);
            }
        } 
        return true;
    }

首先,更新灭屏相关属性值,然后通过setWakefulnessLocked()方法,将唤醒状态mWakefulnessRaw值设置为Dozing;最后如果goToSleep()中还带有PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE标记,则将跳过Dozing状态,直接进入Asleep状态。

因此,如果goToSleep()不带PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE时,会先将唤醒状态设置为Dozing状态,再根据条件决定是否进入Asleep。

setWakefulnessLocked()方法在第三篇中也分析过了,会更新mWakefulnessRaw值,然后调用Notifier#onWakefulnessChangeStarted()做系统唤醒状态改变后的交互状态更新,然后执行handleEarlyInteractiveChange()方法。

1.2.Notifier#handleEarlyInteractiveChange()

看下该方法中灭屏流程相关逻辑:

    private void handleEarlyInteractiveChange() {
        synchronized (mLock) {
            if (mInteractive) {
                ......
            } else {
                // Going to sleep...
                // 通知WMS开始灭屏
                final int why = translateOffReason(mInteractiveChangeReason);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mPolicy.startedGoingToSleep(why);
                    }
                });
            }
        }
    }

这里会通知WMS模块开始灭屏,WMS中会进一步通知给Keyguard等进行相应操作。

1.3.updatePowerStateLocked()

当上述方法执行完毕并返回后,开始执行updatePowerStateLocked()方法,在这里我们只看其中灭屏流程相关,有如下部分:

// 向DMS中发起灭屏请求,将亮度设置为0, Display状态设置为DOZE/OFF
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
//更新Dreamland状态
updateDreamLocked(dirtyPhase2, displayBecameReady);
// 收尾工作
finishWakefulnessChangeIfNeededLocked();
//释放锁
updateSuspendBlockerLocked();

下面逐个来看。

1.4.updateDisplayPowerStateLocked()请求DMS

该方法向DMS模块发起请求,DisplayPowerController中收到请求后,会将屏幕亮度设置为0,Display状态设置为Doze或者OFF。该方法详细分析见Android R PowerManagerService模块(一) 启动流程和核心方法。关于DMS中收到请求并设置亮度和Display状态的逻辑,详细分析见 Android R DisplayManagerService模块(3) DMS部分亮灭屏流程

1.5.updateDreamLocked()更新Dream状态

该方法用来决定灭屏后是否会进入Dream状态或Doze状态,如屏保、AOD、FOD等功能就是在此状态下运行。当完成DMS请求且DMS返回请求结果后,才会执行该方法内容,并最终在handleSandman()方法中进行处理:


    private void handleSandman() { // runs on handler thread
        .....
        synchronized (mLock) {
            mSandmanScheduled = false;
            wakefulness = getWakefulnessLocked();
            // 召唤睡眠精灵且Display状态准备完毕
            if (mSandmanSummoned && mDisplayReady) {
                // 确定是需要进入Dreamland
                startDreaming = canDreamLocked() || canDozeLocked();
                mSandmanSummoned = false;   // 重置
            } else {
                startDreaming = false;
            }
        }

        final boolean isDreaming;
        if (mDreamManager != null) {
            // 进入Dreamland状态
            if (startDreaming) {
                mDreamManager.stopDream(false /*immediate*/);
                mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
            }
            // 确认是否完成Dreamland
            isDreaming = mDreamManager.isDreaming();
        } else {
            isDreaming = false;
        }
        // 重置,表示完成Dozing过程
        mDozeStartInProgress = false;

        synchronized (mLock) {
            ......
            if (wakefulness == WAKEFULNESS_DREAMING) {
                ......
            } else if (wakefulness == WAKEFULNESS_DOZING) {
                // 如果在进行Dreaming,则直接返回
                if (isDreaming) {
                    return; // continue dozing
                }
                // 否则真正执行灭屏流程
                reallyGoToSleepNoUpdateLocked(now, Process.SYSTEM_UID);
                updatePowerStateLocked();
            }
        }
        // Stop dream.
        if (isDreaming) {
            mDreamManager.stopDream(false /*immediate*/);
        }
    }

当mWakefulness变为WAKEFULNESS_DOZING后,执行到这里时,如果没有能够进入Dreamland,那么将通过reallyGoToSleepNoUpdateLocked()方法,开始进行真正的”休眠“。

1.6.reallyGoToSleepNoUpdateLocked()

该方法中,将mWakefulnessRaw值设置为WAKEFULNESS_ASLEEP,表示进入休眠状态:

    private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
        ......
        try {
            // 设置唤醒状态为ASLEEP
            setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
                    eventTime);
        } 
        return true;
    }

因此在灭屏过程中,系统唤醒状态会先设置为Dozing,并通过DreamManager去启动进入Dreamland状态。没有进入Dreamland时,才会将唤醒状态设置为Asleep。如果goToSleep()带有PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE标记,则直接进Asleep。

1.7.Notifier#handleLateInteractiveChange()

更新完Dreamland相关状态后,执行finishWakefulnessChangeIfNeededLocked()方法来做唤醒状态变化完成后的任务,并执行Notifier#handleLateInteractiveChange()方法,进行交互状态变化完成后的任务,这里看下灭屏流程部分:

    private void handleLateInteractiveChange() {
        synchronized (mLock) {
            final int interactiveChangeLatency =
                    (int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);
            if (mInteractive) {
                // Finished waking up...
                .......
            } else {
                ......
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mPolicy.finishedGoingToSleep(why);
                    }
                });
                // 表示即将要发送广播状态为ASLEEP
                mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP;
                // 表示即将要发送灭屏广播
                mPendingGoToSleepBroadcast = true;
                // 发送广播
                updatePendingBroadcastLocked();
            }
        }
    }

首先,通过mPolicy.finishedGoingToSleep()通知WMS模块已经完成灭屏。然后发送灭屏广播。

1.8.updatePendingBroadcastLocked()发送灭屏广播

updatePendingBroadcastLocked()方法在上一篇文章中已经分析过,当满足灭屏广播的发送条件时,将会进行灭屏广播的发送:

// frameworks/base/services/core/java/com/android/server/power/Notifier.java
    private void sendGoToSleepBroadcast() {
        if (mActivityManagerInternal.isSystemReady()) {
            mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
        } else {
            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
            sendNextBroadcast();
        }
    }

1.9.updateSuspendBlockerLocked()

最后执行updateSuspendBlockerLocked()方法,灭屏后会释放掉mDisplaySuspendBlocker锁,如果此时没有PARTICAL_WAKE_LOCK、DOZE_WAKE_LOCK、DRAW_WAKE_LOCK这三类锁,mWakeLockSuspendBlocker也将会释放掉,CPU将会在适当时机进行休眠。

释放流程见Android R PowerManagerService模块(二) WakeLock机制

以上就是PMS部分非自动灭屏场景的整个流程,其时序图如下:

gotosleep_power.jpg

2.自动灭屏流程

自动灭屏的影响因素主要有两个:

  • 自动休眠时间:用户在Settings中设置的值;
  • 用户活动时间:用户最后和设备进行交互的时间点。 当用户在某时刻和设备有交互时,会记录该时间点,并以该时间为起始时间,到达"起始时间+自动休眠时间"这个时间点后,开始执行灭屏流程。

在前面几篇文章中多次提到了userActivityNoUpdateLocked()方法,但没有分析,这里正是分析它的最佳时机。因为就是这个方法,会在每一次有用户活动时更新最近一次的交互时间。

2.1.userActivityNoUpdateLocked()更新最近一次交互时间

当用户触摸屏幕、按键时,Input模块中在处理这些Key事件后,会通知PMS来更新用户活动时间:

// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
    ATRACE_CALL();
    android_server_PowerManagerService_userActivity(eventTime, eventType);
}
 
 
// frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
    if (gPowerManagerServiceObj) {
    // ......
        env->CallVoidMethod(gPowerManagerServiceObj,
                gPowerManagerServiceClassInfo.userActivityFromNative,
                nanoseconds_to_milliseconds(eventTime), eventType, 0);
    }
}

input模块中通过JNI调用,进入PMS中:

// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void userActivityFromNative(long eventTime, int event, int flags) {
    userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID);
}
 
private void userActivityInternal(long eventTime, int event, int flags, int uid) {
    synchronized (mLock) {
        // 更新用户活动时间
        if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {  
            // 更新PMS全局状态
            updatePowerStateLocked();   
        }
    }
}

Native层代码调用userActivityFromNative()方法进入PMS中,在这个方法中,首先通过userActivityNoUpdateLocked()方法更新用户活动时间,然后updatePowerStateLocked()方法进行全局状态的更新。 userActivityNoUpdateLocked()方法如下:

private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
        // ......
        // 通知Notifier更新用户活动状态
        mNotifier.onUserActivity(event, uid);
        mAttentionDetector.onUserActivity(eventTime, event);
        // 重置,表示是否WMS覆盖了最长不交互时间阈值
        if (mUserInactiveOverrideFromWindowManager) {
            mUserInactiveOverrideFromWindowManager = false;
            mOverriddenTimeout = -1;
        }
        // 已灭屏,或调用该方法带有USER_ACTIVITY_FLAG_INDIRECT,不会更新用户活动时间
        if (mWakefulness == WAKEFULNESS_ASLEEP
                || mWakefulness == WAKEFULNESS_DOZING
                || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
            return false;
        }
        // 根据userid更新该user在PowerProfileState中记录的用户活动时间
        maybeUpdateForegroundProfileLastActivityLocked(eventTime);
        // 带有USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS标记时,会延长亮屏一会儿
        if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
            if (eventTime > mLastUserActivityTimeNoChangeLights
                    && eventTime > mLastUserActivityTime) {
                // 更新最后一次活动时间给mLastUserActivityTimeNoChangeLights
                mLastUserActivityTimeNoChangeLights = eventTime;
                mDirty |= DIRTY_USER_ACTIVITY;
                // ......
                return true;
            }
        } else {
            if (eventTime > mLastUserActivityTime) {
                // 更新最后一次活动时间给mLastUserActivityTime
                mLastUserActivityTime = eventTime;
                mDirty |= DIRTY_USER_ACTIVITY;
                // ......
                return true;
            }
        }
    } finally { }
    return false;
}

以上方法中,如果调用时带有PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS标记,则将交互时间赋值给mLastUserActivityTimeNoChangeLights变量,否则将交互时间赋给mLastUserActivityTime变量。这个flag标志用于延长亮屏或Dim的时长一小会儿。在第二篇文章中说过,当在释放WakeLock锁时带有ON_AFTER_RELEASE标记,会延长超时灭屏时间,原理就是通过该Flag实现。

当执行完成后。mLastUserActivityTime或者mLastUserActivityTimeNoChangeLights的值得到了更新。接下来又会进入updatePowerStateLocked()方法,来更新PMS全局状态。

2.2.updatePowerStateLocked()更新PMS全局状态

在这个方法中,和自动灭屏相关的逻辑如下:

private void updatePowerStateLocked() {
    // ......
    try {
        for (;;) {
            int dirtyPhase1 = mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;
            updateWakeLockSummaryLocked(dirtyPhase1);
            updateUserActivitySummaryLocked(now, dirtyPhase1);
            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }
        // ......
    } finally { }
}

updateWakeLockSummaryLocked()方法会将当前系统所有的WakeLock统计到mWakeLock变量上。 updateUserActivitySummaryLocked()方法会更新用户活动状态,并确认多久开始自动灭屏。

2.3.updateUserActivitySummaryLocked()

该方法用来更新用户活动状态:

    private void updateUserActivitySummaryLocked(long now, int dirty) {
        // Update the status of the user activity timeout timer.
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
            mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);

            long nextTimeout = 0;
            // mWakefulnessRaw为Asleep时,不执行该流程
            if (getWakefulnessLocked() == WAKEFULNESS_AWAKE
                    || getWakefulnessLocked() == WAKEFULNESS_DREAMING
                    || getWakefulnessLocked() == WAKEFULNESS_DOZING) {
                // 获取细微模式超时时间
                final long attentiveTimeout = getAttentiveTimeoutLocked();
                // 获取彻底进入休眠超时时间
                final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout);
                // 获取自动灭屏超时时间
                final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout,
                        attentiveTimeout);
                // 获取进入Dim所需时间
                final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
                // 是否WindowManager中覆盖了超时时间
                final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
                // DevicePolicy是否对于单用户设置了超时时间
                final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
                // 重置统计值
                mUserActivitySummary = 0;
                // 最近一次用户活动时间>=最近一次唤醒时间
                if (mLastUserActivityTime >= mLastWakeTime) {
                    // 如果最近一次用户活动时间 + 自动休眠设置 - Dim时间大于当前时间,则此时为亮屏状态,mUserActivitySummary状态设置为USER_ACTIVITY_SCREEN_BRIGHT
                    nextTimeout = mLastUserActivityTime
                            + screenOffTimeout - screenDimDuration;
                    if (now < nextTimeout) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else {
                        // 如果最近一次用户活动时间 + 自动休眠时间 > 当前时间 > 最近一次用户活动时间+自动休眠设置-Dim时间,此时为Dim状态
                        // mUserActivitySummary状态设置为USER_ACTIVITY_SCREEN_DIM
                        nextTimeout = mLastUserActivityTime + screenOffTimeout;
                        if (now < nextTimeout) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
                // 如果进该if块,说明不满足mLastUserActivityTime >= mLastWakeTime,那么就需要判断mLastUserActivityTimeNoChangeLights,
                // mLastUserActivityTimeNoChangeLights是带有USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS标记的最近一次用户活动时间
                if (mUserActivitySummary == 0
                        && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                    // 如果当前时间 < 最近一次用户活动时间 + 自动休眠时间,说明要么亮屏,要么Dim,具体根据当前已处状态确认,从而做到延长亮屏或Dim的时长
                    nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                    if (now < nextTimeout) {
                        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
                                || mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                        } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
                // 如果进该if块,说明当前时间 > 最近一次用户活动时间 + 自动休眠时间了,肯定将开始自动灭屏,mUserActivitySummary设置为USER_ACTIVITY_SCREEN_DREAM
                if (mUserActivitySummary == 0) {
                    if (sleepTimeout >= 0) {
                        ......
                    } else {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                        nextTimeout = -1;
                    }
                }
                ......
                // 发送定时消息
                if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                    scheduleUserInactivityTimeout(nextTimeout);
                }
            } else {
                // 当唤醒状态为Asleep时,设置为0
                mUserActivitySummary = 0;
            }
        }
    }

此方法中逻辑比较多且碎,其中细节在代码中都进行了注释。总而言之,进入该方法后,会根据最近一次的用户活动时间和系统设置的自动休眠时间,一步步确定每个用户活动状态变化的时间点,然后通过scheduleUserInactivityTimeout()方法设置一个Msg,并在到达时间点后会再次更新。

最终,用户活动状态经过USER_ACTIVITY_SCREEN_BRIGHT → USER_ACTIVITY_SCREEN_DIM → USER_ACTIVITY_SCREEN_DREAM变化,对应亮屏 → Dim → 灭屏。如果系统状态进入Alseep,则mUserActivitySummary最终会变为0。

经过updateUserActivitySummaryLocked()方法后,得到了mUserActivitySummary。

2.4.updateWakefulnessLocked()

现在看下循环体中的updateWakefulnessLocked()方法,这个方法作为for循环的终止条件,下面看下其逻辑:

    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 | DIRTY_ATTENTIVE | DIRTY_SETTINGS
                | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
            // 当系统唤醒状态为Awake,且到达"睡觉"时间
            if (getWakefulnessLocked() == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                final long time = mClock.uptimeMillis();
                // 判断是否超过细微模式超时时间阈值
                if (isAttentiveTimeoutExpired(time)) {
                    changed = goToSleepNoUpdateLocked(time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
                // 进入屏保,将系统状态设置为Dreaming
                } else if (shouldNapAtBedTimeLocked()) {
                    changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
                } else {
                    // 否则灭屏
                    changed = goToSleepNoUpdateLocked(time,
                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
                }
            }
        }
        return changed;
    }

首先根据isItBedTimeYetLocked()和mWakefulnessRaw来决定是否执行该方法;然后根据shouldNapAtBedTimeLocked()决定是要进入屏保还是直接灭屏。

不管进入哪个状态,都说明此时系统屏幕状态发生了改变,所以该方法会返回true,因此将不会跳出for循环,再次进行一次循环。因此,只有超时灭屏时for循环才会执行两次,其他情况下都会只执行一次for循环就退出。

isItBedTimeYetLocked()方法是判断是否要自动休眠的关键:

    private boolean isItBedTimeYetLocked() {
        if (!mBootCompleted) {
            return false;
        }

        long now = mClock.uptimeMillis();
        // 到达细微模式时
        if (isAttentiveTimeoutExpired(now)) {
            return !isBeingKeptFromInattentiveSleepLocked();
        } else {
            return !isBeingKeptAwakeLocked();
        }
    }

该方法直接返回isBeingKeptAwakeLocked()方法:

    private boolean isBeingKeptAwakeLocked() {
        return mStayOn                                            // 是否开启了不锁定屏幕开关 
                || mProximityPositive                             // 是否有PSensor靠近
                || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0 // 是否持有屏幕相关WakeLock锁
                || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
                        | USER_ACTIVITY_SCREEN_DIM)) != 0         // 用户活动状态是否为Bright或Dim
                || mScreenBrightnessBoostInProgress;              // 是否在进行亮度增强
    }

如果isBeingKeptAwakeLocked()方法有任意一个条件为true,那么就不能进入休眠或者屏保状态,因此只有全部为false时,才会进行自动灭屏。其中条件包括mWakeLockSummary和mUserActivitySummary,所以前面流程中对这两个变量进行统计,就是用在这里起关键作用。

isItBedTimeYetLocked()返回后,将进入屏保或者灭屏,屏保这个功能已经几乎不使用了,就不分析它了。接下来将调用goToSleepNoUpdateLocked()方法,于是开始走灭屏流程,之后的逻辑和非自动灭屏流程一致。

至此,自动灭屏流程分析完毕。从以上流程可以看到,mWakeLockSummary和mUserActivitySummary对自动灭屏来说相当重要,平时如果存在到达自动灭屏时间后不灭屏问题,可以确认下这两个值的状态是否正常。

自动灭屏时序图如下:

gotosleep_timeout (1).jpg

3.PSensor灭屏

日常使用场景中,还有一个常见灭屏,就是距离传感器灭屏。打电话、听语音时都会由Psensor灭屏,避免误触。

然而,虽然都是灭屏,但内部实现却是天差地别,实际上,PSensor的灭屏,只会改变Display模块中的屏幕亮度和Display状态,PM唤醒状态依然保持Awake(即mWakefulnessRaw = AWAKE,mUserActivitySummary = BRIGHT,....... ),这部分内容,在对DisplayManager模块分析时进行。