窗口加入了哪棵树
窗口加入了哪棵树
WMS 接受窗口后,WindowState 不会进入一张扁平列表。普通 Activity 窗口沿 RootWindowContainer、DisplayContent、TaskDisplayArea、Task 和 ActivityRecord 形成逻辑父链; 这棵树负责归属与策略,不等同于 SurfaceFlinger 最终合成的 Layer 树。
逻辑容器树与 Surface 层级必须分开
| 常见误解 | 正确理解 |
|---|---|
| WMS 只有一层“窗口列表” | 窗口挂在多级容器树上,Task、ActivityRecord 都参与归属 |
| 容器树就是 Surface 层级 | 容器树是逻辑归属,Surface 层级是合成侧的另一棵树 |
把 WindowState 放进正确的容器,系统才能回答“这个窗口属于哪个任务、在哪个屏、和谁同层”。容器树管逻辑,SurfaceControl 管画面,两棵树最终在合成时对齐。
典型容器路径
逐步解释:
- ① RootWindowContainer:WMS 容器树的根,
mRoot在 WMS 构造时创建(WindowManagerService.java:1216)。 - ② DisplayContent:一台显示器的逻辑容器,持有该显示的 token 表和输入监视器。
- ③ TaskDisplayArea:应用任务所在区域,分屏时两侧 Stage 也属于它。
- ④ Task:一个任务,管理其中的 ActivityRecord,是分屏的最小容器单元。
- ⑤ ActivityRecord:继承自 WindowToken,是应用窗口的归属凭证和父容器。
- ⑥ WindowState:具体窗口,作为叶子挂在 ActivityRecord 下。
对应的 ASCII 层级:
RootWindowContainer
└── DisplayContent
└── TaskDisplayArea
└── Task
└── ActivityRecord (WindowToken)
└── WindowStatetoken 是“入场券”
加窗时 WMS 通过 DisplayContent.getWindowToken()(DisplayContent.java:1428,内部查 mTokenMap)找到归属凭证;应用窗口的 token 就是 ActivityRecord。找到后 win.mToken.addWindow(win)(WindowManagerService.java:1763)把窗口作为子节点挂进 token。
WindowToken.addWindow()(WindowToken.java:304)内部调用 addChild(win, mWindowComparator)(WindowToken.java:322),按比较器插入子列表,Z-order 雏形由此形成。
源码证据:继承链
阅读目标:确认每层容器的继承关系,证明树形结构不是文档虚构。
| 类 | 行号 | 继承 |
|---|---|---|
RootWindowContainer | 171 | extends WindowContainer<DisplayContent> |
DisplayContent | 283 | extends RootDisplayArea |
TaskDisplayArea | 74 | extends DisplayArea<WindowContainer> |
TaskFragment | 124 | extends WindowContainer<WindowContainer> |
Task | 222 | extends TaskFragment |
ActivityRecord | 417 | extends WindowToken |
WindowToken | 62 | extends WindowContainer<WindowState> |
WindowState | 270 | extends WindowContainer<WindowState> |
这段证据证明: 从根到叶子全是 WindowContainer 子类,窗口确实在“容器树”里,而不是平铺的列表。
逻辑树 ≠ Surface 树
容器树回答“谁拥有窗口”;合成侧还有一棵 Layer 树,由 WindowToken、Task 等容器的 SurfaceControl 组成。窗口变化时 WMS 提交事务调整 Layer 层级,两棵树最终对应,但它们是两套状态。分屏、leash 和动画都在这一层产生复杂结构,详见窗口容器专题与SurfaceControl 与 Transition。
源码入口
源码基准:android-14.0.0_r75。
以下文件默认位于 frameworks/base/services/core/java/com/android/server/wm/,表中省略该前缀:
| 文件 | 关键位置 | 作用 |
|---|---|---|
RootWindowContainer.java | 171 行 class RootWindowContainer | 容器树根 |
DisplayContent.java | 283 行 class DisplayContent;1428 行 getWindowToken() | 显示器容器与 token 表 |
TaskDisplayArea.java | 74 行 class TaskDisplayArea | 应用任务区域 |
Task.java | 222 行 class Task extends TaskFragment | 任务容器 |
ActivityRecord.java | 417 行 final class ActivityRecord extends WindowToken | 应用 token 容器 |
WindowToken.java | 62 行 class WindowToken;304 行 addWindow();322 行 addChild(win, mWindowComparator) | 窗口父容器与入树 |
WindowState.java | 270 行 class WindowState | 窗口记录 |
WindowManagerService.java | 1216 行 mRoot = new RootWindowContainer(this);1763 行 win.mToken.addWindow(win) | 根创建与入树入口 |