ShellTransition源码分析:WMCore收集WindowContainer到finishNow执行

startTransition部分

frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java

  @Override
    public void startTransition(@NonNull IBinder transitionToken,
            @Nullable WindowContainerTransaction t) {
        startTransition(-1 /* unused type */, transitionToken, t);
    }
private IBinder startTransition(@WindowManager.TransitionType int type,
      @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) {
//省略            
		Transition transition = Transition.fromBinder(transitionToken);
		final WindowContainerTransaction wct =
		t != null ? t : new WindowContainerTransaction();
		//省略    
		if (t != null) {
				wctApplied = new Transition.ReadyCondition("start WCT applied");
				transition.mReadyTracker.add(wctApplied);
		} else {
				wctApplied = null;
		}

	 if (transition.shouldApplyOnDisplayThread()) {
		mService.mH.post(() -> {
		    synchronized (mService.mGlobalLock) {
		        transition.start();
		        applyTransaction(wct, -1 /* syncId */, transition, caller);
		        if (wctApplied != null) {
		            wctApplied.meet();
		        }
		    }
		});
		} else {
		  //调用transition.start方法启动
			transition.start();
			//再调用的applyTransaction方法
			applyTransaction(wct, -1 /* syncId */, transition, caller);
		}
//省略          
}

下面重点看看transition.start()和applyTransaction方法
frameworks/base/services/core/java/com/android/server/wm/Transition.java

    /**
     * Formally starts the transition. Participants can be collected before this is started,
     * but this won't consider itself ready until started -- even if all the participants have
     * drawn.
     */
    void start() {
        if (mState < STATE_COLLECTING) {
            throw new IllegalStateException("Can't start Transition which isn't collecting.");
        } else if (mState >= STATE_STARTED) {
            Slog.w(TAG, "Transition already started id=" + mSyncId + " state=" + mState);
            // The transition may be aborted (STATE_ABORT) or timed out (STATE_PLAYING by
            // SyncGroup#finishNow), so do not revert the state to STATE_STARTED.
            return;
        }
        mState = STATE_STARTED;//赋值mState为STATE_STARTED
        ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",
                mSyncId);
        applyReady();//这里会判断当前是否ready,设置到SyncEngine中

        mLogger.mStartTimeNs = SystemClock.elapsedRealtimeNanos();

        mController.updateAnimatingState();
    }
    
  private void applyReady() {
        if (mState < STATE_STARTED) return;
        final boolean ready;
        if (mController.useFullReadyTracking()) {
            ready = mReadyTracker.isReady();
        } else {
            ready = mReadyTrackerOld.allReady();//获取是否ready值
        }
        boolean changed = mSyncEngine.setReady(mSyncId, ready);//再对sync进行设置ready
        if (changed && ready) {
            mLogger.mReadyTimeNs = SystemClock.elapsedRealtimeNanos();
            mOnTopTasksAtReady.clear();
            for (int i = 0; i < mTargetDisplays.size(); ++i) {
                addOnTopTasks(mTargetDisplays.get(i), mOnTopTasksAtReady);
            }
            mController.onTransitionPopulated(this);
        }
    }

start干的事情主要有2个:
1、把Transition的mState变成STATE_STARTED
2、调用applyReady方法,主要就是获取一下ready值,再设置,所以这个地方其实并没有说有完全设置read为true,而是根据当前ready值来

再接下来看看applyTransaction(wct, -1 /* syncId */, transition, caller);方法调用
因为wct其实是null传递过来的,但是applyTransaction实现主要又是针对wct有内容的情况,所以applyTransaction基本上啥也没干针对这种启动Activity场景。

那么到这里WMShell -----------------> WMCore这个过程就完成了,接下来的就是WMCore等待收集的WindowContainer完成绘制finish后,再触发onTransactionReady了.

WMCore收集的wc情况

前面Transition收集只讲解最基本的collect打开的ActivityRecord,但是打开一个Activity其实涉及的wc还是很多,比如打开Activity意味者上一Activity要被隐藏,而且隐藏的Activity还可能显示壁纸。
为了更好定位出collect收集了哪些wc,又是在什么时机收集的,这里加入日志打印更加方便定位
在这里插入图片描述
简单的桌面打开Activity场景一共有如下6次收集
在这里插入图片描述
收集的wc有3个是重复的,都是ActivityRecord,所以最后收集到了4个wc,即Transition的mParticipants集合一共有四个元素,一般对应的SyncGroup的mRootMembers也有四个元素。

第1次collect在startActivityUnchecked

 collect ActivityRecord{3762177 u0 com.android.dialer/.main.impl.MainActivity t-1}
 java.lang.Exception
 	at com.android.server.wm.Transition.collect(Transition.java:685)
 	at com.android.server.wm.TransitionController.collect(TransitionController.java:804)
 	at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1541)
 	at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1361)
 	at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:782)
 	at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1312)
 	at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1257)
 	at com.android.server.wm.ActivityTaskManagerService.startActivity(ActivityTaskManagerService.java:1232)
 	at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:910)
 	at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5722)
 	at android.os.Binder.execTransactInternal(Binder.java:1500)

第2次collect,因为Activity要启动肯定需要有对应Task,这里一般会新建一个Task,新建Task一般属于从无到有所以会触发collectExistenceChange进行收集Task并且置位mExistenceChange = true

   java.lang.Exception
   	at com.android.server.wm.Transition.collect(Transition.java:685)
   	at com.android.server.wm.Transition.collectExistenceChange(Transition.java:795)
   	at com.android.server.wm.TransitionController.collectExistenceChange(TransitionController.java:810)
   	at com.android.server.wm.ActivityStarter.setNewTask(ActivityStarter.java:2932)
   	at com.android.server.wm.ActivityStarter.startActivityInner(ActivityStarter.java:1829)
   	at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1544)
   	at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1361)
   	at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:782)
   	at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1312)
   	at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1257)
   	at com.android.server.wm.ActivityTaskManagerService.startActivity(ActivityTaskManagerService.java:1232)
   	at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:910)
   	at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5722)
   	at android.os.Binder.execTransactInternal(Binder.java:1500)
   	at android.os.Binder.execTransact(Binder.java:1444)

第3次collect因为要启动Activity在进行handleStartResult时候判断存在性有变化,所以会触发collectExistenceChange方法里面会collect,前面Activity已经收集过,所以这次也属于无效收集

    collect ActivityRecord{3762177 u0 com.android.dialer/.main.impl.MainActivity t266}
    java.lang.Exception
    	at com.android.server.wm.Transition.collect(Transition.java:685)
    	at com.android.server.wm.Transition.collectExistenceChange(Transition.java:795)
    	at com.android.server.wm.TransitionController.collectExistenceChange(TransitionController.java:810)
    	at com.android.server.wm.ActivityStarter.handleStartResult(ActivityStarter.java:1652)
    	at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1551)
    	at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1361)
    	at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:782)
    	at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1312)
    	at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1257)
    	at com.android.server.wm.ActivityTaskManagerService.startActivity(ActivityTaskManagerService.java:1232)
    	at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:910)
    	at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5722)
    	at android.os.Binder.execTransactInternal(Binder.java:1500)
    	at android.os.Binder.execTransact(Binder.java:1444)

第4次collect,因为Launcher的ActivityPasue后,系统会保证前台Activity显示,所以触发收集,但是因为前面已经收集过了所以这次无效

    collect ActivityRecord{3762177 u0 com.android.dialer/.main.impl.MainActivity t266}
    java.lang.Exception
    	at com.android.server.wm.Transition.collect(Transition.java:685)
    	at com.android.server.wm.TransitionController.collect(TransitionController.java:804)
    	at com.android.server.wm.ActivityRecord.setVisibility(ActivityRecord.java:5583)
    	at com.android.server.wm.ActivityRecord.setVisibility(ActivityRecord.java:5544)
    	at com.android.server.wm.EnsureActivitiesVisibleHelper.makeVisibleAndRestartIfNeeded(EnsureActivitiesVisibleHelper.java:238)
    	at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:181)
    	at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:130)
    	at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:1332)
    	at com.android.server.wm.Task.lambda$ensureActivitiesVisible$19(Task.java:5036)
    	at com.android.server.wm.Task.$r8$lambda$DbhuUlekQ2cVQp1TiLmGb_W7C-g(Task.java:0)
    	at com.android.server.wm.Task$$ExternalSyntheticLambda2.accept(R8$$SyntheticClass:0)
    	at com.android.server.wm.Task.forAllLeafTasks(Task.java:3154)
    	at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:5035)
    	at com.android.server.wm.DisplayContent.lambda$ensureActivitiesVisible$46(DisplayContent.java:6549)
    	at com.android.server.wm.DisplayContent.$r8$lambda$B9Mi2o96X6cYtjvyI8f4PcEeMbM(DisplayContent.java:0)
    	at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda22.accept(R8$$SyntheticClass:0)
    	at com.android.server.wm.Task.forAllRootTasks(Task.java:3166)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2206)
    	at com.android.server.wm.DisplayContent.ensureActivitiesVisible(DisplayContent.java:6548)
    	at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1913)
    	at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1896)
    	at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1987)
    	at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6599)
    	at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:231)
    	at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:698)
    	at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:168)
    	at android.os.Binder.execTransactInternal(Binder.java:1500)
    	at android.os.Binder.execTransact(Binder.java:1444)

第5次collect,因为Launcher要Pasue所以Launcher可见性就变得不可见,不可见设置时候就触发collect收集

    collect ActivityRecord{edc7080 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t253}
    java.lang.Exception
    	at com.android.server.wm.Transition.collect(Transition.java:685)
    	at com.android.server.wm.TransitionController.collect(TransitionController.java:804)
    	at com.android.server.wm.ActivityRecord.setVisibility(ActivityRecord.java:5583)
    	at com.android.server.wm.ActivityRecord.setVisibility(ActivityRecord.java:5544)
    	at com.android.server.wm.ActivityRecord.makeInvisible(ActivityRecord.java:6330)
    	at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:208)
    	at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:130)
    	at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:1332)
    	at com.android.server.wm.Task.lambda$ensureActivitiesVisible$19(Task.java:5036)
    	at com.android.server.wm.Task.$r8$lambda$DbhuUlekQ2cVQp1TiLmGb_W7C-g(Task.java:0)
    	at com.android.server.wm.Task$$ExternalSyntheticLambda2.accept(R8$$SyntheticClass:0)
    	at com.android.server.wm.Task.forAllLeafTasks(Task.java:3154)
    	at com.android.server.wm.Task.forAllLeafTasks(Task.java:3142)
    	at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:5035)
    	at com.android.server.wm.DisplayContent.lambda$ensureActivitiesVisible$46(DisplayContent.java:6549)
    	at com.android.server.wm.DisplayContent.$r8$lambda$B9Mi2o96X6cYtjvyI8f4PcEeMbM(DisplayContent.java:0)
    	at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda22.accept(R8$$SyntheticClass:0)
    	at com.android.server.wm.Task.forAllRootTasks(Task.java:3166)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    	at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2206)
    	at com.android.server.wm.DisplayContent.ensureActivitiesVisible(DisplayContent.java:6548)
    	at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1913)
    	at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1896)
    	at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1987)
    	at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6599)
    	at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:231)
    	at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:698)
    	at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:168)
    	at android.os.Binder.execTransactInternal(Binder.java:1500)
    	at android.os.Binder.execTransact(Binder.java:1444)

第6次collect的是ImageWallpaper,触发时机本质就是Launcher隐藏了,Launcher显示Wallpaper的,所以Launcher隐藏自然Wallpaper也要隐藏

12-17 11:18:13.227   544   562 I lsm888888: collect Window{7198a68 u0 com.android.systemui.wallpapers.ImageWallpaper}
12-17 11:18:13.227   544   562 I lsm888888: java.lang.Exception
    at com.android.server.wm.Transition.collect(Transition.java:685)
    at com.android.server.wm.WallpaperController.collectTopWallpapers(WallpaperController.java:771)
    at com.android.server.wm.Transition.collect(Transition.java:711)
    at com.android.server.wm.TransitionController.collect(TransitionController.java:804)
    at com.android.server.wm.ActivityRecord.setVisibility(ActivityRecord.java:5583)
    at com.android.server.wm.ActivityRecord.setVisibility(ActivityRecord.java:5544)
    at com.android.server.wm.ActivityRecord.makeInvisible(ActivityRecord.java:6330)
    at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:208)
    at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:130)
    at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:1332)
    at com.android.server.wm.Task.lambda$ensureActivitiesVisible$19(Task.java:5036)
    at com.android.server.wm.Task.$r8$lambda$DbhuUlekQ2cVQp1TiLmGb_W7C-g(Task.java:0)
    at com.android.server.wm.Task$$ExternalSyntheticLambda2.accept(R8$$SyntheticClass:0)
    at com.android.server.wm.Task.forAllLeafTasks(Task.java:3154)
    at com.android.server.wm.Task.forAllLeafTasks(Task.java:3142)
    at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:5035)
    at com.android.server.wm.DisplayContent.lambda$ensureActivitiesVisible$46(DisplayContent.java:6549)
    at com.android.server.wm.DisplayContent.$r8$lambda$B9Mi2o96X6cYtjvyI8f4PcEeMbM(DisplayContent.java:0)
    at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda22.accept(R8$$SyntheticClass:0)
    at com.android.server.wm.Task.forAllRootTasks(Task.java:3166)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2213)
    at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:2206)
    at com.android.server.wm.DisplayContent.ensureActivitiesVisible(DisplayContent.java:6548)
    at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1913)
    at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:1896)
    at com.android.server.wm.TaskFragment.completePause(TaskFragment.java:1987)
    at com.android.server.wm.ActivityRecord.activityPaused(ActivityRecord.java:6599)
    at com.android.server.wm.ActivityClientController.activityPaused(ActivityClientController.java:231)
    at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:698)
    at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:168)
    at android.os.Binder.execTransactInternal(Binder.java:1500)
    at android.os.Binder.execTransact(Binder.java:1444)

进入SyncGroup等待期间

上面收集到了4个wc,那么Transition要可以进入下一个环节就必须要保证,4个wc都已经进行FinishSync才可以进入到Finished。
要进入Finished需要满足下面两个条件:

1、Transition处于ready = true状态,因为只有属于ready后,才会触发wc的是否finish检测
2、挨个遍历SyncGroup的mRootMember是否都进行finish,只要有一个没有就不可以

那么是什么时机设置ready为true呢?
堆栈可以看出来是在ActivityRecord.onStartingWindowDrawn会触发executeAppTransition调用到TransitionController.setReady

frameworks/base/services/core/java/com/android/server/wm/Transition.java

   void setReady(WindowContainer wc, boolean ready) {
        android.util.Log.i("lsm888888","call setReady "+ready,new Exception());
        if (!isCollecting() || mSyncId < 0) return;
        mReadyTrackerOld.setReadyFrom(wc, ready);
        applyReady();
    }
    
    private void applyReady() {
        if (mState < STATE_STARTED) return;
        final boolean ready;
        if (mController.useFullReadyTracking()) {
            ready = mReadyTracker.isReady();
        } else {
            ready = mReadyTrackerOld.allReady();
        }
        ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                "Set transition ready=%b %d", ready, mSyncId);
        boolean changed = mSyncEngine.setReady(mSyncId, ready);//根据当前mSyncId调用到SyncGroup的
    
    }

frameworks/base/services/core/java/com/android/server/wm/BLASTSyncEngine.java

 boolean setReady(int id, boolean ready) {
        return getSyncGroup(id).setReady(ready);
    }
     /** returns true if readiness changed. */
        private boolean setReady(boolean ready) {
            if (mReady == ready) {
                return false;
            }
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready %b", mSyncId, ready);
            mReady = ready;//就是让mReady为true
            if (ready) {
                mWm.mWindowPlacerLocked.requestTraversal();
            }
            return true;
        }

相关堆栈

    call setReady true
    java.lang.Exception
    	at com.android.server.wm.Transition.setReady(Transition.java:943)
    	at com.android.server.wm.TransitionController.setReady(TransitionController.java:894)
    	at com.android.server.wm.TransitionController.setReady(TransitionController.java:899)
    	at com.android.server.wm.DisplayContent.executeAppTransition(DisplayContent.java:5690)
    	at com.android.server.wm.ActivityRecord.onStartingWindowDrawn(ActivityRecord.java:7012)
    	at com.android.server.wm.WindowState.performShowLocked(WindowState.java:4431)
    	at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:259)
    	at com.android.server.wm.DisplayContent.lambda$new$8(DisplayContent.java:1016)
    	at com.android.server.wm.DisplayContent.$r8$lambda$-dBz3LtsWovWVT0SE5m__EwNfT4(DisplayContent.java:0)
    	at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda32.accept(R8$$SyntheticClass:0)
    	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2833)
    	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:2823)
    	at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4663)
    	at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4528)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1799)
    	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:1816)
    	at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:5047)
    	at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:985)
    	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:785)
    	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:751)
    	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
    	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
    	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
    	at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
    	at android.os.Handler.handleCallback(Handler.java:959)
    	at android.os.Handler.dispatchMessage(Handler.java:100)
    	at android.os.Looper.loopOnce(Looper.java:232)
    	at android.os.Looper.loop(Looper.java:317)
    	at android.os.HandlerThread.run(HandlerThread.java:85)
    	at com.android.server.ServiceThread.run(ServiceThread.java:46)

wc的Finished检测
检测触发函数是performSurfacePlacementNoTrace
在这里插入图片描述
具体检测逻辑代码


    void onSurfacePlacement() {
        if (mActiveSyncs.isEmpty()) return;

        while (!mTmpFinishQueue.isEmpty()) {
            if (visitBounds <= 0) {
                Slog.e(TAG, "Trying to finish more syncs than theoretically possible. This "
                        + "should never happen. Most likely a dependency cycle wasn't detected.");
            }
            --visitBounds;
            final SyncGroup group = mTmpFinishQueue.remove(0);
            final int grpIdx = mActiveSyncs.indexOf(group);
            // Skip if it's already finished:
            if (grpIdx < 0) continue;
            if (!group.tryFinish()) continue;//这里会调用到SyncGroup的
         
        }
    }

这里onSurfacePlacement主要就是调用SyncGroup的tryFinish方法

       /** @return `true` if it finished. */
        private boolean tryFinish() {
            if (!mReady) {//这里注意如果mReady为false就会直接返回
                Log.i("WindowManager"," tryFinish "+mReady);
                return false;
            }
            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s",
                    mSyncId, mRootMembers);
            if (!mDependencies.isEmpty()) {
                ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished dependencies: %s",
                        mSyncId, mDependencies);
                return false;
            }
            for (int i = mRootMembers.size() - 1; i >= 0; --i) {//遍历mRootMembers的每个wc
                final WindowContainer wc = mRootMembers.valueAt(i);
                if (!wc.isSyncFinished(this)) {//如果有一个没有完成就会中断
                    ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished container: %s",
                            mSyncId, wc);
                    return false;
                }
            }
            finishNow();
            return true;
        }

重点看看wc.isSyncFinished方法,这里isSyncFinished重载比较多,重点判断还是WindowContainer为最重要

    boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
        if (!isVisibleRequested()) {
            return true;
        }
        if (mSyncState == SYNC_STATE_NONE && getSyncGroup() != null) {
            prepareSync();
        }
        //如果WindowState还没绘制完成就是这个状态,其他非WindowState一般都不是这个SYNC_STATE_WAITING_FOR_DRAW
        if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW) {
            return false;
        }
        // READY
        // Loop from top-down.
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final WindowContainer child = mChildren.get(i);
            //这里会遍历每个child是否isSyncFinished为true
            final boolean childFinished = group.isIgnoring(child) || child.isSyncFinished(group);
            if (childFinished && child.isVisibleRequested() && child.fillsParent()) {
                // Any lower children will be covered-up, so we can consider this finished.
                return true;
            }
            if (!childFinished) {
                return false;
            }
        }
        return true;
    }

上面可以看出其实遍历ActivityRecord的isSyncFinished其实就会遍历到它对应的WindowState的isSyncFinished。
所以核心看看WindowState相关的设置情况:
正常情况下只有WindowState会把mSyncState设置成SYNC_STATE_WAITING_FOR_DRAW
在这里插入图片描述
注意这里的prepareSync其实在前面的SyncGroup的addToSync时候调用的
在这里插入图片描述
在finishDraw时候才会设置的

在这里插入图片描述onSyncFinishedDrawing调用堆栈情况

onSyncFinishedDrawing:3929, WindowContainer (com.android.server.wm)
finishDrawing:5874, WindowState (com.android.server.wm)
finishDrawingWindow:2857, WindowManagerService (com.android.server.wm)
finishDrawing:350, Session (com.android.server.wm)
onTransact:815, IWindowSession$Stub (android.view)
onTransact:206, Session (com.android.server.wm)
execTransactInternal:1505, Binder (android.os)
execTransact:1444, Binder (android.os)
<think>嗯,我现在要理解Android中的shellTransition流程。首先,我需要知道什么是Shell Transition。听起来像是和界面转场动画或者应用切换相关的。Android系统中的Shell通常指的是系统级的UI组件,比如任务管理器、最近应用列表、主屏幕等,可能由SystemUI负责。 那Transition流程可能涉及到应用窗口之间的切换动画,比如打开应用、返回桌面、多任务切换时的动画效果。在Android 12之后,Material You设计语言引入了一些新的动画效果,可能和这个有关。 我记得在Android开发中,Activity和Fragment的转场动画是通过overridePendingTransition或者设置SharedElement来处理的。但系统级的转场,比如从应用回到桌面,可能涉及到更底层的实现,比如WindowManagerService或者SurfaceFlinger之类的服务。 ShellTransition可能是指这些系统级转场的管理流程。比如当用户点击Home键时,系统需要处理当前应用的退出动画和主屏幕的进入动画。这时候Shell(比如SystemUI中的组件)会协调这些转场效果,确保动画流畅。 可能需要了解WindowContainer和相关的Transition类。在Android的窗口管理系统中,每个窗口都是一个WindowContainer,而Transition用于处理窗口之间的变化,比如添加、移除、调整大小等操作。ShellTransition可能是Shell模块中处理这些Transition的部分。 另外,Android 10或11引入了WindowOrganizer,允许对窗口进行更灵活的管理,这可能和ShellTransition有关联。例如,使用WindowOrganizer来组织多个窗口的过渡动画。 流程可能分为几个步骤:检测窗口变化,创建Transition对象,收集动画所需的参数,执行动画,最后完成过渡。Shell在这里可能负责监听窗口变化事件,然后触发相应的过渡动画。 另外,ShellTransition可能使用新的API,比如StartingWindow或与TaskOrganizer相关的接口。在代码中,可能涉及到Shell模块中的类,如ShellTaskOrganizer,TransitionHandler等。 需要查阅Android源码中的相关部分,比如frameworks/base/libs/WindowManager/Shell/ 目录下的代码,可能有关于过渡处理的实现。例如,在Shell中处理Task的过渡,使用Animator或SurfaceControl来管理动画效果。 总结一下,ShellTransition的流程大概是这样的:当系统检测到窗口状态变化(比如启动应用、返回桌面、分屏等),Shell模块会创建一个Transition对象,收集当前和目标状态的信息,然后应用相应的动画效果,同步各个窗口的变化,最终完成过渡,并清理资源。 可能还需要处理中断的情况,比如在动画执行过程中又有新的过渡请求,这时候需要处理动画的取消或合并。此外,性能优化也很重要,确保动画流畅不掉帧。 不过,可能我对某些细节还不清楚,比如具体的类名和调用流程。可能需要进一步查看Android开发者文档或源代码来确认这些细节。</think>Android 中的 **ShellTransition 流程**是系统级窗口过渡动画的核心机制,主要用于管理应用窗口与系统 UI(如任务切换、分屏、返回主屏等场景)之间的动态切换效果。该流程由 **SystemUI Shell 模块**(如 `WindowManagerShell`)协调,确保过渡动画的流畅性和一致性,尤其在 Android 12(Material You)及更高版本中更为重要。 --- ### **核心流程解析** 1. **触发过渡事件** 当窗口状态变化(如启动/退出应用、多任务切换、分屏操作)时,系统通过 `WindowManagerService` 检测到变更,并通知 Shell 模块(如 `ShellTaskOrganizer`)。 2. **创建 Transition 对象** Shell 创建 `Transition` 实例(如 `ChangeTransition` 或 `TaskTransition`),记录当前窗口树(`WindowContainer` 层级结构)的初始状态与目标状态。 3. **收集动画参数** - 通过 `Transition.Info` 收集参与过渡的窗口信息(如位置、尺寸、可见性)。 - 识别动画类型(如打开应用为 `OPEN`,返回桌面为 `CLOSE`)。 4. **执行动画** - **动画引擎**:使用 `SurfaceAnimator` 或 `ValueAnimator` 驱动动画,结合 `SurfaceControl` 操作窗口图层。 - **协调同步**:通过 `TransitionPlayer` 或 `RemoteAnimationRunner` 同步多个窗口的动画时序。 - **视觉效果**:应用系统预设的动画效果(如缩放、位移、透明度变化)。 5. **完成过渡** - 动画结束后,更新窗口状态(如销毁旧窗口、提交新布局)。 - 释放资源并通知 `WindowManagerService` 完成本次过渡。 --- ### **关键组件与类** - **WindowContainer** 窗口层级结构的基类(如 `Task`、`ActivityRecord`),用于追踪窗口状态。 - **Transition** 及其子类 定义过渡行为,如 `AppTransition`(应用启动/退出)、`TaskFragmentTransition`(分屏)。 - **ShellTaskOrganizer** 管理任务(Task)的 Shell 组件,处理任务切换、分屏等逻辑。 - **RemoteAnimationRunner** 跨进程通信机制,协调 SystemUI 与应用进程的动画同步。 --- ### **代码示例(简化逻辑)** ```java // Shell 模块中处理过渡的示例 public class ShellTransitionHandler { public void handleTransition(TransitionRequestInfo info) { Transition transition = new ChangeTransition(info); transition.setAnimation(new ParallelAnimation( createWindowAnimation(info.getType()), createBackgroundAnimation() )); transition.start(); } private Animator createWindowAnimation(int type) { if (type == TYPE_OPEN) { return new ScaleAnimator(0.9f, 1.0f); } else { return new AlphaAnimator(1.0f, 0.0f); } } } ``` --- ### **优化与挑战** - **性能**:依赖硬件加速(如 `SurfaceFlinger`)确保 60/90/120fps 流畅度。 - **中断处理**:若新过渡打断当前动画,需合并或取消未完成操作。 - **一致体验**:统一应用与系统 UI 的动画风格(如圆角、阴影)。 --- ### **开发者相关** - **自定义过渡**:通过 `WindowManager.LayoutParams` 或 Jetpack `WindowManager` 库调整窗口行为。 - **调试工具**:使用 `adb shell dumpsys window transitions` 查看过渡状态。 ShellTransitionAndroid 窗口系统的“粘合剂”,平衡了灵活性与性能,为用户提供无缝的交互体验。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值