Android13 WMS窗口相關(guān)流程(五)

接著上篇:http://www.itdecent.cn/p/95e8654036a8

2.3 窗口狀態(tài)刷新

當(dāng)應(yīng)用端執(zhí)行measure-layout-draw之后,便會(huì)調(diào)用WMS.finishDrawingWindow,處理Surface的狀態(tài)變更并將Surface show出來。
首先還是看一下該階段的流程圖,對(duì)整個(gè)流程有個(gè)初步的了解。
將整個(gè)流程分為三部分:
1.WMS接受客戶端請(qǐng)求,將mDrawState更新為COMMIT_DRAW_PENDING,并請(qǐng)求窗口布局。
2.mDrawState更新為HAS_DRAW,再次請(qǐng)求窗口布局。
3.執(zhí)行show Surface。

2.3.1 接受客戶端請(qǐng)求

代碼路徑:framework/services/core/java/com/android/server/wm/Session.java

    @Override
    public void finishDrawing(IWindow window,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
        if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
        //調(diào)用WMS中的finishDrawingWindow處理
        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
    }

2.3.2 finishDrawingWindow

1.在WMS中根據(jù)客戶端的Binder在mWindowMap中獲取對(duì)應(yīng)的WindowState。
2.調(diào)用WindowState.finishDrawing執(zhí)行mDrawState的狀態(tài)變更。
3.將WindowState.mLayoutNeeded標(biāo)志位置為true。
4.請(qǐng)求進(jìn)行布局刷新。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowManagerService.java

    void finishDrawingWindow(Session session, IWindow client,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
        if (postDrawTransaction != null) {
            postDrawTransaction.sanitize();
        }

        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                /*1.根據(jù)客戶端的Binder在mWindowMap中獲取對(duì)應(yīng)的WindowState*/
                WindowState win = windowForClientLocked(session, client, false);
                ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
                        win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
                /*2.finishDrawing執(zhí)行mDrawState的狀態(tài)更變*/
                if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
                    if (win.hasWallpaper()) {
                        win.getDisplayContent().pendingLayoutChanges |=
                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                    }
                    /*3.將當(dāng)前WindowState.mLayoutNeeded置為true*/
                    //該標(biāo)志位是判斷是否進(jìn)行窗口大小尺寸計(jì)算的條件之一
                    win.setDisplayLayoutNeeded();
                    /*4.請(qǐng)求進(jìn)行布局刷新*/
                    mWindowPlacerLocked.requestTraversal();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

1.mDrawState的狀態(tài)更變
在finishDrawingWindow中調(diào)用WindowState的finishDrawing方法
win.finishDrawing(postDrawTransaction, seqId)
這個(gè)方法主要調(diào)用了WindowStateAnimator的finishDrawingLocked進(jìn)行狀態(tài)更變
代碼路徑:framework/services/core/java/com/android/server/wm/WindowState.java

   boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
        ......
        //調(diào)用WindowStateAnimator.finishDrawingLocked,會(huì)將mDrawState的狀態(tài)更改為COMMIT_DRAW_PENDING
        final boolean layoutNeeded =
                mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
        mClientWasDrawingForSync = false;
        // We always want to force a traversal after a finish draw for blast sync.
        return !skipLayout && (hasSyncHandlers || layoutNeeded);
    }

我們繼續(xù)看看WindowStateAnimator中的finishDrawingLocked()方法
首先判斷mDrawState的狀態(tài)是否為DRAW_PENDING,在我們創(chuàng)建SurfaceControl時(shí),會(huì)將mDrawState狀態(tài)更新為DRAW_PENDING。因此接下來將狀態(tài)調(diào)整為COMMIT_DRAW_PENDING。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

    boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction,
            boolean forceApplyNow) {
        ......
        boolean layoutNeeded = false;

        if (mDrawState == DRAW_PENDING) {
            ......
            //如果當(dāng)前狀態(tài)為DRAW_PENDING,則將mDrawState更變?yōu)镃OMMIT_DRAW_PENDING
            mDrawState = COMMIT_DRAW_PENDING;
            layoutNeeded = true;
        }
        ......
        return layoutNeeded;
    }

2.請(qǐng)求布局刷新
在finishDrawingWindow中請(qǐng)求布局刷新
mWindowPlacerLocked.requestTraversal();
requestTraversal中主要做了兩件事:
1.首先將遍歷標(biāo)志為mTraversalSchedule置為true。
2.其次發(fā)送handle消息mPerformSurfacePlacement

    void requestTraversal() {
        //判斷遍歷標(biāo)志mTraversalScheduled是否為true
        if (mTraversalScheduled) {
            return;
        }

        // Set as scheduled even the request will be deferred because mDeferredRequests is also
        // increased, then the end of deferring will perform the request.
        //將遍歷標(biāo)志位置為true
        mTraversalScheduled = true;
        if (mDeferDepth > 0) {
            mDeferredRequests++;
            if (DEBUG) Slog.i(TAG, "Defer requestTraversal " + Debug.getCallers(3));
            return;
        }
        //發(fā)送handle消息,處理消息會(huì)調(diào)用mPerformSurfacePlacement
        mService.mAnimationHandler.post(mPerformSurfacePlacement);
    }

mPerformSurfacePlacement會(huì)新建一個(gè)線程調(diào)用performSurfacePlacement。
performSurfacePlacement方法我們?cè)谥vrelayoutWindow相關(guān)流程的時(shí)候講過,這是執(zhí)行遍歷布局的入口??梢曰乜聪隆?.2.4 計(jì)算窗口大小位置中的“1.處理窗口布局循環(huán)”】

    private class Traverser implements Runnable {
        @Override
        public void run() {
            synchronized (mService.mGlobalLock) {
                //調(diào)用執(zhí)行performSurfacePlacement
                performSurfacePlacement();
            }
        }
    }

    private final Traverser mPerformSurfacePlacement = new Traverser();
    
    final void performSurfacePlacement(boolean force) {
        //當(dāng)mDeferDepth大于0且force為false時(shí),則將延遲布局請(qǐng)求數(shù)+1,并直接返回
        if (mDeferDepth > 0 && !force) {
            mDeferredRequests++;
            return;
        }
        //將循環(huán)的最大次數(shù)設(shè)置為6次
        int loopCount = 6;
        do {
            //將該標(biāo)志為設(shè)置為false
            mTraversalScheduled = false;
            //執(zhí)行窗口布局操作
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        //只有當(dāng)mTraversalScheduled為true且循環(huán)次數(shù)大于0時(shí),才會(huì)再次循環(huán)執(zhí)行布局
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }

    private void performSurfacePlacementLoop() {
        //若當(dāng)前已經(jīng)進(jìn)行布局操作,則無需重復(fù)調(diào)用直接返回
        if (mInLayout) {
            ......
            return;
        }
        ......
        //將該標(biāo)志位置為true,表示正在處于布局過程中
        mInLayout = true;
        ......
        try {
            /*1.調(diào)用RootWindowContainer的performSurfacePlacement()方法對(duì)所有窗口執(zhí)行布局操作*/
            mService.mRoot.performSurfacePlacement();

            mInLayout = false;

            if (mService.mRoot.isLayoutNeeded()) {
                /*2.若需要布局,且布局次數(shù)小于6次,則需要再次請(qǐng)求布局*/
                if (++mLayoutRepeatCount < 6) {
                    //該方法中會(huì)將mTraversalScheduled標(biāo)志位設(shè)置位true
                    requestTraversal();
                } else {
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
                mLayoutRepeatCount = 0;
            }

            if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
                mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
                mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
            }
        } catch (RuntimeException e) {
            mInLayout = false;
            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
        }
    }

代碼路徑:framework/services/core/java/com/android/server/wm/RootWindowContainer.java

    void performSurfacePlacement() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
            //調(diào)用performSurfacePlacementNoTrace()
            performSurfacePlacementNoTrace();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    // "Something has changed!  Let's make it correct now."
    // TODO: Super long method that should be broken down...
    void performSurfacePlacementNoTrace() {
        ......
        /*1.如果有焦點(diǎn)變化,更新焦點(diǎn)*/
        if (mWmService.mFocusMayChange) {
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(
                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
        }
        ......
        
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
        //開啟事務(wù),獲取GlobalTransactionWrapper對(duì)象
        mWmService.openSurfaceTransaction();
        try {
            /*2.執(zhí)行窗口尺寸計(jì)算,surface狀態(tài)變更等操作*/
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            //關(guān)閉事務(wù),把事務(wù)提交
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            if (SHOW_LIGHT_TRANSACTIONS) {
                Slog.i(TAG,
                        "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
            }
        }
        ......
        /*3.將Surface狀態(tài)變更為HAS_DRAWN,觸發(fā)App觸發(fā)動(dòng)畫。該過程在“2.3.3mDrawState變更為HAS_DRAW”流程中再詳細(xì)分析*/
        checkAppTransitionReady(surfacePlacer);
        ......
        /*4.遍歷所有DisplayContent,如果壁紙有變化,更新壁紙*/
        for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
            final DisplayContent displayContent = mChildren.get(displayNdx);
            //判斷DisplayContent的壁紙是否需要改變
            if (displayContent.mWallpaperMayChange) {
                ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper may change!  Adjusting");
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                if (DEBUG_LAYOUT_REPEATS) {
                    surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
                            displayContent.pendingLayoutChanges);
                }
            }
        }
        /*5.在此處理焦點(diǎn)變化*/
        if (mWmService.mFocusMayChange) {
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                    false /*updateInputWindows*/);
        }
        ......
        /*6.如果過程中size或者位置變化,則通知客戶端重新relayout*/
        handleResizingWindows();

        if (mWmService.mDisplayFrozen) {
            ProtoLog.v(WM_DEBUG_ORIENTATION,
                    "With display frozen, orientationChangeComplete=%b",
                    mOrientationChangeComplete);
        }
        if (mOrientationChangeComplete) {
            if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
                mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
            }
            mWmService.stopFreezingDisplayLocked();
        }

        // Destroy the surface of any windows that are no longer visible.
        /*7.銷毀不可見的窗口*/
        i = mWmService.mDestroySurface.size();
        if (i > 0) {
            do {
                i--;
                WindowState win = mWmService.mDestroySurface.get(i);
                win.mDestroying = false;
                final DisplayContent displayContent = win.getDisplayContent();
                if (displayContent.mInputMethodWindow == win) {
                    displayContent.setInputMethodWindowLocked(null);
                }
                if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
                win.destroySurfaceUnchecked();
            } while (i > 0);
            mWmService.mDestroySurface.clear();
        }
        ......
    }

這里我們主要關(guān)注applySurfaceChangesTransaction();和checkAppTransitionReady(surfacePlacer);

  • 窗口位置計(jì)算與窗口狀態(tài)刷新流程不同點(diǎn)
    可以發(fā)現(xiàn),窗口位置計(jì)算流程與窗口狀態(tài)刷新流程都調(diào)用了performSurfacePlacement,兩次調(diào)用的主要不同點(diǎn)在于:
    1.窗口狀態(tài)刷新流程在DisplayContent.applySurfaceChangesTransaction中調(diào)用mApplySurfaceChangesTransaction,處理mDrawState狀態(tài)。
    2.窗口狀態(tài)刷新流程在RootWindowContainer.performSurfacePlacementNoTrace中調(diào)用checkAppTransitionReady,處理mDrawState狀態(tài)變更為HAS_DRAWN,觸發(fā)Activity過渡動(dòng)畫。
    3.窗口狀態(tài)刷新流程在WindowSurfacePlacementLoop.performSurfacePlacementLoop中會(huì)調(diào)用requestTraversal,請(qǐng)求再次布局。
    4.窗口狀態(tài)刷新流程在DisplayContent.applySurfaceChangesTransaction中調(diào)用prepareSurfaces()處理處理surface的位置、大小以及顯示等。
2.3.3 mDrawState變更為HAS_DRAW

1.mApplySurfaceChangesTransaction
RootWindowContainer的applySurfaceChangesTransaction()方法最終會(huì)調(diào)用到DisplayContent中調(diào)用的applySurfaceChangesTransaction()方法,我們接著該方法中的mApplySurfaceChangesTransaction跟蹤。
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
如果當(dāng)前WindowState存在surfaceControl,則進(jìn)入到WindowStateAnimator進(jìn)行mDrawState的狀態(tài)更變。
代碼路徑:framework/services/core/java/com/android/server/wm/DisplayContent.java

    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
        ......
        //首先判斷當(dāng)前windowState的是否有surfaceControl
        if (w.mHasSurface) {
            // Take care of the window being ready to display.
            //調(diào)用WindowStateAnimator的commitFinishDrawingLocked()方法
            final boolean committed = winAnimator.commitFinishDrawingLocked();
            ......
        }
        ......
    };

繼續(xù)看看WindowStateAnimator的commitFinishDrawingLocked()方法
final boolean committed = winAnimator.commitFinishDrawingLocked();
1.對(duì)mDrawState的狀態(tài)進(jìn)行過濾,非COMMIT_DRAW_PENDING和READY_TO_SHOW則直接返回。
2.此時(shí)我們的mDrawState已經(jīng)在“【2.3.2 finishDrawingWindow】”將狀態(tài)更新為COMMIT_DRAW_PENDING,因此此處將其變更為READY_TO_SHOW。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

    // This must be called while inside a transaction.
    boolean commitFinishDrawingLocked() {
        //非COMMIT_DRAW_PENDING和READY_TO_SHOW則直接返回
        if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
            return false;
        }
        ProtoLog.i(WM_DEBUG_ANIM, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
                mSurfaceController);
        //將狀態(tài)更變?yōu)镽EADY_TO_SHOW
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        //如果ActivityRecord為空,或者canShowWindows()為true,或者窗口類型為啟動(dòng)窗口,則直接進(jìn)入到WindowState.performShowLocked()流程
        //進(jìn)入performShowLocked()流程后mDrawState更新HAS_DRAWN
        //由于非這三種情況最終也會(huì)調(diào)用到performShowLocked(),因此下面這種情況我們暫不討論
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
            result = mWin.performShowLocked();
        }
        return result;
    }

2.checkAppTransitionReady()
這里我們繼續(xù)跟蹤RootWindowContainer.performSurfacePlacementNoTrace()方法中的checkAppTransitionReady()方法
checkAppTransitionReady(surfacePlacer);
該方法會(huì)遍歷所有DisplayContent,處理activity的過濾動(dòng)畫,此處我們只有跟蹤有關(guān)mDrawState狀態(tài)更變的相關(guān)代碼
代碼路徑:framework/services/core/java/com/android/server/wm/RootWindowContainer.java

    private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
        // Trace all displays app transition by Z-order for pending layout change.
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final DisplayContent curDisplay = mChildren.get(i);

            // If we are ready to perform an app transition, check through all of the app tokens
            // to be shown and see if they are ready to go.
            //檢查所有要顯示的app token,是否已經(jīng)準(zhǔn)備就緒
            if (curDisplay.mAppTransition.isReady()) {
                // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
                curDisplay.mAppTransitionController.handleAppTransitionReady();
                if (DEBUG_LAYOUT_REPEATS) {
                    surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
                            curDisplay.pendingLayoutChanges);
                }
            }
            ......
        }
    }

調(diào)用AppTransitionController的handleAppTransitionReady()方法,該方法主要還是在處理activity的過渡動(dòng)畫,但是在應(yīng)用過渡動(dòng)畫時(shí),還做了以下事情
1.分別調(diào)用 handleClosingApps以及handleOpeningApps對(duì)要關(guān)閉的和要打開的Activity進(jìn)行可見性更新。
2.由于activity的可見性變更,將DisplayContent.mLayoutNeeded設(shè)置為true,該標(biāo)志位在DisplayContent.performLayoutNoTrace中用來判斷是否對(duì)當(dāng)前Displaycontent下的所有窗口進(jìn)行刷新。
代碼路徑:framework/services/core/java/com/android/server/wm/AppTransitionController.java

    /**
     * Handle application transition for given display.
     */
    void handleAppTransitionReady() {
        ......
        try {
            //應(yīng)用app transition動(dòng)畫
            applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
                    voiceInteraction);
            /*1.1處理closing activity可見性*/
            handleClosingApps();
            /*1.2處理opening actvity可見性*/
            handleOpeningApps();
            ......
        } finally {
            mService.mSurfaceAnimationRunner.continueStartingAnimations();
        }
        ......

        // This has changed the visibility of windows, so perform
        // a new layout to get them all up-to-date.
        /*2.由于activity的可見性變更,將DisplayContent.mLayoutNeeded標(biāo)志位置為true*/
        mDisplayContent.setLayoutNeeded();
        ......
    }

我們先看看 handleClosingApps()
該方法中主要的作用就是將所有即將close的activity的mVisible標(biāo)志設(shè)置為false。該標(biāo)志位在后續(xù)prepareSurfaces中是判斷是否show surface的條件之一。

   private void handleClosingApps() {
        final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
        final int appsCount = closingApps.size();

        for (int i = 0; i < appsCount; i++) {
            final ActivityRecord app = closingApps.valueAt(i);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", app);
            //設(shè)置activity的可見性,將mVisible設(shè)置為false
            app.commitVisibility(false /* visible */, false /* performLayout */);
            app.updateReportedVisibilityLocked();
            // Force the allDrawn flag, because we want to start
            // this guy's animations regardless of whether it's
            // gotten drawn.
            //強(qiáng)制將allDrawn設(shè)置為true
            app.allDrawn = true;
            ......
        }
    }

再看看,與handleClosingApps類似,主要處理兩件事情:
1.將所有即將open的activity的mVisible標(biāo)志位設(shè)置為true.
2.調(diào)用ActivityRecord.showAllWindowsLocked(),最終會(huì)調(diào)用到WindowState.performShowLocked() ,處理mDrawState的狀態(tài)變更

    private void handleOpeningApps() {
        final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
        final int appsCount = openingApps.size();

        for (int i = 0; i < appsCount; i++) {
            final ActivityRecord app = openingApps.valueAt(i);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
            /*1.設(shè)置activity的可見性,將mVisible設(shè)置為true*/
            app.commitVisibility(true /* visible */, false /* performLayout */);
            ......
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                    ">>> OPEN TRANSACTION handleAppTransitionReady()");
            //開啟事務(wù)
            mService.openSurfaceTransaction();
            try {
                /*2.此方法最終會(huì)調(diào)用到WindowState.performShowLocked*/
                app.showAllWindowsLocked();
            } finally {
            //關(guān)閉事務(wù)
            mService.closeSurfaceTransaction("handleAppTransitionReady");
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                        "<<< CLOSE TRANSACTION handleAppTransitionReady()");
            }
            ......
        }
    }

app.commitVisibility(true /* visible /, false / performLayout */);
先調(diào)用到ActivityRecord的howAllWindowsLocked()
代碼路徑:framework/services/core/java/com/android/server/wm/ActivityRecord.java

    /**
     * This must be called while inside a transaction.
     */
    void showAllWindowsLocked() {
        forAllWindows(windowState -> {
            if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
            windowState.performShowLocked();
        }, false /* traverseTopToBottom */);
    }

windowState.performShowLocked();
再調(diào)用到WindowState的performShowLocked()
將mDrawState的狀態(tài)由READY_TO_SHOW變更為HAS_DRAW
代碼路徑:framework/services/core/java/com/android/server/wm/WindowState.java

    // This must be called while inside a transaction.
    boolean performShowLocked() {
        ......
        //獲取WindowStateAnimator.mDrawState
        final int drawState = mWinAnimator.mDrawState;
        //這里判斷(drawState 狀態(tài)為HAS_DRAWN 或者READY_TO_SHOW)且ActivityRecord不為空
        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
            //窗口類型不為啟動(dòng)窗口
            if (mAttrs.type != TYPE_APPLICATION_STARTING) {
                mActivityRecord.onFirstWindowDrawn(this);
            } else {
                mActivityRecord.onStartingWindowDrawn();
            }
        }
        //如果當(dāng)前mDrawState的狀態(tài)不為READY_TO_SHOW ,則直接返回
        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
            return false;
        }
        ......
        // Force the show in the next prepareSurfaceLocked() call.
        mWinAnimator.mLastAlpha = -1;
        ProtoLog.v(WM_DEBUG_ANIM, "performShowLocked: mDrawState=HAS_DRAWN in %s", this);
        //設(shè)置mDrawState的狀態(tài)為HAS_DRAWN
        mWinAnimator.mDrawState = HAS_DRAWN;
        mWmService.scheduleAnimationLocked();
        ......
        return true;
    }

3.再次請(qǐng)求布局
回到WindowSurfacePlacer中通過requestTraversals(),再次請(qǐng)求布局,該方法將mTraversalScheduled標(biāo)志位設(shè)置為true的判斷條件有兩個(gè):
1.遍歷所有DisplayContent.mLayoutNeeded標(biāo)志為是否為true。(由于AppTransitionController.handleAppTransitionReady階段已經(jīng)將mLayoutNeeded置為true,因此該條件為真)
2.重復(fù)布局的次數(shù)不能超過6次,該條件也為真。(因?yàn)楫?dāng)前還只是第一次布局)
代碼路徑:framework/services/core/java/com/android/server/wm/WindowSurfacePlacer.java

    private void performSurfacePlacementLoop() {
        ......
        try {
            ......
            /*1.遍歷所有DisplayContent.mLayoutNeeded標(biāo)志位是否為true*/
            if (mService.mRoot.isLayoutNeeded()) {
                /*2.如果需要布局,且布局次數(shù)小于6次,則需要再次請(qǐng)求布局*/
                if (++mLayoutRepeatCount < 6) {
                    //該方法中會(huì)將mTraversalScheduled標(biāo)志位設(shè)置位true
                    requestTraversal();
                } else {
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
                mLayoutRepeatCount = 0;
            }
            ......
        } catch (RuntimeException e) {
        ......
        }
    }

接下來進(jìn)入第二次布局循環(huán),其主要目的是為了show surface

2.3.4 show Surface

在第二次循環(huán)中,我們主要關(guān)注DisplayContent中applySurfaceChangesTransaction()方法調(diào)用的prepareSurfaces()

該方法最終會(huì)調(diào)用到根容器WindowContainer,來遍歷所有子容器中的prepareSurfaces。
代碼路徑:framework/services/core/java/com/android/server/wm/DisplayContent.java

    @Override
    void prepareSurfaces() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
        try {
            //獲取事務(wù)
            final Transaction transaction = getPendingTransaction();
            //調(diào)用其父類方法
            super.prepareSurfaces();

            // TODO: Once we totally eliminate global transaction we will pass transaction in here
            //       rather than merging to global.
            SurfaceControl.mergeToGlobalTransaction(transaction);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

調(diào)用其父類方法super.prepareSurfaces();
DisplayContent的父類為WindowContainer
代碼路徑:framework/services/core/java/com/android/server/wm/WindowContainer.java

    void prepareSurfaces() {
        // If a leash has been set when the transaction was committed, then the leash reparent has
        // been committed.
        mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
        //調(diào)用所有子容器中的prepareSurfaces
        for (int i = 0; i < mChildren.size(); i++) {
            mChildren.get(i).prepareSurfaces();
        }
    }

mChildren.get(i).prepareSurfaces();在WindowState.prepareSurfaces中,主要做了兩方面工作。
1.將mWindowFrames中計(jì)算出來的left以及top設(shè)置surface位置,并調(diào)整窗口比例。
2.控制surface的可見性,查看WindowStateAnimator.prepareSurfaceLocked
代碼路徑:framework/services/core/java/com/android/server/wm/WindowState.java

    void prepareSurfaces() {
        mIsDimming = false;
        applyDims();
        //實(shí)際調(diào)用的是其父類WindowContainer的方法
        /*1.最終調(diào)用自身的updateSurfacePosition()(自身有重寫該方法)計(jì)算surface的位置*/
        updateSurfacePositionNonOrganized();
        // Send information to SurfaceFlinger about the priority of the current window.
        updateFrameRateSelectionPriorityIfNeeded();
        //更新窗口比例
        updateScaleIfNeeded();

        /*2.控制surface的可見性,調(diào)用WindowStateAnimator的prepareSurfaceLocked()方法*/
        mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
        super.prepareSurfaces();
    }
    
    @Override
    @VisibleForTesting
    void updateSurfacePosition(Transaction t) {
        if (mSurfaceControl == null) {
            return;
        }

        ......
        mSurfacePlacementNeeded = false;
        //將mSurfacePosition的left以及top設(shè)置mWindowFrames中計(jì)算出來的left以及top,并根據(jù)parent進(jìn)行偏移
        transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
                mSurfacePosition);
        //根據(jù)壁紙的比例對(duì)SurfacePosition進(jìn)行調(diào)整
        if (mWallpaperScale != 1f) {
            final Rect bounds = getLastReportedBounds();
            Matrix matrix = mTmpMatrix;
            matrix.setTranslate(mXOffset, mYOffset);
            matrix.postScale(mWallpaperScale, mWallpaperScale, bounds.exactCenterX(),
                    bounds.exactCenterY());
            matrix.getValues(mTmpMatrixArray);
            mSurfacePosition.offset(Math.round(mTmpMatrixArray[Matrix.MTRANS_X]),
                Math.round(mTmpMatrixArray[Matrix.MTRANS_Y]));
        } else {
            mSurfacePosition.offset(mXOffset, mYOffset);
        }
        ......
    }

mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); 調(diào)用WindowStateAnimator的prepareSurfaceLocked()方法,該則真正的處理觸發(fā)surface show的邏輯。主要分為兩部分。
1.將計(jì)算的alpha應(yīng)用于當(dāng)前surface。
2.判斷是否調(diào)用showSurfaceRobustlyLocked將surface show出來。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

   void prepareSurfaceLocked(SurfaceControl.Transaction t) {
        final WindowState w = mWin;
        //首先判斷是否有SurfaceControl
        if (!hasSurface()) {
            ......
            return;
        }
        //設(shè)置mShowAlpha
        computeShownFrameLocked();

        //判斷parentWindow是否hidden,或者當(dāng)前窗口是否on-screen
        if (w.isParentWindowHidden() || !w.isOnScreen()) {
            ......
        } else if (mLastAlpha != mShownAlpha
                || mLastHidden) {
            mLastAlpha = mShownAlpha;
            ProtoLog.i(WM_SHOW_TRANSACTIONS,
                    "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
                    mSurfaceController, mShownAlpha, w.mHScale, w.mVScale, w);
            /*1.設(shè)置surface的alpha*/
            boolean prepared =
                mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
            //如果當(dāng)前狀態(tài)為HAS_DRAWN
            if (prepared && mDrawState == HAS_DRAWN) {
                if (mLastHidden) {
                /*2.觸發(fā)show surface*/
                    if (showSurfaceRobustlyLocked(t)) {
                        mAnimator.requestRemovalOfReplacedWindows(w);
                        //設(shè)置mLastHidden為false
                        mLastHidden = false;
                        .......
                    } else {
                        w.setOrientationChanging(false);
                    }
                }
            }
        } else {
            if (mWin.isAnimating(TRANSITION | PARENTS)) {
                ProtoLog.v(WM_DEBUG_ANIM, "prepareSurface: No changes in animation for %s", this);
            }
        }

        ......
    }

從上述代碼中可以看出觸發(fā)showSurfaceRobustlyLocked的判斷條件有以下幾點(diǎn):
1.w.isParentWindowHidden判斷其parent的mHidden是否為true,此時(shí)當(dāng)前窗口沒有parent直接返回false
2.w.isOnScreen,判斷當(dāng)前窗口是否在屏幕上,如果該窗口mVisible為true或者在不可見之前正在運(yùn)行動(dòng)畫,判斷為在屏幕上。我們?cè)谏洗尾季值腁ppTransitionController.handleAppTransitionReady階段將當(dāng)前窗口的mVisible置為了true,因此w.isOnScreen返回true。
3.mLastAlpha != mShownAlpha以及mLastHidden滿足其一即可,此處我們分析mLastHidden,該標(biāo)志位在創(chuàng)建SurfaceControl或者h(yuǎn)ide surface時(shí)會(huì)被置為true,因?yàn)楫?dāng)前窗口才剛剛被創(chuàng)建,因此mLastHidden為true。
經(jīng)過以上判斷可以得出我們順利觸發(fā)showSurfaceRobustlyLocked
后面通過WindowStateAnimator將show SurfaceControl的請(qǐng)求傳遞給了WindowSurfaceController

    /**
     * Have the surface flinger show a surface, robustly dealing with
     * error conditions.  In particular, if there is not enough memory
     * to show the surface, then we will try to get rid of other surfaces
     * in order to succeed.
     *
     * @return Returns true if the surface was successfully shown.
     */
    private boolean showSurfaceRobustlyLocked(SurfaceControl.Transaction t) {
        //WindowStateAnimator將show SurfaceControl的請(qǐng)求傳遞給了WindowSurfaceController
        //調(diào)用WindowSurfaceController的showRobustly方法
        boolean shown = mSurfaceController.showRobustly(t);
        //如果沒有成功返回false
        if (!shown)
            return false;

        t.merge(mPostDrawTransaction);
        return true;
    }

在WindowSurfaceController中,首先判斷標(biāo)志位mSurfaceShown,若為true則直接返回;若為false,則將mSurfaceShown置為true,并調(diào)用SurfaceControl.show。至此真正的繪圖已經(jīng)顯示出來,但是否真正的被用戶看見,還需要看其parent是否被show。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowSurfaceController.java

    boolean showRobustly(SurfaceControl.Transaction t) {
        ......

        //首先判斷surface是否已經(jīng)shown
        if (mSurfaceShown) {
            return true;
        }
        //將mSurfaceShown設(shè)置為true
        setShown(true);
        //調(diào)用SurfceControl中的show方法,將surface show出來
        t.show(mSurfaceControl);
        if (mAnimator.mIsWallpaper) {
            EventLog.writeEvent(EventLogTags.WM_WALLPAPER_SURFACE,
                    mAnimator.mWin.getDisplayId(), 1 /* request shown */);
        }
        return true;
    }

從SurfaceControl的創(chuàng)建以及show的流程上看,可以發(fā)現(xiàn)WMS是通過WindowSurfaceController對(duì)SurfaceControl進(jìn)行管理的。
最后我們看一下SurfaceControl中的show方法
代碼路徑:frameworks/base/core/java/android/view/SurfaceControl.java

        /**
         * Request that a given surface and it's sub-tree be shown.
         *
         * @param sc The surface to show.
         * @return This transaction.
         * @hide
         */
        @UnsupportedAppUsage
        public Transaction show(SurfaceControl sc) {
            checkPreconditions(sc);
            nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
            return this;
        }

2.4 performSurfacePlacement()流程總結(jié)

image.png

在“【2.2 窗口位置計(jì)算】”以及“【2.3 窗口狀態(tài)刷新】”部分均調(diào)用了WindowSurfacePlacer.performSurfacePlacement(),實(shí)際上任何窗口屬性變化都會(huì)觸發(fā)該方法,但我們?cè)趐erformSurfacePlacement中只關(guān)注了窗口位置大小計(jì)算以及窗口狀態(tài)變更的相關(guān)流程。此處再對(duì)該流程進(jìn)行簡(jiǎn)單的梳理。
當(dāng)調(diào)用到WindowSurfacePlacer.performSurfacePlacement()時(shí)首先會(huì)執(zhí)行“1”更新所有窗口的大小以及狀態(tài)信息,在執(zhí)行“2”處理是否在此調(diào)用執(zhí)行performSurfacePlacement。
1.1.1:主要調(diào)用computeFrames,計(jì)算窗口的尺寸大小。
1.1.2:主要處理mDrawState的狀態(tài)變更,在commitFinishDrawingLocked中會(huì)將處于DRAW_PENDING狀態(tài)的mDrawState更新為COMMIT_DRAW_PENDING。
1.1.3:主要根據(jù)computerFrames中計(jì)算出來的窗口大小來設(shè)置Surface的位置,并調(diào)用SurfaceControl.show()將窗口show出來。
1.2:將處于COMMIT_DRAW_PENDING狀態(tài)的mDrawState更新為READY_TO_SHOW,并將DisplayContent.mLayoutNeeded設(shè)置為true。在“2”中會(huì)判斷該標(biāo)志位來處理是否再次調(diào)用performSurfacePlacement的操作。

————————————————
版權(quán)聲明:本文為CSDN博主「yi諾千金」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yimelancholy/article/details/130339779

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容