performSurfacePlacementNoTrace()
这一段从performSurfacePlacement()开始讲起,因为在trace中可以看到在SystemServer中,动效会从performSurfacePlacement这个tag点触发。这里的流程就是在窗口状态改变之后,会触发performSurfacePlacement流程,在performSurfacePlacement流程中会进行一系列的检查,从而决定是开启动效流程,或者是继续等待,直到动效的前置条件已经就绪再开启动效,具体流程就在这里展开:
void performSurfacePlacement() {
    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
    try {
        performSurfacePlacementNoTrace();
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
}
onSurfacePlacement()
然后在performSurfacePlacementNoTrace()中会触发BLASTSyncEngine中的onSurfacePlacement()方法。
void onSurfacePlacement() {
         if (mActiveSyncs.isEmpty()) return;          (1)
        // queue in-order since we want interdependent syncs to become ready in the same order they
        // started in.
        mTmpFinishQueue.addAll(mActiveSyncs);	
       // There shouldn't be any dependency cycles or duplicates, but add an upper-bound just
        // in case. Assuming absolute worst case, each visit will try and revisit everything
        // before it, so n + (n-1) + (n-2) ... = (n+1)*n/2
         int visitBounds = ((mActiveSyncs.size() + 1) * mActiveSyncs.size()) / 2; //(2)
         while (!mTmpFinishQueue.isEmpty()) {
             if (visitBounds <= 0) {
                 Slog.e(TAG, "Trying to finish more syncs than theoretically possible. This "
                         + "should never happen. Most likely a dependency cycle wasn't detected.");
             }
             --visitBounds;
             final SyncGroup group = mTmpFinishQueue.remove(0); //(3)
             final int grpIdx = mActiveSyncs.indexOf(group);  //(4)
             // Skip if it's already finished:
            if (grpIdx < 0) continue;
            if (!group.tryFinish()) continue;   //(5)
            // Finished, so update dependencies of any prior groups and retry if unblocked.
            int insertAt = 0;
             for (int i = 0; i < mActiveSyncs.size(); ++i) {    //(6)
                 final SyncGroup active = mActiveSyncs.get(i);   //(7)
                if (!active.mDependencies.remove(group)) continue; //(8)
                // Anything afterwards is already in queue.
                if (i >= grpIdx) continue;   //(9)
                if (!active.mDependencies.isEmpty()) continue; //(10)
                 // `active` became unblocked so it can finish, since it started earlier, it should
                 // be checked next to maintain order.
                mTmpFinishQueue.add(insertAt, mActiveSyncs.get(i));  //(11)
                 insertAt += 1;
             }
        }
     }
在onSurfacePlacement()方法中,首先在(1)处检查的是mActiveSyncs是否为空。在代码中找到mActiveSyncs的声明,发现其声明如下,所以对其操作都在该文件内。在本文件中只找到唯一一处向其中添加对象的地方就在startSyncSet方法中。这里可以接上篇博客启动动效流程梳理(一),其中在Transition.java中将mState置为STATE_COLLECTING时,会触发该操作,所以一般从前面的流程走过来的话,这里的mActiveSyncs一般是不为空的。
private final ArrayList<SyncGroup> mActiveSyncs = new ArrayList<>();
void startSyncSet(SyncGroup s, long timeoutMs, boolean parallel) {
    final boolean alreadyRunning = mActiveSyncs.size() > 0;
    if (!parallel && alreadyRunning) {
        // We only support overlapping syncs when explicitly declared `parallel`.
        Slog.e(TAG, "SyncGroup " + s.mSyncId
                + ": Started when there is other active SyncGroup");
    }
    mActiveSyncs.add(s);
    // For now, parallel implies this.
    s.mIgnoreIndirectMembers = parallel;
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started %sfor listener: %s",
            s.mSyncId, (parallel && alreadyRunning ? "(in parallel) " : ""), s.mListener);
    scheduleTimeout(s, timeoutMs);
}
在判断完mActiveSyncs是否为空之后,会将其移入mTmpFinishQueue中,然后再将元素从mTmpFinishQueue中依次从头移除,即(3)处所示,然后再在mActiveSyncs中找到该元素对应的索引,正常情况下grpIdx是大于等于0的,因为可以看到mTmpFinishQueue就是mActiveSyncs拷贝过来的,但是在(5)处会进入到tryFinish的流程中,这里可能会移除mActiveSyncs中的group对象,所以不排除这种可能,所以这里的注释就是这个意思。
TryFinish()
然后先进(5)的tryFinish()看下做了什么:
private boolean tryFinish() {
    if (!mReady) return false;
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s",
            mSyncId, mRootMembers);
    if (!mDependencies.isEmpty()) {  //(12)
        ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished dependencies: %s",
                mSyncId, mDependencies);
        return false;
    }
    for (int i = mRootMembers.size() - 1; i >= 0; --i) {  //(13)
        final WindowContainer wc = mRootMembers.valueAt(i);
        if (!wc.isSyncFinished(this)) {
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished container: %s",
                    mSyncId, wc);
            return false;
        }
    }
    finishNow();  //(14)
    return true;
}
首先是检查mReady标志位,这里只有在setReady处才会改变mReady的属性,所以也就是说,只有执行setReady(true)后才会执行接下来的流程。然后会检查当前的SyncGroup的mDependencies中的SyncGroup是否为空,而mDependencies的注解是必须在当前SyncGroup之前finish的SyncGroup队列。 根据(12)处的注释解读,mDependencies中的成员,会在finish后被移除队列,所以如果一个SyncGroup在tryFinish时,其mDependencies不为空,就会直接返回失败。 再到(13)处的for循环,这里回去检查当前的SyncGroup的mRootMembers中的各个成员是否绘制完成,如果存在未绘制完成的WindowContainer,则也直接返回false。这里的绘制完成是通过finishDrawing触发,finishDrawing会在应用侧绘制完成时触发,这块前面博客启动动效流程梳理(一)中也讲到过。
FinishNow()
做完上述两个检查才会继续执行到finishNow流程中。finishNow流程的话,简单讲下,首先是创建一个Transaction对象merged,然后再将子节点mRootMembers的mSyncTransaction都合并进merged中。再去执行mRootMembers的mChildren的finishSync方法,这里就看WindowContainer的mChildren是什么类型了,反正基本操作就是将mSyncState置为SYNC_STATE_NONE,且mSyncGroup置为null。之后再将mRootMembers中各个成员及其成员的mChildren都放入wcAwaitingCommit之中。
private void finishNow() {
    if (mTraceName != null) {
        Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, mTraceName, mSyncId);
    }
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Finished!", mSyncId);
    SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();
    if (mOrphanTransaction != null) {
        merged.merge(mOrphanTransaction);
    }
    for (WindowContainer wc : mRootMembers) {
        wc.finishSync(merged, this, false /* cancel */);
    }
    final ArraySet<WindowContainer> wcAwaitingCommit = new ArraySet<>();
    for (WindowContainer wc : mRootMembers) {
        wc.waitForSyncTransactionCommit(wcAwaitingCommit);
    }
    class CommitCallback implements Runnable {
        // Can run a second time if the action completes after the timeout.
        boolean ran = false;
        public void onCommitted(SurfaceControl.Transaction t) {
            synchronized (mWm.mGlobalLock) {
                if (ran) {
                    return;
                }
                mHandler.removeCallbacks(this);
                ran = true;
                for (WindowContainer wc : wcAwaitingCommit) {
                    wc.onSyncTransactionCommitted(t);
                }
                t.apply();
                wcAwaitingCommit.clear();
            }
        }
        // Called in timeout
        @Override
        public void run() {
            // Sometimes we get a trace, sometimes we get a bugreport without
            // a trace. Since these kind of ANRs can trigger such an issue,
            // try and ensure we will have some visibility in both cases.
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionCommitTimeout");
            Slog.e(TAG, "WM sent Transaction to organized, but never received" +
                    " commit callback. Application ANR likely to follow.");
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            synchronized (mWm.mGlobalLock) {
                onCommitted(merged.mNativeObject != 0
                        ? merged : mWm.mTransactionFactory.get());
            }
        }
    };
    CommitCallback callback = new CommitCallback();
    merged.addTransactionCommittedListener(Runnable::run,
            () -> callback.onCommitted(new SurfaceControl.Transaction())); //(15)
    mHandler.postDelayed(callback, BLAST_TIMEOUT_DURATION);  //(16)
    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
    mListener.onTransactionReady(mSyncId, merged);
    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    mActiveSyncs.remove(this);
    mHandler.removeCallbacks(mOnTimeout);
    // Immediately start the next pending sync-transaction if there is one.
    if (mActiveSyncs.size() == 0 && !mPendingSyncSets.isEmpty()) {
        ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "PendingStartTransaction found");
        final PendingSyncSet pt = mPendingSyncSets.remove(0);
        pt.mStartSync.run();
        if (mActiveSyncs.size() == 0) {
            throw new IllegalStateException("Pending Sync Set didn't start a sync.");
        }
        // Post this so that the now-playing transition setup isn't interrupted.
        mHandler.post(() -> {
            synchronized (mWm.mGlobalLock) {
                pt.mApplySync.run();
            }
        });
    }
    // Notify idle listeners
    for (int i = mOnIdleListeners.size() - 1; i >= 0; --i) {
        // If an idle listener adds a sync, though, then stop notifying.
        if (mActiveSyncs.size() > 0) break;
        mOnIdleListeners.get(i).run();
    }
}
在finishNow方法中定义了一个CommitCallback类,其实现了Runnable接口。CommitCallback类中有两个方法,run和onCommitted,主要就是onCommitted方法,这个方法会获取WindowManagerService的大锁,然后遍历wcAwaitingCommit中的成员,并将其mSyncTransaction合并到merged中,然后将merged进行apply()。而callback的onCommitted方法则会在(15)处,于Transaction被从应用侧apply到SF侧的同时调用,这里的机制可以看到上一篇博客WCT系列(五):addTransactionCommittedListener。
 在之后就是mListener.onTransactionReady(mSyncId, merged)该方法的调用,这里就是回去播放动效了。该方法需要跳到wm\Transition.java中查看,简单的归纳下该方法的具体作用:
 1、 将mState状态修改为STATE_PLAYING;并设置mStartTransaction和mFinishTransaction的状态;
 2、 通过动效的mParticipants和mChanges参数计算出mTargets参数;
 3、 计算出TransitionInfo类型的info参数的值;
 4、 将需要播放的Transition对象从mCollectingTransition列表中移到mPlayingTransition列表中;
 5、 发送onTransitionReady Binder到shell线程;
 


















