WCT系列(二):SyncTransactionQueue类详解

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告知应用侧,应用侧再对其进行应用。直到这里,才完成了整个流程。
下面也画了一个图进行演示:

在这里插入图片描述

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值