WCT系列(四):BLASTSyncEngine

news2024/11/15 15:35:57

WCT系列(一):WindowContainerTransaction类详解
WCT系列(二):SyncTransactionQueue类详解
WCT系列(三):WindowOrganizerController
WCT系列(四):BLASTSyncEngine
在这里插入图片描述

在这里插入图片描述

1、什么是BLASTSyncEngine?

/**
 * Utility class for collecting WindowContainers that will merge transactions.
 * For example to use to synchronously resize all the children of a window container
 *   1. Open a new sync set, and pass the listener that will be invoked
 *        int id startSyncSet(TransactionReadyListener)
 *      the returned ID will be eventually passed to the TransactionReadyListener in combination
 *      with a set of WindowContainers that are ready, meaning onTransactionReady was called for
 *      those WindowContainers. You also use it to refer to the operation in future steps.
 *   2. Ask each child to participate:
 *       addToSyncSet(int id, WindowContainer wc)
 *      if the child thinks it will be affected by a configuration change (a.k.a. has a visible
 *      window in its sub hierarchy, then we will increment a counter of expected callbacks
 *      At this point the containers hierarchy will redirect pendingTransaction and sub hierarchy
 *      updates in to the sync engine.
 *   3. Apply your configuration changes to the window containers.
 *   4. Tell the engine that the sync set is ready
 *       setReady(int id)
 *   5. If there were no sub windows anywhere in the hierarchy to wait on, then
 *      transactionReady is immediately invoked, otherwise all the windows are poked
 *      to redraw and to deliver a buffer to {@link WindowState#finishDrawing}.
 *      Once all this drawing is complete, all the transactions will be merged and delivered
 *      to TransactionReadyListener.
 *
 * This works primarily by setting-up state and then watching/waiting for the registered subtrees
 * to enter into a "finished" state (either by receiving drawn content or by disappearing). This
 * checks the subtrees during surface-placement.
 */

根据定义,BLASTSyncEngine有这五个功能:
1)开启一个syncset,同时传递一个listener,int id startSyncSet(TransactionReadyListener) 这里的ID将会被放在一组准备好的WindowContainer中传递给TransactionListener。而这就意味着这些WindowContainer已经调用了onTransactionReady。
2)令每一个子容器加入addToSyncSet(int id, WindowContainer wc)
如果子容器将会被参数的改变说影响(即在其层次结构中有一个可见的窗口,那么我们会增加一个回调的计数器)。同时,容器的层次结构将会把pendingTransaction和他的子层次结构更新到同步引擎中;
3)应用你对WindowContainer的参数的修改;
4)告诉BLASTSyncEngine,SyncSet已经准备好了:通过setReady(int id);
5)如果层次结构中没有子窗口在等待,这transactionReady将会被立即调用,否则所有窗口将会被送去重新绘制,且给WindowState#finishDrawing传送缓冲区。一旦绘制完成,所有transaction将被合并并且传送给 TransactionReadyListener。

2、同步流程解析:

这里就可以回到在WindowOrganizerController那里跳过的applySyncTransaction方法中继续分析了:

public int applySyncTransaction(WindowContainerTransaction t,
        IWindowContainerTransactionCallback callback) {
    if (t == null) {
        throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
    }
    enforceTaskPermission("applySyncTransaction()");
    final CallerInfo caller = new CallerInfo();
    final long ident = Binder.clearCallingIdentity();
    try {
        synchronized (mGlobalLock) {
            if (callback == null) {
                applyTransaction(t, -1 /* syncId*/, null /*transition*/, caller);
                return -1;
            }

            /**
             * If callback is non-null we are looking to synchronize this transaction by
             * collecting all the results in to a SurfaceFlinger transaction and then delivering
             * that to the given transaction ready callback. See {@link BLASTSyncEngine} for the
             * details of the operation. But at a high level we create a sync operation with a
             * given ID and an associated callback. Then we notify each WindowContainer in this
             * WindowContainer transaction that it is participating in a sync operation with
             * that ID. Once everything is notified we tell the BLASTSyncEngine "setSyncReady"
             * which means that we have added everything to the set. At any point after this,
             * all the WindowContainers will eventually finish applying their changes and notify
             * the BLASTSyncEngine which will deliver the Transaction to the callback.
             */
            final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);  //(1)
            final int syncId = syncGroup.mSyncId;
            if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {//(5)
                mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup);  //(6)
                applyTransaction(t, syncId, null /*transition*/, caller);   //(7)
                setSyncReady(syncId);//(8)
            } else {
                // Because the BLAST engine only supports one sync at a time, queue the
                // transaction.
                mService.mWindowManager.mSyncEngine.queueSyncSet(
                        () -> mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup),
                        () -> {
                            applyTransaction(t, syncId, null /*transition*/, caller);
                            setSyncReady(syncId);
                        });
            }
            return syncId;
        }
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

1) prepareSyncWithOrganizer:

首先看到(1)出的prepareSyncWithOrganizer方法:

private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
        IWindowContainerTransactionCallback callback) {
    final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
            .prepareSyncSet(this, "", BLASTSyncEngine.METHOD_BLAST);
    mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);//(2)
    return s;
}

private final HashMap<Integer, IWindowContainerTransactionCallback>
        mTransactionCallbacksByPendingSyncId = new HashMap();

SyncGroup prepareSyncSet(TransactionReadyListener listener, String name, int method) {
    return new SyncGroup(listener, mNextSyncId++, name, method);
}

private SyncGroup(TransactionReadyListener listener, int id, String name, int method) { //(3)
    mSyncId = id;
    mSyncMethod = method;
    mListener = listener;
    mOnTimeout = () -> {
        Slog.w(TAG, "Sync group " + mSyncId + " timeout");
        synchronized (mWm.mGlobalLock) {
            onTimeout();
        }
    };
    if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
        mTraceName = name + "SyncGroupReady";
        Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, mTraceName, id);
    }
}

private void onTimeout() {  //(4)
//如果激活的SyncGroup中没有id为mSyncId的SyncGroup则直接返回
    if (!mActiveSyncs.contains(mSyncId)) return;
//初始化allFinished参数
    boolean allFinished = true;
//遍历mRootMembers中的WindowContainer是否已经SyncFinished
    for (int i = mRootMembers.size() - 1; i >= 0; --i) {
        final WindowContainer<?> wc = mRootMembers.valueAt(i);
        if (!wc.isSyncFinished()) {
            allFinished = false;
            Slog.i(TAG, "Unfinished container: " + wc);
        }
    }
    if (allFinished && !mReady) {
//这块应该是一个异常模块,SyncGroup都finish了但是却没设置ready
        Slog.w(TAG, "Sync group " + mSyncId + " timed-out because not ready. If you see "
                + "this, please file a bug.");
    }
    finishNow();
}

该方法中,通过BLASTSyncEngine中的prepareSyncSet方法创建了一个SyncGroup类型的对象,并将他的mSyncId和传入的callback一同放入了mTransactionCallbacksByPendingSyncId这个map中。这里再回顾下上一节WindowOrganizerController中的知识点,这个callback呢就是一个SyncCallback类型的对象,主要是要调用其中的onTransactionReady回调函数。这里将mSyncId和callback放入map中以后,在系统侧完成了transaction应用后,就可以根据这个mSyncId找到对应的onTransactionReady回调。
而SyncGroup类是BLASTSyncEngine的一个内部类,其构造函数如上(3)处的代码,需要mSyncId(int)、mSyncMethod(int)、mListener(TransactionReadyListener
)和一个超时的mOnTimeOut(Runnable)。而且每个SyncGroup的mSyncId都是唯一的,因为在构建的时候会通过自增对其进行赋值。
其中超时Runnable就是防止某个WindowContainer长时间没完成isSyncFinished操作时,直接调用finishNow。而isSyncFinished的详细操作如下:

boolean isSyncFinished() {
//查看整个容器内各个WindowContainer的isVisibleRequested()返回结果
    if (!isVisibleRequested()) {
        return true;
    }
//如果state为SYNC_STATE_NONE,则遍历整个容器内的WindowContainer并执行
//其prepareSync函数
    if (mSyncState == SYNC_STATE_NONE) {
        prepareSync();
    }
    if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW) {
        return false;
    }
    // READY
    // Loop from top-down.
    for (int i = mChildren.size() - 1; i >= 0; --i) {
        final WindowContainer child = mChildren.get(i);
        final boolean childFinished = child.isSyncFinished();
        if (childFinished && child.isVisibleRequested() && child.fillsParent()) {
            // Any lower children will be covered-up, so we can consider this finished.
            return true;
        }
        if (!childFinished) {
            return false;
        }
    }
    return true;
}

上面一下子讲的有点多,这里先回到(2)这个地方。在完成了SyncGroup的创建和保存后,会继续(1)处的代码执行。接下来来到(5)处,发现这里会检查BLASTSyncEngine中的mActiveSyncs的size是否为0。如果是0就会执行到(6)(7)(8)三个地方的方法。那这里就比较容易理解了,就是mActiveSyncs同时只能有一个正在执行呗。
于是再去看看mActiveSyncs是什么:

private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>();

这一看就明白了,就是一个稀疏数组呗。那就看看什么时候会向这个数组中添加元素呢?

void startSyncSet(SyncGroup s, long timeoutMs) {
    if (mActiveSyncs.size() != 0) {
        // We currently only support one sync at a time, so start a new SyncGroup when there is
        // another may cause issue.
        ProtoLog.w(WM_DEBUG_SYNC_ENGINE,
                "SyncGroup %d: Started when there is other active SyncGroup", s.mSyncId);
    }
    mActiveSyncs.put(s.mSyncId, s);
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s",
            s.mSyncId, s.mListener);
    scheduleTimeout(s, timeoutMs);
}

你看从这里就能看到We currently only support one sync at a time.这不就是证明了(5)处的理解是对的了嘛。 然后这个方法中会向mActiveSyncs中添加元素,而其元素为SyncGroup对象的mSyncId和SyncGroup对象本身组成的键值对。
而调用startSyncSet的地方就是(6)处。所以在当前mActiveSyncs为空时,就会向其中添加我们刚刚构建的一个SyncGroup对象。然后在(8)处,我们会调用setSyncReady方法,并将前面构建的SyncGroup对象的mSyncId传进去。
当然(5)处检查mActiveSyncs是否为空时,也可能会出现当前不为空的状态。那么这时候就会进入else语句,然后调用BLASTSyncEngine的queueSyncSet方法:

void queueSyncSet(@NonNull Runnable startSync, @NonNull Runnable applySync) {
    final PendingSyncSet pt = new PendingSyncSet();
    pt.mStartSync = startSync;
    pt.mApplySync = applySync;
    mPendingSyncSets.add(pt);
}

而该方法这是将startSyncSet和applySyncTransaction两个操作分别封装为两个Runnable对象,然后放入mPendingSyncSets(ArrayList类型)之中暂存起来。其会在finishNow方法中被执行。

2) addToSyncSet

在执行applyTransaction的过程中,当syncId(还是刚刚构建的SyncGroup对象的mSyncId)大于0时,会调用一个函数,addToSyncSet。那这里继续查看其具体实现:

void addToSyncSet(int syncId, WindowContainer wc) {
    mService.mWindowManager.mSyncEngine.addToSyncSet(syncId, wc);
}

BLASTSyncEngine.java
void addToSyncSet(int id, WindowContainer wc) {
    getSyncGroup(id).addToSync(wc);
}

private SyncGroup getSyncGroup(int id) {
    final SyncGroup syncGroup = mActiveSyncs.get(id);
    if (syncGroup == null) {
        throw new IllegalStateException("SyncGroup is not started yet id=" + id);
    }
    return syncGroup;
}

private void addToSync(WindowContainer wc) {
    if (!mRootMembers.add(wc)) { //(9)
        return;
    }
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc);
    wc.setSyncGroup(this);  //(10)
    wc.prepareSync();  //(11)
    if (mReady) {
        mWm.mWindowPlacerLocked.requestTraversal();
    }
}
final ArraySet<WindowContainer> mRootMembers = new ArraySet<>();

如上:该方法就是在mActiveSyncs中找到指定id的SyncGroup,然后向其中添加WindowContainer。而这个WindowContainer则是添加到了SyncGroup的mRootMembers(ArraySet类型)成员变量中了。并且在添加的过程中,还会将这个WindowContainer对象的SyncGroup设置为当前SyncGroup。如果已经setReady这里甚至会直接请求绘制新一帧。 前面的WindowOrganizerController章节已经讲过了,applyTransaction方法,这里就是遍历了所有参与的WindowContainer,并将其添加到了SyncGroup当中。

至于addToSyncSet方法,可不止在这一处执行,还有1、applyHierarchyOP方法中也执行了这个方法;2、reparentChildrenTaskHierarchyOp方法中;3、applyTransaction方法中。
都是将相关的WindowContainer添加到对应的SyncGroup中。而(9)处这个判断则是为了防止这三处对WindowContainer的重复添加。

a) setSyncGroup

void setSyncGroup(@NonNull BLASTSyncEngine.SyncGroup group) {
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "setSyncGroup #%d on %s", group.mSyncId, this);
    if (group != null) {
        if (mSyncGroup != null && mSyncGroup != group) {
            // This can still happen if WMCore starts a new transition when there is ongoing
            // sync transaction from Shell. Please file a bug if it happens.
            throw new IllegalStateException("Can't sync on 2 engines simultaneously"
                    + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId);
        }
    }
    mSyncGroup = group;
}

在这里可以看到,就是简单将当前的WindowContainer的mSyncGroup指向我们指定的SyncGroup对象。但是如果当前WindowContainer对象已经有了mSyncGroup并且还是与当前指定的对象不同,那就得抛出异常了。而这个mSyncGroup如果已经被赋值,则说明这个WindowContainer正在被这个SyncGroup等待。如果他没被赋值,则只会被他的福WindowContainer等待(当他在SyncGroup中时)

b) prepareSync

boolean prepareSync() {
    if (mSyncState != SYNC_STATE_NONE) {
        // Already part of sync
        return false;
    }
    for (int i = getChildCount() - 1; i >= 0; --i) {
        final WindowContainer child = getChildAt(i);
        child.prepareSync();
    }
    mSyncState = SYNC_STATE_READY;///(12)
    return true;
}

这里又出现了一个变量,mSyncState,对于这个变量,我们可以根据其定义进行了解:

public static final int SYNC_STATE_NONE = 0;

/** This is currently waiting for itself to finish drawing. */
public static final int SYNC_STATE_WAITING_FOR_DRAW = 1;

/** This container is ready, but it might still have unfinished children. */
public static final int SYNC_STATE_READY = 2;

@IntDef(prefix = { "SYNC_STATE_" }, value = {
        SYNC_STATE_NONE,
        SYNC_STATE_WAITING_FOR_DRAW,
        SYNC_STATE_READY,
})
@interface SyncState {}
@SyncState int mSyncState = SYNC_STATE_NONE;

从上面可知,他只能取0/1/2三个值,而这三个值分别对应着:0->当前WindowContainer没有参与到一次同步操作中; 1->当前WindowContainer正在等待自身的绘制; 2->当前的WindowContainer已经绘制完成,但是其子WindowContainer可能未完成绘制。

所以在同步开始前,需要将其状态置为2;即(12)处的操作。当然这里可能会有点疑问,为什么这里什么也没操作就直接置为ready了呢?因为我们的WindowContainer是所有窗口类的父类,还会有不同的子类对其进行重写。而这里只是在其子WindowContainer完成prepareSync之后,即可置为ready,所以子WindowContainer的prepareSync其实才是关键所在。这里找到WindowState的prepareSync方法看一下。
如(13)处可见,这个WindowState的mSyncState的状态是从SYNC_STATE_WAITING_FOR_DRAW开始的,而不是上来就只为ready。

boolean prepareSync() {
    if (!mDrawHandlers.isEmpty()) {
        Slog.w(TAG, "prepareSync with mDrawHandlers, " + this + ", " + Debug.getCallers(8));
    }
    if (!super.prepareSync()) {
        return false;
    }
    if (mIsWallpaper) {
        // TODO(b/233286785): Add sync support to wallpaper.
        return false;
    }
    mSyncState = SYNC_STATE_WAITING_FOR_DRAW;  //(13)

    if (mPrepareSyncSeqId > 0) {
        ProtoLog.d(WM_DEBUG_SYNC_ENGINE, "Preparing to sync a window that was already in the"
                        + " sync, so try dropping buffer. win=%s", this);
        dropBufferFrom(mSyncTransaction);
    }

    mSyncSeqId++;
    if (getSyncMethod() == BLASTSyncEngine.METHOD_BLAST) {
        mPrepareSyncSeqId = mSyncSeqId;
    }
    requestRedrawForSync();
    return true;
}

不过问题又来了,WindowState的初始状态既然不是SYNC_STATE_READY,那么他在什么时候被设置为SYNC_STATE_READY的呢?这个问题放到下面的5)onTransactionReady模块再讲。

3) 将WindowContainerTransaction应用到WindowContainer

这个地方在WindowOrganizerController那篇博客已经讲解过了,这里就先不赘述了。

4) setReady:

回到(8)处,继续讲回到applySyncTransaction方法中,在确定了当前的mActiveSyncs中无元素时(5),将创建好的SyncGroup对象通过startSyncSet方法,放入mActiveSyncs之中(6),然后应用本次WindowContainerTransaction包含的所有修改(7)。 最后执行完所有的任务后,执行到(8)处setSyncReady(syncId);
这个方法有什么用呢?于是我们跟随代码一步一步的深挖下去。

void setSyncReady(int id) {
    ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id);
    mService.mWindowManager.mSyncEngine.setReady(id);
}

BLASTSyncEngine.java
void setReady(int id, boolean ready) {
    getSyncGroup(id).setReady(ready);
}

void setReady(int id) {
    setReady(id, true);
}

private void setReady(boolean ready) {
    if (mReady == ready) {
        return;
    }
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId);
    mReady = ready;
    if (!ready) return;
    mWm.mWindowPlacerLocked.requestTraversal();
}

通过代码可见,setSyncReady(syncId)方法最终调到了BLASTSyncEngine内部类SyncGroup中的setReady方法,这个方法的具体功能就是将mActiveSyncs中mSyncId为(8)处传入的syncId的SyncGroup对象的mReady设置为true,表示着本次WindowContainerTransaction中的修改已经全部应用完成了,并在最后请求一次界面刷新。

5) TransactionReady

在刷新界面的时候,RootWindowContainer中的performSurfacePlacementNoTrace会调用一次BLASTSyncEngine的onSurfacePlacement方法。这里也可以看到,在上面将SyncGroup的mReady置为true之后,这里(14)处才能继续执行下去。

void onSurfacePlacement() {
    // backwards since each state can remove itself if finished
    for (int i = mActiveSyncs.size() - 1; i >= 0; --i) {
        mActiveSyncs.valueAt(i).onSurfacePlacement();
    }
}

private void onSurfacePlacement() {
    if (!mReady) return; //(14)
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s", mSyncId, mRootMembers);
    for (int i = mRootMembers.size() - 1; i >= 0; --i) { //(15)
        final WindowContainer wc = mRootMembers.valueAt(i); //(16)
        if (!wc.isSyncFinished()) {  //(17)
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished container: %s", mSyncId, wc);
            return;
        }
    }
    finishNow();   //(18)
}

在上述代码的(15)和(16)处,就是去遍历mRootMembers中的WindowContainers,并确认其是否isSyncFinished。mRootMembers中的元素,前面讲过,就是在addToSync的时候进行填充的。而isSyncFinished返回的结果表示的是当前的WindowContainer是否已经完成同步了。那isSyncFinished具体做了哪些操作呢?这个函数在2、1)中就已经初步看了下,但是当时没有详细分析,现在对其进行详细的拆解:
在这里插入图片描述

boolean isSyncFinished() {
    if (!isVisibleRequested()) {
        return true;
    }
    if (mSyncState == SYNC_STATE_NONE) {
        prepareSync();
    }
    if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW) {
        return false;
    }
    // READY
    // Loop from top-down.
    for (int i = mChildren.size() - 1; i >= 0; --i) {
        final WindowContainer child = mChildren.get(i);
        final boolean childFinished = child.isSyncFinished();
        if (childFinished && child.isVisibleRequested() && child.fillsParent()) {
            // Any lower children will be covered-up, so we can consider this finished.
            return true;
        }
        if (!childFinished) {
            return false;
        }
    }
    return true;
}

而根据前面的分析2、2)、b)中,在prepareSync的时候,主要是看WindowState容器是否被设置为SYNC_STATE_READY即可,因为父WindowContainer都是在等子WindowContainer的prepareSync操作而已。而WindowState的prepareSync则是将其状态设置为SYNC_STATE_WAITING_FOR_DRAW,那么什么时候会将其置为SYNC_STATE_READY呢?在代码中搜索将状态置为SYNC_STATE_READY的地方,只找到了一处:

boolean onSyncFinishedDrawing() {
    if (mSyncState == SYNC_STATE_NONE) return false;
    mSyncState = SYNC_STATE_READY;
    mSyncMethodOverride = BLASTSyncEngine.METHOD_UNDEFINED;
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "onSyncFinishedDrawing %s", this);
    return true;
}

那又是哪里调用的onSyncFinshedDrawing方法呢?继续寻找:

boolean isSyncFinished() {
    if (!isVisibleRequested()) {
        // Don't wait for invisible windows. However, we don't alter the state in case the
        // window becomes visible while the sync group is still active.
        return true;
    }
    if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mWinAnimator.mDrawState == HAS_DRAWN
            && !mRedrawForSyncReported && !mWmService.mResizingWindows.contains(this)) {
        // Complete the sync state immediately for a drawn window that doesn't need to redraw.
        onSyncFinishedDrawing();
    }
    return super.isSyncFinished();
}

而这里的finishDrawing方法,根据调用栈能看到,是从ViewRootImpl.reportDrawFinished -> Session.finshDrawing -> WMS.finshDrawingWindow -> WindowState.finishDrawing -> WindowContainer.onSyncFinishedDrawing这一套流程调用过来的。 在之前关于WindowManagerService的相关博客中,我已经讲解过了,Session类的作用,主要就是应用侧与系统侧沟通的桥梁,应用侧可以通过Session来调用WMS的一些功能。 所以那就是说,finishDrawing就是应用侧绘制完成后主动通知系统侧,这时候才能将对应的WindowState的mSyncState设置为SYNC_STATE_READY了。
当然这里还有另一个条件,必须满足这一个条件,isSyncFinished才能返回true:

  • 所有的子窗口的isSyncFinished也是true,并且所有窗口都要显示,并且能够覆盖到他的parent窗口,则返回true;
  • 如果找到一个子窗口的isSyncFinished为false的话,则返回false;
  • 如果遍历完所有子窗口,但是上述两个条件都不满足,那也可以返回true;

从这里也可以看出,只有mRootMembers中的所有元素完成了同步,这时候才能进入finshNow流程,即代码中的(18)处。 接下来就看下finshNow中具体执行了什么流程。

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, false /* cancel */);
    }

    final ArraySet<WindowContainer> wcAwaitingCommit = new ArraySet<>();
    for (WindowContainer wc : mRootMembers) {
        wc.waitForSyncTransactionCommit(wcAwaitingCommit);
    }
    class CommitCallback implements Runnable {
        boolean ran = false;
        public void onCommitted() {
            synchronized (mWm.mGlobalLock) {
                if (ran) {
                    return;
                }
                mWm.mH.removeCallbacks(this);
                ran = true;
                SurfaceControl.Transaction t = new SurfaceControl.Transaction();
                for (WindowContainer wc : wcAwaitingCommit) {
                    wc.onSyncTransactionCommitted(t);
                }
                t.apply();
                wcAwaitingCommit.clear();
            }
        }
        @Override
        public void run() {
            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);
            onCommitted();

        }
    };
    CommitCallback callback = new CommitCallback();
    merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::onCommitted);
    mWm.mH.postDelayed(callback, BLAST_TIMEOUT_DURATION);

    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
    mListener.onTransactionReady(mSyncId, merged);
    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    mActiveSyncs.remove(mSyncId);
    mWm.mH.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.
        mWm.mH.post(() -> {
            synchronized (mWm.mGlobalLock) {
                pt.mApplySync.run();
            }
        });
    }
}

不过finishNow流程还是比较复杂的,这里就看下几个核心的地方:

a)存放所有Transaction的容器merged:

SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();
if (mOrphanTransaction != null) {
    merged.merge(mOrphanTransaction); //(19)
}
for (WindowContainer wc : mRootMembers) {
    wc.finishSync(merged, false /* cancel */);//(20)
}

首先是这一块流程,这里可见首先新建了一个Transaction对象:merged,然后将mOrphanTransation放入其中。但是mOrphanTransation又是什么东西呢?根据调用关系,可以看到只有在onSyncReparent中,(21)处对其进行了操作,这里从函数名就可以推测出就是用来将当前WindowContainer重新放到另一个parent下的方法。再根据finishSync方法就可以看到,主要就是将当前WindowContainer和其子WindowContainer的mSyncTransaction(其中存放的就是对该WindowContainer的一些修改)放到mOrphanTransation。 这里的目的就是在SyncGroup中的WindowContainer的父WindowContainer发生变化时,会将他的mSyncTransaction放入mOrphanTransation,避免在reparent的过程中保存在WindowContainer的mSyncTransaction中的修改会丢失。

private void onSyncReparent(WindowContainer oldParent, WindowContainer newParent) {
…………………………………………………………………
        if (newParent == null || newParent.mSyncState == SYNC_STATE_NONE) {
……………………………………………………………………
            if (newParent == null) {
                // This is getting removed.
                if (oldParent.mSyncState != SYNC_STATE_NONE) {
                    // In order to keep the transaction in sync, merge it into the parent.
                    finishSync(oldParent.mSyncTransaction, true /* cancel */);
                } else if (mSyncGroup != null) {
                    // This is watched directly by the sync-group, so merge this transaction into
                    // into the sync-group so it isn't lost
                    finishSync(mSyncGroup.getOrphanTransaction(), true /* cancel */);   //(21)
                } else {
                    throw new IllegalStateException("This container is in sync mode without a sync"
                            + " group: " + this);
                }
                return;
…………………………………………………………………
}
void finishSync(Transaction outMergedTransaction, boolean cancel) {
    if (mSyncState == SYNC_STATE_NONE) return;
    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "finishSync cancel=%b for %s", cancel, this);
    outMergedTransaction.merge(mSyncTransaction);
    for (int i = mChildren.size() - 1; i >= 0; --i) {
        mChildren.get(i).finishSync(outMergedTransaction, cancel);
    }
    if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this);
    mSyncState = SYNC_STATE_NONE;
    mSyncMethodOverride = BLASTSyncEngine.METHOD_UNDEFINED;
    mSyncGroup = null;
}

b)finishSync:

在(20)处又调用了finishSync方法,将mRootMembers中的WindowContainer及其子WindowContainer中的mSyncTransaction都放到了merged当中, 而且最终还会将每个WindowContainer的mSyncState置为SYNC_STATE_NONE,mSyncGroup也会置为null,这就意味着将这些WindowContainer的状态复位了。

c)CmmitCallback:

class CommitCallback implements Runnable {
    // Can run a second time if the action completes after the timeout.
    boolean ran = false;
    public void onCommitted() {
        synchronized (mWm.mGlobalLock) {
            if (ran) {
                return;
            }
            mWm.mH.removeCallbacks(this);
            ran = true;
            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
            for (WindowContainer wc : wcAwaitingCommit) {
                wc.onSyncTransactionCommitted(t);
            }
            t.apply();
            wcAwaitingCommit.clear();
        }
    }

    // Called in timeout
    @Override
    public void run() {
        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);
        onCommitted();
    }
};
CommitCallback callback = new CommitCallback();
merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::onCommitted);
mWm.mH.postDelayed(callback, BLAST_TIMEOUT_DURATION);

public Transaction addTransactionCommittedListener(
        @NonNull @CallbackExecutor Executor executor,
        @NonNull TransactionCommittedListener listener) {
    TransactionCommittedListener listenerInner =
            () -> executor.execute(listener::onTransactionCommitted);
    nativeAddTransactionCommittedListener(mNativeObject, listenerInner);
    return this;
}

public interface TransactionCommittedListener {
    void onTransactionCommitted();
}

这里具体的原因不是很清楚,主要的操作是:申明一个内部类CommitCallback,然后通过merged注册一个CommittedListener,这个TransactionCommittedListener函数的功能,主要是在merged这个对象执行Committed的时候触发,然后新起一个线程,执行listener对象的onTransactionCommitted方法。 那listener对象的onTransactionCommitted方法体是什么呢? 根据调用处发现这个listener对象是用lambda表达式写的:callback::onCommitted; 而TransactionCommittedListener类也是一个接口,所以定义的时候,按照传统的方式,这里应该是写成下面的方式:

merged.addTransactionCommittedListener((r) -> {
    r.run();
}, new SurfaceControl.TransactionCommittedListener() {
    @Override
    public void onTransactionCommitted() {
        callback.onCommitted();
    }
});

继而在上述函数的基础上进一步简化:

merged.addTransactionCommittedListener((r) -> {
    r.run();
}, () -> {
    callback.onCommitted();
});

最后就可简化成merged.addTransactionCommittedListener(® -> { r.run(); }, callback::onCommitted); 这种形式,不过有一说一,lambda表达式虽然能让代码变得更简洁,但是也确实降低了代码的可读性。
而这里就看一下callback的onCommitted的方法到底是干嘛的,其实根据代码的解读,就是简单的将mRootMembers中的WindowContainer的mSyncTransaction全部放到一个新的Transaction中,然后apply。
而merged是什么会执行commit方法呢?这里就涉及到一些Transaction的知识,一般来说Transaction都是通过binder发送至SystemUI侧,然后经过一些处理后,再由binder发送至SurfaceFlinger侧。而在提交到SurfaceFlinger的时候就会触发commit操作,这时候TransactionCommittedListener的onTransactionCommitted回调就会被触发。
所以这个流程就是在merged被commit的时候,系统侧会同时apply mRootMembers中所有WindowContainer的mSyncTransactions。

d)onTransactionReady:

mListener.onTransactionReady(mSyncId, merged);
在finishNow中,还有一个比较熟悉的方法,就是这个onTransactionReady方法,这个onTransactionReady其实就是WindowOrganizerController中的那个,最终的还是跨进程调用的SyncTransactionQueue.java中的onTransactionReady,这个前面已经讲过了。

public void onTransactionReady(int syncId, SurfaceControl.Transaction t) {
    ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Transaction ready, syncId=%d", syncId);
    final IWindowContainerTransactionCallback callback =
            mTransactionCallbacksByPendingSyncId.get(syncId);

    try {
        callback.onTransactionReady(syncId, t);
    } catch (RemoteException e) {
        // If there's an exception when trying to send the mergedTransaction to the client, we
        // should immediately apply it here so the transactions aren't lost.
        t.apply();
    }

    mTransactionCallbacksByPendingSyncId.remove(syncId);
}

e)移除SyncGroup

mActiveSyncs.remove(mSyncId);
在执行完上面的所有操作后,在最后,会根据mSyncId从mActiveSyncs中移除这个对应SyncGroup。而到了这里,所有对WindowContainers的修改都合并到了merged中,并且也传输到了systemUI侧(通过onTransactionReady),最后也会在SyncTransactionQueue里的SyncCallback中的onTransactionReady中apply这些修改。

6) 总结:

有一说一BLASTSyncEngine这个类功能有点多,想通过看一遍博客就了解是很难的,前面讲了这么多,如果真的想深入的理解,还得自己跟着代码一个一个的看,并将相关的思路都记录下来。

首先对我们本篇博客进行一个总结,我们首先讲解了SyncGroup类,然后顺着上一篇博客WindowOrganizerController的流程,讲解其中和BLASTSyncEngine相关的内容。
1、 在applySyncTransaction中通过prepareSyncWithOrganizer创建一个SyncGroup;
2、 检查当前mActiveSyncs中是否有SyncGroup对象,其实如果为空,那就执行接下来的操作,不为空就是将接下来的操作暂存起来,等待时机执行;
3、 在applyTransaction时,通过addToSyncSet方法将WindowContainerTransaction中相关的WindowContainer放入mRootMembers中,并将WindowContainer的子窗口WindowState的mSyncState标志位置为SYNC_STATE_WAITING_FOR_DRAW,并应用WindowContainerTransaction中包含的所有修改;
4、 执行完步骤3之后,将SyncGroup的mReady状态置为true;
5、 在之后的界面刷新时,通过onSurfacePlacement方法,不断检查SyncGroup中的WindowContainer是否全部同步完成(主要是通过isSyncFinished,只有应用侧完成finishDrawing才会将WindowState的状态设置为SYNC_STATE_READY);
6、 一旦完成同步,finishSync将SyncGroup的mRootMembers中所有的参与同步WindowContainer的相关mSyncTransaction和SyncGroup的mOrphanTransaction合并到一个Transaction对象merged中,最后通过onTransactionReady发送至systemUI侧,并apply,最后将mSyncState置为SYNC_STATE_NONE。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2091145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图片拼图怎么做?4个方法打造具有高级感的拼图作品

被阿勒泰的日落治愈了&#xff0c;旅行中的每一刻都值得珍藏。 这次的阿勒泰之行&#xff0c;我不仅带回了一堆美好的回忆&#xff0c;还有手机里满满的精彩瞬间。从壮丽的山川到静谧的湖泊&#xff0c;从晨曦初现到夜幕降临&#xff0c;每一帧都是大自然的馈赠。但是&#xf…

C++ 设计模式——职责链模式

目录 C 设计模式——职责链模式1. 主要组成成分2. 逐步构建职责链模式步骤1&#xff1a;定义处理者接口步骤2&#xff1a;定义抽象处理者步骤3: 创建具体处理者步骤4: 配置职责链 3. 备忘录模式 UML 图UML 图解析 4. 单纯与非单纯的职责链模式4.1 敏感词过滤器父类4.2 具体过滤…

C++:类的定义、实例化

目录 一、类的定义 1.1 类的定义格式 1.2 访问限定符 1.3 类域 二、实例化 2.1 实例化概念 2.2 对象大小 一、类的定义 1.1 类的定义格式 • class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省…

设备上的实时自定义手势识别

这篇论文的标题是《On-device Real-time Custom Hand Gesture Recognition》&#xff0c;主要研究了如何在移动设备上实时识别自定义手势。以下是论文的主要内容概述&#xff1a; 摘要&#xff1a; 论文指出现有的手势识别系统大多限于预定义的手势集&#xff0c;但用户和开发…

鸿蒙(HarmonyOS)常见的三种弹窗方式

最近有一个想法&#xff0c;做一个针对鸿蒙官方API的工具箱项目&#xff0c;介绍常用的控件&#xff0c;以及在项目中如何使用&#xff0c;今天介绍Harmony中如何实现弹窗功能。 警告弹窗 警告弹窗是一个App中非常常用的弹窗&#xff0c;例如&#xff1a; 删除一条记录&…

帕金森患者在运动时有哪些类型的运动推荐?

帕金森病患者在进行运动时&#xff0c;可以考虑以下几种类型的运动&#xff1a; 有氧运动&#xff1a;如散步、慢跑、爬山、骑自行车、健美操、广场舞等&#xff0c;这些运动有助于改善心肺功能&#xff0c;同时也能提升肌肉力量和灵活性。 柔性运动&#xff1a;包括瑜伽、太极…

<Rust>egui学习之小部件(七):如何在窗口中添加颜色选择器colorpicker部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第七篇博…

笔记整理—内核!启动!

常规启动时&#xff0c;各镜像都在SD卡中的各种分区中&#xff0c;内核放在kernel分区&#xff0c;从SD卡到DDR的连接处&#xff08;内核不需要进行重定位&#xff0c;直接从链接处启动&#xff09;。uboot从sd卡分区读使用movi命令。 使用fastboot指令可以查看分区情况&#x…

【赵渝强老师】MongoDB的MMAPv1存储引擎

在MongoDB 3.2版本以前&#xff0c;MongoDB使用MMAPv1作为默认的存储引擎。在MMAPv1的存储引擎中&#xff0c;包含以下的组成部分&#xff1a; Database 每个Database由一个.ns名称空间文件及若干个数据文件组成。数据文件从0开始编号&#xff0c;依次为.0、.1、.2等。数据文件…

小心GitHub账号被盗

最近有小伙伴反馈在 GitHub 上解压了不明文件之后&#xff0c;GitHub 账号被盗了。 事情是这样的&#xff1a; 有小伙伴在 GitHub 某仓库的 issue 中正常和人讨论问题&#xff0c;有个人光速回复了一条消息&#xff0c;给了一个链接&#xff0c;让下载一个名为 fix.rar 的文件…

C++系列-STL容器之list

STL容器之list list容器的基本结构list容器的特点list容器的优点list容器的缺点 list容器的构造函数list容器的常用接口list大小及空否list访问list迭代器相关list增删查改push and popinsert其它 list赋值操作 list容器的基本结构 list容器的内部结构是双向循环链表&#xff…

Java笔试面试题AI答之面向对象(8)

文章目录 43. 解释Java接口隔离原则和单一原则如何理解 &#xff1f;单一职责原则&#xff08;Single Responsibility Principle, SRP&#xff09;接口隔离原则&#xff08;Interface Segregation Principle, ISP&#xff09; 44. Java 有没有 goto? 如果有&#xff0c;一般用…

004.Python爬虫系列_web请求全过程剖析(重点)

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

2024年8月31日历史上的今天大事件早读

1449年8月31日 明朝“土木之变” 1907年8月31日 英、法、俄三国协约形成 1914年8月31日 “骆派”京韵大鼓的创建者骆玉笙诞生 1916年8月31日 蔡锷东渡日本养病 1935年8月31日 美国通过《中立法案》 1937年8月31日 日本华北方面军成立 1941年8月31日 晋察冀边区完成民主大…

2024最新最全:国内外人工智能AI工具网站大全!

国内外人工智能AI工具网站大全&#xff08;一键收藏&#xff0c;应有尽有&#xff09; 摘要一、AI写作工具二、AI图像工具 2.1、常用AI图像工具2.2、AI图片插画生成2.3、AI图片背景移除2.4、AI图片无损调整2.5、AI图片优化修复2.6、AI图片物体抹除 三、AI音频工具四、AI视频工…

南京观海微电子----CMOS门电路(OD门、传输门、双向模拟开关、三态门)

【 1. MOS管】 MOS管&#xff1a;绝缘栅型场效应管。 【 2. CMOS电路】 当NMOS管和PMOS管成对出现在电路中&#xff0c;且二者在工作中互补&#xff0c;称为CMOS管(Complementary Metal-Oxide-Semiconductor)。 电路结构 拉电流 如下图所示&#xff0c;输入低电平&#xff…

王者荣耀 设置游戏头像 不用微信头像

我们在微信 我 选择 设置 在里面找到 个人信息与权限 如果找不到看看有木有一个叫隐私的选项 点击 进入之后 选择授权管理 找到王者荣耀 然后点击右侧的小箭头进入 点击下面的 解除授权 确认一下 解除授权 然后重新打开王者 选择微信登录 我们这里 选择新建昵称头像 选…

线性代数之线性方程组

目录 线性方程组 1. 解的个数 齐次线性方程组&#xff1a; 非齐次线性方程组&#xff1a; 2. 齐次线性方程组的解 3. 非齐次线性方程组的解 4. 使用 Python 和 NumPy 求解线性方程组 示例代码 齐次线性方程组 非齐次线性方程组 示例结果 齐次线性方程组 非齐次线性…

Unity获取SceneView尺寸

获取SceneView尺寸 var sceneView SceneView.lastActiveSceneView; var size new Vector2(sceneView.position.width,sceneView.position.height);

Elasticsearch学习(1)-mac系统安装elasticsearch基础

Elasticsearch基础 1. 传统数据库与elasticsarch2. 下载Elasticsearch7. 经过上述所有操作&#xff0c;就可以得到一个具体的连接可视化页面3. 安装kibana4. 其余知识点 elasticsearch是什么&#xff1f; Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能…