第 23 章:窗口系统 Android 窗口系统是一套多层架构,涵盖原生合成服务(SurfaceFlinger)、Java 框架服务(WindowManagerService),以及负责编排动画与功能 UI 的展示库(WM Shell)。本章对窗口管理层进行全面分析 —— 该策略引擎位于申请屏幕空间的应用与负责向显示器绘制像素的合成器之间。第 13 章(图形与渲染流水线)介绍了缓冲区如何从应用经 HWUI 流转至 SurfaceFlinger。本章介绍其上层逻辑:窗口如何被创建、跟踪、组织为层级结构、通过转场执行动画,以及如何在多显示器与多种窗口模式下完成管理。配套的三份深度报告(参见 23.11 节)包含 100 小节深度解析;本章提供理解该报告所需的架构基础。23.1 窗口管理架构23.1.1 架构总览窗口管理系统划分为四个独立层级,各层级职责清晰分离:应用进程(ViewRootImpl + WindowManager) WindowManagerService(策略引擎) ActivityTaskManagerService(任务生命周期) RootWindowContainer(层级根节点) TransitionController(转场编排) WindowOrganizerController(调度管理器) ShellTaskOrganizer(任务 Surface 控制) Transitions(动画播放器) ShellController(功能注册器) SurfaceFlinger(合成器) InputFlinger(输入分发)核心要点:全部三层 Java 层(应用、WM Core、WM Shell)均可直接向 SurfaceFlinger 下发SurfaceControl.Transaction命令。这并非严格流水线,而是协作模型:WM Core 设定策略,Shell 负责展示效果,二者均向合成器推送 Surface 操作。23.1.2 WindowManagerServiceWindowManagerService(WMS)是窗口系统的核心策略引擎。源码路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javaAndroid 17 代码树中该类代码超 11500 行,是 Android 框架中体量最大的类之一。WMS 继承IWindowManager.Stub,实现Watchdog.Monitor与WindowManagerPolicy.WindowManagerFuncs接口:public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {WMS 职责:窗口生命周期管理:通过IWindowSession完成窗口的添加、移除、重布局焦点管理:决定哪个窗口接收输入焦点,包含 5 种更新模式:UPDATE_FOCUS_NORMAL、UPDATE_FOCUS_WILL_ASSIGN_LAYERS、UPDATE_FOCUS_PLACING_SURFACES、UPDATE_FOCUS_WILL_PLACE_SURFACES、UPDATE_FOCUS_REMOVING_FOCUS策略执行:窗口类型权限、安全内容标记、悬浮窗限制Surface 同步:全局锁mGlobalLock保护全部窗口状态,与 ActivityTaskManagerService 共享显示器配置:DPI 覆盖、强制缩放模式、显示器设置动画协调:窗口动画缩放系数、转场超时关键常量定义运行边界:static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000; // 2秒 static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // 2小时单动画时长上限为TransitionAnimation.MAX_ANIMATION_DURATION,在WindowState.applyAnimationLocked()通过restrictDuration()导入生效,不属于 WMS 自身字段。WMS 持有关键子系统控制器引用:mDisplayAreaPolicyProvider:控制每块显示器上 DisplayArea 层级如何构建mWindowTracing / mTransitionTracer:调试基础设施mConstants:通过 WindowManagerConstants 实现运行时可配置参数23.1.3 WindowContainer 层级窗口系统将所有窗口相关对象建模为WindowContainer节点树。每个节点维护父引用、按 Z 序排列的子节点列表,并且与 SurfaceFlinger 层树中的SurfaceControl一一映射。源码文件:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java(代码超 3800 行)class WindowContainerE extends WindowContainer extends ConfigurationContainerE implements ComparableWindowContainer, Animatable { private WindowContainerWindowContainer mParent = null; protected final ArrayListE mChildren = new ArrayListE(); protected SurfaceControl mSurfaceControl; protected final SurfaceAnimator mSurfaceAnimator; final TransitionController mTransitionController; }WindowContainer 核心属性:子节点按 Z 序排序:mChildren列表维护 Z 序,最顶层子元素位于列表尾部(索引最大)。常量POSITION_TOP(Integer.MAX_VALUE)、POSITION_BOTTOM(Integer.MIN_VALUE)用于显式指定层级。Surface 一一映射:mSurfaceControl对应 SurfaceFlinger 层树中的本节点。任何层级变更(重设父节点、重排序)都会生成对应的SurfaceControl.Transaction。通过 leash 执行动画:mSurfaceAnimator管理独立的SurfaceControl(称为 leash),动画期间插入在本节点与其父节点之间。所有子节点重挂载至 leash,以此对整棵子树做变换动画。同步状态机:mSyncState标记当前容器是否参与 BLAST 同步组,取值:SYNC_STATE_NONE、SYNC_STATE_WAITING_FOR_DRAW、SYNC_STATE_READY。配置传播:继承ConfigurationContainer,配置变更(旋转、密度、窗口模式)会向下级树节点逐级传递。23.1.4 完整类继承层级下图展示从WindowContainer向下到具体叶子类型的完整继承关系:普通显示器从根到叶子的层级结构:RootWindowContainer └── DisplayContent (display 0) └── DisplayArea.Root ├── DisplayArea (HideDisplayCutout) │ ├── DisplayArea (OneHanded) │ │ ├── DisplayArea (Magnification) │ │ │ ├── TaskDisplayArea (DefaultTaskDisplayArea) │ │ │ │ ├── Task (root task) │ │ │ │ │ ├── Task (leaf task) │ │ │ │ │ │ ├── ActivityRecord │ │ │ │ │ │ │ └── WindowState (main window) │ │ │ │ │ │ │ └── WindowState (sub-window) │ │ │ │ │ │ └── ActivityRecord │ │ │ │ │ └── Task (leaf task) │ │ │ │ └── Task (root task - PiP) │ │ │ └── WindowToken (TYPE_WALLPAPER) │ │ │ └── WindowState (wallpaper) │ │ └── WindowToken (TYPE_STATUS_BAR) │ │ └── WindowState (status bar) │ └── DisplayArea (AppZoomOut) ├── ImeContainer │ └── WindowToken (TYPE_INPUT_METHOD) │ └── WindowState (IME) ├── WindowToken (TYPE_NAVIGATION_BAR) │ └── WindowState (nav bar) └── WindowToken (TYPE_NOTIFICATION_SHADE) └── WindowState (shade)23.1.5 WindowStateWindowState代表服务端单个窗口。继承WindowContainerWindowState,其子节点为子窗口(TYPE_APPLICATION_PANEL、TYPE_APPLICATION_MEDIA等)。源码文件:frameworks/base/services/core/java/com/android/server/wm/WindowState.java(代码超 6400 行)class WindowState extends WindowContainerWindowState implements WindowManagerPolicy.WindowState, InputTarget, InsetsControlTarget {WindowState 实现三个关键接口:WindowManagerPolicy.WindowState:窗口属性策略查询InputTarget:输入分发目标InsetsControlTarget:Insets 动画控制关键字段:字段类型用途mSessionSession与客户端进程的 Binder 连接mAttrsWindowManager.LayoutParams窗口类型、标志位、软输入模式mViewVisibilityint客户端请求的可见性(VISIBLE/INVISIBLE/GONE)mWindowFramesWindowFrames计算得到的框架、显示框架、内容框架mRequestedWidth/Heightint客户端请求尺寸mGlobalScalefloat兼容性缩放系数mInsetsSourceProvidersSparseArray该窗口向其他窗口提供的 InsetsmWinAnimatorWindowStateAnimator旧版动画状态23.1.6 DisplayContentDisplayContent代表窗口层级中的一块逻辑显示器。继承链:RootDisplayArea→DisplayArea.Dimmable→DisplayArea→WindowContainer。源码文件:frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java(代码超 7700 行)class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo { final int mDisplayId; @Nullable String mCurrentUniqueDisplayId; private SurfaceControl mOverlayLayer; private SurfaceControl mInputOverlayLayer; private final ImeContainer mImeWindowsContainer; int mMinSizeOfResizeableTaskDp; }DisplayContent 维护若干特殊 Surface 层:mOverlayLayer:始终置顶 Surface(严格模式闪烁、放大悬浮层)mInputOverlayLayer:输入相关悬浮 SurfacemPointerEventDispatcherOverlayLayer:接收显示器上全部指针输入mA11yOverlayLayer:无障碍悬浮 Surface每个 DisplayContent 会创建独立的InsetsStateController管理系统栏 Insets、独立InputMonitor做输入分发、独立DisplayFrames用于布局计算。23.1.7 RootWindowContainerRootWindowContainer是窗口层级的绝对根节点。是 WindowManagerService 的直接子节点,持有全部 DisplayContent 实例。源码文件:frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java主要职责:performSurfacePlacement():主布局流程,计算窗口位置并推送 Surface 事务updateFocusedWindowLocked():跨显示器确定全局焦点窗口管理显示器接入 / 断开时的增删逻辑将 Intent 与 Activity 路由至对应显示器23.1.8 Surface 放置周期窗口布局由RootWindowContainer.performSurfacePlacement()驱动,循环执行:常量LAYOUT_REPEAT_THRESHOLD(4) 限制单次放置周期内布局重复执行最大次数,防止布局变更不断触发新布局造成死循环。23.1.9 WMS 内部数据结构WindowManagerService 维护多组核心集合,实现窗口快速查找与生命周期管理:// 活跃客户端Session(每个连接进程一个) final ArraySetSession mSessions = new ArraySet(); // 快速查找:IWindow binder令牌 → WindowState final HashMapIBinder, WindowState mWindowMap = new HashMap(); // 快速查找:InputWindowHandle令牌 → WindowState final HashMapIBinder, WindowState mInputToWindowMap = new HashMap(); // 当前正在调整大小的窗口(事务完成后通知客户端) final ArrayListWindowState mResizingWindows = new ArrayList(); // 框架发生变更待处理窗口 final ArrayListWindowState mFrameChangingWindows = new ArrayList(); // 需要销毁Surface的窗口 final ArrayListWindowState mDestroySurface = new ArrayList(); // 紧急:内存不足时强制移除窗口 final ArrayListWindowState mForceRemoves = new ArrayList(); // "全部窗口绘制完成"事件回调 final ArrayMapWindowContainer?, Message mWaitingForDrawnCallbacks = new ArrayMap(); // 隐藏非系统悬浮窗的窗口(FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) private ArrayListWindowState mHidingNonSystemOverlayWindows = new ArrayList(); // 每个输入令牌对应的按键拦截信息 final MapIBinder, KeyInterceptionInfo mKeyInterceptionInfoForToken = Collections.synchronizedMap(new ArrayMap()); // IME显示器策略缓存(不加锁读取) volatile MapInteger, Integer mDisplayImePolicyCache = Collections.unmodifiableMap(new ArrayMap());mGlobalLock(WindowManagerGlobalLock)是 WMS 与 ActivityTaskManagerService 共享的核心同步原语。所有窗口层级修改操作必须持有该锁。23.1.10 窗口 Session每一个创建窗口的应用进程都会通过IWindowSession与 WMS 建立 Session。Session 是按进程划分的 Binder 连接,提供以下 API:添加窗口(addToDisplayAsUser)移除窗口(remove)重布局(尺寸 / 位置变更)(relayout)绘制完成(finishDrawing)窗口位置更新输入事件分发设置调用流程:23.1.11 全局锁与线程安全WindowManagerGlobalLock(mGlobalLock)是 system server 中竞争非常激烈的锁。保护:全部 WindowContainer 层级操作窗口状态变更(可见性、焦点、配置)Surface 事务准备显示器配置变更WMS 与 ATMS 共享这把锁,避免跨服务操作发生死锁。动画系统使用独立SurfaceAnimationThread执行动画回调,避免帧回调期间持有mGlobalLock。WMS 使用多种机制降低锁竞争:Volatile 缓存:mDisplayImePolicyCache为 volatile Map,无需加锁即可读Handler 投递:需要锁但非紧急操作投递至WindowManagerService.HHandler只读快照:InsetsState、TransitionInfo、TaskInfo为快照对象,可脱离锁传递到其他线程 / 进程23.1.12 BLASTSyncEngine源码文件:frameworks/base/services/core/java/com/android/server/wm/BLASTSyncEngine.javaBLASTSyncEngine 是同步机制,保证参与转场的全部窗口完成重绘后,再执行转场动画。名称来源于 BLAST(Buffer Layered Ahead of SurfaceFlinger Transaction),该缓冲区投递机制替代旧版 BufferQueue 消费端模型。同步引擎 5 步执行逻辑(源码文档):打开同步集合:startSyncSet(TransactionReadyListener),返回 ID添加参与者:addToSyncSet(id, WindowContainer)注册容器执行变更:配置变更、重设父节点、可见性变更标记就绪:setReady(id),标记所有变更已完成等待绘制:每个参与者重绘;全部完成后触发transactionReady同步方法:METHOD_UNDEFINED = -1; // 未指定方法 METHOD_NONE = 0; // App内部绘制,仅上报完成状态 METHOD_BLAST = 1; // App发送缓冲区,同步统一应用并行同步系统防止依赖环:如果同步 B 依赖同步 A,某个容器已经被 B 监听,又加入 A,则容器会从 B 迁移至 A,不会产生循环依赖。23.1.13 DisplayContent 内部实现Android17 代码树中 DisplayContent 代码超 7700 行,维护显示器完整状态。除前面介绍外,核心内部字段:// 显示器度量与配置 int mInitialDisplayWidth, mInitialDisplayHeight; int mInitialDisplayDensity; float mInitialPhysicalXDpi, mInitialPhysicalYDpi; DisplayCutout mInitialDisplayCutout; RoundedCorners mInitialRoundedCorners; DisplayShape mInitialDisplayShape; // 可覆盖度量(adb shell wm size/density) int mBaseDisplayWidth, mBaseDisplayHeight; int mBaseDisplayDensity; boolean mIsSizeForced, mIsDensityForced; // 显示器策略与旋转 final DisplayPolicy mDisplayPolicy; final DisplayRotation mDisplayRotation; DisplayFrames mDisplayFrames; // Token注册表(IBinder → WindowToken) private final HashMapIBinder, WindowToken mTokenMap = new HashMap(); // 系统手势排除区域 private final Region mSystemGestureExclusion = new Region(); private int mSystemGestureExclusionLimit; // 避让保留区域(PiP避让等场景) SetRect mRestrictedKeepClearAreas = new ArraySet(); SetRect mUnrestrictedKeepClearAreas = new ArraySet(); // 布局状态 private boolean mLayoutNeeded; int pendingLayoutChanges; boolean mWaitingForConfig; // PiP任务控制器 final PinnedTaskController mPinnedTaskController; // DisplayArea策略(控制DisplayArea层级) final DisplayAreaPolicy mDisplayAreaPolicy; // 内容录制(屏幕捕获/镜像) @Nullable ContentRecorder mContentRecorder;mDisplayAreaPolicy十分关键:由 WMS 配置的DisplayAreaPolicy.Provider创建,决定当前显示器的 DisplayArea 层级结构。不同设备类型可提供不同策略。显示器通过mDisplayRotation跟踪旋转,维护旋转相关缓存:mDisplayCutoutCache:刘海几何mRoundedCornerCache:圆角几何mPrivacyIndicatorBoundsCache:隐私指示器边界mDisplayShapeCache:显示器外形缓存使用RotationCache,每次旋转变更不会重复计算几何,仅旋转真正变化时重新计算。23.2 WM Shell 库23.2.1 Shell 与 Core:架构拆分窗口系统分为两大部分:维度WM CoreWM Shell代码路径frameworks/base/services/core/.../server/wm/frameworks/base/libs/WindowManager/Shell/运行进程System server(WM 主线程)System server(SystemUI / Shell 线程)角色策略引擎:决定要做什么展示引擎:决定长什么样子API 对外暴露System server 内部通过 AIDL 向 SystemUI、Launcher 导出窗口访问方式直接操作 WindowState/TaskTaskOrganizer 回调、SurfaceControl动画职责触发转场、管理同步接收 TransitionInfo,执行 Surface 动画拆分目的:允许 OEM 与系统组件(SystemUI、Launcher)自定义窗口行为,无需修改核心 WM 策略。WM Core 表达意图(“该任务进入 PiP”),Shell 决定展示效果(“使用这条曲线动画滑动到该角落”)。23.2.2 Shell 目录结构Shell 库按功能模块组织:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/ ├── ShellTaskOrganizer.java — 任务生命周期中心监听器 ├── RootTaskDisplayAreaOrganizer.java — DisplayArea管理 ├── RootDisplayAreaOrganizer.java — RootDisplayArea控制 ├── WindowManagerShellWrapper.java — WMS API包装器 ├── dagger/ — 依赖注入模块 │ ├── WMShellModule.java — 手机特有Provider │ ├── WMShellBaseModule.java — 通用Provider │ ├── WMShellConcurrencyModule.java — 线程配置 │ ├── TvWMShellModule.java — TV设备特有Provider │ ├── WMComponent.java — Dagger组件定义 │ └── WMSingleton.java — 作用域注解 ├── transition/ — 转场动画系统 │ ├── Transitions.java — 转场主播放器 │ ├── DefaultTransitionHandler.java — 默认动画 │ ├── MixedTransitionHandler.java — 跨功能转场 │ └── RemoteTransitionHandler.java — Launcher远程转场 ├── splitscreen/ — 分屏功能 │ ├── StageCoordinator.java — 分屏布局管理 │ ├── SplitScreenController.java — API对外层 │ └── SplitScreenTransitions.java — 分屏专属动画 ├── pip/ — 画中画PiP │ ├── PipTaskOrganizer.java — PiP任务管理 │ ├── PipTransition.java — PiP转场处理器 │ └── PipAnimationController.java — PiP动画逻辑 ├── bubbles/ — 气泡通知 │ ├── BubbleController.java — 气泡生命周期 │ ├── BubbleStackView.java — 气泡UI │ └── BubbleTransitions.java — 气泡动画 ├── desktopmode/ — 桌面窗口模式 │ ├── DesktopTasksController.kt — 桌面任务管理 │ ├── DesktopTasksLimiter.kt — 任务数量限制 │ └── WindowDragTransitionHandler.kt — 拖拽移动 ├── freeform/ — 自由窗口模式 │ ├── FreeformTaskListener.java — 自由窗口任务事件 │ └── FreeformTaskTransitionHandler.java — 自由窗口动画 ├── back/ — 预测返回手势 │ ├── BackAnimationController.java — 返回手势处理 │ └── CrossTaskBackAnimation.java — 跨任务返回动画 ├── windowdecor/ — 窗口装饰(标题栏) ├── onehanded/ — 单手模式 ├── unfold/ — 折叠屏展开动画 ├── recents/ — 最近任务集成 ├── fullscreen/ — 全屏任务监听器 ├── keyguard/ — 锁屏转场处理器 ├── common/ — 通用工具类 ├── sysui/ — SystemUI集成 ├── animation/ — 动画工具 └── protolog/ — ProtoLog配置23.2.3 ShellTaskOrganizerShellTaskOrganizer是 Shell 接收 WM Core 任务生命周期事件的中枢。继承TaskOrganizer,根据窗口模式将事件分发给注册的监听器。源码文件:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java监听器类型系统将任务路由到对应功能模块:TASK_LISTENER_TYPE_FULLSCREEN→ FullscreenTaskListenerTASK_LISTENER_TYPE_MULTI_WINDOW→ StageCoordinator(分屏)TASK_LISTENER_TYPE_PIP→ PipTaskOrganizerTASK_LISTENER_TYPE_FREEFORM→ FreeformTaskListenerTASK_LISTENER_TYPE_DESKTOP_MODE→ DesktopTasksController当 WM Core 修改任务窗口模式,ShellTaskOrganizer 自动将任务重新路由至对应监听器。例如进入 PiP 时,任务管理由全屏监听器移交至 PipTaskOrganizer。23.2.4 依赖注入架构Shell 使用 Dagger2 做依赖注入,模块分层:源码说明:WMShellBaseModule.java:全设备通用组件(ShellTaskOrganizer、Transitions、DisplayController、SyncTransactionQueue)WMShellModule.java:手机平板组件(手机 PiP 实现、Bubbles、桌面模式、分屏)TvWMShellModule.java:TV 组件(TV 端 PiP,无 Bubbles)WMShellConcurrencyModule.java:线程基础设施@WMSingleton作用域注解保证 ShellTaskOrganizer、Transitions 等组件在 Shell 组件内为单例:@WMSingleton @Component(modules = { WMShellBaseModule.class, WMShellConcurrencyModule.class, WMShellModule.class, // TV设备替换为TvWMShellModule ShellBackAnimationModule.class, PipModule.class, PinnedLayerModule.class, }) public interface WMComponent { ... }设备差异化通过替换设备专属模块实现。TV 设备使用 TvWMShellModule 替代 WMShellModule,提供 TV 专属 PiP 实现,完全移除 Bubbles。23.2.5 Shell 通信模型Shell 与外部组件多通道通信:同进程 Shell ↔ WM CoreShell 直接调用 WM Core API(例如TaskOrganizer.applyTransaction()),二者运行在同一个 system server 进程。WM Core 通过 organizer 回调通知 Shell(TaskOrganizer.onTaskAppeared()、ITransitionPlayer.onTransitionReady())。跨线程通过 Handler 投递。同进程 Shell ↔ SystemUISystemUI 在自身进程中加载 Dagger Shell 组件。Shell 通过 Dagger 注入对外暴露接口(Pip、SplitScreen、Bubbles),直接 Java 方法调用,带线程注解@ExternalThread、@ShellMainThread。跨进程 Shell ↔ LauncherLauncher 通过 AIDL Binder 接口通信(IShellTransitions、ISplitScreen、IBackAnimation等)。Shell 通过ExternalInterfaceBinder模式提供 Binder 实现。调用从 Binder 线程分发到 Shell 主线程。23.2.6 线程模型Shell 为多线程架构,显式线程注解,基于 Executor 分发。源码文件:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java@ShellMainThread是 Shell 组件主执行线程,优先级同 SurfaceFlinger、RenderThread,保证窗口管理操作不会被低优先级任务抢占。线程契约:Shell 组件运行于@ShellMainThreadSystemUI 调用 Shell 通过@ExternalMainThreadExecutor 投递到 Shell 线程Launcher AIDL 调用同样分发至 Shell 线程需要精准帧时序的动画运行于@ShellAnimationThread重任务(截图、持久化)运行于@ShellBackgroundThread配置开关enableShellMainThread()决定创建独立 Shell 主线程,还是复用 SysUI 主线程:public static boolean enableShellMainThread(Context context) { return context.getResources().getBoolean(R.bool.config_enableShellMainThread); }消息队列监控阈值投递、分发均为 30ms,调试版本检测线程阻塞:private static final int MSGQ_SLOW_DELIVERY_THRESHOLD_MS = 30; private static final int MSGQ_SLOW_DISPATCH_THRESHOLD_MS = 30;23.3 转场系统23.3.1 概览:从旧 AppTransition 到 Shell Transitions转场系统管理窗口变更(打开、关闭、大小调整、旋转)对应的动画。Android 从旧版 AppTransition 演进为 Shell Transitions 架构:旧架构中 WM Core 既要做策略决策,又要执行动画;新架构 WM Core 收集参与窗口,Shell 负责驱动动画。ENABLE_SHELL_TRANSITIONS = true开启 Shell 转场,作为主流路径。优势:Shell 可以编排复杂多窗口动画(例如同时进入分屏的两个任务),旧系统无法实现。23.3.2 TransitionController(WM Core 侧)源码文件:frameworks/base/services/core/java/com/android/server/wm/TransitionController.java(代码超 2200 行)TransitionController 在 WM Core 侧负责转场收集与同步阶段。Javadoc 核心说明:“同一时间,仅允许一个转场作为主收集器。但收集分为两个阶段:(1) 执行 WM 变更并记录参与容器;(2) 等待参与容器就绪(例如重绘内容)。