2【Android 12】【WCT的发送】SyncTransactionQueue

编程入门 行业动态 更新时间:2024-10-13 00:30:35

2【<a href=https://www.elefans.com/category/jswz/34/1771384.html style=Android 12】【WCT的发送】SyncTransactionQueue"/>

2【Android 12】【WCT的发送】SyncTransactionQueue

一、WindowOrganizer发送WCT的两种方式

WindowContainerTransaction通过WindowOrganizer来发送,WindowOrganizer提供了两个方法WindowOrganizer#applyTransaction和WindowOrganizer#applySyncTransaction。

/*** Base class for organizing specific types of windows like Tasks and DisplayAreas** @hide*/
@TestApi
public class WindowOrganizer {/*** Apply multiple WindowContainer operations at once.* @param t The transaction to apply.*/@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)public void applyTransaction(@NonNull WindowContainerTransaction t) {try {if (!t.isEmpty()) {getWindowOrganizerController().applyTransaction(t);}} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}/*** Apply multiple WindowContainer operations at once.* @param t The transaction to apply.* @param callback This transaction will use the synchronization scheme described in*        BLASTSyncEngine.java. The SurfaceControl transaction containing the effects of this*        WindowContainer transaction will be passed to this callback when ready.* @return An ID for the sync operation which will later be passed to transactionReady callback.*         This lets the caller differentiate overlapping sync operations.*/@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)public int applySyncTransaction(@NonNull WindowContainerTransaction t,@NonNull WindowContainerTransactionCallback callback) {try {return getWindowOrganizerController().applySyncTransaction(t, callback.mInterface);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}......@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)IWindowOrganizerController getWindowOrganizerController() {return IWindowOrganizerControllerSingleton.get();}private static final Singleton<IWindowOrganizerController> IWindowOrganizerControllerSingleton =new Singleton<IWindowOrganizerController>() {@Overrideprotected IWindowOrganizerController create() {try {return ActivityTaskManager.getService().getWindowOrganizerController();} catch (RemoteException e) {return null;}}};
}

这两个方法,都是先取到一个IWindowOrganizerController对象,然后调用IWindowOrganizerController的相关接口。

IWindowOrganizerController在服务端的实现是WindowOrganizerController,因此最终WindowContainerTransaction跨进程发送到系统服务端的WindowOrganizerController。

WindowOrganizer#applyTransaction和WindowOrganizer#applySyncTransaction分别对应WindowOrganizerController#applyTransaction和WindowOrganizerController#applySyncTransaction:

/*** Server side implementation for the interface for organizing windows* @see android.window.WindowOrganizer*/
class WindowOrganizerController extends IWindowOrganizerController.Stubimplements BLASTSyncEngine.TransactionReadyListener {...... @Overridepublic void applyTransaction(WindowContainerTransaction t) {enforceTaskPermission("applyTransaction()");if (t == null) {throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");}final long ident = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {applyTransaction(t, -1 /*syncId*/, null /*transition*/);}} finally {Binder.restoreCallingIdentity(ident);}}@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);}}......
}

WindowOrganizerController是应用WindowContainerTransaction的地方,以后会在其他笔记中分析。

从发送方式来看,可以把WindowContainerTransaction分为两种,同步的和异步的。

1)、异步的WindowContainerTransaction发送方式很简单,举一个例子,LegaycSplitScreenController#onSplitScreenSupported:

public void onSplitScreenSupported() {// Set starting tile bounds based on middle targetfinal WindowContainerTransaction tct = new WindowContainerTransaction();int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;mSplitLayout.resizeSplits(midPos, tct);mTaskOrganizer.applyTransaction(tct);
}

创建一个WindowContainerTransaction对象,设置好相关参数,直接调用WindowOrganizer#applyTransaction发送即可。

2)、同步WindowContainerTransaction的发送需要借助SyncTransactionQueue,最终会调用WindowOrganizer#applySyncTransaction,本文主要分析SyncTransactionQueue是如何发送同步WindowContainerTransaction的。

二、SyncTransactionQueue介绍

/*** Helper for serializing sync-transactions and corresponding callbacks.*/
public final class SyncTransactionQueue

SyncTransactionQueue,一个用于序列化同步WindowContainerTransaction和相应callback的助手类,有两个关键词,一个是序列化,一个是同步。

SyncTransactionQueue也提供了两个方法来发送WCT,SyncTransactionQueue#queue和SyncTransactionQueue#queueIfWaiting。

结合分屏,看下SyncTransactionQueue是如何工作的。

1 SyncTransactionQueue#queue

分屏的逻辑中,SyncTransactionQueue#queue方法不是直接被调用的,而是间接通过WindowManagerProxy来调用,比如在LegacySplitScreenController#splitPrimaryTask中:

     final WindowContainerTransaction wct = new WindowContainerTransaction();// Clear out current windowing mode before reparenting to split task.wct.setWindowingMode(topRunningTask.token, WINDOWING_MODE_UNDEFINED);wct.reparent(topRunningTask.token, mSplits.mPrimary.token, true /* onTop */);mWindowManagerProxy.applySyncTransaction(wct);

我们创建了一个WindowContainerTransaction对象,然后设置了相关属性后,调用WindowManagerProxy#applySyncTransaction:

    /*** Utility to apply a sync transaction serially with other sync transactions.** @see SyncTransactionQueue#queue*/void applySyncTransaction(WindowContainerTransaction wct) {mSyncTransactionQueue.queue(wct);}

mSyncTransactionQueue是WindowManagerProxy的SyncTransactionQueue类型的成员变量,那么这里会走到SyncTransactionQueue#queue:

    /*** Queues a sync transaction to be sent serially to WM.*/public void queue(WindowContainerTransaction wct) {SyncCallback cb = new SyncCallback(wct);synchronized (mQueue) {if (DEBUG) Slog.d(TAG, "Queueing up " + wct);mQueue.add(cb);if (mQueue.size() == 1) {cb.send();}}}

注释上说,这个方法将一个要序列化发送到WM的同步WindowContainerTransaction进行排队。

内容很简单,基于传入的WindowContainerTransaction创建一个SyncCallback对象,并加到mQueue队列中,如果队列中只有它一个,那么执行SyncCallback#send。

2 SyncTransactionQueue#queueIfWaiting

    /*** Queues a sync transaction only if there are already sync transaction(s) queued or in flight.* Otherwise just returns without queueing.* @return {@code true} if queued, {@code false} if not.*/public boolean queueIfWaiting(WindowContainerTransaction wct) {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;}

和SyncTransactionQueue#queue的区别是,如果此时mQueue中没有正在等待的SyncCallback,那么直接返回,不进行排队。

3 SyncCallback

上面看到,如果我们想要发送一个WindowContainerTransaction,都是将WindowContainerTransaction封装到一个SyncCallback对象中,然后调用SyncCallback#send,那么有必要看下SyncCallback的作用是什么。

    private class SyncCallback extends WindowContainerTransactionCallback {int mId = -1;final WindowContainerTransaction mWCT;SyncCallback(WindowContainerTransaction wct) {mWCT = wct;}// Must be sychronized on mQueuevoid send() {if (mInFlight != null) {throw new IllegalStateException("Sync Transactions must be serialized. In Flight: "+ mInFlight.mId + " - " + mInFlight.mWCT);}mInFlight = this;if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT);mId = new WindowOrganizer().applySyncTransaction(mWCT, this);if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId);mMainExecutor.executeDelayed(mOnReplyTimeout, REPLY_TIMEOUT);}@BinderThread@Overridepublic void onTransactionReady(int id,@NonNull SurfaceControl.Transaction t) {mMainExecutor.execute(() -> {synchronized (mQueue) {if (mId != id) {Slog.e(TAG, "Got an unexpected onTransactionReady. Expected "+ mId + " but got " + id);return;}mInFlight = null;mMainExecutor.removeCallbacks(mOnReplyTimeout);if (DEBUG) Slog.d(TAG, "onTransactionReady id=" + mId);mQueue.remove(this);onTransactionReceived(t);if (!mQueue.isEmpty()) {mQueue.get(0).send();}}});}}

SyncCallback是一个内部类,创建的地方在SyncTransactionQueue#queue和SyncTransactionQueue#queueIfWaiting,存储了一个要发给WM 的WindowContainerTransaction对象。

3.1 SyncCallback#send

        // Must be sychronized on mQueuevoid send() {if (mInFlight != null) {throw new IllegalStateException("Sync Transactions must be serialized. In Flight: "+ mInFlight.mId + " - " + mInFlight.mWCT);}mInFlight = this;if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT);mId = new WindowOrganizer().applySyncTransaction(mWCT, this);if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId);mMainExecutor.executeDelayed(mOnReplyTimeout, REPLY_TIMEOUT);}

1)、调用WindowOrganizer#applySyncTransaction发送一个同步callback到WM端,由WindowOrganizerController处接收。最终从WM端会返回一个syncId,这个ID保存在SyncCallback的成员变量mId中,和SyncCallback一一对应。

2)、将mInFlight指向这个被发送到WM的callback。

3)、另外发送完之后开启一个防超时线程:

    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());}}};

超时后调用SyncCallback#onTransactionReady,防止出现堵塞的情况。

3.2. SyncCallback#onTransactionReady

        @BinderThread@Overridepublic void onTransactionReady(int id,@NonNull SurfaceControl.Transaction t) {mMainExecutor.execute(() -> {synchronized (mQueue) {if (mId != id) {Slog.e(TAG, "Got an unexpected onTransactionReady. Expected "+ mId + " but got " + id);return;}mInFlight = null;mMainExecutor.removeCallbacks(mOnReplyTimeout);if (DEBUG) Slog.d(TAG, "onTransactionReady id=" + mId);mQueue.remove(this);onTransactionReceived(t);if (!mQueue.isEmpty()) {mQueue.get(0).send();}}});}

SyncCallback#send中通过WindowOrganizer#applySyncTransaction将WindowContainerTransaction发送给WM端后,WM端就开始应用WindowContainerTransaction,提取WindowContainerTransaction中的设置进行相应处理,这需要一段时间。等WM端处理结束,会由WindowOrganizerController#onTransactionReady回调SyncCallback#onTransactionReceived(具体情况可以参考BLAST机制介绍),并且返回一个集成了对多个WindowContainer操作的Transaction和一个ID。

SyncCallback#onTransactionReceived接收到这个Transaction和ID之后,做了以下几件事:

1)、检查ID的一致性。

2)、将mInFlight置空。

3)、移除掉防延迟mOnReplyTimeout。

4)、将该SyncCallback从mQueue中移除。

5)、调用SyncTransactionQueue#onTransactionReceived完成Transaction的apply。

6)、如果mQueue中还有其他正在等待的SyncCallback,调用他们的send方法。

4 SyncTransactionQueue#onTransactionReceived

// Synchronized on mQueue
private void onTransactionReceived(@NonNull SurfaceControl.Transaction t) {Slog.i("SyncTransactionQueue", "SyncTransactionQueue#onTransactionReceived");if (DEBUG) Slog.d(TAG, "  Running " + mRunnables.size() + " sync runnables");for (int i = 0, n = mRunnables.size(); i < n; ++i) {mRunnables.get(i).runWithTransaction(t);}mRunnables.clear();t.apply();t.close();
}

上一步提到了,当WM端完成了WindowContainerTransaction的应用后,会返回一个Transaction对象给SyncCallback#onTransactionReady,然后SyncCallback#onTransactionReady再调用SyncTransactionQueue#onTransactionReceived完成Transaction的apply。

SyncTransactionQueue#onTransactionReceive做了两件事:

1)、执行之前由SyncTransactionQueue#runInSync中添加到mRunnables的TransactionRunnable。

2)、调用Transaction#apply。

注意,直到这里,从WM端传来的Transaction才被apply,同步WindowContainerTransaction才算完成。

进退分屏的过程中,我们会通过WindowContainerTransaction为一些Task设置Bounds,执行一些Task的reparent操作等,这些操作都会引起Task的position、size等属性的改变,这些改变最终会收集到一个Transaction对象中。但是由于整个过程是在WindowOrganizerController#applySyncTransaction的调用中进行的,因此收集了Task的postion和size等变化的Transaction不会马上apply,而是等到所有相关的窗口绘制完成,然后全部merge到一个Transaction中,再由WindowOrganizerController#onTransactionReady发送到SyncCallback#onTransactionReady处,最终在SyncTransactionQueue#onTransactionReceived中完成apply。

这一点很容易导致问题。

三、总结

1)、发送WindowContainerTransaction的方式有两种,异步的WindowOrganizer#applyTransaction和同步的WindowOrganizer#applySyncTransaction。异步WindowContainerTransacton的发送很简单,直接拿到一个WindowOrganizer对象,调用其applyTransaction方法即可。同步WindowContainerTransaction的发送比较麻烦,不能直接调用WindowOrganizer#applySyncTransaction方法,需要借助SyncTransactionQueue。

2)、SyncTransactionQueue#queue和SyncTransactionQueue#queueIfWaiting是SyncTransactionQueue提供的两个用于发送同步WindowContainerTransaction的方法。

3)、通过SyncTransactionQueue发送的WindowContainerTransaction具有序列化和同步的特点。

4)、序列化表现在,在SyncTransactionQueue的参与下,所有的WindowContainerTransaction都会以序列化的方式发送:SyncTransactionQueue内部有一个SyncCallback的队列mQueue,要发送给WM端的WindowContainerTransaction会被封装为一个SyncCallback对象加入到mQueue中,然后按照SyncCallback入队的顺序调用SyncCallback#send方法进行发送,只有当前一个WindowContainerTransaction对应的SyncCallback#onTransactionReady回调完成,下一个WindowContainerTransaction对应的SyncCallback#send才会被调用。

5)、同步表现在,SyncTransactionQueue作为BLAST机制的一部分实现了同步:WindowContainerTransaction在WM端应用后,WM端会将所有涉及到的WindowContainer的修改合入到一个Transaction中,等待所有涉及的窗口绘制完成,再回调SyncCallback#onTransactionReady,最终在SyncTransactionQueue#onTransactionReceived中完成这个从WM端传过来的Transaction的apply,直到这时,同步WindowContainerTransaction应用的整个过程才算结束。

更多推荐

2【Android 12】【WCT的发送】SyncTransactionQueue

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

发布评论

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

>www.elefans.com

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