4【Android 12】【WCT的同步】BLASTSyncEngine

编程入门 行业动态 更新时间:2024-10-13 04:21:10

4【<a href=https://www.elefans.com/category/jswz/34/1771384.html style=Android 12】【WCT的同步】BLASTSyncEngine"/>

4【Android 12】【WCT的同步】BLASTSyncEngine

一、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 wi`ll 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.*/
class BLASTSyncEngine

渣翻:

用于收集将merge transactions的WindowContainers 的工具类。

例如用于同步调整一个WindowContainer下的所有子WindowContainer的尺寸 :

1)、打开一个新的同步集,并传递将被调用的listener:

int id startSyncSet(TransactionReadyListener) 

返回的ID最终会与一组准备好的WindowContainers一起传递给TransactionReadyListener,这意味那些WindowContainers已经调用了onTransactionReady。您还可以使用它来指代以后步骤中的操作。

2)、 要求每个子容器参与:

 addToSyncSet(int id, WindowContainer wc)

如果子容器认为它会受到Configuration更改的影响(也就是在其子层次结构中有一个可见的窗口,那么我们将增加一个预期的计数器回调)。此时,容器层次结构会将 pendingTransaction 和子层次结构更新重定向到同步引擎。

3)、将configurationchanges应用到WindowContainers。

4)、告诉BLASTSyncEngine同步集已准备好:

setReady(int id)

5)、如果层次结构中的任何地方都没有子窗口等待,则立即调用transactionReady,否则所有窗口都将被推动去重绘和去给WindowState#finishDrawing传送缓冲区。一旦所有这些绘制完成,所有transaction将被合并并且交付给 TransactionReadyListener。

这主要通过设置状态然后观察/等待注册的子树进入“完成”状态(通过接收绘制的内容或消失)来工作。这会在surface-placement期间检查子树。

根据WindowOrganizerController的情况看下1-5条的执行情况。

二、同步流程分析

在分析WindowContainerTransaction的应用时,关于WindowContainerTransaction#applySyncTransaction方法,当时是跳过了很多内容直接去分析WindowContainerTransaction是如何应用到WindowContainer上了,那些跳过的内容也就是和同步机制相关的,这次就来跟踪下同步的流程。

    @Overridepublic int applySyncTransaction(WindowContainerTransaction t,IWindowContainerTransactionCallback callback) {enforceTaskPermission("applySyncTransaction()");if (t == null) {throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");}final long ident = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {/*** 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.*/int syncId = -1;if (callback != null) {syncId = startSyncWithOrganizer(callback);}applyTransaction(t, syncId, null /*transition*/);if (syncId >= 0) {setSyncReady(syncId);}return syncId;}} finally {Binder.restoreCallingIdentity(ident);}}

1 调用BLASTSyncEngine#startSyncSet创建SyncGroup

WindowOrganizerController#applyTransaction的根据之前的分析,已经知道了,就是为WindowContainer应用WindowContainerTransaction中的设置。

在applyTransaction之前,有这样一个操作:

    @Overridepublic int applySyncTransaction(WindowContainerTransaction t,IWindowContainerTransactionCallback callback) {......try {synchronized (mGlobalLock) {/*** 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.*/int syncId = -1;if (callback != null) {syncId = startSyncWithOrganizer(callback);}applyTransaction(t, syncId, null /*transition*/);......}} finally {Binder.restoreCallingIdentity(ident);}}

这里,如果是通过WindowOrganizer#applyTransaction,那么这里传入callback的就是null。

如果是WindowOrganizer#applySyncTransaction,就会传入一个callback,之前分析WCT的发送的时候,知道这里的callback是一个SyncCallback类型的回调。接下来看下callback不为空的情况。

    @VisibleForTestingint startSyncWithOrganizer(IWindowContainerTransactionCallback callback) {int id = mService.mWindowManager.mSyncEngine.startSyncSet(this);mTransactionCallbacksByPendingSyncId.put(id, callback);return id;}

这里调用了BLASTSyncEngine#startSyncSet,BLASTSyncEngine#startSyncSet返回了一个唯一的ID,接着把这个ID和callback存储到HashMp类型的mTransactionCallbacksByPendingSyncId中去,那么可以知道ID和callback应该是一一对应的关系。后续当WM端的transaction完成后,在WindowOrganizerController#onTransactionReady中会根据ID再取回callback。

接着看下BLASTSyncEngine#startSyncSet都干了什么。

    int startSyncSet(TransactionReadyListener listener) {final int id = mNextSyncId++;final SyncGroup s = new SyncGroup(listener, id);mActiveSyncs.put(id, s);ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener);return id;}

1)、将mNextSyncId赋值给id,然后自增1。

private int mNextSyncId = 0;

这里看到,mNextSyncId是BLASTSyncEngine的成员变量,由于BLASTSyncEngine只在WMS的构造器中创建了一次,唯一实例由WMS持有,那么可以知道mNextSyncId也是全局唯一一份,每次BLASTSyncEngine#startSyncSet都会自增1,保证了ID的唯一性。

2)、以这个唯一ID和传入的WindowOrganizerController对象为基础,创建了一个SyncGroup对象。

        private SyncGroup(TransactionReadyListener listener, int id) {mSyncId = id;mListener = listener;}

SyncGroup是BLASTSyncEngine的内部类,创建的唯一位置便是在BLASTSyncEngine#startSyncSet。

3)、将ID和创建的SyncGroup对象加入到mActiveSyncs队列中。

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

mActiveSyncs是BLASTSyncEngine的成员变量。

4)、最后,将这个具有唯一性的ID返回。

那么这个ID的值是唯一的,对应了一个SyncGroup对象,也对应了一个callback。

2 调用BLASTSyncEngine#addToSyncSet将所有参与同步的WindowContainer添加到SyncGroup中

在WindowOrganizerController#startSyncWithOrganizer之后,便是调用WindowOrganizerController#applyTransaction来为WindowContainer应用WindowContainerTransaction设置的修改(即Configuration更改,层级调整之类的):

    /*** @param syncId If non-null, this will be a sync-transaction.* @param transition A transition to collect changes into.*/private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,@Nullable Transition transition) {......try {......Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =t.getChanges().entrySet().iterator();while (entries.hasNext()) {......// Make sure we add to the syncSet before performing// operations so we don't end up splitting effects between the WM// pending transaction and the BLASTSync transaction.if (syncId >= 0) {addToSyncSet(syncId, wc);}if (transition != null) transition.collect(wc);int containerEffect = applyWindowContainerChange(wc, entry.getValue());......}......} finally {mService.continueWindowLayout();}}

然而在调用WindowOrganizerController#applyWindowContainerChange方法应用之前修改之前,还有一个重要的步骤:

                // Make sure we add to the syncSet before performing// operations so we don't end up splitting effects between the WM// pending transaction and the BLASTSync transaction.if (syncId >= 0) {addToSyncSet(syncId, wc);}

这个方法目前看到有三处需要执行,一是在WindowOrganizerController#applyWindowContainerChange之前,二是在WindowOrganizerController#reparentChildrenTasksHierarchyOp之前,三是在WindowOrganizerController#sanitizeAndApplyHierarchyOp之前。

接下来分析WindowOrganzierController#addToSyncSet的内容:

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

WindowOrganizerController#addToSyncSet调用了BLASTSyncEngine#addToSyncSet。

    void addToSyncSet(int id, WindowContainer wc) {mActiveSyncs.get(id).addToSync(wc);}

在第一小节中我们创建了SyncGroup对象,并且和ID是一一对应,保存在了BLASTSyncEngine的成员变量mActiveSyncs中,所以这里就可以通过ID从mActiveSyncs中拿到对应的SyncGroup。

那么这里调用的就是SyncGroup#addToSyncSet:

        private void addToSync(WindowContainer wc) {if (!mRootMembers.add(wc)) {return;}ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc);wc.setSyncGroup(this);wc.prepareSync();mWm.mWindowPlacerLocked.requestTraversal();}

接下来的内容就是,之前BLASTSyncEngine注释中所提到的,将所有参与同步的WindowContainer都加入到同步集中,参与同步的WindowContainer,也就是WindowContainerTransaction中保存的那些客户端指定的WindowContainer。

逐步分析SyncGroup#addToSync的内容。

2.1 将传入的WindowContainer加入到SyncGroup的mRootMembers队列

            if (!mRootMembers.add(wc)) {return;}

mRootMembers是SyncGroup的成员变量:

final ArraySet<WindowContainer> mRootMembers = new ArraySet<>();

这里使用ArraySet保证WindowContainer只会被添加一次,毕竟我们上面看到,入口有三处。

后续SyncGroup通过遍历mRootMembers队列来判断所有参与同步的WindowContainer是否完成同步。

2.2 WindowContainer#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) {throw new IllegalStateException("Can't sync on 2 engines simultaneously");}}mSyncGroup = group;}

很简单,将WindowContainer.mSyncGroup指向当前SyncGroup。

WindowContainer的成员变量mSyncGroup的定义是:

    /*** If non-null, references the sync-group directly waiting on this container. Otherwise, this* container is only being waited-on by its parents (if in a sync-group). This has implications* on how this container is handled during parent changes.*/BLASTSyncEngine.SyncGroup mSyncGroup = null;

如果非空,说明其SyncGroup正在等待此WindowContainer。否则,这个WindowCOntainer只会被它的父WindowContainer等待(如果在SyncGroup中)。这会影响在父WindowContainer更改期间这个WindowContainer要如何被处理。

2.3 WindowContainer#prepareSync

    /*** Prepares this container for participation in a sync-group. This includes preparing all its* children.** @return {@code true} if something changed (eg. this wasn't already in the sync group).*/boolean prepareSync() {if (mSyncState != SYNC_STATE_NONE) {// Already part of syncreturn false;}for (int i = getChildCount() - 1; i >= 0; --i) {final WindowContainer child = getChildAt(i);child.prepareSync();}mSyncState = SYNC_STATE_READY;return true;}

这里新增了一个WindowContainer.mSyncState的概念:

    /** This isn't participating in a sync. */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 {}

SYNC_STATE_NONE表示当前WindowContainer没有参与到一次同步操作中。

SYNC_STATE_WAITING_FOR_DRAW表示当前WindowContainer正在等待自身绘制完成。

SYNC_STATE_READY表示当前WindowContainer已经绘制完成,但是其子WindowContainer中可能还有没有完成同步的。

可以看到,在同步之前,需要将mSyncState置为SYNC_STATE_READY。如果mSyncState不是SYNC_STATE_NONE,表示当前WindowContainer仍然处于同步过程中。并且这里还调用了子容器的prepareSync方法,这一步将使得所有子容器的mSyncState都被置为SYNC_STATE_READY。

这里可能会比较疑惑,为什么直接就把WindowContainer的mSyncState的状态设置为SYNC_STATE_READY了,同步不是才刚开始?我们看到,除了WindowContainer有prepareSync方法之外,WindowState也重写了这个方法:

    @Overrideboolean prepareSync() {if (!super.prepareSync()) {return false;}// In the WindowContainer implementation we immediately mark ready// since a generic WindowContainer only needs to wait for its// children to finish and is immediately ready from its own// perspective but at the WindowState level we need to wait for ourselves// to draw even if the children draw first our don't need to sync, so we start// in WAITING state rather than READY.mSyncState = SYNC_STATE_WAITING_FOR_DRAW;requestRedrawForSync();mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,BLAST_TIMEOUT_DURATION);return true;}

这里的注释也可以解答我们刚刚的疑问:

在WindowContainer的实现中,我们直接将mSyncState置为SYNC_STATE_READY,因为对于一个通用的WindowContainer而言,它只需要等待它的子WindowContainer完成同步,如果它有子WindowContainer完成同步,那么对它自己而言它也就完成同步处于就绪状态了。

但是在WindowState这一层,每一个WindowState都需要等待自己绘制完成,即使子窗口先绘制完成。所以对于WindowState,是以SYNC_STATE_WAITING_FOR_DRAW状态开始而不是SYNC_STATE_READY状态。

3 将WindowContainerTransaction应用到WindowContainer

    @Overridepublic int applySyncTransaction(WindowContainerTransaction t,IWindowContainerTransactionCallback callback) {......try {synchronized (mGlobalLock) {......applyTransaction(t, syncId, null /*transition*/);......}} finally {Binder.restoreCallingIdentity(ident);}}

这一步的具体内容在分析WCT的应用的时候有比较系统的介绍过了。

4 BLASTSyncTransaction#setReady标记SyncGroup已经准备就绪

    @Overridepublic int applySyncTransaction(WindowContainerTransaction t,IWindowContainerTransactionCallback callback) {......try {synchronized (mGlobalLock) {......applyTransaction(t, syncId, null /*transition*/);if (syncId >= 0) {setSyncReady(syncId);}return syncId;}} finally {Binder.restoreCallingIdentity(ident);}}

这一步发生在WindowOrganizerController#applyTransaction之后,即WindowContainerTransaction中的设置都已经应用到WindowContainer上了。

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

WindowOrganizerController#setSyncReady调用BLASTSyncEngine#setReady。

    void setReady(int id, boolean ready) {mActiveSyncs.get(id).setReady(ready);}void setReady(int id) {setReady(id, true);}

BLASTSyncEngine#setReady调用SyncGroup#setReady。

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

将SyncGroup的成员变量mReady置为true,表示所有WindowContainerTransaction都已经应用完成,然后请求一次界面刷新。

5 等待窗口绘制完成后调用transactionReady

每次刷新界面的时候,RootWindowContainer#performSurfacePlacementNoTrace会调用BLASTSyncEngine#onSurfacePlacement。

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

这里又调用了SyncGroup#onSurfacePlacement。

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

这里会对加入到mRootMembers的WindowContainer进行遍历,mRootMembers里的数据是之前调用addToSync的时候填充的。WindowContainer#isSyncFinished返回true表示当前WindowContainer同步完成。只有当mRootMembers中所有的WindowContainer都同步完成,本次同步才算结束,才可以调用SyncGroup#finishNow。

由于这个方法在每次界面刷新的时候都会调用,所以这里的工作就是不断检查当前SyncGroup中的所有WindowContainer是否同步完成,一旦同步完成,就去调用SyncGroup#finishNow。

这里先跳过WindowContainer#isSyncFinished,看下SyncGroup#finishNow:

        private void finishNow() {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 */);}mListener.onTransactionReady(mSyncId, merged);mActiveSyncs.remove(mSyncId);}

SyncGroup#finishNow做了以下几件事:

5.1 取得一个存放最终结果的Transaction

            SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();if (mOrphanTransaction != null) {merged.merge(mOrphanTransaction);}

将mOrphanTransaction合并到此Transaction中,mOrphanTransactionon从调用的地方来看,当SyncGroup中的WindowContainer的父WindowContainer发生变化时,会将该WindowContainer的mSyncTransaction合入到mOrphanTransactionon,避免该WindowContainer的mSyncTransaction保存的修改在parent更改的时候丢失。

5.2 调用WindowContainer#finishSync

    /*** Recursively finishes/cleans-up sync state of this subtree and collects all the sync* transactions into `outMergedTransaction`.* @param outMergedTransaction A transaction to merge all the recorded sync operations into.* @param cancel If true, this is being finished because it is leaving the sync group rather*               than due to the sync group completing.*/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);}mSyncState = SYNC_STATE_NONE;if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this);mSyncGroup = null;}

这里传入的5.1中创建的存放最终结果的outMergedTransaction。

1)、将当前WindowContainer自身的mSyncTransaction合入到outMergedTransaction。

2)、WindowContainer#finishSync递归调用所有子WindowContainer#finishSync,最终将WindowContainerTransaction带来的所有Transaction变化全部都合并到outMergedTransaction。

3)、将mSyncState重置为同步前的状态SYNC_STATE_NONE,mSyncGroup置空。

5.3 调用TransactionReadyListener#onTransactionReady

mListener.onTransactionReady(mSyncId, merged);

这里的TransactionReadyListener就是WindowOrganizerController,是在WindowOrganizerController调用startSyncSet创建SyncGroup的时候传入的,所以这里调用的是WindowOrganizerController#onTransactionReady:

    @Overridepublic 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);}

所有参与到此次同步的WindowContainer都完成同步后,会由WindowOrganizerController根据syncId从mTransactionCallbacksByPendingSyncId中找到对应的回调对象,即SyncCallback,然后调用SyncCallback#onTransactionReady,并且传入存放了最终同步结果的Transaction。

5.4 将ID从mActiveSyncs中移除。

mActiveSyncs.remove(mSyncId);

直到这里,本次同步操作在WM端的部分才算完成了,所有configuration更改引起的Transaction变化全部都合并到了一个Transaction中,并且传给了SystemUI,后续需要SystemUI的SyncTransactionQueue那边进行apply,之前对SyncTransactionQueue的分析中也有讲过。

5.5 WindowContainer何时被视为同步完成

上面跳过了一个重要环节,在BLASTSyncEngine#onSurfacePlacement中,会对参与本次同步的所有WindowContainer调用WindowContainer#isSyncFinished判断其是否同步完成。只有SyncGroup中的所有WindowContainer都同步完成,才会调用SyncGroup#finishNow。

当时跳过了WindowContainer#isSyncFinished的分析,这一节来详细分析一下。

    /*** Checks if the subtree rooted at this container is finished syncing (everything is ready or* not visible). NOTE, this is not const: it will cancel/prepare itself depending on its state* in the hierarchy.** @return {@code true} if this subtree is finished waiting for sync participants.*/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;}

判断一个WindowContainer是否完成同步,不仅当前WindowContainer的mSyncState得是SYNC_STATE_READY,它的子WindowContainer也要有完成同步的。

根据之前对WindowContaIner#prepareSync的分析,非WindowState类型的容器,在同步开始的时候都已经在WindowContainer#prepareSync中设置其mSyncState为SYNC_STATE_READY了,所以这里只需要看WindowState类型的子容器有没有就绪就好了,其它类型的WIndowContainer都不需要关注。

另外WindowState类型的容器一开始在WindowState#prepareSync中将mSyncState设置为SYNC_STATE_WAITING_FOR_DRAW,那么对于WindowState来说,isSyncFinished方法能够返回true,首要条件就是,mSyncState必须在后续被设置为SYNC_STATE_READY,这一步只能在WindowContainer#onSyncFinishedDrawing:

    /*** Call this when this container finishes drawing content.** @return {@code true} if consumed (this container is part of a sync group).*/boolean onSyncFinishedDrawing() {if (mSyncState == SYNC_STATE_NONE) return false;mSyncState = SYNC_STATE_READY;mWmService.mWindowPlacerLocked.requestTraversal();ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "onSyncFinishedDrawing %s", this);return true;}

WindowContainer#onSyncFinishedDrawing唯一调用的地方又在WindowState#finishDrawing:

    boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {if (mOrientationChangeRedrawRequestTime > 0) {final long duration =SystemClock.elapsedRealtime() - mOrientationChangeRedrawRequestTime;Slog.i(TAG, "finishDrawing of orientation change: " + this + " " + duration + "ms");mOrientationChangeRedrawRequestTime = 0;} else if (mActivityRecord != null && mActivityRecord.mRelaunchStartTime != 0&& mActivityRecord.findMainWindow() == this) {final long duration =SystemClock.elapsedRealtime() - mActivityRecord.mRelaunchStartTime;Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms");mActivityRecord.mRelaunchStartTime = 0;}executeDrawHandlers(postDrawTransaction);if (!onSyncFinishedDrawing()) {return mWinAnimator.finishDrawingLocked(postDrawTransaction);}if (postDrawTransaction != null) {mSyncTransaction.merge(postDrawTransaction);}mWinAnimator.finishDrawingLocked(null);// We always want to force a traversal after a finish draw for blast sync.return true;}

这个方法唯一的调用栈是从APP端调过来的:

ViewRootImpl#reportedDrawFinished

-> Session#finishDrawing(跨进程)-> WMS#finishDrawingWindow-> WindowState#finishDrawing-> WindowContainer#onSyncFinishedDrawing

那么也就是说,只有APP端完成了界面绘制并且通知到了WM端,当前WindowState才能设置其mSyncState为SYNC_STATE_READY。

然而这个还是条件之一,判断一个WindowContainer是否完成同步,还有其他限制:

        // 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;

1)、如果我们能先找到一个已经完成绘制的子窗口,并且该子窗口后续要显示,且能够覆盖的了它下面的所有子窗口,那么可以认为当前WindowContainer绘制完成。

2)、如果我们找不到一个满足条件1的子窗口,但是所有窗口都已经绘制完成,那么也可以认为当前WindowContainer绘制完成;

3)、如果我们在找到一个满足条件1的子窗口之前,先找到一个没有完成绘制的子窗口,那么就认为当前WindowContainer没有绘制完成。

三、总结

1 BLASTSyncEngine机制流程

1)、在WindowOrganizerController#applyTransaction之前,调用BLASTSyncEngine#startSyncSet,创建一个拥有唯一ID的SyncGroup对象:

WindowOrganizerController#startSyncWithOrganizer

-> BLASTSyncEngine#startSyncSet

2)、在WindowContainerTransaction中的设置应用到各个WindowContainer之前,调用BLASTSyncEngine#addToSyncSet将这些要应用WindowContainerTransaction的WindowContainer加入到SyncGroup中,并且调用WindowContainer#prepareSync为这些WindowContainer设置初始状态:

WindowOrganizerController#addToSyncSet

-> BLASTSyncEngine#addToSyncSet -> SyncGroup#addToSync -> WindowContainer#prepareSync

3)、所有参与同步的WindowContainer应用WindowContainerTransaction。

4)、所有参与同步的WindowContainer应用WindowContainerTransaction之后,通知BLASTSyncEngineSyncGroup已经准备就绪,可以开始请求绘制。

WindowOrganizerController#setSyncReady

-> BLASTSyncEngine#setReady -> BLASTSyncEngine#setReady -> SyncGroup#setReady

随后在每次界面刷新时,都会调用BLASTSyncEngine#onSurfacePlacement,不断去检查本次SyncGroup中的所有WindowContainer是否已经全部完成同步:

RootWindowContainer#performSurfacePlacementNoTrace

-> BLASTSyncEngine#onSurfacePlacement -> SyncGroup#onSurfacePlacement

5)、一旦所有的容器都已经同步完成,那么调用WindowContainer#finishSync将所有参与同步WindowContainer的有关于Transaction改动,即WindowContainer的成员变量mSyncTransaction和SyncGroup的成员变量mOrphanTransaction,合入到一个Transaction中,再将该Transaction传给WindowOrganizerController,最终发送给客户端(这里就是SyncCallback):

SyncGroup#onSurfacePlacement

-> SyncGroup#finishNow -> WindowOrganizerController#onTransactionReady (跨进程)-> SyncCallback#onTransactionReady

2 WindowContainer同步状态mSyncState

有三种状态:SYNC_STATE_NONE、SYNC_STATE_WAITING_FOR_DRAW和SYNC_STATE_READY,看下都是在什么时候设置的。

1)、同步开始,所有非WindowState类型的WindowContainer的mSyncState会被设置为SYNC_STATE_READY:

    /*** Prepares this container for participation in a sync-group. This includes preparing all its* children.** @return {@code true} if something changed (eg. this wasn't already in the sync group).*/boolean prepareSync() {if (mSyncState != SYNC_STATE_NONE) {// Already part of syncreturn false;}for (int i = getChildCount() - 1; i >= 0; --i) {final WindowContainer child = getChildAt(i);child.prepareSync();}mSyncState = SYNC_STATE_READY;return true;}

WindowState类型的容器mSyncState会被设置为SYNC_STATE_WAITING_FOR_DRAW:

    @Overrideboolean prepareSync() {if (!super.prepareSync()) {return false;}// In the WindowContainer implementation we immediately mark ready// since a generic WindowContainer only needs to wait for its// children to finish and is immediately ready from its own// perspective but at the WindowState level we need to wait for ourselves// to draw even if the children draw first our don't need to sync, so we start// in WAITING state rather than READY.mSyncState = SYNC_STATE_WAITING_FOR_DRAW;requestRedrawForSync();mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,BLAST_TIMEOUT_DURATION);return true;}

2)、窗口绘制完成,对于WindowState,mSyncState被设置为SYNC_STATE_READY:

    /*** Call this when this container finishes drawing content.** @return {@code true} if consumed (this container is part of a sync group).*/boolean onSyncFinishedDrawing() {if (mSyncState == SYNC_STATE_NONE) return false;mSyncState = SYNC_STATE_READY;mWmService.mWindowPlacerLocked.requestTraversal();ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "onSyncFinishedDrawing %s", this);return true;}

3)、同步结束,所有WindowContainer的mSyncState被重置为SYNC_STATE_NONE:

    /*** Recursively finishes/cleans-up sync state of this subtree and collects all the sync* transactions into `outMergedTransaction`.* @param outMergedTransaction A transaction to merge all the recorded sync operations into.* @param cancel If true, this is being finished because it is leaving the sync group rather*               than due to the sync group completing.*/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);}mSyncState = SYNC_STATE_NONE;if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this);mSyncGroup = null;}

3 同步完成的本质

要看一个WindowContainer(一般是Task)是否同步完成,其实是看它包含的ActivityRecord对应的窗口是否绘制完成:

ViewRootImpl#reportedDrawFinished

-> Session#finishDrawing(跨进程)-> WMS#finishDrawingWindow-> WindowState#finishDrawing-> WindowContainer#onSyncFinishedDrawing

这个依赖于APP端界面的绘制情况。

更多推荐

4【Android 12】【WCT的同步】BLASTSyncEngine

本文发布于:2024-03-07 23:33:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1719225.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Android   BLASTSyncEngine   WCT

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!