Android13 WMS窗口相关流程(五)

接着上篇://www.greatytc.com/p/95e8654036a8

2.3 窗口状态刷新

当应用端执行measure-layout-draw之后,便会调用WMS.finishDrawingWindow,处理Surface的状态变更并将Surface show出来。
首先还是看一下该阶段的流程图,对整个流程有个初步的了解。
将整个流程分为三部分:
1.WMS接受客户端请求,将mDrawState更新为COMMIT_DRAW_PENDING,并请求窗口布局。
2.mDrawState更新为HAS_DRAW,再次请求窗口布局。
3.执行show Surface。

2.3.1 接受客户端请求

代码路径: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);
        //调用WMS中的finishDrawingWindow处理
        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
    }

2.3.2 finishDrawingWindow

1.在WMS中根据客户端的Binder在mWindowMap中获取对应的WindowState。
2.调用WindowState.finishDrawing执行mDrawState的状态变更。
3.将WindowState.mLayoutNeeded标志位置为true。
4.请求进行布局刷新。
代码路径: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.根据客户端的Binder在mWindowMap中获取对应的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执行mDrawState的状态更变*/
                if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
                    if (win.hasWallpaper()) {
                        win.getDisplayContent().pendingLayoutChanges |=
                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                    }
                    /*3.将当前WindowState.mLayoutNeeded置为true*/
                    //该标志位是判断是否进行窗口大小尺寸计算的条件之一
                    win.setDisplayLayoutNeeded();
                    /*4.请求进行布局刷新*/
                    mWindowPlacerLocked.requestTraversal();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

1.mDrawState的状态更变
在finishDrawingWindow中调用WindowState的finishDrawing方法
win.finishDrawing(postDrawTransaction, seqId)
这个方法主要调用了WindowStateAnimator的finishDrawingLocked进行状态更变
代码路径:framework/services/core/java/com/android/server/wm/WindowState.java

   boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
        ......
        //调用WindowStateAnimator.finishDrawingLocked,会将mDrawState的状态更改为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);
    }

我们继续看看WindowStateAnimator中的finishDrawingLocked()方法
首先判断mDrawState的状态是否为DRAW_PENDING,在我们创建SurfaceControl时,会将mDrawState状态更新为DRAW_PENDING。因此接下来将状态调整为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) {
            ......
            //如果当前状态为DRAW_PENDING,则将mDrawState更变为COMMIT_DRAW_PENDING
            mDrawState = COMMIT_DRAW_PENDING;
            layoutNeeded = true;
        }
        ......
        return layoutNeeded;
    }

2.请求布局刷新
在finishDrawingWindow中请求布局刷新
mWindowPlacerLocked.requestTraversal();
requestTraversal中主要做了两件事:
1.首先将遍历标志为mTraversalSchedule置为true。
2.其次发送handle消息mPerformSurfacePlacement

    void requestTraversal() {
        //判断遍历标志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.
        //将遍历标志位置为true
        mTraversalScheduled = true;
        if (mDeferDepth > 0) {
            mDeferredRequests++;
            if (DEBUG) Slog.i(TAG, "Defer requestTraversal " + Debug.getCallers(3));
            return;
        }
        //发送handle消息,处理消息会调用mPerformSurfacePlacement
        mService.mAnimationHandler.post(mPerformSurfacePlacement);
    }

mPerformSurfacePlacement会新建一个线程调用performSurfacePlacement。
performSurfacePlacement方法我们在讲relayoutWindow相关流程的时候讲过,这是执行遍历布局的入口。可以回看下【2.2.4 计算窗口大小位置中的“1.处理窗口布局循环”】

    private class Traverser implements Runnable {
        @Override
        public void run() {
            synchronized (mService.mGlobalLock) {
                //调用执行performSurfacePlacement
                performSurfacePlacement();
            }
        }
    }

    private final Traverser mPerformSurfacePlacement = new Traverser();
    
    final void performSurfacePlacement(boolean force) {
        //当mDeferDepth大于0且force为false时,则将延迟布局请求数+1,并直接返回
        if (mDeferDepth > 0 && !force) {
            mDeferredRequests++;
            return;
        }
        //将循环的最大次数设置为6次
        int loopCount = 6;
        do {
            //将该标志为设置为false
            mTraversalScheduled = false;
            //执行窗口布局操作
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        //只有当mTraversalScheduled为true且循环次数大于0时,才会再次循环执行布局
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }

    private void performSurfacePlacementLoop() {
        //若当前已经进行布局操作,则无需重复调用直接返回
        if (mInLayout) {
            ......
            return;
        }
        ......
        //将该标志位置为true,表示正在处于布局过程中
        mInLayout = true;
        ......
        try {
            /*1.调用RootWindowContainer的performSurfacePlacement()方法对所有窗口执行布局操作*/
            mService.mRoot.performSurfacePlacement();

            mInLayout = false;

            if (mService.mRoot.isLayoutNeeded()) {
                /*2.若需要布局,且布局次数小于6次,则需要再次请求布局*/
                if (++mLayoutRepeatCount < 6) {
                    //该方法中会将mTraversalScheduled标志位设置位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 {
            //调用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.如果有焦点变化,更新焦点*/
        if (mWmService.mFocusMayChange) {
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(
                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
        }
        ......
        
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
        //开启事务,获取GlobalTransactionWrapper对象
        mWmService.openSurfaceTransaction();
        try {
            /*2.执行窗口尺寸计算,surface状态变更等操作*/
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            //关闭事务,把事务提交
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            if (SHOW_LIGHT_TRANSACTIONS) {
                Slog.i(TAG,
                        "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
            }
        }
        ......
        /*3.将Surface状态变更为HAS_DRAWN,触发App触发动画。该过程在“2.3.3mDrawState变更为HAS_DRAW”流程中再详细分析*/
        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.在此处理焦点变化*/
        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();
        }
        ......
    }

这里我们主要关注applySurfaceChangesTransaction();和checkAppTransitionReady(surfacePlacer);

  • 窗口位置计算与窗口状态刷新流程不同点
    可以发现,窗口位置计算流程与窗口状态刷新流程都调用了performSurfacePlacement,两次调用的主要不同点在于:
    1.窗口状态刷新流程在DisplayContent.applySurfaceChangesTransaction中调用mApplySurfaceChangesTransaction,处理mDrawState状态。
    2.窗口状态刷新流程在RootWindowContainer.performSurfacePlacementNoTrace中调用checkAppTransitionReady,处理mDrawState状态变更为HAS_DRAWN,触发Activity过渡动画。
    3.窗口状态刷新流程在WindowSurfacePlacementLoop.performSurfacePlacementLoop中会调用requestTraversal,请求再次布局。
    4.窗口状态刷新流程在DisplayContent.applySurfaceChangesTransaction中调用prepareSurfaces()处理处理surface的位置、大小以及显示等。
2.3.3 mDrawState变更为HAS_DRAW

1.mApplySurfaceChangesTransaction
RootWindowContainer的applySurfaceChangesTransaction()方法最终会调用到DisplayContent中调用的applySurfaceChangesTransaction()方法,我们接着该方法中的mApplySurfaceChangesTransaction跟踪。
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
如果当前WindowState存在surfaceControl,则进入到WindowStateAnimator进行mDrawState的状态更变。
代码路径:framework/services/core/java/com/android/server/wm/DisplayContent.java

    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
        ......
        //首先判断当前windowState的是否有surfaceControl
        if (w.mHasSurface) {
            // Take care of the window being ready to display.
            //调用WindowStateAnimator的commitFinishDrawingLocked()方法
            final boolean committed = winAnimator.commitFinishDrawingLocked();
            ......
        }
        ......
    };

继续看看WindowStateAnimator的commitFinishDrawingLocked()方法
final boolean committed = winAnimator.commitFinishDrawingLocked();
1.对mDrawState的状态进行过滤,非COMMIT_DRAW_PENDING和READY_TO_SHOW则直接返回。
2.此时我们的mDrawState已经在“【2.3.2 finishDrawingWindow】”将状态更新为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);
        //将状态更变为READY_TO_SHOW
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        //如果ActivityRecord为空,或者canShowWindows()为true,或者窗口类型为启动窗口,则直接进入到WindowState.performShowLocked()流程
        //进入performShowLocked()流程后mDrawState更新HAS_DRAWN
        //由于非这三种情况最终也会调用到performShowLocked(),因此下面这种情况我们暂不讨论
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
            result = mWin.performShowLocked();
        }
        return result;
    }

2.checkAppTransitionReady()
这里我们继续跟踪RootWindowContainer.performSurfacePlacementNoTrace()方法中的checkAppTransitionReady()方法
checkAppTransitionReady(surfacePlacer);
该方法会遍历所有DisplayContent,处理activity的过滤动画,此处我们只有跟踪有关mDrawState状态更变的相关代码
代码路径: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,是否已经准备就绪
            if (curDisplay.mAppTransition.isReady()) {
                // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
                curDisplay.mAppTransitionController.handleAppTransitionReady();
                if (DEBUG_LAYOUT_REPEATS) {
                    surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
                            curDisplay.pendingLayoutChanges);
                }
            }
            ......
        }
    }

调用AppTransitionController的handleAppTransitionReady()方法,该方法主要还是在处理activity的过渡动画,但是在应用过渡动画时,还做了以下事情
1.分别调用 handleClosingApps以及handleOpeningApps对要关闭的和要打开的Activity进行可见性更新。
2.由于activity的可见性变更,将DisplayContent.mLayoutNeeded设置为true,该标志位在DisplayContent.performLayoutNoTrace中用来判断是否对当前Displaycontent下的所有窗口进行刷新。
代码路径:framework/services/core/java/com/android/server/wm/AppTransitionController.java

    /**
     * Handle application transition for given display.
     */
    void handleAppTransitionReady() {
        ......
        try {
            //应用app transition动画
            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标志位置为true*/
        mDisplayContent.setLayoutNeeded();
        ......
    }

我们先看看 handleClosingApps()
该方法中主要的作用就是将所有即将close的activity的mVisible标志设置为false。该标志位在后续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);
            //设置activity的可见性,将mVisible设置为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.
            //强制将allDrawn设置为true
            app.allDrawn = true;
            ......
        }
    }

再看看,与handleClosingApps类似,主要处理两件事情:
1.将所有即将open的activity的mVisible标志位设置为true.
2.调用ActivityRecord.showAllWindowsLocked(),最终会调用到WindowState.performShowLocked() ,处理mDrawState的状态变更

    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.设置activity的可见性,将mVisible设置为true*/
            app.commitVisibility(true /* visible */, false /* performLayout */);
            ......
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                    ">>> OPEN TRANSACTION handleAppTransitionReady()");
            //开启事务
            mService.openSurfaceTransaction();
            try {
                /*2.此方法最终会调用到WindowState.performShowLocked*/
                app.showAllWindowsLocked();
            } finally {
            //关闭事务
            mService.closeSurfaceTransaction("handleAppTransitionReady");
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                        "<<< CLOSE TRANSACTION handleAppTransitionReady()");
            }
            ......
        }
    }

app.commitVisibility(true /* visible /, false / performLayout */);
先调用到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();
再调用到WindowState的performShowLocked()
将mDrawState的状态由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 状态为HAS_DRAWN 或者READY_TO_SHOW)且ActivityRecord不为空
        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
            //窗口类型不为启动窗口
            if (mAttrs.type != TYPE_APPLICATION_STARTING) {
                mActivityRecord.onFirstWindowDrawn(this);
            } else {
                mActivityRecord.onStartingWindowDrawn();
            }
        }
        //如果当前mDrawState的状态不为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);
        //设置mDrawState的状态为HAS_DRAWN
        mWinAnimator.mDrawState = HAS_DRAWN;
        mWmService.scheduleAnimationLocked();
        ......
        return true;
    }

3.再次请求布局
回到WindowSurfacePlacer中通过requestTraversals(),再次请求布局,该方法将mTraversalScheduled标志位设置为true的判断条件有两个:
1.遍历所有DisplayContent.mLayoutNeeded标志为是否为true。(由于AppTransitionController.handleAppTransitionReady阶段已经将mLayoutNeeded置为true,因此该条件为真)
2.重复布局的次数不能超过6次,该条件也为真。(因为当前还只是第一次布局)
代码路径:framework/services/core/java/com/android/server/wm/WindowSurfacePlacer.java

    private void performSurfacePlacementLoop() {
        ......
        try {
            ......
            /*1.遍历所有DisplayContent.mLayoutNeeded标志位是否为true*/
            if (mService.mRoot.isLayoutNeeded()) {
                /*2.如果需要布局,且布局次数小于6次,则需要再次请求布局*/
                if (++mLayoutRepeatCount < 6) {
                    //该方法中会将mTraversalScheduled标志位设置位true
                    requestTraversal();
                } else {
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
                mLayoutRepeatCount = 0;
            }
            ......
        } catch (RuntimeException e) {
        ......
        }
    }

接下来进入第二次布局循环,其主要目的是为了show surface

2.3.4 show Surface

在第二次循环中,我们主要关注DisplayContent中applySurfaceChangesTransaction()方法调用的prepareSurfaces()

该方法最终会调用到根容器WindowContainer,来遍历所有子容器中的prepareSurfaces。
代码路径:framework/services/core/java/com/android/server/wm/DisplayContent.java

    @Override
    void prepareSurfaces() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
        try {
            //获取事务
            final Transaction transaction = getPendingTransaction();
            //调用其父类方法
            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);
        }
    }

调用其父类方法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();
        //调用所有子容器中的prepareSurfaces
        for (int i = 0; i < mChildren.size(); i++) {
            mChildren.get(i).prepareSurfaces();
        }
    }

mChildren.get(i).prepareSurfaces();在WindowState.prepareSurfaces中,主要做了两方面工作。
1.将mWindowFrames中计算出来的left以及top设置surface位置,并调整窗口比例。
2.控制surface的可见性,查看WindowStateAnimator.prepareSurfaceLocked
代码路径:framework/services/core/java/com/android/server/wm/WindowState.java

    void prepareSurfaces() {
        mIsDimming = false;
        applyDims();
        //实际调用的是其父类WindowContainer的方法
        /*1.最终调用自身的updateSurfacePosition()(自身有重写该方法)计算surface的位置*/
        updateSurfacePositionNonOrganized();
        // Send information to SurfaceFlinger about the priority of the current window.
        updateFrameRateSelectionPriorityIfNeeded();
        //更新窗口比例
        updateScaleIfNeeded();

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

        ......
        mSurfacePlacementNeeded = false;
        //将mSurfacePosition的left以及top设置mWindowFrames中计算出来的left以及top,并根据parent进行偏移
        transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
                mSurfacePosition);
        //根据壁纸的比例对SurfacePosition进行调整
        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()); 调用WindowStateAnimator的prepareSurfaceLocked()方法,该则真正的处理触发surface show的逻辑。主要分为两部分。
1.将计算的alpha应用于当前surface。
2.判断是否调用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;
        }
        //设置mShowAlpha
        computeShownFrameLocked();

        //判断parentWindow是否hidden,或者当前窗口是否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.设置surface的alpha*/
            boolean prepared =
                mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
            //如果当前状态为HAS_DRAWN
            if (prepared && mDrawState == HAS_DRAWN) {
                if (mLastHidden) {
                /*2.触发show surface*/
                    if (showSurfaceRobustlyLocked(t)) {
                        mAnimator.requestRemovalOfReplacedWindows(w);
                        //设置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);
            }
        }

        ......
    }

从上述代码中可以看出触发showSurfaceRobustlyLocked的判断条件有以下几点:
1.w.isParentWindowHidden判断其parent的mHidden是否为true,此时当前窗口没有parent直接返回false
2.w.isOnScreen,判断当前窗口是否在屏幕上,如果该窗口mVisible为true或者在不可见之前正在运行动画,判断为在屏幕上。我们在上次布局的AppTransitionController.handleAppTransitionReady阶段将当前窗口的mVisible置为了true,因此w.isOnScreen返回true。
3.mLastAlpha != mShownAlpha以及mLastHidden满足其一即可,此处我们分析mLastHidden,该标志位在创建SurfaceControl或者hide surface时会被置为true,因为当前窗口才刚刚被创建,因此mLastHidden为true。
经过以上判断可以得出我们顺利触发showSurfaceRobustlyLocked
后面通过WindowStateAnimator将show SurfaceControl的请求传递给了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的请求传递给了WindowSurfaceController
        //调用WindowSurfaceController的showRobustly方法
        boolean shown = mSurfaceController.showRobustly(t);
        //如果没有成功返回false
        if (!shown)
            return false;

        t.merge(mPostDrawTransaction);
        return true;
    }

在WindowSurfaceController中,首先判断标志位mSurfaceShown,若为true则直接返回;若为false,则将mSurfaceShown置为true,并调用SurfaceControl.show。至此真正的绘图已经显示出来,但是否真正的被用户看见,还需要看其parent是否被show。
代码路径:framework/services/core/java/com/android/server/wm/WindowSurfaceController.java

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

        //首先判断surface是否已经shown
        if (mSurfaceShown) {
            return true;
        }
        //将mSurfaceShown设置为true
        setShown(true);
        //调用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的创建以及show的流程上看,可以发现WMS是通过WindowSurfaceController对SurfaceControl进行管理的。
最后我们看一下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()流程总结

image.png

在“【2.2 窗口位置计算】”以及“【2.3 窗口状态刷新】”部分均调用了WindowSurfacePlacer.performSurfacePlacement(),实际上任何窗口属性变化都会触发该方法,但我们在performSurfacePlacement中只关注了窗口位置大小计算以及窗口状态变更的相关流程。此处再对该流程进行简单的梳理。
当调用到WindowSurfacePlacer.performSurfacePlacement()时首先会执行“1”更新所有窗口的大小以及状态信息,在执行“2”处理是否在此调用执行performSurfacePlacement。
1.1.1:主要调用computeFrames,计算窗口的尺寸大小。
1.1.2:主要处理mDrawState的状态变更,在commitFinishDrawingLocked中会将处于DRAW_PENDING状态的mDrawState更新为COMMIT_DRAW_PENDING。
1.1.3:主要根据computerFrames中计算出来的窗口大小来设置Surface的位置,并调用SurfaceControl.show()将窗口show出来。
1.2:将处于COMMIT_DRAW_PENDING状态的mDrawState更新为READY_TO_SHOW,并将DisplayContent.mLayoutNeeded设置为true。在“2”中会判断该标志位来处理是否再次调用performSurfacePlacement的操作。

————————————————
版权声明:本文为CSDN博主「yi诺千金」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yimelancholy/article/details/130339779

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

推荐阅读更多精彩内容