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。