灭屏流程

分析了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

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将会在适当时机进行休眠。


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对自动灭屏来说相当重要,平时如果存在到达自动灭屏时间后不灭屏问题,可以确认下这两个值的状态是否正常。

自动灭屏时序图如下:


3.PSensor灭屏

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容