BLAST深入源码剖析

背景:

BLAST深入源码剖析_第1张图片
以前分屏pip课程时候讲解过pip由小变大时候有使用到一个方式方式叫做同步事务,这个之前课程也讲解了他的使用方式和作用及表面原理,并没有深入到BLASTBufferQueue部分讲解。
刚好这次需要讲解BLASTBufferQueue的新特性,刚好以这个为案例进行分析。

服务端部分sync逻辑

回忆一下当时代码同步事务调用代码:
BLAST深入源码剖析_第2张图片

可以看到这里先调用了的是
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后继续往下执行时候发现如下:
BLAST深入源码剖析_第3张图片
主要 mDrewOnceForSync = false赋值操作关键
接下来继续分析,发现mDrewOnceForSync为false后就会导致cancelAndRedraw为false,会进入相应if条件

BLAST深入源码剖析_第4张图片

这里调用到了关键方法createSyncIfNeeded
BLAST深入源码剖析_第5张图片

上面有两个部分比较主要:
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的如下代码:

BLAST深入源码剖析_第6张图片
会调用到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;
        }

调用到了前面的

BLAST深入源码剖析_第7张图片
调用reportDrawFinished通知服务端,且携带了mSurfaceChangedTransaction

 private void reportDrawFinished(int seqId) {
        try {
            mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, seqId);
        } 
    }

什么时候才会触发上面的onBufferReady呢?
接下来看如下代码:
BLAST深入源码剖析_第8张图片
因为上面已经设置了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中
BLAST深入源码剖析_第9张图片
1、把callback设置给了mTransactionReadyCallback,这个就是java层面一路传递下来的回调方法
2、设置了mSyncTransaction后,那么后面就是把绘制相关的Transaction放到这个事务中
设置后等待Buffer准备好了后会进行queue,会触发BLASTBufferQueue::onFrameAvailable
BLAST深入源码剖析_第10张图片
BLASTBufferQueue::onFrameAvailable干了2件事比较重要

1、BLASTBufferQueue::acquireNextBufferLocked方法,原来分析时候都知道最后会apply,但是sync模式是不会的。
BLAST深入源码剖析_第11张图片

2、因为前面设置了callback所以最后会执行如下代码
mTransactionReadyCallback赋值给prevCallback

  if (mAcquireSingleBuffer) {
                prevCallback = mTransactionReadyCallback;
                prevTransaction = mSyncTransaction;
                mTransactionReadyCallback = nullptr;
                mSyncTransaction = nullptr;
            }

赋值后再执行callback回调

if (prevCallback) {
    prevCallback(prevTransaction);
}

注意:
这里还会有一个mergePendingTransactions,这个方法就是如下:
BLAST深入源码剖析_第12张图片

这里会把mPending进行merge到入参t中,那么mPendingTransactions是哪来的呢?
靠下面这个方法加入的
BLAST深入源码剖析_第13张图片
这个方法是ViewRootImpl中调用的
BLAST深入源码剖析_第14张图片

继续systemserver处理部分

绘制好了会回调开始createSyncIfNeed这里
BLAST深入源码剖析_第15张图片
mSurfaceChangedTransaction会进行merge,然后会调用reportDrawFinished,会进行跨进程调用到wms的finishDraw方法
BLAST深入源码剖析_第16张图片

核心代码调用到了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()让重新进行遍历
BLAST深入源码剖析_第17张图片
这次因为已经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

BLAST深入源码剖析_第18张图片

相关服务端的Sync日志如下:
BLAST深入源码剖析_第19张图片

systemui端的响应

BLAST深入源码剖析_第20张图片
这里的onTransactionReady只是一个抽象看看具体实现在SyncTransactionQueue类中
BLAST深入源码剖析_第21张图片
调用到了对应onTransactionReceived方法
BLAST深入源码剖析_第22张图片
这里的就调用到了最开始的那个发起调用的lamada方法:
BLAST深入源码剖析_第23张图片

本文章对应视频手把手教你学framework:
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
在这里插入图片描述

私聊作者+v(androidframework007)

七件套专题:在这里插入图片描述
点击这里 https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频:https://www.bilibili.com/video/BV1wc41117L4/

你可能感兴趣的:(surfaceflinger,分屏,framework,车机车载,分屏,surfaceflinger,c++,系统开发)