天天看點

Android N DisplayManager服務解析(二)

版權聲明:轉載請聯系本人,感謝配合!本站位址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/77430743

PowerManagerService:負責協調裝置上電源管理功能的服務。

DisplayPowerController:控制螢幕顯示相關的電源狀态。處理距離傳感器、光線傳感器和螢幕關閉時的動畫等。這個元件在其他電源管理服務中是獨立的,也就是說它不會共享任何狀态,而隻是通過異步回調來通知其他電源管理子產品某些狀态已經改變。這個類在内部做的一切都是被序列化的,盡管它可能被來自外部的其他線程通路。

DisplayManagerService:它管理顯示的整個生命周期,決定怎樣基于目前的實體顯示裝置來配置邏輯顯示,并且當狀态改變時發生通知給系統和應用。為了發現和配置依附于系統的一系列實體顯示裝置,DMS依賴于一系列 DisplayAdapter 元件。根據裝置的不同分為不同的顯示擴充卡:一個顯示擴充卡用于内置的本地顯示器;one for simulated non-functional displays when the system is headless;one for simulated overlay displays used for development;一個用于WiFi顯示。通過注冊的 DisplayAdapter.Listener ,擴充卡來和 DMS 異步地交流顯示裝置的狀态。這裡有兩個主要的原因。 首先它很好的封裝了兩個類的職責:顯示擴充卡處理各個顯示裝置,顯示管理服務處理全局狀态。其次,它消除了異步的查找顯示裝置時導緻的死鎖。

DisplayPowerState:控制顯示狀态。當屬性改變的時候,該元件以統一的順序發生一個回調以應用這些改變。這個元件必須且隻能被屬于 DPC 的 Looper 線程來建立和通路。

在PMS的systemReady方法中,會初始化各種元件,其中就包括這裡的DMI,也就是DisplayManagerInternal,它位于hardware包下,作為顯示管理的本地服務借口,而DMS等處于server包下,LocalService就繼承于它,而DMS本身繼承于SystemService。這SS是運作在系統程序中的用于server的基礎類,負責提供了相關的生命周期和回調。

回調到DisplayManagerService LocalService.initPowerManagement

DMS.requestGlobalDisplayStateInternal -> applyGlobalDisplayStateLocked -> updateDisplayStateLocked

LocalDisplayDevice.requestDisplayStateLocked

以下都是在requestDisplayStateLocked傳回的Runnable中調用的:

SurfaceControl.setDisplayPowerMode 調到native層

mBacklight.setBrightness

DisplayPowerController

DPC控制螢幕顯示相關的電源狀态,包括距離傳感器和光線傳感器等。

這個類比較多龐大,我們逐漸來看,首先是構造方法。在這裡對它所持有的對象進行了初始化,包括以下内容:

mHandler,内部持有的DisplayControllerHandler,用于分發事件。

mCallbacks,

mBatteryStates,

mSensorManager

mWindowManagerPolicy

mBlanker

調節螢幕電源狀态,這裡指的是螢幕狀态,之後會通過mHandler來發送一條異步的MSG_UPDATE_POWER_STATE消息。

/**
     * Requests a new power state.
     * The controller makes a copy of the provided object and then
     * begins adjusting the power state to match what was requested.
     *
     * @param request The requested power state.
     * @param waitForNegativeProximity If true, issues a request to wait for
     * negative proximity before turning the screen back on, assuming the screen
     * was turned off by the proximity sensor.
     * @return True if display is ready, false if there are important changes that must
     * be made asynchronously (such as turning the screen on), in which case the caller
     * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
     * then try the request again later until the state converges.
     */
    public boolean requestPowerState(DisplayPowerRequest request,
            boolean waitForNegativeProximity) {
        if (DEBUG) {
            Slog.d(TAG, "requestPowerState: "
                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
        }

        synchronized (mLock) {
            boolean changed = false;

            if (waitForNegativeProximity
                    && !mPendingWaitForNegativeProximityLocked) {
                mPendingWaitForNegativeProximityLocked = true;
                changed = true;
            }

            if (mPendingRequestLocked == null) {
                mPendingRequestLocked = new DisplayPowerRequest(request);
                changed = true;
            } else if (!mPendingRequestLocked.equals(request)) {
                mPendingRequestLocked.copyFrom(request);
                changed = true;
            }

            if (changed) {
                mDisplayReadyLocked = false;
            }

            if (changed && !mPendingRequestChangedLocked) {
                mPendingRequestChangedLocked = true;
                sendUpdatePowerStateLocked();
            }

            return mDisplayReadyLocked;
        }
    }           

接下來就看看對于MSG_UPDATE_POWER_STATE消息是如何處理的,在handler中直接調用了updatePowerState()方法。

initialize() 為預設顯示裝置初始化電源狀态,包括根據螢幕狀态和亮度回報給電源Line 508

根據mPowerRequest.policy來設定state和brightness

對距離傳感器做相應的操作

執行螢幕狀态變化的動畫

息屏時亮度設為BRIGHTNESS_OFF

判斷和使用自動亮度

boost這個沒有了解,再看看源碼,

再分别對自動亮度和手動亮度調節做處理

如果低電量模式開啟,在亮度的閥值之上,對亮度進行減半

在螢幕點亮狀态或休眠時,animate螢幕亮度。如果是息屏、挂起,或者從VR狀态轉入轉出時,跳過動畫。

判斷對于新的狀态請求,顯示裝置是否就緒

通知policy螢幕已經點亮,真正執行時在mWindowManagerPolicy.screenTurnedOn()

擷取鎖、通知狀态、釋放鎖

DisplayPowerState

該元件用于控制顯示狀态,當屬性改變的時候,其以統一的順序将這些改變回調出去。這個元件隻能被DisplayPowerController的Looper線程來建立和通路。

DisplayPowerState主要負責設定螢幕狀态和螢幕亮度等。這裡的dozing也是一種螢幕狀态,它是指在低電量模式下,螢幕的休眠狀态,但是此時仍然是亮屏的,這是為了讓螢幕在沒有發生互動時而顯示内容的一種優化(其中又分為DOZE和DOZE_SUSPEND兩種狀态,後者能夠實作always-on等功能)。

/**
     * Sets whether the screen is on, off, or dozing.
     */
    public void setScreenState(int state) {
        if (mScreenState != state) {
            if (DEBUG) {
                Slog.d(TAG, "setScreenState: state=" + state);
            }

            mScreenState = state;
            mScreenReady = false;
            scheduleScreenUpdate();
        }
    }

    /**
     * Sets the display brightness.
     *
     * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
     */
    public void setScreenBrightness(int brightness) {
        if (mScreenBrightness != brightness) {
            if (DEBUG) {
                Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
            }

            mScreenBrightness = brightness;
            if (mScreenState != Display.STATE_OFF) {
                mScreenReady = false;
                scheduleScreenUpdate();
            }
        }
    }           

其中最重要的就是這個scheduleScreenUpdate方法,它會去在mPhotonicModulator中異步地設定螢幕狀态和亮度。

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

            int brightness = mScreenState != Display.STATE_OFF
                    && mColorFadeLevel > 0f ? mScreenBrightness : 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線程在DPS的構造函數中就已經start了,始終在運作着。那麼對于一次setState操作,這個現場裡究竟會發生什麼呢?

1.在setState之後,該方法就會擷取到mLock,這樣在run中隻會走到for循環裡,但不會進到synchronized裡面的代碼中。

2.在setState中,首先會判斷螢幕狀态和背光是否發生改變,如果是就繼續往下走,将這兩個值賦給現場内部的mPending*,這個會在run()中使用。

3.判斷狀态是否都在改變中,判斷完後分别進行指派,如果不在就調用mLock.notifyAll()通知現場可以進行修改了。然後setState方法傳回false,因為還沒有設定完畢。

4.此時就輪到run方法中擷取mLock了,在這裡首先state和backlight會擷取到來自setState中存儲到線程内的值,如果設定的狀态和實際的狀态不一樣,就不會将InProgress的值設為false,因為現在正是要進行修改。

5.然後就會去調用mBlander去設定螢幕狀态和背光。

6.在螢幕狀态和背光都設定好之後,因為是run方法,for循環還得繼續,此時因為值沒有變化,不用修改,是以就會去wait。

public boolean setState(int state, int backlight) {
            synchronized (mLock) {
                boolean stateChanged = state != mPendingState;
                boolean backlightChanged = backlight != mPendingBacklight;
                if (stateChanged || backlightChanged) {
                    if (DEBUG) {
                        Slog.d(TAG, "Requesting new screen state: state="
                                + Display.stateToString(state) + ", backlight=" + backlight);
                    }

                    mPendingState = state;
                    mPendingBacklight = backlight;

                    boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
                    mStateChangeInProgress = stateChanged;
                    mBacklightChangeInProgress = backlightChanged;

                    if (!changeInProgress) {
                        mLock.notifyAll();
                    }
                }
                return !mStateChangeInProgress;
            }
        }           
@Override
        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) {
                        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);
            }
        }           

繼續閱讀