分屏初始化

150 阅读8分钟

分屏相关的总控制在SplitScreenController中,关于SplitScreenController的初始化参考 juejin.cn/post/753231…

libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
public SplitScreenController(Context context,
        ShellInit shellInit,
        ShellCommandHandler shellCommandHandler,
        ShellController shellController,
        ShellTaskOrganizer shellTaskOrganizer,
        SyncTransactionQueue syncQueue,
        RootTaskDisplayAreaOrganizer rootTDAOrganizer,
        DisplayController displayController,
        DisplayImeController displayImeController,
        DisplayInsetsController displayInsetsController,
        DragAndDropController dragAndDropController,
        Transitions transitions,
        TransactionPool transactionPool,
        IconProvider iconProvider,
        Optional<RecentTasksController> recentTasks,
        LaunchAdjacentController launchAdjacentController,
        Optional<WindowDecorViewModel> windowDecorViewModel,
        Optional<DesktopTasksController> desktopTasksController,
        @Nullable StageCoordinator stageCoordinator,
        MultiInstanceHelper multiInstanceHelper,
        SplitState splitState,
        ShellExecutor mainExecutor,
        Handler mainHandler) {
    mShellCommandHandler = shellCommandHandler;
    mShellController = shellController;
    mTaskOrganizer = shellTaskOrganizer;
    mSyncQueue = syncQueue;
    mContext = context;
    mLauncherApps = context.getSystemService(LauncherApps.class);
    mRootTDAOrganizer = rootTDAOrganizer;
    mMainExecutor = mainExecutor;
    mMainHandler = mainHandler;
    mDisplayController = displayController;
    mDisplayImeController = displayImeController;
    mDisplayInsetsController = displayInsetsController;
    mDragAndDropController = dragAndDropController;
    mTransitions = transitions;
    mTransactionPool = transactionPool;
    mIconProvider = iconProvider;
    mRecentTasksOptional = recentTasks;
    mLaunchAdjacentController = launchAdjacentController;
    mWindowDecorViewModel = windowDecorViewModel;
    mDesktopTasksController = desktopTasksController;
    mStageCoordinator = stageCoordinator;
    mMultiInstanceHelpher = multiInstanceHelper;
    mSplitState = splitState;
    mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
    if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
        // 添加到InitCallbacks,后面systemui会启动所有InitCallback,并调用this::onInit方法
        shellInit.addInitCallback(this::onInit, this);
    }
}

void onInit() {
    mShellCommandHandler.addDumpCallback(this::dump, this);
    mShellCommandHandler.addCommandCallback("splitscreen", mSplitScreenShellCommandHandler,
            this);
    mShellController.addKeyguardChangeListener(this);
    mShellController.addExternalInterface(ISplitScreen.DESCRIPTOR,
            this::createExternalInterface, this);
    if (mStageCoordinator == null) {
        // TODO: Multi-display
        // 创建StageCoordinator
        mStageCoordinator = createStageCoordinator();
    }
    if (mDragAndDropController != null) {
        mDragAndDropController.setSplitScreenController(this);
    }
    mWindowDecorViewModel.ifPresent(viewModel -> viewModel.setSplitScreenController(this));
    mDesktopTasksController.ifPresent(controller -> controller.setSplitScreenController(this));
}

protected StageCoordinator createStageCoordinator() {
    return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
            mTaskOrganizer, mDisplayController, mDisplayImeController,
            mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
            mMainExecutor, mMainHandler, mRecentTasksOptional, mLaunchAdjacentController,
            mWindowDecorViewModel, mSplitState);
}

libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
        ShellTaskOrganizer taskOrganizer, DisplayController displayController,
        DisplayImeController displayImeController,
        DisplayInsetsController displayInsetsController, Transitions transitions,
        TransactionPool transactionPool, IconProvider iconProvider, ShellExecutor mainExecutor,
        Handler mainHandler, Optional<RecentTasksController> recentTasks,
        LaunchAdjacentController launchAdjacentController,
        Optional<WindowDecorViewModel> windowDecorViewModel, SplitState splitState) {
    mContext = context;
    mDisplayId = displayId;
    mSyncQueue = syncQueue;
    mTaskOrganizer = taskOrganizer;
    mLogger = new SplitscreenEventLogger();
    mMainExecutor = mainExecutor;
    mMainHandler = mainHandler;
    mRecentTasks = recentTasks;
    mLaunchAdjacentController = launchAdjacentController;
    mWindowDecorViewModel = windowDecorViewModel;
    mSplitState = splitState;
    // 创建分屏顶层task,listener传的是this,也就是StageCoordinator
    taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);

    ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Creating main/side root task");
    if (enableFlexibleSplit()) {
       ......
    } else {
        // 创建mMainStage  mSideStage
        mMainStage = new StageTaskListener(
                mContext,
                mTaskOrganizer,
                mDisplayId,
                this /*stageListenerCallbacks*/,
                mSyncQueue,
                iconProvider,
                mWindowDecorViewModel, STAGE_TYPE_MAIN);
        mSideStage = new StageTaskListener(
                mContext,
                mTaskOrganizer,
                mDisplayId,
                this /*stageListenerCallbacks*/,
                mSyncQueue,
                iconProvider,
                mWindowDecorViewModel, STAGE_TYPE_SIDE);
    }
    mDisplayController = displayController;
    mDisplayImeController = displayImeController;
    mDisplayInsetsController = displayInsetsController;
    mTransactionPool = transactionPool;
    final DeviceStateManager deviceStateManager =
            mContext.getSystemService(DeviceStateManager.class);
    deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
            new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged));
    mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
            this::onTransitionAnimationComplete, this);
    mDisplayController.addDisplayWindowListener(this);
    // 添加到transitions 的handler列表
    transitions.addHandler(this);
}
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
        StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
        IconProvider iconProvider,
        Optional<WindowDecorViewModel> windowDecorViewModel, int id) {
    mContext = context;
    mCallbacks = callbacks;
    mSyncQueue = syncQueue;
    mIconProvider = iconProvider;
    mWindowDecorViewModel = windowDecorViewModel;
    // 创建roottask 类型是WINDOWING_MODE_MULTI_WINDOW
    taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
    mId = id;
}
libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
public void createRootTask(int displayId, int windowingMode, TaskListener listener) {
    createRootTask(displayId, windowingMode, listener, false /* removeWithTaskOrganizer */);
}


public void createRootTask(int displayId, int windowingMode, TaskListener listener,
        boolean removeWithTaskOrganizer) {
    ProtoLog.v(WM_SHELL_TASK_ORG, "createRootTask() displayId=%d winMode=%d listener=%s" ,
            displayId, windowingMode, listener.toString());
            // 新创建了binder作为token
    final IBinder cookie = new Binder();
    setPendingLaunchCookieListener(cookie, listener);
    super.createRootTask(displayId, windowingMode, cookie, removeWithTaskOrganizer);
}

public void setPendingLaunchCookieListener(IBinder cookie, TaskListener listener) {
    synchronized (mLock) {
        //将cookie和TaskListener保存到map中,后面监听task状态变化时候需要
        mLaunchCookieToListener.put(cookie, listener);
    }
}

core/java/android/window/TaskOrganizer.java
public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie,
        boolean removeWithTaskOrganizer) {
    try {
        mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie,
                removeWithTaskOrganizer);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

frameworks/base/services/core/java/com/android/server/wm/TaskOrganizerController.java
public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie,
            boolean removeWithTaskOrganizer) {
        enforceTaskPermission("createRootTask()");
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
                createRootTask(display, windowingMode, launchCookie, removeWithTaskOrganizer);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
    
    
 Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie,
            boolean removeWithTaskOrganizer) {
        // We want to defer the task appear signal until the task is fully created and attached to
        // to the hierarchy so that the complete starting configuration is in the task info we send
        // over to the organizer.
        final Task task = new Task.Builder(mService)
                // 传过来的是WINDOWING_MODE_MULTI_WINDOW
                .setWindowingMode(windowingMode)
                .setIntent(new Intent())
                // CreatedByOrganizer为true
                .setCreatedByOrganizer(true)
                .setDeferTaskAppear(true)
                // 设置了launchCookie,是从systemui传过来的binder token
                .setLaunchCookie(launchCookie)
                // parent是DefaultTaskDisplayArea
                .setParent(display.getDefaultTaskDisplayArea())
                .setRemoveWithTaskOrganizer(removeWithTaskOrganizer)
                .build();
        task.setDeferTaskAppear(false /* deferTaskAppear */);
        return task;
    }

task创建完成会回调ITaskOrganizer的对应方法比如onTaskAppeared、onTaskVanished、onTaskInfoChanged。

WMshell端的ITaskOrganizer注册流程

在WMShellComponent初始化列表中有ShellTaskOrganizer的初始化,参考 juejin.cn/post/753231… 最后mInitCallbacks添加的部分

libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
protected ShellTaskOrganizer(ShellInit shellInit,
        ShellCommandHandler shellCommandHandler,
        ITaskOrganizerController taskOrganizerController,
        @Nullable CompatUIHandler compatUI,
        Optional<UnfoldAnimationController> unfoldAnimationController,
        Optional<RecentTasksController> recentTasks,
        ShellExecutor mainExecutor) {
    super(taskOrganizerController, mainExecutor);
    mShellCommandHandler = shellCommandHandler;
    mCompatUI = compatUI;
    mRecentTasks = recentTasks;
    mUnfoldAnimationController = unfoldAnimationController.orElse(null);
    if (shellInit != null) {
         // 加入到mInitCallbacks,并调用onInit
        shellInit.addInitCallback(this::onInit, this);
    }
}


private void onInit() {
    android.util.Log.d("xmsysui","ShellTaskOrganizer onInit = ", new Exception());
    mShellCommandHandler.addDumpCallback(this::dump, this);
    if (mCompatUI != null) {
        mCompatUI.setCallback(compatUIEvent -> {
            switch(compatUIEvent.getEventId()) {
                case SIZE_COMPAT_RESTART_BUTTON_APPEARED:
                    onSizeCompatRestartButtonAppeared(compatUIEvent.asType());
                    break;
                case SIZE_COMPAT_RESTART_BUTTON_CLICKED:
                    onSizeCompatRestartButtonClicked(compatUIEvent.asType());
                    break;
                default:

            }
        });
    }
    registerOrganizer();
}

public List<TaskAppearedInfo> registerOrganizer() {
    synchronized (mLock) {
        ProtoLog.v(WM_SHELL_TASK_ORG, "Registering organizer");
        // 调用父类TaskOrganizer.java 的register
        final List<TaskAppearedInfo> taskInfos = super.registerOrganizer();
        for (int i = 0; i < taskInfos.size(); i++) {
            final TaskAppearedInfo info = taskInfos.get(i);
            ProtoLog.v(WM_SHELL_TASK_ORG, "Existing task: id=%d component=%s",
                    info.getTaskInfo().taskId, info.getTaskInfo().baseIntent);
            onTaskAppeared(info);
        }
        return taskInfos;
    }
}

core/java/android/window/TaskOrganizer.java
public List<TaskAppearedInfo> registerOrganizer() {
    try {
        //将本地的mInterface传递给systemserver
        return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList();
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
    @Override
    public void addStartingWindow(StartingWindowInfo windowInfo) {
        mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo));
    }

    @Override
    public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) {
        mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(removalInfo));
    }

    @Override
    public void copySplashScreenView(int taskId)  {
        mExecutor.execute(() -> TaskOrganizer.this.copySplashScreenView(taskId));
    }

    @Override
    public void onAppSplashScreenViewRemoved(int taskId) {
        mExecutor.execute(() -> TaskOrganizer.this.onAppSplashScreenViewRemoved(taskId));
    }

    @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
        mExecutor.execute(() -> TaskOrganizer.this.onTaskAppeared(taskInfo, leash));
    }

    @Override
    public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
        mExecutor.execute(() -> TaskOrganizer.this.onTaskVanished(taskInfo));
    }

    @Override
    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
        mExecutor.execute(() -> TaskOrganizer.this.onTaskInfoChanged(info));
    }

    @Override
    public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
        mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info));
    }

    @Override
    public void onImeDrawnOnTask(int taskId) {
        mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId));
    }
};

将mInterface binder对象传递给systemserver,systemserver保存该对象,当有task状态变化,splashscreen逻辑时调用systemui进程。

分析onTaskAppeared
@Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
        mExecutor.execute(() -> TaskOrganizer.this.onTaskAppeared(taskInfo, leash));
    }

调用子类

libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
    if (leash != null) {
        leash.setUnreleasedWarningCallSite("ShellTaskOrganizer.onTaskAppeared");
    }
    synchronized (mLock) {
        onTaskAppeared(new TaskAppearedInfo(taskInfo, leash));
    }
}

private void onTaskAppeared(TaskAppearedInfo info) {
    final int taskId = info.getTaskInfo().taskId;
    mTasks.put(taskId, info);
    // 获取taskListener,就是上面mainStage sideStage的时候,随创建rootTask一起放到map中的StageTaskListener
    final TaskListener listener =
            getTaskListener(info.getTaskInfo(), true /*removeLaunchCookieIfNeeded*/);
    ProtoLog.v(WM_SHELL_TASK_ORG, "Task appeared taskId=%d listener=%s", taskId, listener);
    if (listener != null) {
        // 调用onTaskAppeared回调
        listener.onTaskAppeared(info.getTaskInfo(), info.getLeash());
    }
    if (mUnfoldAnimationController != null) {
        mUnfoldAnimationController.onTaskAppeared(info.getTaskInfo(), info.getLeash());
    }

    if (info.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
        ProtoLog.v(WM_SHELL_TASK_ORG, "Adding overlay to home task");
        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        t.setLayer(mHomeTaskOverlayContainer, Integer.MAX_VALUE);
        t.reparent(mHomeTaskOverlayContainer, info.getLeash());
        t.apply();
    }

    notifyLocusVisibilityIfNeeded(info.getTaskInfo());
    notifyCompatUI(info.getTaskInfo(), listener);
    mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo()));
}


private TaskListener getTaskListener(RunningTaskInfo runningTaskInfo,
        boolean removeLaunchCookieIfNeeded) {

    final int taskId = runningTaskInfo.taskId;
    TaskListener listener;

    // First priority goes to listener that might be pending for this task.
    // 获取launchCookies,就是创建rootTask时 new出来的binder
    final ArrayList<IBinder> launchCookies = runningTaskInfo.launchCookies;
    for (int i = launchCookies.size() - 1; i >= 0; --i) {
        final IBinder cookie = launchCookies.get(i);
        //从map中获取listener
        listener = mLaunchCookieToListener.get(cookie);
        if (listener == null) continue;

        if (removeLaunchCookieIfNeeded) {
            // Remove the cookie and add the listener.
            // 从map中移除,并加到mTaskListeners中 taskid->listener
            mLaunchCookieToListener.remove(cookie);
            //加到mTaskListeners中 taskid->listener
            mTaskListeners.put(taskId, listener);
        }
        return listener;
    }

    // Next priority goes to taskId specific listeners.
    listener = mTaskListeners.get(taskId);
    if (listener != null) return listener;

    // Next priority goes to the listener listening to its parent.
    if (runningTaskInfo.hasParentTask()) {
        listener = mTaskListeners.get(runningTaskInfo.parentTaskId);
        if (listener != null) return listener;
    }

    // Next we try type specific listeners.
    final int taskListenerType = taskInfoToTaskListenerType(runningTaskInfo);
    return mTaskListeners.get(taskListenerType);
}

根据创建rootTask时候new出来的binder,到本地mLaunchCookieToListener中查找对应的TaskListener,如果找到了就把mLaunchCookieToListener的记录删除,添加到mTaskListeners,这里面保存的是taskid->TaskListener的对应关系,然后调用TaskListener的onTaskAppeared

开启分屏前的层级结构树

                  ├─ DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  ├─ Task=40 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │  └─ ActivityRecord{64283180 u0 com.android.gallery3d/.app.GalleryActivity t40} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │     └─ 4645f6d com.android.gallery3d/com.android.gallery3d.app.GalleryActivity type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  ├─ Task=1 type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │  └─ Task=39 type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │     └─ ActivityRecord{49798294 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t39} type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │        └─ d535140 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  ├─ Task=41 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │  └─ ActivityRecord{161909326 u0 com.android.messaging/.ui.conversationlist.ConversationListActivity t41} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │     └─ cc7d7e6 com.android.messaging/com.android.messaging.ui.conversationlist.ConversationListActivity type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  └─ Task=3 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │     ├─ Task=4 type=undefined mode=MULTI-WINDOW override-mode=MULTI-WINDOW requested-bounds=[0,975][1080,1920] bounds=[0,975][1080,1920]
                  │     └─ Task=5 type=undefined mode=MULTI-WINDOW override-mode=MULTI-WINDOW requested-bounds=[0,0][1080,945] bounds=[0,0][1080,945]
                  └─ Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                     └─ WallpaperWindowToken{cc6e4fc token=android.os.Binder@d3f51ef} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                        └─ f62bf63 com.android.systemui.wallpapers.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]

开启分屏后的层级结构树

                  ├─ DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  ├─ Task=3 type=standard mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │  │  ├─ Task=4 type=standard mode=MULTI-WINDOW override-mode=MULTI-WINDOW requested-bounds=[0,975][1080,1920] bounds=[0,975][1080,1920]
                  │  │  │  └─ Task=40 type=standard mode=MULTI-WINDOW override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,975][1080,1920]
                  │  │  │     └─ ActivityRecord{64283180 u0 com.android.gallery3d/.app.GalleryActivity t40} type=standard mode=MULTI-WINDOW override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,975][1080,1920]
                  │  │  │        └─ 4645f6d com.android.gallery3d/com.android.gallery3d.app.GalleryActivity type=standard mode=MULTI-WINDOW override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,975][1080,1920]
                  │  │  └─ Task=5 type=standard mode=MULTI-WINDOW override-mode=MULTI-WINDOW requested-bounds=[0,0][1080,945] bounds=[0,0][1080,945]
                  │  │     └─ Task=41 type=standard mode=MULTI-WINDOW override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,945]
                  │  │        └─ ActivityRecord{161909326 u0 com.android.messaging/.ui.conversationlist.ConversationListActivity t41} type=standard mode=MULTI-WINDOW override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,945]
                  │  │           └─ cc7d7e6 com.android.messaging/com.android.messaging.ui.conversationlist.ConversationListActivity type=standard mode=MULTI-WINDOW override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,945]
                  │  └─ Task=1 type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │     └─ Task=39 type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │        └─ ActivityRecord{49798294 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t39} type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  │           └─ d535140 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                  └─ Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                     └─ WallpaperWindowToken{cc6e4fc token=android.os.Binder@d3f51ef} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]
                        └─ f62bf63 com.android.systemui.wallpapers.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,1920]

可以看到task=3 task=4 task=5就是上面SplitScreenController初始化时创建的rootTask,4和5都是挂在3下面的,这三个开启分屏前都是放在DefaultTaskDisplayArea的孩子的底部,开启分屏后把task=40挂到task=4下面,task=41挂到task=5下面,并且把task=3移动到top位置置顶。 上面的代码StageCoordinator创建task=3时,传的WINDOWING_MODE_FULLSCREEN,但是上面的结构树看task=3的mode=fullscreen,应该是分屏逻辑里面有地方重新设置了。