当前位置: 首页 > news >正文

AOSP 13 分屏源码分析

AOSP 13 分屏源码分析

本文档基于 AOSP 13 源码,梳理系统级分屏(Split Screen)的架构、核心类、进入/退出流程及调试方法。

1. 概述

AOSP 13 的分屏实现已从传统 SystemUI View 迁移到WM Shell(WindowManager Shell)

  • SystemUI:托管 Shell 进程、桥接 Launcher,不包含分屏核心 UI 逻辑
  • WM Shell:Stage 管理、分割线、窗口 bounds、过渡动画
  • Launcher3 Quickstep:分屏选择 UI、动画、跨进程调用 Shell
  • system_server:Task 树、WINDOWING_MODE_MULTI_WINDOW、应用WindowContainerTransaction

注意:SystemUI 中的SplitShade*SplitClockView通知栏分屏布局,与多窗口分屏无关。
WindowManager/Jetpack/下的SplitPairRule属于Activity Embedding(应用内分屏),与系统分屏是两套机制。


2. 整体架构

system_server

WM Shell

SystemUI

Launcher3 Quickstep

用户触发

ISplitScreen AIDL

WindowContainerTransaction

最近任务、长按图标

Taskbar 拖拽

键盘快捷键

RecentsView

SplitSelectStateController

SystemUiProxy

SystemUIService

WMShell

OverviewProxyService

SplitScreenController

StageCoordinator

MainStage + SideStage

SplitLayout + DividerView

TaskOrganizerController

WindowOrganizerController

层级职责
Launcher3分屏选择 UI、动画、调用ISplitScreen.startTasks()
SystemUI启动 WM Shell,把ISplitScreenBinder 传给 Launcher
WM ShellStage 管理、分割线、窗口 bounds、过渡动画
system_serverTask 树、WINDOWING_MODE_MULTI_WINDOW、应用 WCT

3. 核心目录

路径内容
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顶层入口,实现ISplitScreenAIDL
StageCoordinatorsplitscreen/StageCoordinator.java核心编排器:WCT 构建、进入/退出、Stage 协调
MainStagesplitscreen/MainStage.java主 Stage,默认 launch 目标
SideStagesplitscreen/SideStage.java副 Stage,用户显式 pin 的任务
StageTaskListenersplitscreen/StageTaskListener.java通过ShellTaskOrganizer创建MULTI_WINDOWroot task
SplitLayoutcommon/split/SplitLayout.java计算 bounds、分割线位置、拖拽 dismiss
DividerViewcommon/split/DividerView.java分割线触摸(拖动/双击)
SplitWindowManagercommon/split/SplitWindowManager.java托管TYPE_DOCK_DIVIDER窗口
SplitScreenTransitionssplitscreen/SplitScreenTransitions.java分屏过渡动画
DragAndDropControllerdraganddrop/DragAndDropController.java拖拽进入分屏

5.2 Launcher 层

文件职责
SplitSelectStateControllerutil/SplitSelectStateController.java分屏选择状态机,记录第一个/第二个 App
RecentsViewviews/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 进程启动,间接启动 WMShell
WMShellwmshell/WMShell.javaShell 生命周期桥接(唤醒、全屏退出)
SystemUIInitializerSystemUIInitializer.java构建WMComponent,注入 SplitScreen

5.4 system_server 层

文件职责
TaskOrganizerControllerserver/wm/TaskOrganizerController.javaShell task organizer IPC
WindowOrganizerControllerserver/wm/WindowOrganizerController.java应用 WCT(reparent、bounds、launch)
TaskDisplayAreaserver/wm/TaskDisplayArea.java创建 multi-window root task
RecentTasksserver/wm/RecentTasks.java分屏对分组显示在最近任务

6. 跨进程 API:ISplitScreen.aidl

Launcher 与 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.aidl


7. 进入分屏流程

7.1 触发方式

方式入口
最近任务菜单TaskShortcutFactoryTaskView.initiateSplitSelect()
Overview 卡片 Split 按钮RecentsView.initiateSplitSelect(TaskView)
桌面/All Apps 长按SplitShortcut.ktSplitScreenSelectState
Taskbar 拖拽DragAndDropControllerDragAndDropPolicy
键盘快捷键SplitWithKeyboardShortcutController
重新启动已有分屏对GroupedTaskView.launchTasks()
通知拖拽DragAndDropController同一套流程
ADB 调试SplitScreenShellCommandHandlercmd splitscreen

7.2 两 App 选择流程(最常见)

Step 1 — 选第一个 App
RecentsView.initiateSplitSelect() → SplitSelectStateController.setInitialTaskSelect() → Launcher 进入 SplitScreenSelectState(显示第一个 App 占位 UI)
Step 2 — 选第二个 App
RecentsView.confirmSplitSelect() → SplitSelectStateController.launchSplitTasks() → launchTasks(taskId1, intent1, taskId2, intent2, stagePosition, ...)
Step 3 — Launcher → Shell
SystemUiProxy.startTasks(taskId1, options1, taskId2, options2, splitPosition, splitRatio, remoteTransition, instanceId) → ISplitScreen.startTasks() [Binder 跨进程]
Step 4 — Shell 构建 WCT

StageCoordinator.startTasks()核心逻辑:

  1. setSideStagePosition(splitPosition, wct)— 设置 SideStage 位置(上/左 或 下/右)
  2. 第一个 task → SideStage:addActivityOptions(options1, mSideStage)+wct.startTask(taskId1, options1)
  3. startWithTask()处理第二个 task:
    • mMainStage.activate(wct, false)— 激活 MainStage
    • mSplitLayout.setDivideRatio(splitRatio)— 设置分割比例
    • updateWindowBounds(mSplitLayout, wct)— 计算各 Stage bounds
    • 第二个 task → MainStage:addActivityOptions(mainOptions, mMainStage)+wct.startTask(mainTaskId, mainOptions)
    • SplitScreenTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_PAIR_OPEN, ...)
Step 5 — system_server 应用 WCT
WindowOrganizerController.applyTransaction(wct) → Task reparent 到 WINDOWING_MODE_MULTI_WINDOW root → TaskOrganizerController 回调 Shell(ShellTaskOrganizer)
Step 6 — 完成进入

StageCoordinator.finishEnterSplitScreen()

  1. mSplitLayout.init()— 初始化 bounds
  2. setDividerVisibility(true, t)— 显示分割线
  3. updateSurfaceBounds()— 更新 Surface bounds
  4. updateRecentTasksSplitPair()— 注册分屏对到 RecentTasks

7.3 拖拽进入分屏

用户拖拽 App 图标 → DragAndDropController 显示 DragLayout(分屏区域) → DragAndDropPolicy 解析目标(左/右/上/下) → SplitScreenController.startIntent() / startTask() → StageCoordinator.prepareEnterSplitScreen() + launch

7.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子任务进入 PiP
EXIT_REASON_FULLSCREEN_SHORTCUT全屏快捷键
EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP锁屏 show-on-top
EXIT_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 ↔ SplitScreenSelectState

10. 调试方法

10.1 ADB 命令

adb shell cmd splitscreenhelp

10.2 Logcat 过滤

adb logcat-sStageCoordinator SplitScreenController SplitSelectStateController

10.3 排查优先级

问题类型优先查看
分屏行为、WCTStageCoordinator.java
用户入口、动画SplitSelectStateController.java
分割线交互SplitLayout.java+DividerView.java
Task 树策略TaskOrganizerController.java/WindowOrganizerController.java
Launcher 绑定SystemUiProxy.java+TouchInteractionService.java

11. 关键源码索引

功能文件关键方法
启动两个 taskStageCoordinator.javastartTasks()
完成进入分屏StageCoordinator.javafinishEnterSplitScreen()
准备进入分屏StageCoordinator.javaprepareEnterSplitScreen()
Launcher 发起分屏SplitSelectStateController.javalaunchSplitTasks()/launchTasks()
跨进程调用SystemUiProxy.javastartTasks()
分屏 API 定义ISplitScreen.aidlstartTasks(),exitSplitScreen()
布局计算SplitLayout.javainit(),setDivideRatio()
分割线 UIDividerView.java触摸 drag / double-tap
Shell 托管WMShell.javainitSplitScreen()
http://www.jsqmd.com/news/1105862/

相关文章:

  • 国内洗发水OEM/控油去屑洗发水代工/草本洗发水代工哪个源头厂家好?
  • # 03. 让 Agent 更聪明:System Prompt 的分层设计
  • 《传世无双》2026年7月最新官网下载:新手全阶段副本挑战指南
  • AI率爆表怎么办?10款AI智能降重工具实测(含免费降ai率工具)真实避坑指南
  • 深圳钣金外壳定制厂家产品优势
  • 从“能跑“到“能打“:我把Shell脚本踩过的坑,攒成了这篇避坑指南
  • AI工程化中Harness性能优化实战与调优方法论
  • LangChain 调用 Qwen 与 Ollama 的环境变量笔记
  • 从0到1:企业级AI项目迭代日记 Vol.58|一个工单解决的事,不值得等一个发版周期
  • JWT与Session+Cookie认证方案选型实战指南
  • 等保测评核心:高危漏洞、高危端口与弱口令的实战防护指南
  • 编程学习工程化:让服务解释编译错误而不是代写答案
  • 无法使用dbeaver、navicat连接opengauss
  • 华为HCCDA-AI认证题库解析与AI开发实战指南
  • 若依(RuoYi)管理系统取消登录验证完整指南
  • 【单片机毕业设计】基于 STM32 的红外测温报警阈值控制系统设计,基于 GY906 的便携式多点温度采集监测装置开发(014701)
  • 抖音下载器终极指南:5分钟掌握免费批量下载技巧
  • PCF8591与PIC18F2682的I2C通信与混合信号处理实践
  • 模型评测体系:平均分高不代表线上好用
  • KMS_VL_ALL_AIO:5分钟完成Windows和Office永久激活的终极指南
  • 第7篇:数据主权架构的TCO模型:如何向CFO证明“数据不动”更省钱?
  • 工程化工作流 系统设计:工具调用要先定义权限和状态
  • 自动化查询优化评测:平均耗时下降不代表可以上线
  • 第2篇:从“数据集中治理”到“数据原位治理”:DISC架构的治理哲学
  • Python 科学计算仿真系统:三层递进式性能优化实战 NVIDIA GTX 1050 Ti (4GB) + Intel Core i7 (12 逻辑核)
  • 多源像素时序融合渲染,增量网格迭代空间实景
  • Linux 内核调优:不要把所有性能问题都甩给参数
  • Moneta亿汇:从公开信息出发,分析产品理解成本与客户支持
  • QKeyMapper:基于Windows输入拦截与虚拟设备模拟的跨平台输入重映射架构解析
  • 小批量定制非标双叠自锁垫圈,会拖延项目交付吗?