赞
踩
/** * 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上了,那些跳过的内容也就是和同步机制相关的,这次就来跟踪下同步的流程。
@Override public 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); } }
WindowOrganizerController#applyTransaction的根据之前的分析,已经知道了,就是为WindowContainer应用WindowContainerTransaction中的设置。
在applyTransaction之前,有这样一个操作:
@Override public 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不为空的情况。
@VisibleForTesting
int 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。
在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的内容:
@VisibleForTesting
void 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的内容。
if (!mRootMembers.add(wc)) {
return;
}
mRootMembers是SyncGroup的成员变量:
final ArraySet<WindowContainer> mRootMembers = new ArraySet<>();
这里使用ArraySet保证WindowContainer只会被添加一次,毕竟我们上面看到,入口有三处。
后续SyncGroup通过遍历mRootMembers队列来判断所有参与同步的WindowContainer是否完成同步。
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要如何被处理。
/** * 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 sync return 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也重写了这个方法:
@Override boolean 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状态。
@Override
public int applySyncTransaction(WindowContainerTransaction t,
IWindowContainerTransactionCallback callback) {
......
try {
synchronized (mGlobalLock) {
......
applyTransaction(t, syncId, null /*transition*/);
......
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
这一步的具体内容在分析WCT的应用的时候有比较系统的介绍过了。
@Override public 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上了。
@VisibleForTesting
void setSyncReady(int id) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id);
mService.mWindowManager.mSyncEngine.setReady(id);
}
@VisibleForTesting
void 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都已经应用完成,然后请求一次界面刷新。
每次刷新界面的时候,RootWindowContainer#performSurfacePlacementNoTrace会调用BLASTSyncEngine#onSurfacePlacement。
void onSurfacePlacement() {
// backwards since each state can remove itself if finished
for (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做了以下几件事:
SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();
if (mOrphanTransaction != null) {
merged.merge(mOrphanTransaction);
}
将mOrphanTransaction合并到此Transaction中,mOrphanTransactionon从调用的地方来看,当SyncGroup中的WindowContainer的父WindowContainer发生变化时,会将该WindowContainer的mSyncTransaction合入到mOrphanTransactionon,避免该WindowContainer的mSyncTransaction保存的修改在parent更改的时候丢失。
/** * 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置空。
mListener.onTransactionReady(mSyncId, merged);
这里的TransactionReadyListener就是WindowOrganizerController,是在WindowOrganizerController调用startSyncSet创建SyncGroup的时候传入的,所以这里调用的是WindowOrganizerController#onTransactionReady:
@Override 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); }
所有参与到此次同步的WindowContainer都完成同步后,会由WindowOrganizerController根据syncId从mTransactionCallbacksByPendingSyncId中找到对应的回调对象,即SyncCallback,然后调用SyncCallback#onTransactionReady,并且传入存放了最终同步结果的Transaction。
mActiveSyncs.remove(mSyncId);
直到这里,本次同步操作在WM端的部分才算完成了,所有configuration更改引起的Transaction变化全部都合并到了一个Transaction中,并且传给了SystemUI,后续需要SystemUI的SyncTransactionQueue那边进行apply,之前对SyncTransactionQueue的分析中也有讲过。
上面跳过了一个重要环节,在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)、在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
有三种状态: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 sync return 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:
@Override boolean 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; }
要看一个WindowContainer(一般是Task)是否同步完成,其实是看它包含的ActivityRecord对应的窗口是否绘制完成:
ViewRootImpl#reportedDrawFinished
-> Session#finishDrawing
(跨进程)
-> WMS#finishDrawingWindow
-> WindowState#finishDrawing
-> WindowContainer#onSyncFinishedDrawing
这个依赖于APP端界面的绘制情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。