
AOSP 13 分屏源码分析本文档基于 AOSP 13 源码梳理系统级分屏Split Screen的架构、核心类、进入/退出流程及调试方法。1. 概述AOSP 13 的分屏实现已从传统 SystemUI View 迁移到WM ShellWindowManager Shell。SystemUI托管 Shell 进程、桥接 Launcher不包含分屏核心 UI 逻辑WM ShellStage 管理、分割线、窗口 bounds、过渡动画Launcher3 Quickstep分屏选择 UI、动画、跨进程调用 Shellsystem_serverTask 树、WINDOWING_MODE_MULTI_WINDOW、应用WindowContainerTransaction注意SystemUI 中的SplitShade*、SplitClockView是通知栏分屏布局与多窗口分屏无关。WindowManager/Jetpack/下的SplitPairRule属于Activity Embedding应用内分屏与系统分屏是两套机制。2. 整体架构system_serverWM ShellSystemUILauncher3 Quickstep用户触发ISplitScreen AIDLWindowContainerTransaction最近任务、长按图标Taskbar 拖拽键盘快捷键RecentsViewSplitSelectStateControllerSystemUiProxySystemUIServiceWMShellOverviewProxyServiceSplitScreenControllerStageCoordinatorMainStage SideStageSplitLayout DividerViewTaskOrganizerControllerWindowOrganizerController层级职责Launcher3分屏选择 UI、动画、调用ISplitScreen.startTasks()SystemUI启动 WM Shell把ISplitScreenBinder 传给 LauncherWM ShellStage 管理、分割线、窗口 bounds、过渡动画system_serverTask 树、WINDOWING_MODE_MULTI_WINDOW、应用 WCT3. 核心目录路径内容frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/分屏核心逻辑frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/分割线、布局计算frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/拖拽进入分屏packages/apps/Launcher3/quickstep/最近任务分屏 UI 与状态机frameworks/base/services/core/java/com/android/server/wm/Task/Window 策略frameworks/base/packages/SystemUI/src/com/android/systemui/wmshell/Shell 生命周期托管4. Task 层级模型StageCoordinator定义了分屏的核心规则SideStage 有子任务→ 分屏才算激活MainStage 有子任务→ 仅在 Coordinator 激活时MainStage 与 SideStage 都可见→ 分割线才显示两个 Stage 放在同一个single-top root task下实际窗口树结构Display └── Split Root Task (single-top, mRootTaskInfo) ├── MainStage root (WINDOWING_MODE_MULTI_WINDOW) ← 默认启动目标 │ └── App Task ├── SideStage root (WINDOWING_MODE_MULTI_WINDOW) ← 用户显式选中的任务 │ └── App Task └── Divider (TYPE_DOCK_DIVIDER, DividerView)启动时通过ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN指定任务进入哪个 Stage。5. 关键类职责5.1 WM Shell 层类文件职责SplitScreenControllersplitscreen/SplitScreenController.java顶层入口实现ISplitScreenAIDLStageCoordinatorsplitscreen/StageCoordinator.java核心编排器WCT 构建、进入/退出、Stage 协调MainStagesplitscreen/MainStage.java主 Stage默认 launch 目标SideStagesplitscreen/SideStage.java副 Stage用户显式 pin 的任务StageTaskListenersplitscreen/StageTaskListener.java通过ShellTaskOrganizer创建MULTI_WINDOWroot taskSplitLayoutcommon/split/SplitLayout.java计算 bounds、分割线位置、拖拽 dismissDividerViewcommon/split/DividerView.java分割线触摸拖动/双击SplitWindowManagercommon/split/SplitWindowManager.java托管TYPE_DOCK_DIVIDER窗口SplitScreenTransitionssplitscreen/SplitScreenTransitions.java分屏过渡动画DragAndDropControllerdraganddrop/DragAndDropController.java拖拽进入分屏5.2 Launcher 层类文件职责SplitSelectStateControllerutil/SplitSelectStateController.java分屏选择状态机记录第一个/第二个 AppRecentsViewviews/RecentsView.javainitiateSplitSelect()/confirmSplitSelect()SystemUiProxySystemUiProxy.java封装ISplitScreen跨进程调用SplitScreenSelectStateuioverrides/states/SplitScreenSelectState.javaOverview 中选第二个 App 时的 UI 状态SplitShortcut.ktsplitscreen/SplitShortcut.kt桌面/All Apps 长按分屏GroupedTaskViewviews/GroupedTaskView.java重新启动已有分屏对TopTaskTrackerTopTaskTracker.java实现ISplitScreenListener跟踪 Stage 任务5.3 SystemUI 层类文件职责SystemUIServiceSystemUIService.javaSystemUI 进程启动间接启动 WMShellWMShellwmshell/WMShell.javaShell 生命周期桥接唤醒、全屏退出SystemUIInitializerSystemUIInitializer.java构建WMComponent注入 SplitScreen5.4 system_server 层类文件职责TaskOrganizerControllerserver/wm/TaskOrganizerController.javaShell task organizer IPCWindowOrganizerControllerserver/wm/WindowOrganizerController.java应用 WCTreparent、bounds、launchTaskDisplayAreaserver/wm/TaskDisplayArea.java创建 multi-window root taskRecentTasksserver/wm/RecentTasks.java分屏对分组显示在最近任务6. 跨进程 APIISplitScreen.aidlLauncher 与 Shell 通过 AIDL 通信Binder key 为KEY_EXTRA_SHELL_SPLIT_SCREEN。核心方法// 同时启动两个 task 进入分屏onewayvoidstartTasks(inttaskId1,inBundleoptions1,inttaskId2,inBundleoptions2,intsplitPosition,floatsplitRatio,inRemoteTransitionremoteTransition,inInstanceIdinstanceId);// 启动 Intent TaskonewayvoidstartIntentAndTask(inPendingIntentpendingIntent,inBundleoptions1,inttaskId,inBundleoptions2,intsidePosition,floatsplitRatio,inRemoteTransitionremoteTransition,inInstanceIdinstanceId);// 退出分屏onewayvoidexitSplitScreen(inttoTopTaskId);// 注册监听onewayvoidregisterSplitScreenListener(inISplitScreenListenerlistener);文件路径frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl7. 进入分屏流程7.1 触发方式方式入口最近任务菜单TaskShortcutFactory→TaskView.initiateSplitSelect()Overview 卡片 Split 按钮RecentsView.initiateSplitSelect(TaskView)桌面/All Apps 长按SplitShortcut.kt→SplitScreenSelectStateTaskbar 拖拽DragAndDropController→DragAndDropPolicy键盘快捷键SplitWithKeyboardShortcutController重新启动已有分屏对GroupedTaskView.launchTasks()通知拖拽DragAndDropController同一套流程ADB 调试SplitScreenShellCommandHandlercmd splitscreen7.2 两 App 选择流程最常见Step 1 — 选第一个 AppRecentsView.initiateSplitSelect() → SplitSelectStateController.setInitialTaskSelect() → Launcher 进入 SplitScreenSelectState显示第一个 App 占位 UIStep 2 — 选第二个 AppRecentsView.confirmSplitSelect() → SplitSelectStateController.launchSplitTasks() → launchTasks(taskId1, intent1, taskId2, intent2, stagePosition, ...)Step 3 — Launcher → ShellSystemUiProxy.startTasks(taskId1, options1, taskId2, options2, splitPosition, splitRatio, remoteTransition, instanceId) → ISplitScreen.startTasks() [Binder 跨进程]Step 4 — Shell 构建 WCTStageCoordinator.startTasks()核心逻辑setSideStagePosition(splitPosition, wct)— 设置 SideStage 位置上/左 或 下/右第一个 task → SideStageaddActivityOptions(options1, mSideStage)wct.startTask(taskId1, options1)startWithTask()处理第二个 taskmMainStage.activate(wct, false)— 激活 MainStagemSplitLayout.setDivideRatio(splitRatio)— 设置分割比例updateWindowBounds(mSplitLayout, wct)— 计算各 Stage bounds第二个 task → MainStageaddActivityOptions(mainOptions, mMainStage)wct.startTask(mainTaskId, mainOptions)SplitScreenTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_PAIR_OPEN, ...)Step 5 — system_server 应用 WCTWindowOrganizerController.applyTransaction(wct) → Task reparent 到 WINDOWING_MODE_MULTI_WINDOW root → TaskOrganizerController 回调 ShellShellTaskOrganizerStep 6 — 完成进入StageCoordinator.finishEnterSplitScreen()mSplitLayout.init()— 初始化 boundssetDividerVisibility(true, t)— 显示分割线updateSurfaceBounds()— 更新 Surface boundsupdateRecentTasksSplitPair()— 注册分屏对到 RecentTasks7.3 拖拽进入分屏用户拖拽 App 图标 → DragAndDropController 显示 DragLayout分屏区域 → DragAndDropPolicy 解析目标左/右/上/下 → SplitScreenController.startIntent() / startTask() → StageCoordinator.prepareEnterSplitScreen() launch7.4 将已有 Task 移入分屏SplitScreenController.enterSplitScreen(taskId, leftOrTop) → moveToStage() → prepareEnterSplitScreen(wct, taskInfo, startPosition)8. 退出分屏常见退出原因SplitScreenController定义常量含义EXIT_REASON_DRAG_DIVIDER拖动分割线超过阈值 dismiss 一侧EXIT_REASON_RETURN_HOME返回桌面EXIT_REASON_APP_FINISHEDApp 结束EXIT_REASON_DEVICE_FOLDED折叠屏折叠EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOWApp 不支持多窗口EXIT_REASON_CHILD_TASK_ENTER_PIP子任务进入 PiPEXIT_REASON_FULLSCREEN_SHORTCUT全屏快捷键EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP锁屏 show-on-topEXIT_REASON_ROOT_TASK_VANISHEDRoot task 消失9. 类关系图SplitScreen (interface) ↑ implemented by SplitScreenController ├── StageCoordinator (core logic) │ ├── MainStage extends StageTaskListener │ ├── SideStage extends StageTaskListener │ ├── SplitLayout implements SplitLayoutHandler │ │ └── SplitWindowManager → DividerView │ └── SplitScreenTransitions ├── DragAndDropController (drag-to-split) └── ISplitScreenImpl (AIDL stub) StageTaskListener └── ShellTaskOrganizer.createRootTask(MULTI_WINDOW) ↔ TaskOrganizerController (system_server) Launcher side: SplitSelectStateController → SystemUiProxy → ISplitScreen TopTaskTracker extends ISplitScreenListener RecentsView ↔ SplitSelectStateController ↔ SplitScreenSelectState10. 调试方法10.1 ADB 命令adb shell cmd splitscreenhelp10.2 Logcat 过滤adb logcat-sStageCoordinator SplitScreenController SplitSelectStateController10.3 排查优先级问题类型优先查看分屏行为、WCTStageCoordinator.java用户入口、动画SplitSelectStateController.java分割线交互SplitLayout.javaDividerView.javaTask 树策略TaskOrganizerController.java/WindowOrganizerController.javaLauncher 绑定SystemUiProxy.javaTouchInteractionService.java11. 关键源码索引功能文件关键方法启动两个 taskStageCoordinator.javastartTasks()完成进入分屏StageCoordinator.javafinishEnterSplitScreen()准备进入分屏StageCoordinator.javaprepareEnterSplitScreen()Launcher 发起分屏SplitSelectStateController.javalaunchSplitTasks()/launchTasks()跨进程调用SystemUiProxy.javastartTasks()分屏 API 定义ISplitScreen.aidlstartTasks(),exitSplitScreen()布局计算SplitLayout.javainit(),setDivideRatio()分割线 UIDividerView.java触摸 drag / double-tapShell 托管WMShell.javainitSplitScreen()