Surface状态的状态切换流程如下:
在这里插入图片描述

所以现在更明确的当前流程的主线任务:
1、找到设置 Surface 状态为 COMMIT_DRAW_PENDING、 READY_TO_SHOW 和 HAS_DRAWN 的地方。
2、找到执行 SurfaceControl.Transaction::show 和 SurfaceControl.Transaction::apply 执行的地方就完成了。

完整流程图

本篇的主要逻辑和上篇一样,也是在一次 layout 里,layout 几户覆盖了所有的窗口逻辑,非常复杂,这里只贴出关于窗口显示逻辑流程图:
在这里插入图片描述

应用端处理

既然是绘制完成后的处理,触发的地方还是应用端本身,只有应用端绘制完成了才会触发逻辑。

再看一下 ViewRootImpl::setView 的调用链:

ViewRootImpl::setView
   ViewRootImpl::requestLayout
      ViewRootImpl::scheduleTraversals             
            ViewRootImpl.TraversalRunnable::run              -- Vsync相关--scheduleTraversals
                ViewRootImpl::doTraversal
                    ViewRootImpl::performTraversals 
                        ViewRootImpl::relayoutWindow
                            Session::relayout                -- 第二步:relayoutWindow
                            ViewRootImpl::updateBlastSurfaceIfNeeded
                                Surface::transferFrom        -- 应用端Surface赋值
                        ViewRootImpl::performMeasure         -- View绘制三部曲 --Measure
                        ViewRootImpl::performLayout          -- View绘制三部曲 --Layout  
                        ViewRootImpl::createSyncIfNeeded
                            SurfaceSyncGroup::init 
                                ViewRootImpl::reportDrawFinished 
                                    Session::finishDrawing   -- 第三步:finishDrawingWindow
                        ViewRootImpl::performDraw            -- View绘制三部曲 --Draw    
                        SurfaceSyncGroup::markSyncReady      -- 触发绘制完成回调
   Session.addToDisplayAsUser                                -- 第一步:addWindow

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">

在这里插入图片描述
前面分析【relayoutWindow流程】的时候已经分析过 ViewRootImpl::performTraversals 方法了,不过当前重点不一样,所以还需要再看一遍这个方法(增加了一些当前流程相关的代码)

当前分析 finishDrawing 流程,首先可以看到 relayoutWindow 方法执行后,会触发3个View绘制的方法,也就是常说的 View 绘制三部曲:measure、layout、draw

但是这里有个奇怪的地方: “4.1 createSyncIfNeeded” 方法是触发 finishDrawingWindow 的,但是这个方法在 “3.3 performDraw”的上面。

这是因为代码的顺序不代表真正的执行顺序,这里的“4.1 createSyncIfNeeded”只是设置了“回调”,等时机到了就会触发执行,而这个时机就是 View 绘制完成后,在 “4.2 markSyncReady 触发”

这一部分的逻辑有点绕,不过目前分析的是主流程,所以这块逻辑以上的描述当黑盒理解这段的调用: View 绘制结束后就会在 4.2 出触发 4.1 内部的执行,进入触发 finishDrawingWindow 流程即可。
这部分的代码 U 做了重构,后面再单独写一篇详细解释直接的调用逻辑。

finishDrawingWindow 的触发

在 ViewRootImpl::performTraversals 方法最后会执行 SurfaceSyncGroup::markSyncReady 方法,最终会触发 ViewRootImpl::createSyncIfNeeded 方法下的 ViewRootImpl::reportDrawFinished 来真正 finishDrawingWindow 流程。

# ViewRootImpl
    // 创建对象
    private SurfaceSyncGroup mActiveSurfaceSyncGroup;
    // 是否有同步的内容需要上报
    boolean mReportNextDraw;

    private void createSyncIfNeeded() {
        // 如果已经在本地进行同步或者没有需要同步的内容
        // mReportNextDraw 变量也是控制每一帧绘制完不都要执行 finishDrawingWindow 流程的原因
        if (isInWMSRequestedSync() || !mReportNextDraw) {
            return;
        }
        
        // 获取当前同步序列号
        final int seqId = mSyncSeqId;
        
        // 传入一个匿名类
        mWmsRequestSyncGroupState = WMS_SYNC_PENDING;
        mWmsRequestSyncGroup = new SurfaceSyncGroup("wmsSync-" + mTag, t -> {
                // 合并传入的transaction到mSurfaceChangedTransaction中
                mWmsRequestSyncGroupState = WMS_SYNC_MERGED;
                // 重点* 报告绘制完成,传入之前获取的序列号
                reportDrawFinished(t, seqId);
        });
        
        if (DEBUG_BLAST) {
            // 打印日志
            Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
        }
        
        // 将mSyncTarget添加到mSyncId对应的同步中
        mWmsRequestSyncGroup.add(this, null /* runnable */);
    }
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这个方法的重点就是在应用绘制完成后触发 finishDrawingWindow 流程,也就是触发 ViewRootImpl::reportDrawFinished 方法。

# ViewRootImpl

    private void reportDrawFinished(@Nullable Transaction t, int seqId) {
        // 日志和Trace相关
        if (DEBUG_BLAST) {
            Log.d(mTag, "reportDrawFinished");
        }
        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.instant(Trace.TRACE_TAG_VIEW, "reportDrawFinished " + mTag + " seqId=" + seqId);
        }

        try {
            // 重点* finishDrawing流程
            mWindowSession.finishDrawing(mWindow, t, seqId);
            ......
        } ......
        ......
    }

# Session
    @Override
    public void finishDrawing(IWindow window,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
        if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
        if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishDrawing: " + mPackageName);
        }
        // 触发WMS 执行finishDrawingWindow 流程
        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这个方法的重点就是在应用绘制完成后触发 finishDrawingWindow 流程,也就是触发 ViewRootImpl::reportDrawFinished 方法。

# ViewRootImpl

    private void reportDrawFinished(@Nullable Transaction t, int seqId) {
        // 日志和Trace相关
        if (DEBUG_BLAST) {
            Log.d(mTag, "reportDrawFinished");
        }
        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.instant(Trace.TRACE_TAG_VIEW, "reportDrawFinished " + mTag + " seqId=" + seqId);
        }

        try {
            // 重点* finishDrawing流程
            mWindowSession.finishDrawing(mWindow, t, seqId);
            ......
        } ......
        ......
    }

# Session
    @Override
    public void finishDrawing(IWindow window,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
        if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
        if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishDrawing: " + mPackageName);
        }
        // 触发WMS 执行finishDrawingWindow 流程
        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

唯一做的一件事就是跨进程触发 WindowManagerService::finishDrawingWindow 。 到这里应用端的事情就处理完了,后面的流程在 system_service 进程。

system_service处理

system_service 处理主要的调用链整理如下:

WindowManagerService::finishDrawingWindow
    WindowState::finishDrawing
        WindowStateAnimator::finishDrawingLocked    -- COMMIT_DRAW_PENDING
    WindowPlacerLocked::requestTraversal           -- 触发layout
        Traverser::run
            WindowSurfacePlacer::performSurfacePlacement
                WindowSurfacePlacer::performSurfacePlacementLoop
                    RootWindowContainer::performSurfacePlacement  -- 开始layout逻辑
                        RootWindowContainer::performSurfacePlacementNoTrace
                            WindowManagerService::openSurfaceTransaction      -- 打开Surface事务
                            RootWindowContainer::applySurfaceChangesTransaction  -- 处理Surface事务
                                DisplayContent::applySurfaceChangesTransaction   -- 遍历每个屏幕
                                    DisplayContent::performLayout                          -- relayoutWinodw 流程
                                    DisplayContent::forAllWindows                          -- 每个窗口执行mApplySurfaceChangesTransaction
                                        WindowStateAnimator::commitFinishDrawingLocked     -- READY_TO_SHOW
                                            WindowState::performShowLocked                 -- HAS_DRAWN
                                    DisplayContent::prepareSurfaces                        -- Surface 处理
                                        WindowContainer::prepareSurfaces                   -- 遍历每个孩子
                                            WindowState::prepareSurfaces                   -- 忽略其他,只看窗口的实现
                                            WindowStateAnimator::prepareSurfaceLocked
                                                WindowSurfaceController::showRobustly
                                                    WindowSurfaceController::setShown
                                                        SurfaceControl.Transaction::show    -- Surface显示
                            WindowManagerService::closeSurfaceTransaction    -- 处理关闭Surface事务
                                SurfaceControl::closeTransaction
                                    GlobalTransactionWrapper::applyGlobalTransaction
                                        GlobalTransactionWrapper::nativeApplyTransaction    -- 触发native

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

在这里插入图片描述

# WindowManagerService
    final WindowSurfacePlacer mWindowPlacerLocked;

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

        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                // 获取到对应的WindowState
                WindowState win = windowForClientLocked(session, client, false);
                // T版本这里是个 proto日志
                Slog.w(TAG, "finishDrawingWindow: "+win+" mDrawState="
                         +(win != null ? win.mWinAnimator.drawStateToString() : "null"));
                // 重点* 1. 执行WindowState::finishDrawing
                if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
                    if (win.hasWallpaper()) {
                        win.getDisplayContent().pendingLayoutChanges |=
                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                    }
                    // 将当前WindowState.mLayoutNeeded置为true
                    win.setDisplayLayoutNeeded();
                    // 重点* 2. 请求进行布局刷新
                    mWindowPlacerLocked.requestTraversal();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

system_service 进程第一个处理的方法就是 WindowManagerService::finishDrawingWindow 这个方法也就做了2件事:

这里有上述的2个流程需要分析,首先会执行 WindowState::finishDrawing ,将WindowState状态设置为 COMMIT_DRAW_PENDING ,表示应用端已经绘制完成了,可以提交给SF了。
第一步操作完之后,就会执行 WindowSurfacePlacer::requestTraversal ,这个方法是执行一次 layout 逻辑。

在前面看窗口状态 COMMIT_DRAW_PENDING 定义的时候,google 注释提过: “会下一次 layout 的时候显示到屏幕上”,指的就是在这里触发的 layout。

在第二步 layout 的时候会遍历每个窗口,目前只关心当前分析的场景的这个窗口,在这次 layout 会做3件事:

下面开始在代码中梳理流程。

WindowState状态 – COMMIT_DRAW_PENDING

# WindowState
    final WindowStateAnimator mWinAnimator;
    boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
   		......
   		// 主流程
        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);
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

主要是执行了 WindowStateAnimator::finishDrawingLocked ,内部会将 WindowState 的状态设置为 COMMIT_DRAW_PENDING ,这个是非常重要的一步。

# WindowStateAnimator

    boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction,
            boolean forceApplyNow) {
        ......
        // 只有当前状态是DRAW_PENDING的时候才可以走进逻辑
        if (mDrawState == DRAW_PENDING) {
            ProtoLog.v(WM_DEBUG_DRAW,
                    "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", mWin,
                    mSurfaceController);
            if (startingWindow) {
                // 如果是StartingWindow还有专门的log
                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Draw state now committed in %s", mWin);
            }
            mDrawState = COMMIT_DRAW_PENDING;
            // 表示需要 layout
            layoutNeeded = true;
        }
        ......
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这样第一步就执行完了,流程很简单,只是设置窗口状态为 COMMIT_DRAW_PENDING 。

本次layout 流程简述

上一小节只是改了状态,下一个状态是 READY_TO_SHOW ,前面看到google对它有一个注释:The surface will be displayed when the next layout is run.
也就是说在下一次 layout 会触发 Surface 的显示,所以关键流程还是在 “next layout”,
那什么是 “next layout” ?
我们知道屏幕上有任何风吹操作都会触发一次 layout 流程,主要就是执行 WindowSurfacePlacer::performSurfacePlacement 这就是 一次 layout 。

WindowPlacerLocked::requestTraversal 触发的 layout 流程就是之前 relayoutWindow 流程看到的 WindowSurfacePlacer::performSurfacePlacement 。这个流程触发的地方非常多,只是当前 finishDrawingWindow 会主动触发一次罢了。对于这种高频率触发的方法,需要留意一下,初学者知道每个主流程会走什么逻辑就好,慢慢的随着知识体系的构建,再看这个流程其实就没那么复杂了。

WindowSurfacePlacer::performSurfacePlacement 的逻辑会遍历屏幕上每一个窗口,然后让其根据最新情况做对应的处理,比如 relayoutWinodw 流程的时候就会遍历到窗口做
执行 computeFrames 计算窗口大小。

当前分析的场景自然也会遍历窗口,触发这次 layout 的目的就是让当前这个窗口的 Surface 提交到 SurfaceFlinger 。

这个流程之前看过了,所以直接从 RootWindowContainer::performSurfacePlacement 方法开始

# RootWindowContainer

    // 这个方法加上了trace
    void performSurfacePlacement() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
            performSurfacePlacementNoTrace();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
    // 主要干活的还是这个
    void performSurfacePlacementNoTrace() {
        ......
        // Trace
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
        // 开启Surface事务
        mWmService.openSurfaceTransaction();
        try {
            // 重点* 1. 处理Surface事务
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            // 关闭Surface事务
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        ......
        // 重点* 2. 处理App事务
        checkAppTransitionReady(surfacePlacer);
        ......
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这里就有2个主要流程,也是2个类型的事务处理:

可以看到这行代码前后有 SurfaceTransaction 的打开和关闭,那说明这里的逻辑是会触发 Surface 操作的。

applySurfaceChangesTransaction 方法内部做很多事,比如上一篇的 layoutWindow 流程,当前分析的场景在这个方法里会执行将窗口状态设置为 READY_TO_SHOW 和 HAS_DRAWN ,并且构建一个 Surface 事务来显示当前窗口的 Surface 。

然后会在 WindowManagerService::closeSurfaceTransaction 方法中触发 SurfaceTransaction 的apply 把 Surface 操作的事务提交到 SurfaceFlinger 。

这个方法知道一下即可,当前流程不重点分析。

applySurfaceChangesTransaction 方法概览

# RootWindowContainer
    private void applySurfaceChangesTransaction() {
        ......
        // 遍历每个屏幕
        final int count = mChildren.size();
        for (int j = 0; j < count; ++j) {
            final DisplayContent dc = mChildren.get(j);
            dc.applySurfaceChangesTransaction();
        }
        ......
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

不考虑多个屏幕的场景。

# DisplayContent
    // 需要更新是否已经绘制的集合
    private final LinkedList<ActivityRecord> mTmpUpdateAllDrawn = new LinkedList();

    void applySurfaceChangesTransaction() {
        ......
        // 新的执行,清除数据
        mTmpUpdateAllDrawn.clear();
        ......
        // 重点* 1. layoutWindow 流程
        performLayout(true /* initial */, false /* updateInputWindows */);
        ......
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
        try {
            // 重点* 2. 遍历所有窗口执行 lambda表达式
            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        // 重点* 3. Surface 操作
        prepareSurfaces();
        ......
        // 如果有需要更新的ActivityRecord则处理
        while (!mTmpUpdateAllDrawn.isEmpty()) {
            final ActivityRecord activity = mTmpUpdateAllDrawn.removeLast();
            // See if any windows have been drawn, so they (and others associated with them)
            // can now be shown.
            // 内部会设置这个ActivityRecord 下的 allDrawn 为true
            activity.updateAllDrawn();
        }
    }
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这里有有个3重要的流程:

第一点在 relayoutWindow 流程分析过来,本篇分析后面2个。

这里还有一个重要的数据结构:mTmpUpdateAllDrawn

这个集合存储的是这次 layout 执行到当前 applySurfaceChangesTransaction 方法时,哪些 ActivityRecord 需要更新 allDrawn 属性了。

ActivityRecord 下面的这个 allDrawn 变量表示当前 ActivityRecord 下面的窗口是否全部绘制。

执行方法前会先把 mTmpUpdateAllDrawn 清空,然后在方法末尾遍历是否有元素。 那这个集合的元素是在哪里添加的呢?

在每个 WindowState 执行 mApplySurfaceChangesTransaction 时,如果符合条件就会加入集合。

READY_TO_SHOW和HAS_DRAWN状态更改

状态的设置在上面说的3个重点流程的第二点,也就是这一句代码触发。

forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

这句代码会从上到下遍历每个窗口,然后执行 lambda 表达式, mApplySurfaceChangesTransaction 的定义如下:

# DisplayContent

    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
	    ......
        final WindowStateAnimator winAnimator = w.mWinAnimator;
        ......
        // 判断当前是否有Surface
        if (w.mHasSurface) {
            // Take care of the window being ready to display.
            // 重点 * 1. 主流程设置为 READY_TO_SHOW 和 HAS_DRAWN
            final boolean committed = winAnimator.commitFinishDrawingLocked();
            ......
        }
        ......
        // 重点 * 2. allDrawn 相关逻辑
        // 拿到这个WindowState所属的ActivityRecord
        final ActivityRecord activity = w.mActivityRecord;
        // 已经请求可见
        if (activity != null && activity.isVisibleRequested()) {
            activity.updateLetterboxSurface(w);
            // 更新绘制状态
            final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);
            if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {
                // 符合条件加入集合
                mTmpUpdateAllDrawn.add(activity);
            }
        }
        w.updateResizingWindowIfNeeded();
    };

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这里有2个逻辑需要注意:

当前还是先看设置 Surface 状态的流程,allDrawn相关的后面单独梳理。

mHasSurface 在 relayoutWindow 流程创建 Surface 时设置为 true ,表示当前 WindowState 的已经有 Surface 。
然后就调用其 WindowStateAnimator::commitFinishDrawingLocked 。

# WindowStateAnimator

    boolean commitFinishDrawingLocked() {
        ......
        // 1. 当前状态的判断,不满足则return
        if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
            return false;
        }
        // 2. 日志
        ProtoLog.i(WM_DEBUG_ANIM, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
                mSurfaceController);
        // 3. 设置状态
        mDrawState = READY_TO_SHOW;
        ......
        // 4. 系统Window或者StartWindow则会走后续流程设置为 HAS_DRAW
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
            result = mWin.performShowLocked();
        }
        return result;
        ......
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这里有4个点,其中后面2个很重要:

可以看到现在窗口的状态已经是 READY_TO_SHOW 了,至于能不能执行到下一步的条件,当前场景是 Activity 下的窗口,所以如果要进去只能满足 “activity.canShowWindows()” 这条。
先给结论,绝大部分情况下,是满足条件的,所以先继续走主线任务,然后再看这个条件的具体控制条件,已经如果这里没满足条件,那又会在什么逻辑把 Surface 状态设置成 HAS_DRAW 。

继续看刷主线任务:HAS_DRAW 。

# WindowState
    boolean performShowLocked() {
    	......
		// 获取到当前状态
        final int drawState = mWinAnimator.mDrawState;
        // 当前分析过来的条件肯定都是满足的
        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
        	//窗口类型不为启动窗口
            if (mAttrs.type != TYPE_APPLICATION_STARTING) {
                // remonve startWindow 流程
                mActivityRecord.onFirstWindowDrawn(this);
            } else {
                mActivityRecord.onStartingWindowDrawn();
            }
        }
		// 不满足条件则直接返回,避免重复设置HAS_DRAWN
        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
            return false;
        }
        ......
        // 日志
        ProtoLog.v(WM_DEBUG_ANIM, "performShowLocked: mDrawState=HAS_DRAWN in %s", this);
        // 重点* 状态为HAS_DRAWN
        mWinAnimator.mDrawState = HAS_DRAWN;
        mWmService.scheduleAnimationLocked();
        ......
        return true;
    }
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这里会对当前窗口状态做检查,只有满足条件才会将状态设为 HAS_DRAWN。 然后因为这会窗口已经要显示了,可以移除 StartWindow 了。(以后会单独分析).

第一条主线任务到这里已经完成了,状态状态已经被设置为 HAS_DRAWN 了!

但是这毕竟只是代码中状态,一个类的变量而已,还没看到实际显示 Surface 的代码。具体的 Surface 显示逻辑在 prepareSurfaces 中。

SurfaceControl.Transaction::show

到这里状态状态已经是 READY_TO_SHOW 了,现在需要真正的将窗口显示事务提交到 SurfaceFlinger。

# DisplayContent

    @Override
    void prepareSurfaces() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
        try {
            // 1. 拿到事务
            final Transaction transaction = getPendingTransaction();
            // 2. 调用父类方法
            super.prepareSurfaces();

            // 3. 把事务merge到全局事务,供后续统一处理
            SurfaceControl.mergeToGlobalTransaction(transaction);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这里的主要流程是“super.prepareSurfaces();”,不过可以看到前后先是获取到了一个事务,然后再把这个事务 merge 到全局事务,这个全局事务就是 SurfaceControl 下面的一个类,也是一个 Surface 事务。

那说明这之间的 super.prepareSurfaces() 会有 Surface 事务的处理,才需要把它 merge 到全局事务中。

当前逻辑中 super.prepareSurfaces() 内部对 Surface 的处理就是将目标创建的 Surface 显示的事务。

统一处理 GlobalTransaction 的时机就是在后面 WindowManagerService::closeSurfaceTransaction 方法处理。

DisplayContent 的父类是 DisplayArea ,不过 DisplayArea::prepareSurfaces 方法也是调用了父类 WindowContainer 的方法,所以直接看 WindowContainer::prepareSurfaces

# WindowContainer
    void prepareSurfaces() {
        ......
        for (int i = 0; i < mChildren.size(); i++) {
            // 遍历孩子
            mChildren.get(i).prepareSurfaces();
        }
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

WindowContainer::prepareSurfaces 这个方法被很多子类重写,比如前面提到的 DisplayContent 和 DisplayArea ,另外还有像场景的 Task , ActivityRecord , WindowState 等,但是他们内部重写的逻辑也会再调用 “super.prepareSurfaces();”来遍历他的孩子,最终会调用到 DisplayContent 每个容器类,这里的调用略微有点绕,不过也不是很复杂,放慢思路理一下就好了。

其他类的重新不管,当前分析的窗口,所以直接看 WindowState 的实现。

# WindowState

    @Override
    void prepareSurfaces() {
        ......
        // 主流程
        mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
        // 调用父类,继续遍历它的孩子
        super.prepareSurfaces();
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

主要是调用了 WindowStateAnimator::prepareSurfaceLocked 方法,注意参数是是获取了一个 Transaction ,说明要开始对 Surface 做操作了。

# WindowStateAnimator

    WindowSurfaceController mSurfaceController;

    void prepareSurfaceLocked(SurfaceControl.Transaction t) {
        ......
        // 状态是 HAS_DRAWN 才执行
        if (prepared && mDrawState == HAS_DRAWN) {
            if (mLastHidden) {
                mSurfaceController.showRobustly(t);
                ......
            }
        }
        ......
    }


 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

这个方法在 U 有修改,简化了流程。google的修改链接为:
谷歌修改

这里又将 Transaction 交到了 WindowSurfaceController 处理,这个类我们在 relayoutWindow 的时候创建窗口 Surface 的时候提过,Window 的 Surface 创建是在这里类控制的,那么提交的逻辑交给它也很合理。

# WindowSurfaceController

    void showRobustly(SurfaceControl.Transaction t) {
        // 1. 关键日志
        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SHOW (performLayout): %s", title);
        ......
        // 2. 内部将mSurfaceShown设置为true
        setShown(true);
        // 3. 重点* Surface真正的显示
        t.show(mSurfaceControl);
        ......
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

又完成了一个主线任务 SurfaceControl.Transaction::show
现在只要找到 SurfaceControl.Transaction::apply 的执行地方,就说明 Framework 层已经通知 SurfaceFlinger 了,整个流程也就结束。

SurfaceControl.Transaction::apply–提交显示Surface事务到SurfaceFlinger

根据前面的分析,直接看 WindowManagerService::closeSurfaceTransaction 方法

# WindowManagerService
    /**
     * Closes a surface transaction.
     * @param where debug string indicating where the transaction originated
     */
    void closeSurfaceTransaction(String where) {
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
            SurfaceControl.closeTransaction();
            mWindowTracing.logState(where);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
# SurfaceControl
    // SurfaceControl下定义的全局事务
    static GlobalTransactionWrapper sGlobalTransaction;

    public static void closeTransaction() {
        synchronized(SurfaceControl.class) {
            ......
            sGlobalTransaction.applyGlobalTransaction(false);
        }
    }

    private static class GlobalTransactionWrapper extends SurfaceControl.Transaction {
        void applyGlobalTransaction(boolean sync) {
            ......
            //  重点* apply
            nativeApplyTransaction(mNativeObject, sync);
        }
    }

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

虽然没有看到 SurfaceControl.Transaction::apply 但是这个 GlobalTransactionWrapper 也是其子类,这里调用 native 方法也就是 apply 了。

finishDrawingWindow流程总结

当前流程在 layout 逻辑的处理流程图大概如下:
在这里插入图片描述
这里处理完后在 WindowManagerService::closeSurfaceTransaction 方法把这一次 layout 中对各个窗口的 Surface 操作统一提交到 Surface 处理,这样做有一个好处就是如果逐个提交不仅仅浪费资源,而且还能存在不同步的情况导致显示异常,把这一次 layout 所有的 Surface 提交统一放在一个 Transaction 里做提交,这样能确保显示的正常。
这样一来 finishDrawingWindow 流程的两条主线:状态,SurfaceTransaction 的 apply 就都执行完了。

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/baiduwaimai/article/details/142305363","extend1":"pc","ab":"new"}">>
注:本文转载自blog.csdn.net的芸丿兮的文章"https://blog.csdn.net/baiduwaimai/article/details/142305363"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!