背景:
以前分屏pip课程时候讲解过pip由小变大时候有使用到一个方式方式叫做同步事务,这个之前课程也讲解了他的使用方式和作用及表面原理,并没有深入到BLASTBufferQueue部分讲解。
刚好这次需要讲解BLASTBufferQueue的新特性,刚好以这个为案例进行分析。
服务端部分sync逻辑
回忆一下当时代码同步事务调用代码:
可以看到这里先调用了的是
SyncTransactionQueued.queue方法,传递的参数是WindowContainerTransaction类型,主要是记录某个WindowContainer的相关操作事务。
进行queue动作完成后,紧接着就是runInSync执行,这个方法参数非常关键,代表是一个同步事务等待同步后进行回调执行的部分,而且这个时候会有一个Transaction的参数,里面就包含了相关WindowContainer的绘制相关事务。
下面就来分析一下关键的queue方法:
/**
* Queues a sync transaction to be sent serially to WM.
*/
public void queue(WindowContainerTransaction wct) {
SyncCallback cb = new SyncCallback(wct);//基于wct入参创建一个SyncCallback
synchronized (mQueue) {
mQueue.add(cb);//添加到mQueue
if (mQueue.size() == 1) {
cb.send();//调用SyncCallback的send
}
}
}
// Must be sychronized on mQueue
void send() {
if (mLegacyTransition != null) {
} else {
mId = new WindowOrganizer().applySyncTransaction(mWCT, this);//这里直接调用了applySyncTransaction方法
}
}
这里applySyncTransaction入参有两个一个是最前面传递的windowcontainertransition和一个CallBack就是SyncCallback
下面是applySyncTransaction相关调用堆栈:
01-02 19:25:16.991 12004 12004 I lsm2222 : java.lang.Exception
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.window.WindowOrganizer.applySyncTransaction(WindowOrganizer.java:79)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.common.SyncTransactionQueue$SyncCallback.send(SyncTransactionQueue.java:42)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.common.SyncTransactionQueue.queue(SyncTransactionQueue.java:29)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.pip.PipTaskOrganizer.exitPip(PipTaskOrganizer.java:246)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.pip.phone.PipMotionHelper.expandLeavePip(PipMotionHelper.java:16)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.pip.phone.PipTouchHandler$PipMenuListener.onPipExpand(PipTouchHandler.java:5)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.pip.phone.PhonePipMenuController$$ExternalSyntheticLambda2.accept(Unknown Source:8)
01-02 19:25:16.991 12004 12004 I lsm2222 : at java.util.ArrayList.forEach(ArrayList.java:1262)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.pip.phone.PipMenuView$$ExternalSyntheticLambda7.run(R8$$SyntheticClass:54)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.wm.shell.pip.phone.PipMenuView$4.onAnimationEnd(PipMenuView.java:55)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:600)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.animation.AnimatorSet.endAnimation(AnimatorSet.java:1301)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.animation.AnimatorSet.doAnimationFrame(AnimatorSet.java:1086)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:307)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.animation.AnimationHandler.-$$Nest$mdoAnimationFrame(Unknown Source:0)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:86)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1229)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.view.Choreographer.doCallbacks(Choreographer.java:899)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.view.Choreographer.doFrame(Choreographer.java:827)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.os.Handler.handleCallback(Handler.java:942)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.os.Handler.dispatchMessage(Handler.java:99)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.os.Looper.loopOnce(Looper.java:201)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.os.Looper.loop(Looper.java:288)
01-02 19:25:16.991 12004 12004 I lsm2222 : at android.app.ActivityThread.main(ActivityThread.java:7872)
01-02 19:25:16.991 12004 12004 I lsm2222 : at java.lang.reflect.Method.invoke(Native Method)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
01-02 19:25:16.991 12004 12004 I lsm2222 : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
看看相关的applySyncTransaction业务
public int applySyncTransaction(@NonNull WindowContainerTransaction t,
@NonNull WindowContainerTransactionCallback callback) {
return getWindowOrganizerController().applySyncTransaction(t, callback.mInterface);
}
这里就是一个跨进程到了systemserver端WindowOrganizerController的applySyncTransaction
frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java
@Override
public int applySyncTransaction(WindowContainerTransaction t,
IWindowContainerTransactionCallback callback) {
try {
synchronized (mGlobalLock) {
//这里使用传递来的callback作为参数调用prepareSyncWithOrganizer,返回了一个SyncGroup
final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);
final int syncId = syncGroup.mSyncId;
if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {
mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup);
applyTransaction(t, syncId, null /*transition*/, caller);
setSyncReady(syncId);
} else {
}
return syncId;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
这里再看看 prepareSyncWithOrganizer方法:
private BLASTSyncEngine.SyncGroup prepareSyncWithOrganizer(
IWindowContainerTransactionCallback callback) {
//主要调用到了BLASTSyncEngine的prepareSyncSet方法,返回一个SyncGroup
final BLASTSyncEngine.SyncGroup s = mService.mWindowManager.mSyncEngine
.prepareSyncSet(this, "", BLASTSyncEngine.METHOD_BLAST);
mTransactionCallbacksByPendingSyncId.put(s.mSyncId, callback);
return s;
}
//下面是prepareSyncSet方法
SyncGroup prepareSyncSet(TransactionReadyListener listener, String name, int method) {
//直接够着了SyncGroup,一个重要参数是mNextSyncId,这个代表是SyncGroup的id,而且是自加的
return new SyncGroup(listener, mNextSyncId++, name, method);
}
接下来再看看applySyncTransaction剩下部分
final int syncId = syncGroup.mSyncId;//获取上面的syncId
//这里会判断mSyncEngine中是否有ActiveSync,第一次都是没有
if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {
//这里会调用的startSyncSet方法
mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup);
//接下来在直接调用了applyTransaction
applyTransaction(t, syncId, null /*transition*/, caller);
//把syncId设置成syncReady
setSyncReady(syncId);
} else {
}
下面看看startSyncSet方法
void startSyncSet(SyncGroup s, long timeoutMs) {
//其实就是把SyncGroup放到mActiveSyncs中
mActiveSyncs.put(s.mSyncId, s);
scheduleTimeout(s, timeoutMs);
}
再看看setSyncReady
void setSyncReady(int id) {
//就是吧SyncGroup状态设置成Ready
mService.mWindowManager.mSyncEngine.setReady(id);
}
下面重点介绍一下applyTransaction方法
这里主要关心的是和syncId有关的
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
@Nullable Transition transition, @NonNull CallerInfo caller,
@Nullable Transition finishTransition) {
//省略其他
final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
if (syncId >= 0) {
addToSyncSet(syncId, wc);
}
//省略其他
}
这里有一个非常关键方法就是addToSyncSet,会调用到BLASTSyncEngine的addToSyncSet方法
frameworks/base/services/core/java/com/android/server/wm/BLASTSyncEngine.java
void addToSyncSet(int id, WindowContainer wc) {
//通过id获取到对应的SyncGroup的addToSync
getSyncGroup(id).addToSync(wc);
}
private void addToSync(WindowContainer wc) {
wc.setSyncGroup(this);//调用WindowContainer的setSyncGroup设置SyncGounp
wc.prepareSync();//调用关键方法prepareSync
mWm.mWindowPlacerLocked.requestTraversal();
}
下面重点来分析这个prepareSync方法:
frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
boolean prepareSync() {
if (mSyncState != SYNC_STATE_NONE) {
// Already part of sync
return false;
}
for (int i = getChildCount() - 1; i >= 0; --i) {//主要遍历子wc进行相关的prepareSync
final WindowContainer child = getChildAt(i);
child.prepareSync();
}
mSyncState = SYNC_STATE_READY;//设置成SYNC_STATE_READY状态
return true;
}
注意对于prepareSync属于WindowContainer的基类方法,Task没有实现那就是默认WindowContainer实现的,所以一直会调用到有自己实现的WindowState的
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
@Override
boolean prepareSync() {
mSyncState = SYNC_STATE_WAITING_FOR_DRAW;//状态变成SYNC_STATE_WAITING_FOR_DRAW
mSyncSeqId++;
if (getSyncMethod() == BLASTSyncEngine.METHOD_BLAST) {
mPrepareSyncSeqId = mSyncSeqId;
}
requestRedrawForSync();//这里比较关键调用了要求重绘
return true;
}
//这个方法很简单就是mRedrawForSyncReported值设置成了false
void requestRedrawForSync() {
mRedrawForSyncReported = false;
}
客户端部分sync逻辑
服务端systemserver会触发应用进行相关的configration变化然后导致app需要进行重新布局relayout操作,这里肯定会触发ViewRootImpl重新进行布局relayoutWindow
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
relayoutResult = mWindowSession.relayout(mWindow, params,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
mTempInsets, mTempControls, mRelayoutBundle);
mRelayoutRequested = true;
//获取服务服务端到的seqid,如果大于0会赋值给mSyncSeqId
final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
if (maybeSyncSeqId > 0) {
mSyncSeqId = maybeSyncSeqId;
}
return relayoutResult;
}
这里mRelayoutBundle.getInt(“seqid”)就是把服务端设置的,可以看一下服务端的代码
app端设置了mSyncSeqId后继续往下执行时候发现如下:
主要 mDrewOnceForSync = false赋值操作关键
接下来继续分析,发现mDrewOnceForSync为false后就会导致cancelAndRedraw为false,会进入相应if条件
这里调用到了关键方法createSyncIfNeeded
上面有两个部分比较主要:
1、SurfaceSyncer.setupSync方法
public int setupSync(@NonNull Consumer<Transaction> syncRequestComplete) {
synchronized (mSyncSetLock) {
final int syncId = mIdCounter++;
SyncSet syncSet = new SyncSet(syncId, transaction -> {
synchronized (mSyncSetLock) {
mSyncSets.remove(syncId);
}
//注意这里会用transaction通过syncRequestComplete回调出去
syncRequestComplete.accept(transaction);
});
mSyncSets.put(syncId, syncSet);
return syncId;
}
}
private SyncSet(int syncId, Consumer<Transaction> syncRequestComplete) {
mSyncId = syncId;
//参数syncRequestComplete赋值mSyncRequestCompleteCallback
mSyncRequestCompleteCallback = syncRequestComplete;
}
可以看到其实就是创建了一个SyncSet,返回SyncSet对应syncId
2、SurfaceSyncer.addToSync,mSyncTarget添加到Sync
frameworks/base/core/java/android/window/SurfaceSyncer.java
boolean addSyncableSurface(SyncTarget syncTarget) {
//创建了对应的SyncBufferCallback
SyncBufferCallback syncBufferCallback = new SyncBufferCallback() {
@Override
public void onBufferReady(Transaction t) {
synchronized (mLock) {
if (t != null) {
//这里有一个核心操作那就是merge
mTransaction.merge(t);
}
mPendingSyncs.remove(hashCode());
//这里也是核心方法会触发检测及回调完成事件
checkIfSyncIsComplete();
}
}
};
synchronized (mLock) {
mPendingSyncs.add(syncBufferCallback.hashCode());
mSyncTargets.add(syncTarget);
}
//回调onReadyToSync且返回带了syncBufferCallback参数
syncTarget.onReadyToSync(syncBufferCallback);
return true;
}
先看看syncTarget.onReadyToSync方法,会调用到ViewRootImpl的如下代码:
会调用到readyToSync方法
private void readyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
//syncBufferCallback会赋值给mSyncBufferCallback成员变量
mSyncBufferCallback = syncBufferCallback;
}
再看看onBufferReady回调里面的checkIfSyncIsComplete
private void checkIfSyncIsComplete() {
for (SyncTarget syncTarget : mSyncTargets) {
syncTarget.onSyncComplete();
}
mSyncTargets.clear();
//mTransaction作为参数开始回调mSyncRequestCompleteCallback
mSyncRequestCompleteCallback.accept(mTransaction);
mFinished = true;
}
调用到了前面的
调用reportDrawFinished通知服务端,且携带了mSurfaceChangedTransaction
private void reportDrawFinished(int seqId) {
try {
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, seqId);
}
}
什么时候才会触发上面的onBufferReady呢?
接下来看如下代码:
因为上面已经设置了mSyncBufferCallback,所以不为null,然后就可以进入对应的registerCallbacksForSync方法了。
private void registerCallbacksForSync(boolean syncBuffer,
final SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
@Override
public void onFrameDraw(long frame) {
}
@Override
public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
//省略
//上面设置syncBuffer为true所以进入如下代码
if (syncBuffer) {
//会调用mBlastBufferQueue进行syncNextTransaction
mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
}
return didProduceBuffer -> {
if (!didProduceBuffer) {
//会再次设置成null
mBlastBufferQueue.syncNextTransaction(null);
syncBufferCallback.onBufferReady(
mBlastBufferQueue.gatherPendingTransactions(frame));
return;
}
};
//省略
}
syncNextTransaction方法就是会让BLASTBufferQueue在queueBuffer后不会进行Transaction的直接提交,而是放入到mSyncTransaction中
1、把callback设置给了mTransactionReadyCallback,这个就是java层面一路传递下来的回调方法
2、设置了mSyncTransaction后,那么后面就是把绘制相关的Transaction放到这个事务中
设置后等待Buffer准备好了后会进行queue,会触发BLASTBufferQueue::onFrameAvailable
BLASTBufferQueue::onFrameAvailable干了2件事比较重要
1、BLASTBufferQueue::acquireNextBufferLocked方法,原来分析时候都知道最后会apply,但是sync模式是不会的。
2、因为前面设置了callback所以最后会执行如下代码
mTransactionReadyCallback赋值给prevCallback
if (mAcquireSingleBuffer) {
prevCallback = mTransactionReadyCallback;
prevTransaction = mSyncTransaction;
mTransactionReadyCallback = nullptr;
mSyncTransaction = nullptr;
}
赋值后再执行callback回调
if (prevCallback) {
prevCallback(prevTransaction);
}
注意:
这里还会有一个mergePendingTransactions,这个方法就是如下:
这里会把mPending进行merge到入参t中,那么mPendingTransactions是哪来的呢?
靠下面这个方法加入的
这个方法是ViewRootImpl中调用的
继续systemserver处理部分
绘制好了会回调开始createSyncIfNeed这里
mSurfaceChangedTransaction会进行merge,然后会调用reportDrawFinished,会进行跨进程调用到wms的finishDraw方法
核心代码调用到了WindowState的finishDrawing具体代码
boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
//执行DrawHandlers
final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction, syncSeqId);
if (!syncStillPending) {
//关键步骤onSyncFinishedDrawing
onSyncFinishedDrawing();
}
if (postDrawTransaction != null) {
//客户端传递的postDrawTransaction进行merge到mSyncTransaction
mSyncTransaction.merge(postDrawTransaction);
// Consume the transaction because the sync group will merge it.
postDrawTransaction = null;
}
return !skipLayout && (hasSyncHandlers || layoutNeeded);
}
上面有一个关键步骤onSyncFinishedDrawing
boolean onSyncFinishedDrawing() {
if (mSyncState == SYNC_STATE_NONE) return false;
mSyncState = SYNC_STATE_READY;
mSyncMethodOverride = BLASTSyncEngine.METHOD_UNDEFINED;
mWmService.mWindowPlacerLocked.requestTraversal();
return true;
}
mSyncState的mSyncState变成了SYNC_STATE_READY,然后调用 mWmService.mWindowPlacerLocked.requestTraversal()让重新进行遍历
这次因为已经SYNC_STATE_READY所以isSyncFinished为true,即整个同步完成了,调用finishNow
private void finishNow() {
//开始调用Task的finishSync
for (WindowContainer wc : mRootMembers) {
wc.finishSync(merged, false /* cancel */);
}
//进行onTransactionReady的跨进程调用到systemui进程
mListener.onTransactionReady(mSyncId, merged);
}
这里主要步骤
1、调用了Task的finishSync
void finishSync(Transaction outMergedTransaction, boolean cancel) {
if (mSyncState == SYNC_STATE_NONE) return;
//这里关键一步mSyncTransaction被merge到了outMergedTransaction中
outMergedTransaction.merge(mSyncTransaction);
for (int i = mChildren.size() - 1; i >= 0; --i) {
//开始迭代子容器进行挨个finishSync,WindowState自然最后会被遍历到
mChildren.get(i).finishSync(outMergedTransaction, cancel);
}
//设置相关Sync变量
mSyncState = SYNC_STATE_NONE;
mSyncMethodOverride = BLASTSyncEngine.METHOD_UNDEFINED;
mSyncGroup = null;
}
2、onTransactionReady方法传递到了客户端systemui
相关服务端的Sync日志如下:
systemui端的响应
这里的onTransactionReady只是一个抽象看看具体实现在SyncTransactionQueue类中
调用到了对应onTransactionReceived方法
这里的就调用到了最开始的那个发起调用的lamada方法:
本文章对应视频手把手教你学framework:
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
私聊作者+v(androidframework007)
七件套专题:
点击这里 https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw