1. 程式人生 > >Android7.0 PowerManagerService亮滅屏分析(二)

Android7.0 PowerManagerService亮滅屏分析(二)

    在PowerManagerService中對各種狀態進行判斷後,將其數值封裝進DisplayPowerRequest中傳入DisplayPowerController中進一步處理。在亮屏過程中DisplayPowerController會根據傳過來的數值來設定新的電源狀態為亮屏,然後呼叫DisplayPowerState來對狀態進行設定,在分析DisplayPowerState時會具體講解。由於此時ColorFade level(就是在手機螢幕的一層surface,當level為0是為一層黑幀,level為1.0時為透明)的值為0,表示螢幕還沒有繪製好,所以此時需要block screen直到window介面繪製完成。當需要亮屏時呼叫PhoneWindowManager的screenTurningOn函式,通知window螢幕就要點亮了。然後呼叫WMS中函式waitForAllWindowsDrawn函式等待將所有需要繪製的window繪製完成後回調回來,超時時間為1000ms。在WMS中獲取需要繪製的window將其加入mWaitingForDrawn中等待繪製,通過檢查mWaitingForDrawn是否為空來判斷,window是否繪製完成。此時screenTurningOn函式就執行完了,剩下的就是等待windows繪製完成。


DisplayManagerService.java中的LocalService繼承了DisplayManagerInternal.java, 所以就會呼叫LocalService的requestPowerState函式請求電源狀態. 

    private final class LocalService extends DisplayManagerInternal {
        @Override
        public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
                SensorManager sensorManager) {    //初始化函式在PowerManagerService的systemReady函式中呼叫
            synchronized (mSyncRoot) {
                DisplayBlanker blanker = new DisplayBlanker() {   //建立blanker物件
                    @Override
                    public void requestDisplayState(int state, int brightness) {
                        // The order of operations is important for legacy reasons.
                        if (state == Display.STATE_OFF) {
                            requestGlobalDisplayStateInternal(state, brightness);
                        }

                        callbacks.onDisplayStateChange(state);

                        if (state != Display.STATE_OFF) {
                            requestGlobalDisplayStateInternal(state, brightness);
                        }
                    }
                };
                mDisplayPowerController = new DisplayPowerController(    //建立DisplayPowerController物件
                        mContext, callbacks, handler, sensorManager, blanker);
            }
        }

        @Override
        public boolean requestPowerState(DisplayPowerRequest request,
                boolean waitForNegativeProximity) {
            return mDisplayPowerController.requestPowerState(request,
                    waitForNegativeProximity);     //呼叫DisplayPowerController請求電源狀態
        }
       //.....
}

    在DisplayPowerController中通過Handler傳送MSG_UPDATE_POWER_STATE訊息呼叫updatePowerState來更新電源狀態. updatePowerState也是一個非常核心的函式,在該函式中將PowerManagerService中傳過來的引數獲取出來根據policy獲取裝置的請求狀態是ON, OFF還是DOZE, 應用距離感測器, 將最終的請求狀態呼叫DisplayPowerState進行設定. 判斷裝置是否打開了自動亮度調節, 計算最終螢幕要達到的目標亮度並通過亮度漸變動畫慢慢的點亮螢幕,最終變為高亮.

    private void updatePowerState() {
        // Update the power state request.
        final boolean mustNotify;
        boolean mustInitialize = false;
        boolean autoBrightnessAdjustmentChanged = false;

        synchronized (mLock) {
            mPendingUpdatePowerStateLocked = false;
            if (mPendingRequestLocked == null) {
                return; // wait until first actual power request
            }

            if (mPowerRequest == null) { //判斷mPowerRequest是否為NULL,如果為空新建立一個, 否則直接將mPendingRequestLocked複製給他  
                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
                mPendingWaitForNegativeProximityLocked = false;
                mPendingRequestChangedLocked = false;
                mustInitialize = true;
            } else if (mPendingRequestChangedLocked) {
                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
                mPowerRequest.copyFrom(mPendingRequestLocked);
                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
                mPendingWaitForNegativeProximityLocked = false;
                mPendingRequestChangedLocked = false;
                mDisplayReadyLocked = false;
            }

            mustNotify = !mDisplayReadyLocked;
        }

        // Initialize things the first time the power state is changed.
        if (mustInitialize) {
            initialize();//power state第一次發生變化時需要做一些初始化,如:建立DisplayPowerState, 亮滅屏動畫,亮度漸變動畫例項等 
        }

        // Compute the basic display state using the policy.
        // We might override this below based on other factors.
        int state;
        int brightness = PowerManager.BRIGHTNESS_DEFAULT;//設定螢幕預設亮度
        boolean performScreenOffTransition = false;
        switch (mPowerRequest.policy) {
            case DisplayPowerRequest.POLICY_OFF: //設定裝置狀態為OFF 
                state = Display.STATE_OFF;
                performScreenOffTransition = true; //滅屏有過渡動畫  
                break;
            case DisplayPowerRequest.POLICY_DOZE:  //設定裝置狀態為DOZE
                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
                    state = mPowerRequest.dozeScreenState;
                } else {
                    state = Display.STATE_DOZE;
                }
                if (!mAllowAutoBrightnessWhileDozingConfig) {
                    brightness = mPowerRequest.dozeScreenBrightness;//如果在xml檔案中配置了相關屬性,就將dozeScreenBrightness賦給亮度值
                }
                break;
            case DisplayPowerRequest.POLICY_DIM:
            case DisplayPowerRequest.POLICY_BRIGHT:
            default:
                state = Display.STATE_ON;//如果policy為DIM, BRIGHT的話,裝置狀態都為ON
                break;
        }
        assert(state != Display.STATE_UNKNOWN);

        // Apply the proximity sensor.
        if (mProximitySensor != null) {  //距離感測器相關處理
            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
                setProximitySensorEnabled(true);
                if (!mScreenOffBecauseOfProximity
                        && mProximity == PROXIMITY_POSITIVE) {
                    mScreenOffBecauseOfProximity = true;
                    sendOnProximityPositiveWithWakelock();
                }
            } else if (mWaitingForNegativeProximity
                    && mScreenOffBecauseOfProximity
                    && mProximity == PROXIMITY_POSITIVE
                    && state != Display.STATE_OFF) {
                setProximitySensorEnabled(true);
            } else {
                setProximitySensorEnabled(false);
                mWaitingForNegativeProximity = false;
            }
            if (mScreenOffBecauseOfProximity
                    && mProximity != PROXIMITY_POSITIVE) {
                mScreenOffBecauseOfProximity = false;
                sendOnProximityNegativeWithWakelock();
            }
        } else {
            mWaitingForNegativeProximity = false;
        }
        if (mScreenOffBecauseOfProximity) {
            state = Display.STATE_OFF;//如果因為距離感測器滅屏設定裝置狀態為OFF
        }

        // Animate the screen state change unless already animating.
        // The transition may be deferred, so after this point we will use the
        // actual state instead of the desired one.
        animateScreenStateChange(state, performScreenOffTransition);//處理螢幕狀態改變
        state = mPowerState.getScreenState();//獲取新的螢幕狀態 

        // Use zero brightness when screen is off.
        if (state == Display.STATE_OFF) {
            brightness = PowerManager.BRIGHTNESS_OFF; //如果新的狀態是滅屏的話設定brightness為0
        }

        // Configure auto-brightness.
        boolean autoBrightnessEnabled = false;
        if (mAutomaticBrightnessController != null) {
            final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig
                    && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND);
            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
                    && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
                    && brightness < 0;
            final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
                    && mPowerRequest.brightnessSetByUser;
            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
                    mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
                    userInitiatedChange, mPowerRequest.useTwilight);//配置控制自動亮度設定的物件
        }

        // Apply brightness boost.
        // We do this here after configuring auto-brightness so that we don't
        // disable the light sensor during this temporary state.  That way when
        // boost ends we will be able to resume normal auto-brightness behavior
        // without any delay.
        if (mPowerRequest.boostScreenBrightness
                && brightness != PowerManager.BRIGHTNESS_OFF) {
            brightness = PowerManager.BRIGHTNESS_ON;
        }

        // Apply auto-brightness.
        boolean slowChange = false;
        if (brightness < 0) {
            if (autoBrightnessEnabled) {
                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();//獲取自動亮度值
            }
            if (brightness >= 0) {
                // Use current auto-brightness value and slowly adjust to changes.
                brightness = clampScreenBrightness(brightness);//保證亮度值的有效性,不能在0~255之外
                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
                    slowChange = true; // slowly adapt to auto-brightness
                }
                mAppliedAutoBrightness = true;//使用了自動亮度
            } else {
                mAppliedAutoBrightness = false;//沒有使用自動亮度
            }
        } else {
            mAppliedAutoBrightness = false;
        }

        // Use default brightness when dozing unless overridden.
        if (brightness < 0 && (state == Display.STATE_DOZE
                || state == Display.STATE_DOZE_SUSPEND)) {
            brightness = mScreenBrightnessDozeConfig;
        }

        // Apply manual brightness.
        // Use the current brightness setting from the request, which is expected
        // provide a nominal default value for the case where auto-brightness
        // is not ready yet.
        if (brightness < 0) {
            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);//如果亮度值小於0的話,就是用setting中設定的亮度值
        }

        // Apply dimming by at least some minimum amount when user activity
        // timeout is about to expire.
        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
            if (brightness > mScreenBrightnessRangeMinimum) {
                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
            }
            if (!mAppliedDimming) {
                slowChange = false;
            }
            mAppliedDimming = true;
        } else if (mAppliedDimming) {
            slowChange = false;
            mAppliedDimming = false;
        }

        // If low power mode is enabled, cut the brightness level by half
        // as long as it is above the minimum threshold.
        if (mPowerRequest.lowPowerMode) {
            if (brightness > mScreenBrightnessRangeMinimum) {
                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);//低電模式, 亮度是目標亮度的1/2
            }
            if (!mAppliedLowPower) {
                slowChange = false;
            }
            mAppliedLowPower = true;
        } else if (mAppliedLowPower) {
            slowChange = false;
            mAppliedLowPower = false;
        }

        // Animate the screen brightness when the screen is on or dozing.
        // Skip the animation when the screen is off or suspended.
        if (!mPendingScreenOff) {
            if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
                animateScreenBrightness(brightness,
                        slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : mBrightnessRampRateFast);//使用亮度漸變動畫設定亮度, 漸變速度依賴於rate
            } else {
                animateScreenBrightness(brightness, 0);//動畫速率為0, 沒有動畫
            }
        }
        //..........
    }

根據上面程式碼分析在updatePowerState中主要做的事情主要有兩件事:
1.呼叫animateScreenStateChange函式處理螢幕狀態變化
2.呼叫animateScreenBrightness函式設定螢幕亮度
下面將詳細講解這兩件事情:
animateScreenStateChange函式處理螢幕狀態變化

    private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
        // If there is already an animation in progress, don't interfere with it.
        if (mColorFadeOnAnimator.isStarted()    
                || mColorFadeOffAnimator.isStarted()) {
            if (target != Display.STATE_ON) {
                return;    //如果此時有亮滅屏動畫, 並且目標狀態不是ON,就返回.
            }
            // If display state changed to on, proceed and stop the color fade and turn screen on.
            mPendingScreenOff = false;
        }

        // If we were in the process of turning off the screen but didn't quite
        // finish.  Then finish up now to prevent a jarring transition back
        // to screen on if we skipped blocking screen on as usual.
        if (mPendingScreenOff && target != Display.STATE_OFF) {
            setScreenState(Display.STATE_OFF);
            mPendingScreenOff = false;
            mPowerState.dismissColorFadeResources();
        }

        if (target == Display.STATE_ON) {    //亮屏
            // Want screen on.  The contents of the screen may not yet
            // be visible if the color fade has not been dismissed because
            // its last frame of animation is solid black.
            if (!setScreenState(Display.STATE_ON)) {    //設定螢幕狀態,如果返回false就blocked亮屏, 不能往下執行
                return; // screen on blocked
            }
            if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
                // Perform screen on animation.     
                if (mPowerState.getColorFadeLevel() == 1.0f) {   //執行亮屏動畫, 將Color Fade level漸變為1.0f
                    mPowerState.dismissColorFade();
                } else if (mPowerState.prepareColorFade(mContext,
                        mColorFadeFadesConfig ?
                                ColorFade.MODE_FADE :
                                        ColorFade.MODE_WARM_UP)) {
                    mColorFadeOnAnimator.start();
                } else {
                    mColorFadeOnAnimator.end();
                }
            } else {
                // Skip screen on animation.
                mPowerState.setColorFadeLevel(1.0f);   //跳過亮屏, 直接設定Color Fade level為1.0f
                mPowerState.dismissColorFade();
            }
          //...........
        } else {
            // Want screen off.   //滅屏
            mPendingScreenOff = true;
            if (mPowerState.getColorFadeLevel() == 0.0f) {
                // Turn the screen off.
                // A black surface is already hiding the contents of the screen.
                setScreenState(Display.STATE_OFF);   //如果Color Fade level為0.0f, 設定螢幕狀態為OFF
                mPendingScreenOff = false;
                mPowerState.dismissColorFadeResources();
            } else if (performScreenOffTransition  //performScreenOffTransition為true, 有滅屏過渡動畫
                    && mPowerState.prepareColorFade(mContext,
                            mColorFadeFadesConfig ?
                                    ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
                    && mPowerState.getScreenState() != Display.STATE_OFF) {
                // Perform the screen off animation.
                mColorFadeOffAnimator.start();    //滅屏動畫,Color fade leve慢慢將1.0變為0.0f
            } else {
                // Skip the screen off animation and add a black surface to hide the
                // contents of the screen.
                mColorFadeOffAnimator.end();     //跳過滅屏動畫
            }
        }
    }

    在上面函式中主要就是呼叫setScreenState設定螢幕狀態, 只有設定好狀態並且setScreenState返回true,之後才會判斷是否有亮度漸變動畫將Color Fade Level設定為1.0f. 否則一直會阻塞在setScreenState函式上.

    private boolean setScreenState(int state) {
        if (mPowerState.getScreenState() != state) {
            final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
            mPowerState.setScreenState(state);   //呼叫DisplayPowerState設定螢幕狀態

            // Tell battery stats about the transition.
            try {
                mBatteryStats.noteScreenState(state);
            } catch (RemoteException ex) {
                // same process
            }
        }

        // Tell the window manager policy when the screen is turned off or on unless it's due
        // to the proximity sensor.  We temporarily block turning the screen on until the
        // window manager is ready by leaving a black surface covering the screen.
        // This surface is essentially the final state of the color fade animation and
        // it is only removed once the window manager tells us that the activity has
        // finished drawing underneath.
        final boolean isOff = (state == Display.STATE_OFF);   //是否是滅屏狀態
        if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
                && !mScreenOffBecauseOfProximity) {
            mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
            unblockScreenOn();
            mWindowManagerPolicy.screenTurnedOff();
            PMSFactory.getInstance().createExtraDisplayPowerState(mContext).setButtonOn(false);
        } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
            mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_ON;
            if (mPowerState.getColorFadeLevel() == 0.0f) {    //亮屏處理, 此時Colorfade level為0.0f 為true
                blockScreenOn();        //block亮屏, 建立一個mPendingScreenOnUnblocker物件
            } else {
                unblockScreenOn(); //將建立的mPendingScreenOnUnblocker物件銷燬,設定NULL
            }
            mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);    //呼叫PhoneWindowManager進行處理
            if (PMSFactory.getInstance().createExtraDisplayPowerController(mContext).getButtonTimeout() != -2){
                PMSFactory.getInstance().createExtraDisplayPowerState(mContext).setButtonOn(true);
            }
        }

        // Return true if the screen isn't blocked.
        return mPendingScreenOnUnblocker == null;   //blockScreenOn時建立一個mPendingScreenOnUnblocker物件,所以返回false, block亮屏
    }
    private void blockScreenOn() {
        if (mPendingScreenOnUnblocker == null) {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
            mPendingScreenOnUnblocker = new ScreenOnUnblocker();
            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();   //開始blocked亮屏的時間
            Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
        }
    }

    private void unblockScreenOn() {
        if (mPendingScreenOnUnblocker != null) {
            mPendingScreenOnUnblocker = null;
            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
            Slog.i(TAG, "Unblocked screen on after " + delay + " ms");   //輸出log,一共block亮屏多長時間
            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
        }
    }

在setScreenState函式中主要做了兩件事情:
1.呼叫DisplayPowerState對螢幕狀態進行設定
2.通知PhoneWindowManager對keyguard和windows進行繪製.
設定螢幕狀態


    當設定螢幕狀態時,如果新狀態與之前的狀態不同時就會將新的狀態值記錄在成員變數mScreenState中,這樣可以讓其它類來獲取當前的螢幕狀態。之後在一個Runnable物件的run函式中根據螢幕狀態與ColorFade level來進行獲取螢幕亮度,此時是亮屏操作但是windows尚未繪製完成level仍然是0.0,此時獲取的亮度值為0,由此可知,只要windows繪製不完成亮度值會一直為0,即螢幕不會亮。

    private final Runnable mScreenUpdateRunnable = new Runnable() {
        @Override
        public void run() {
            mScreenUpdatePending = false;

            int brightness = mScreenState != Display.STATE_OFF
                    && mColorFadeLevel > 0f ? mScreenBrightness : 0;   //根據螢幕狀態設定亮度值, 亮屏時如果color Fade Level為0.0f, brightness一直為0,不會亮屏
            if (mPhotonicModulator.setState(mScreenState, brightness)) {
                if (DEBUG) {
                    Slog.d(TAG, "Screen ready");
                }
                mScreenReady = true;
                invokeCleanListenerIfNeeded();
            } else {
                if (DEBUG) {
                    Slog.d(TAG, "Screen not ready");
                }
            }
        }
    };
    通過呼叫執行緒PhotonicModulator的setState函式來記錄所請求的狀態,如果執行緒此時處於wait狀態,就呼叫NotifyAll函式將其喚醒。線上程PhotonicModulator的run函式中為一個死迴圈,不停的進行判斷螢幕亮度與螢幕狀態是否發生了改變,如果兩者都沒有發生變化,為了減輕cpu負載執行緒就會wait。由於此時螢幕狀態發生變化,新的狀態為STATE_ON,所以suspending為false。之後進行請求裝置狀態。
        public void run() {
            for (;;) {
                // Get pending change.
                final int state;
                final boolean stateChanged;
                final int backlight;
                final boolean backlightChanged;
                synchronized (mLock) {
                    state = mPendingState;
                    stateChanged = (state != mActualState);
                    backlight = mPendingBacklight;
                    backlightChanged = (backlight != mActualBacklight);
                    if (!stateChanged) {   //判斷狀態是否變化
                        // State changed applied, notify outer class.
                        postScreenUpdateThreadSafe();
                        mStateChangeInProgress = false;
                    }
                    if (!backlightChanged) {  
                        mBacklightChangeInProgress = false;
                    }
                    if (!stateChanged && !backlightChanged) {   //如果亮度,狀態都沒有改變執行緒將wait
                        try {
                            mLock.wait();
                        } catch (InterruptedException ex) { }
                        continue;
                    }
                    mActualState = state;     //獲取確實的狀態.亮度
                    mActualBacklight = backlight;
                }

                // Apply pending change.
                if (DEBUG) {
                    Slog.d(TAG, "Updating screen state: state="
                            + Display.stateToString(state) + ", backlight=" + backlight);
                }
                mBlanker.requestDisplayState(state, backlight);    //mBlanker為DisplayManagerService中建立的物件,前面有提到.
            }
        }

在DisplayManagerSerice中的LocalService初始化函式initPowerManagement中建立的mBlanker, 所以就呼叫他的requestDisplayState函式

                DisplayBlanker blanker = new DisplayBlanker() {
                    @Override
                    public void requestDisplayState(int state, int brightness) {
                        // The order of operations is important for legacy reasons.
                        if (state == Display.STATE_OFF) {    
                            requestGlobalDisplayStateInternal(state, brightness);   //滅屏先呼叫該函式
                        }

                        callbacks.onDisplayStateChange(state);    //callbacks為PowerManagerService中物件

                        if (state != Display.STATE_OFF) {
                            requestGlobalDisplayStateInternal(state, brightness);   //亮屏呼叫該處函式
                        }
                    }
                };

    在此處先講解回撥PowerManagerService的onDisplayStateChange函式做了那些事情,耗時點在什麼地方. 在該函式中會首先獲取一個mLock的鎖,這把鎖是不是很熟悉,我們在前面講繪製windows流程的時候window與power互動時需要獲取mLock,如果該鎖被別的執行緒持有,window繪製流程就會阻塞。而根據上面流程可以看出,請求裝置狀態是在繪製window之前發生的,所以呼叫函式onDisplayStateChange沒有結束的話,該鎖就一直被持有,導致window繪製流程不能及時返回。

        public void onDisplayStateChange(int state) {
            // This method is only needed to support legacy display blanking behavior
            // where the display's power state is coupled to suspend or to the power HAL.
            // The order of operations matters here.
            synchronized (mLock) {     //獲取mLock鎖
                if (mDisplayState != state) {
                    mDisplayState = state;
                    if (state == Display.STATE_OFF) {  //滅屏
                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
                            setHalInteractiveModeLocked(false);
                        }
                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
                            setHalAutoSuspendModeLocked(true);
                        }
                    } else {      //亮屏
                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
                            setHalAutoSuspendModeLocked(false);    //設定自動suspend模式
                        }
                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
                            setHalInteractiveModeLocked(true);   //設定hal互動模式
                        }
                    }
                }
            }
        }
    private void setHalAutoSuspendModeLocked(boolean enable) {
        if (enable != mHalAutoSuspendModeEnabled) {
            if (DEBUG) {
                Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
            }
            mHalAutoSuspendModeEnabled = enable;
            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")");
            try {
                nativeSetAutoSuspend(enable);   //呼叫JNI設定
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_POWER);
            }
        }
    }
之後就會通過函式setHalAutoSuspendModeLocked呼叫到底層進行處理。而在底層進行處理時可以通過log資訊看出,耗時的長短。
static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    if (enable) {
        ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");  //滅屏執行超過100ms,會輸出log
        autosuspend_enable();
    } else {
        ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_disable() while turning screen on"); //亮屏執行該函式超過100ms, 會輸出該行log
        autosuspend_disable();
    }
}

而在亮屏時呼叫autosuspend_disable()是往/sys/power/state寫 on(亮屏)的函式。在往節點寫入狀態後,呼叫late_resume將LCD resume,關於late_resume 階段 “sprdfb_dispc_resume”函式執行時間可能由於手機硬體資訊的不同,導致執行時間相差較大。
上面執行完之後,現在重新回到DMS中繼續向下進行執行。

在DMS中通過變數mGlobalDisplayState進行記錄當前的裝置狀態,如果裝置狀態發生改變時就會重新記錄,之後更新裝置狀態將device對應的Runnable放入佇列。然後就會將Runnable從佇列中取出執行run函式。根據dumpsys資訊可以知道,裝置資訊中只有一個裝置“內建螢幕”,並且對應的Adapter為LocalDisplayAdapter,所以就會呼叫LocalDisplayAdapter中的run函式。在run函式中會呼叫SurfaceControl中的setDisplayPowerMode函式處理。最終到JNI中,此處也有可能發生超時,也可從輸出log中看出。

static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == NULL) return;

    ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
    SurfaceComposerClient::setDisplayPowerMode(token, mode);
}
之後就呼叫frameworks/native/libs/gui/SurfaceComposerClient.cpp的setDisplayPowerMode函式中, 屬於GUI模組.
void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token,
        int mode) {
    ComposerService::getComposerService()->setPowerMode(token, mode);
}
當該流程結束後,設定裝置狀態就結束了。

繪製keyguard與windows

在DisplayPowerController中呼叫screenTurningOn函式到PhoneWindowManager中.將mPendingScreenOnUnblocker物件傳過來方便完成繪製後回調回來.

    // Called on the DisplayManager's DisplayPowerController thread.
    @Override
    public void screenTurningOn(final ScreenOnListener screenOnListener) {
        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");

        updateScreenOffSleepToken(false);
        synchronized (mLock) {
            mScreenOnEarly = true;
            mScreenOnFully = false;
            mKeyguardDrawComplete = false;
            mWindowManagerDrawComplete = false;
            mScreenOnListener = screenOnListener;

            if (mKeyguardDelegate != null) {
                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);  //傳送超時訊息, 1000ms keyguard還沒有繪製完,就繼續向下執行
                mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);  //呼叫keyguard中函式, 繪製完成後回撥mKeyguardDrawnCallback
            } else {
                if (DEBUG_WAKEUP) Slog.d(TAG,
                        "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
                finishKeyguardDrawn();   //如果沒有keyguard就直接結束繪製
            }
        }
    }
當繪製完keyguard或者keyguard繪製超時都會呼叫finishKeyguardDrawn結束繪製.
    final DrawnListener mKeyguardDrawnCallback = new DrawnListener() {
        @Override
        public void onDrawn() {   //繪製完成呼叫onDrawn函式
            if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onDrawn.");
            mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);  //傳送MSG_KEYGUARD_DRAWN_COMPLETE訊息
        }
    };

    private class PolicyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_KEYGUARD_DRAWN_COMPLETE:    
                    if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete");
                    finishKeyguardDrawn();   //keyguard繪製完成, 結束
                    break;
                case MSG_KEYGUARD_DRAWN_TIMEOUT:
                    Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete");
                    finishKeyguardDrawn();   //keyguard繪製超時, 結束
                    break;
            }
        }
    }
keyguard繪製結束後呼叫WindowManagerService對Windows進行繪製, 繪製windows超時時間也為1000ms
    /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
    static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;      //windows繪製超時時間1000ms

    private void finishKeyguardDrawn() {
        synchronized (mLock) {
            if (!mScreenOnEarly || mKeyguardDrawComplete) {
                return; // We are not awake yet or we have already informed of this event.
            }

            mKeyguardDrawComplete = true;
            if (mKeyguardDelegate != null) {
                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);  //移除keyguard超時的message
            }
            mWindowManagerDrawComplete = false;
        }

        // ... eventually calls finishWindowsDrawn which will finalize our screen turn on
        // as well as enabling the orientation change logic/sensor.
        mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
                WAITING_FOR_DRAWN_TIMEOUT);    //windows繪製完成後回撥mWindowManagerDrawCallback
    }
在WindowManagerService中獲取需要繪製的windows將其加入mWaitingForDrawn中等待繪製,通過檢查mWaitingForDrawn是否為空來判斷,window是否繪製完成。此時screenTurningOn函式就執行完了,剩下的就是等待windows繪製完成.
        @Override
        public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
            boolean allWindowsDrawn = false;
            synchronized (mWindowMap) {
                mWaitingForDrawnCallback = callback;
                final WindowList windows = getDefaultWindowListLocked();  //獲取windows列表
                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                    final WindowState win = windows.get(winNdx);
                    final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
                    if (win.isVisibleLw()
                            && (win.mAppToken != null || isForceHiding)) {
                        win.mWinAnimator.mDrawState = DRAW_PENDING;
                        // Force add to mResizingWindows.
                        win.mLastContentInsets.set(-1, -1, -1, -1);
                        mWaitingForDrawn.add(win);   //將所要繪製的windows加入mWaitingForDrawn中

                        // No need to wait for the windows below Keyguard.
                        if (isForceHiding) {
                            break;
                        }
                    }
                }
                mWindowPlacerLocked.requestTraversal();
                mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);   //先將繪製windows超時的message移除, 以便重新計時
                if (mWaitingForDrawn.isEmpty()) {
                    allWindowsDrawn = true;
                } else {
                    mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);  //傳送繪製超時的延遲訊息
                    checkDrawnWindowsLocked();   //檢查windows是否繪製完成
                }
            }
            if (allWindowsDrawn) {
                callback.run();   //如果所有windows都繪製完成了就呼叫回撥介面, 回到PhoneWindowManager中
            }
        }

    void checkDrawnWindowsLocked() {
        if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
            return;   //如果沒有要繪製的windows或者沒有回撥介面就直接返回了
        }
        for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {  //遍歷要繪製的windows
            WindowState win = mWaitingForDrawn.get(j);
            if (DEBUG_SCREEN_ON) Slog.i(TAG_WM, "Waiting for drawn " + win +
                    ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
                    " mHasSurface=" + win.mHasSurface +
                    " drawState=" + win.mWinAnimator.mDrawState);
            if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
                // Window has been removed or hidden; no draw will now happen, so stop waiting.
                if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win);
                mWaitingForDrawn.remove(win);   //如果window已經被移除或者隱藏 就不需要繪製了, 直接從等待列表中移除 
            } else if (win.hasDrawnLw()) {
                // Window is now drawn (and shown).
                if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "Window drawn win=" + win);
                mWaitingForDrawn.remove(win);    //如果window已經繪製完成,也從等待列表中移除
            }
        }
        if (mWaitingForDrawn.isEmpty()) { //如果等待列表為空
            if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "All windows drawn!");
            mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);  //移除超時訊息
            mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);  //傳送ALL_WINDOWS_DRAWN訊息
        }
    }
這時只用等待所有的windows繪製了.

Windows的繪製在ViewRootImpl的draw函式中,其中ViewRoot的draw是通過vsync進行同步繪製。在繪製完成之後就會呼叫到WMS中DO_TRAVERSAL流程進行呼叫函式checkDrawnWindowsLocked判斷每個window是否繪製完成。繪製完成後會發起ALL_WINDOWS_DRAWN的Message,回調回PhoneWindowManager。由於在呼叫函式performLayoutAndPlaceSurfacesLockedInner過程中需要與Power中的一些函式進行互動,而在Power中函式執行需要獲得mLock鎖,如果該鎖被別的執行緒所持有就會發生阻塞,就不會及時返回發出window繪製完成的訊號,在該流程中具體mLock還會被那些執行緒獲取, 在講解設定設定狀態時講解過可能被power中執行緒獲取.
當window繪製完成後通過介面回撥到PhoneWindowManager中,傳送Window準備好的Message進行結束window繪製,將變數mWindowManagerDrawComplete置為true。最後回到DPC中。
                case ALL_WINDOWS_DRAWN: {   //繪製windows完成
                    Runnable callback;
                    synchronized (mWindowMap) {
                        callback = mWaitingForDrawnCallback;
                        mWaitingForDrawnCallback = null;  
                    }
                    if (callback != null) {
                        callback.run();  //回調回PhoneWindowManager
                    }
                }

                case WAITING_FOR_DRAWN_TIMEOUT: {   //繪製Windows超時
                    Runnable callback = null;
                    synchronized (mWindowMap) {
                        Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);  //輸出超時log資訊
                        mWaitingForDrawn.clear();   //將等待繪製列表清空
                        callback = mWaitingForDrawnCallback;
                        mWaitingForDrawnCallback = null;
                    }
                    if (callback != null) {
                        callback.run(); //回調回PhoneWindowManager
                    }
                    break;
                }
回撥會PhoneWindowManager後傳送所有windows繪製完成的message
    final Runnable mWindowManagerDrawCallback = new Runnable() {
        @Override
        public void run() {
            if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!");
            mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE); //傳送Handler訊息
        }
    };
    private class PolicyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                //........
                case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
                    if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
                    finishWindowsDrawn();    //結束windows繪製
                    break;
                //.......
            }
        }
    }
    private void finishWindowsDrawn() {
        synchronized (mLock) {
            if (!mScreenOnEarly || mWindowManagerDrawComplete) {
                return; // Screen is not turned on or we did already handle this case earlier.
            }

            mWindowManagerDrawComplete = true;   //設定windows繪製完成為true
        }

        finishScreenTurningOn();   //呼叫screenTurningOn就要結束了
    }

    private void finishScreenTurningOn() {
        synchronized (mLock) {
            // We have just finished drawing screen content. Since the orientation listener
            // gets only installed when all windows are drawn, we try to install it again.
            updateOrientationListenerLp();  //更新轉向監聽器
        }
        final ScreenOnListener listener;
        final boolean enableScreen;
        synchronized (mLock) {
            if (DEBUG_WAKEUP) Slog.d(TAG,
                    "finishScreenTurningOn: mAwake=" + mAwake
                            + ", mScreenOnEarly=" + mScreenOnEarly
                            + ", mScreenOnFully=" + mScreenOnFully
                            + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
                            + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);

            if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
                    || (mAwake && !mKeyguardDrawComplete)) {
                return; // spurious or not ready yet
            }

            if (DEBUG_WAKEUP) Slog.i(TAG, "Finished screen turning on...");
            listener = mScreenOnListener;   
            mScreenOnListener = null;
            mScreenOnFully = true;

            // Remember the first time we draw the keyguard so we know when we're done with
            // the main part of booting and can enable the screen and hide boot messages.
            if (!mKeyguardDrawnOnce && mAwake) {
                mKeyguardDrawnOnce = true;
                enableScreen = true;
                if (mBootMessageNeedsHiding) {
                    mBootMessageNeedsHiding = false;
                    hideBootMessages();
                }
            } else {
                enableScreen = false;
            }
        }

        if (listener != null) {
            listener.onScreenOn();    //回調回DisplayPowerController的onScreenOn函式
        }

        if (enableScreen) {
            try {
                mWindowManager.enableScreenIfNeeded();
            } catch (RemoteException unhandled) {
            }
        }
    }

Windows繪製完成回調回來之後,此時就不用block screen了,將mPendingScreenOnUnblocker置為空,並計算screen一共block了多少毫秒。之後進行更新power state,由於之前呼叫DisplayPS設定過狀態為ON,現在狀態沒有發生改變,故不用進行設定直接返回,由於window已經繪製完成mPendingScreenOnUnblocker為空,故返回true。如果沒有亮屏動畫直接將ColorFade level設定為1.0,如果有亮屏動畫的話會有ColorFade level會從0.0逐漸變為1.0。
    private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
        @Override
        public void onScreenOn() {
            Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
            msg.setAsynchronous(true);
            mHandler.sendMessage(msg);   //傳送unblock的訊息
        }
    }

    private final class DisplayControllerHandler extends Handler {
        public DisplayControllerHandler(Looper looper) {
            super(looper, null, true /*async*/);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_POWER_STATE:
                    updatePowerState();
                    break;

                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
                    debounceProximitySensor();
                    break;

                case MSG_SCREEN_ON_UNBLOCKED: //Handler收到unblock的訊息後
                    if (mPendingScreenOnUnblocker == msg.obj) {
                        unblockScreenOn();    //將mPendingScreenOnUnblocker賦值NULL,並且輸出unblock的時間, 之前有講解
                        updatePowerState();   //重新更新power 狀態. setPowerState返回true, 繼續設定Color Fade Level為1.0f
                    }
                    break;
            }
        }
    }

之後就是通過animateScreenBrightness函式設定螢幕亮度.

進而點亮螢幕, 在後文中講解.