SyncTransactionQueue类:
接上一回的WindowContainerTransaction类讲解,上一篇博客根据TaskView.java中的updateTaskVisibility()方法分析了WindowContainerTransaction的功能及使用。本次继续上一篇的思路,主要拆解syncTransactionQueue类。
private void updateTaskVisibility() {
WindowContainerTransaction wct = new WindowContainerTransaction();//(1)
wct.setHidden(mTaskToken, !mSurfaceCreated /* hidden */);//(2
mSyncQueue.queue(wct);//(3)
if (mListener == null) {//(4)
return;
}
int taskId = mTaskInfo.taskId;//(5)
mSyncQueue.runInSync((t) -> {
mListenerExecutor.execute(() -> {
mListener.onTaskVisibilityChanged(taskId, mSurfaceCreated);
});
});//(6)
}
1、 WindowContainerTransaction的构建:
首先回顾下WindowContainerTransaction的使用,当应用侧需要修改WindowContainer的时候,需要发送WindowContainerTransaction消息给系统侧,然后在系统侧完成对WindowContainer的修改。 构建WindowContainerTransaction对象并设置其参数后,即上述代码执行完(1)和(2),就需要需要发送此消息了,就是需要执行(3)
2、 SyncTransactionQueue类:
在设置完成WindowContainerTransaction对象wct之后,将wct放入SyncTransactionQueue的对象mSyncQueue之中。从这里可以看出,SyncTransactionQueue中至少有一个Queue用来存储WindowContainerTransaction类的对象wct。根据推测,进入SyncTransactionQueue.java中查看该类的定义:
public final class SyncTransactionQueue {
private static final boolean DEBUG = false;
private static final String TAG = "SyncTransactionQueue";
// Just a little longer than the sync-engine timeout of 5s
private static final int REPLY_TIMEOUT = 5300;//(7)
private final TransactionPool mTransactionPool;
private final ShellExecutor mMainExecutor;
// Sync Transactions currently don't support nesting or interleaving properly, so
// queue up transactions to run them serially.
private final ArrayList<SyncCallback> mQueue = new ArrayList<>();//(8)
private SyncCallback mInFlight = null;//(9)
private final ArrayList<TransactionRunnable> mRunnables = new ArrayList<>();//(10)
private final Runnable mOnReplyTimeout = () -> {
synchronized (mQueue) {
if (mInFlight != null && mQueue.contains(mInFlight)) {
Slog.w(TAG, "Sync Transaction timed-out: " + mInFlight.mWCT);
mInFlight.onTransactionReady(mInFlight.mId, new SurfaceControl.Transaction());
}
}
};//(11)
public SyncTransactionQueue(TransactionPool pool, ShellExecutor mainExecutor) {//(12)
mTransactionPool = pool;
mMainExecutor = mainExecutor;
}
……………………………………………………………
}
根据上面的代码发现没有可以存储WindowContainerTransaction类对象的容器,那是为什么呢?于是直接去查看SyncTransactionQueue类中的queue()方法的定义。
public void queue(WindowContainerTransaction wct) {
if (wct.isEmpty()) {
if (DEBUG) Slog.d(TAG, "Skip queue due to transaction change is empty");
return;
}
SyncCallback cb = new SyncCallback(wct);//(13)
synchronized (mQueue) {
if (DEBUG) Slog.d(TAG, "Queueing up " + wct);
mQueue.add(cb);//(14)
if (mQueue.size() == 1) {
cb.send();//(15)
}
}
}
在(13)这里可见,其实是将WindowContainerTransaction类(后续记作WCT类吧)的对象wct包装进了SyncCallback类的对象cb中。然后简单看一下SyncCallback吧:
private class SyncCallback extends WindowContainerTransactionCallback {
int mId = -1;
final WindowContainerTransaction mWCT;
final LegacyTransitions.LegacyTransition mLegacyTransition;
SyncCallback(WindowContainerTransaction wct) {
mWCT = wct;
mLegacyTransition = null;
}
……………………………………………………………
}
这里就能看到SyncCallback类中有一个成员对象mWCT和另一个mLegacyTransition,同时也能通过wct一个单参数构造SyncCallback类对象。
所以在前面代码(3)处,将wct放入mSyncQueue中时,就是先将wct包装成cb,然后再将cb放入SyncTransactionQueue的mQueue中(如代码中(14))。
然后继续向下看,如果mQueue的大小为1,则调用cb.send(),这里send应该就是把包含wct消息的cb从应用侧发送到系统侧。暂时先不看其实现方式,继续看该类中调用mQueue的地方,其中还看到一个三参数的queue方法,其内容和本函数差不多,就是在构建cb的时候多加了几个参数,所以就省略了。 但是还有一个queueIfWaiting()方法,对这个方法进行解析:
public boolean queueIfWaiting(WindowContainerTransaction wct) {
if (wct.isEmpty()) {
if (DEBUG) Slog.d(TAG, "Skip queueIfWaiting due to transaction change is empty");
return false;
}
synchronized (mQueue) {
if (mQueue.isEmpty()) {
if (DEBUG) Slog.d(TAG, "Nothing in queue, so skip queueing up " + wct);
return false;
}
if (DEBUG) Slog.d(TAG, "Queue is non-empty, so queueing up " + wct);
SyncCallback cb = new SyncCallback(wct);
mQueue.add(cb);
if (mQueue.size() == 1) {
cb.send();
}
}
return true;
}
对比而言,queueIfWaitting和queue方法的差异点就在如果mQueue为空,则直接返回,不进行排队,不过这里我暂时还不了解为什么会这么设计,不过也不影响代码的分析。这样可见,无论是queue还是queueIfWaiting方法,最终都会执行send()方法,通过名字也可以猜出来send方法是干啥的。
3、 SyncCallback.send():
看到send()方法的具体实现,这个方法中应该就会有跨进程的传输了。
void send() {
if (mInFlight == this) {
// This was probably queued up and sent during a sync runnable of the last callback.
// Don't queue it again.
return;
}
if (mInFlight != null) {
throw new IllegalStateException("Sync Transactions must be serialized. In Flight: "
+ mInFlight.mId + " - " + mInFlight.mWCT);
}
mInFlight = this;//(16)
if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT);
if (mLegacyTransition != null) {
mId = new WindowOrganizer().startLegacyTransition(mLegacyTransition.getType(),
mLegacyTransition.getAdapter(), this, mWCT);
} else {
mId = new WindowOrganizer().applySyncTransaction(mWCT, this);//(15)
}
if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId);
mMainExecutor.executeDelayed(mOnReplyTimeout, REPLY_TIMEOUT);//(16)
}
根据前面(13)处构建cb对象的时候可见,mLegacyTransition其实就是null,所以send()方法中很容易就判断出会进入(15)这里,于是这就到了通信的重点了,这里会通过WindowOrganizer类的applySyncTransaction方法,处理(3)处传过来的wct。
接下来代码(16)处还会开启一个超时处理线程,超时机制是5.3s,超时处理函数是mOnReplyTimeout。
这个地方的实现其实就是在前面的(11)处,通过一个lambda表达式构建的Runnable类的子类的对象,其run方法就是 -> 后的一大堆。简单的理解就是如果队列mQueue中包含mInFlight,就会调用这个mInFlight的onTransactionReady方法。而mInFlight就是一个SyncCallback类的对象,其赋值是在send方法中的(16)处。 所以这里就先推测,这个onTransactionReady方法其实就是在我们应用侧传输给系统的wct在应用后,应用侧会执行的一个逻辑,超时的时候也会执行一次,但是参数肯定和成功应用wct后执行的时候的参数不同罢了。
4、 SyncCallback.onTransactionReady():
从上面的send()方法中,大致猜到onTransactionReady方法的使用场景,但是这个函数具体是怎么实现的呢?
public void onTransactionReady(int id,
@NonNull SurfaceControl.Transaction t) {
mMainExecutor.execute(() -> {
synchronized (mQueue) {
if (mId != id) { //(17)
Slog.e(TAG, "Got an unexpected onTransactionReady. Expected "
+ mId + " but got " + id);
return;
}
mInFlight = null;
mMainExecutor.removeCallbacks(mOnReplyTimeout);//(18)
if (DEBUG) Slog.d(TAG, "onTransactionReady id=" + mId);
mQueue.remove(this);//(19)
onTransactionReceived(t);//(20)
if (mLegacyTransition != null) {
try {
mLegacyTransition.getSyncCallback().onTransactionReady(mId, t);//(21)
} catch (RemoteException e) {
Slog.e(TAG, "Error sending callback to legacy transition: " + mId, e);
}
} else {
t.apply();
t.close();//(22)
}
if (!mQueue.isEmpty()) {
mQueue.get(0).send();//(23)
}
}
});
}
首先(17)这里会先判断SyncCallback对象的id是否一致,即this.mId和mInFlight.mId是否一致。这个this指的就是(13)处构建的cb,只有在mId相同的时候才能进行下一步。
接下来就是清除mQueue中的SyncCallback对象cb了,首先需要对mInFlight进行置空,然后清除这个超时回调(如果是正常流程,这里应该是wct应用成功后触发的,此时超时机制还没触发,如果不移除,一会时间到了这个回调也没意义了)。
接下来就是(21)这块,主要是mLegacyTransition的区别,前面的流程都是知道的,这里就不会执行(21),直接走到else语句的(22)这里。在系统侧执行修改后,会返回SurfaceControl.Transaction的对象t回来,如果是超时机制触发的,那就是返回的默认构造的t。 这里看到t.apply()和t.close(),大概可以理解,其实也是应用什么修改了,不过暂时还没详细了解这个SurfaceControl.Transaction类,所以暂时不讨论,后面讲到这里的时候再分析吧。 目前根据这个流程的推测就是,应用侧将需要修改的内容wct发送给系统侧后,系统侧在他的维护数据库中更新了信息后,然后通过回调onTransactionReady方法,将修改的指令下达给应用侧,然后应用侧再执行修改。 这就像你想改名字,得先向派出所提出申请,然后派出所在户籍管理系统中,修改你的名字,然后再通知你,你名字修改成功了,你以后可以用新名字了,这时候你才能用新的名字。这个通知你的过程就可以理解为onTransactionReady方法,也就是说直到onTransactionReady方法被调用才能说明我们的修改真正的被应用了。这个流程可以参考下文末的配图。
5、 WindowOrganizer.applySyncTransaction:
在执行send方法的时候,调用了WindowOrganizer的applyTransaction方法,这里先大概讲一下,下一节再详细分析WindowOrganizer类和WindowOrganizerController类的详细内容。applySyncTransaction方法的详细实现如下:
public int applySyncTransaction(@NonNull WindowContainerTransaction t,
@NonNull WindowContainerTransactionCallback callback) {
try {
return getWindowOrganizerController().applySyncTransaction(t, callback.mInterface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
从代码中可见,这里其实还是调用了getWindowOrganizerController()的applyTransaction方法,于是再去看下getWindowOrganizerController()是干什么的:
static IWindowOrganizerController getWindowOrganizerController() {
return IWindowOrganizerControllerSingleton.get();
}
private static final Singleton<IWindowOrganizerController> IWindowOrganizerControllerSingleton =
new Singleton<IWindowOrganizerController>() {
@Override
protected IWindowOrganizerController create() {
try {
return ActivityTaskManager.getService().getWindowOrganizerController();
} catch (RemoteException e) {
return null;
}
}
};
其实就是通过Aidl去获取atms中的WindowOrganizerController的远程代理,就能实现从应用侧访问系统侧的方法了,所以这里就是跨进程传输的具体位置了。通过这里去调用系统侧的applySyncTransaction方法。
而在系统侧,即WindowContainerController中,也有一个onTransactionReady方法,其实现如下,最终是通过callback.onTransactionReady()方法实现的此功能,而其中callback就是一个IWindowContainerTransactionCallback,一看就是一个Aidl接口,其实现在WindowContainerTransactionCallback类中,而SyncCallback就是继承自WindowContainerTransactionCallback类,所以系统侧最后调用的就是SyncCallback中的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);
}
6、 最后总结下应用侧需要修改WindowContainer的这个流程:
1)、根据需要修改的地方构建WindowContainerTransaction类对象wct;
2)、通过wct构建SyncCallback类对象cb,然后将cb放入SyncTransactionQueue类的对象mQueue中;
3)、调用cb的send()方法,通过WindowOrganizer的applySyncTransaction方法,将wct传送到系统侧;
4)、系统侧接收到wct后,在其维护的窗口结构中应用wct封装的修改,修改应用完成后,调用onTransactionReady回调到应用侧,并将修改的方式SurfaceControl.Transaction的对象t告知应用侧,应用侧再对其进行应用。直到这里,才完成了整个流程。
下面也画了一个图进行演示: