乐于分享
好东西不私藏

Android 14 WMS窗口层级树源码深度解析

Android 14 WMS窗口层级树源码深度解析

1. WMS窗口层级树概述

在Android系统中,WindowManagerService(WMS)是负责管理所有窗口的核心服务,而窗口层级树是WMS中用于组织和管理窗口显示结构的关键数据结构。它定义了窗口在Z轴上的顺序、布局关系以及显示层级。

1.1 窗口层级树的基本概念

在Android 14中,窗口层级树是一个以RootWindowContainer为根节点的树形结构。每个节点代表一个窗口容器,可以是窗口本身,也可以是一组窗口的容器。这个树结构不仅管理了窗口的显示顺序,还负责窗口的布局和尺寸计算。

// frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.javapublicclassRootWindowContainerextendsWindowContainerimplementsDisplayManager.DisplayListener{// The root of the device window hierarchy.privatefinal WindowManagerService mWmService;// 存储所有DisplayContent的列表,每个DisplayContent对应一个显示屏privatefinal ArrayList<DisplayContent> mDisplays = new ArrayList<>();}

从上述代码可以看出,RootWindowContainer作为窗口层级树的根节点,管理着所有显示屏的窗口内容。

1.2 窗口层级树的整体结构

Android 14的窗口层级树结构可以分为以下几个主要部分:

  1. RootWindowContainer:窗口层级树的根节点,代表整个窗口管理系统
  2. DisplayContent:代表一个显示屏,是窗口层级树中每个显示设备的容器
  3. DisplayArea:显示屏上的一个区域,用于组织窗口的布局
  4. Task/TaskDisplayArea:任务容器,用于管理属于同一任务的一组窗口
  5. WindowToken:窗口令牌,一组相关窗口的容器
  6. WindowState:代表一个具体的窗口
// 窗口层级树结构示例RootWindowContainer └── DisplayContent (主屏幕)     ├── DisplayArea.Tokens (系统窗口容器)     │   ├── WindowToken (StatusBar)     │   ├── WindowToken (NavigationBar)     │   └── WindowToken (InputMethod)     ├── TaskDisplayArea (应用窗口容器)     │   └── Task     │       └── ActivityRecord     │           └── WindowState (Activity窗口)     └── WallpaperWindowToken (壁纸窗口容器)

2. WMS窗口层级树核心数据结构

2.1 WindowContainer - 窗口容器基类

WindowContainer是窗口层级树中所有节点的基类,定义了窗口层级树的基本行为和属性。

// frameworks/base/services/core/java/com/android/server/wm/WindowContainer.javaclassWindowContainerextendsWindowContainer{// 父节点private WindowContainer mParent = null;// 子节点列表,按照Z轴顺序排列,最顶层的窗口容器位于列表尾部protectedfinal WindowList mChildren = new WindowList();// 窗口容器的名称private String mName;// 窗口容器的层级privateint mLayer;// 窗口容器的可见性privateboolean mVisible = true;}

WindowContainer类提供了窗口层级树的基本结构,包括父子关系、Z轴顺序等核心概念。

2.2 DisplayContent - 显示屏内容

DisplayContent代表一个显示屏,是窗口层级树中每个显示设备的容器。它管理着该显示屏上的所有窗口和区域。

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.javaclassDisplayContentextendsRootDisplayAreaimplementsWindowManagerPolicy.DisplayContentInfo{// 显示屏IDprivatefinalint mDisplayId;// 显示屏的区域privatefinal Rect mDisplayFrame;// 窗口放置器privatefinal WindowSurfacePlacer mSurfacePlacer;// 输入监视器privatefinal InputMonitor mInputMonitor;// 显示策略privatefinal DisplayPolicy mDisplayPolicy;}

DisplayContent负责管理单个显示屏上的所有窗口,包括布局、显示和输入处理。

2.3 WindowState - 窗口状态

WindowState代表一个具体的窗口,是窗口层级树中最底层的节点。

// frameworks/base/services/core/java/com/android/server/wm/WindowState.javaclassWindowStateextendsWindowContainerimplementsWindowManagerPolicy.WindowState{// 窗口令牌privatefinal WindowToken mToken;// 窗口属性privatefinal WindowManager.LayoutParams mAttrs;// 窗口框架privatefinal WindowFrames mWindowFrames;// 窗口是否拥有表面privateboolean mHasSurface;// 窗口是否需要布局privateboolean mLayoutNeeded;}

WindowState包含了窗口的所有状态信息,包括位置、大小、可见性等。

2.4 WindowToken - 窗口令牌

WindowToken是一组相关窗口的容器,通常用于管理具有相同父窗口或用途的一组窗口。

// frameworks/base/services/core/java/com/android/server/wm/WindowToken.javaclassWindowTokenextendsWindowContainer{// 窗口令牌类型privatefinalint mType;// 父窗口privatefinal WindowContainer mParent;// 窗口列表privatefinal ArrayList<WindowState> mWindows = new ArrayList<>();}

WindowToken在窗口层级树中充当中间节点,用于组织和管理一组相关的窗口。

3. WMS窗口层级树管理机制

3.1 窗口添加流程

窗口的添加是WMS的核心功能之一。当应用需要显示一个窗口时,它会通过ViewRootImpl向WMS请求添加一个窗口。

  1. 应用端请求添加窗口

    // ViewRootImpl.javapublicvoidsetView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId){// ...// 通过Binder调用WMS的addWindow方法    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, getHostVisibility(),         mDisplay.getDisplayId(), userId, mInsetsController.getRequestedVisibilities(),         inputChannel, mTempInsets, mTempControls);// ...}
  2. WMS处理添加窗口请求

    // WindowManagerService.javapublicintaddWindow(Session session, IWindow window, WindowManager.LayoutParams attrs,int requestedWidth, int requestedHeight, int viewVisibility, int flags,        ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,        SurfaceControl outSurfaceControl, InsetsState outInsetsState,        InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle){// ...// 创建WindowState对象final WindowState win = new WindowState(this, session, window, attrs);// ...// 将窗口添加到窗口层级树中    addWindowToToken(win, attrs);// ...}
  3. 将窗口添加到窗口层级树

    // WindowManagerService.javaprivatevoidaddWindowToToken(WindowState win, WindowManager.LayoutParams attrs){// ...// 获取或创建WindowToken    WindowToken token = getTokenForType(attrs.type, attrs.token, attrs.packageName);// ...// 将WindowState添加到WindowToken中    token.addChild(win);// ...}

3.2 窗口布局流程

窗口布局是WMS的另一个核心功能,它决定了窗口的大小和位置。

  1. 请求布局

    // ViewRootImpl.javapublicvoidrequestLayout(){if (!mHandlingLayoutInLayoutRequest) {        checkThread();        mLayoutRequested = true;        scheduleTraversals();    }}
  2. 执行布局

    // ViewRootImpl.javaprivatevoidperformTraversals(){// ...// 请求WMS重新布局窗口    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);// ...// 执行测量    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);// ...// 执行布局if (didLayout) {        performLayout(lp, mWidth, mHeight);    }// ...}
  3. WMS处理布局请求

    // WindowManagerService.javapublicintrelayoutWindow(Session session, IWindow window, WindowManager.LayoutParams attrs,int requestedWidth, int requestedHeight, int viewVisibility, int flags,        ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,        SurfaceControl outSurfaceControl, InsetsState outInsetsState,        InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle){// ...// 获取WindowState对象final WindowState win = windowForClientLocked(session, window, false);// ...// 设置请求的大小    win.setRequestedSize(requestedWidth, requestedHeight);// ...// 调整窗口参数    displayPolicy.adjustWindowParamsLw(win, attrs);// ...// 执行表面放置    mWindowPlacerLocked.performSurfacePlacement(true/* force */);// ...}
  4. 执行表面放置

    // WindowSurfacePlacer.javafinalvoidperformSurfacePlacement(boolean force){// ...do {        mTraversalScheduled = false;// 执行一次表面放置循环        performSurfacePlacementLoop();// ...    } while (mTraversalScheduled && loopCount > 0);// ...}
  5. 窗口布局计算

    // DisplayPolicy.javapublicvoidlayoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames){// ...// 获取窗口的布局参数final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);// ...// 计算窗口框架    mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,            win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,            win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,            sTmpClientFrames);// ...// 设置窗口框架    win.setFrames(sTmpClientFrames, requestedWidth, requestedHeight);}

3.3 Z轴排序机制

Z轴排序决定了窗口在垂直方向上的显示顺序,即哪个窗口位于上层,哪个窗口位于下层。

  1. Z轴层级定义

    // WindowManagerService.javaprivatestaticfinalint FIRST_APPLICATION_WINDOW = 1;privatestaticfinalint LAST_APPLICATION_WINDOW = 99;privatestaticfinalint FIRST_SYSTEM_WINDOW = 1000;privatestaticfinalint LAST_SYSTEM_WINDOW = 1999;privatestaticfinalint FIRST_SUB_WINDOW = 2000;privatestaticfinalint LAST_SUB_WINDOW = 2999;
  2. 窗口层级分配

    // WindowManagerService.javaprivatevoidassignWindowLayers(WindowState win){// ...// 根据窗口类型分配层级if (win.mAttrs.type >= FIRST_APPLICATION_WINDOW && win.mAttrs.type <= LAST_APPLICATION_WINDOW) {        layer = APPLICATION_LAYER;    } elseif (win.mAttrs.type >= FIRST_SYSTEM_WINDOW && win.mAttrs.type <= LAST_SYSTEM_WINDOW) {        layer = SYSTEM_LAYER;    } elseif (win.mAttrs.type >= FIRST_SUB_WINDOW && win.mAttrs.type <= LAST_SUB_WINDOW) {        layer = SUB_WINDOW_LAYER;    }// ...}
  3. 窗口排序

    // WindowContainer.javaprotectedvoidsortChildren(){// 按照层级排序子窗口    Collections.sort(mChildren, (lhs, rhs) -> {if (lhs.mLayer != rhs.mLayer) {return lhs.mLayer - rhs.mLayer;        }// 如果层级相同,按照添加顺序排序return lhs.mAddOrder - rhs.mAddOrder;    });}

4. 布局流程详解

4.1 布局过程概述

窗口布局是WMS的核心功能之一,它决定了窗口的大小和位置。布局过程涉及多个组件的协作,包括WMS、DisplayPolicy和WindowLayout等。

  1. 布局触发

    • 应用程序调用requestLayout()请求布局
    • WMS调用performSurfacePlacement()触发布局
  2. 布局执行

    • RootWindowContainer.performSurfacePlacement()开始布局过程
    • DisplayContent.performLayout()执行显示屏布局
    • DisplayPolicy.layoutWindowLw()计算每个窗口的布局
  3. 布局应用

    • WindowState.setFrames()应用计算出的布局
    • 窗口的位置和大小得到更新

4.2 布局算法

Android 14的窗口布局算法采用了多种策略,以确保窗口在不同屏幕尺寸和方向下都能正确显示。

  1. 测量阶段

    // WindowLayout.javapublicvoidcomputeFrames(WindowManager.LayoutParams attrs, InsetsState insets,        Rect displayCutoutSafe, Rect bounds, int windowingMode, int requestedWidth,int requestedHeight, int requestedVisibilities, Rect attachedWindowFrame,float globalScale, ClientWindowFrames outFrames){// ...// 计算窗口的可用空间int availableWidth = displayWidth - paddingLeft - paddingRight;int availableHeight = displayHeight - paddingTop - paddingBottom;// ...// 根据布局参数计算窗口大小if (widthMeasureSpec == MeasureSpec.EXACTLY) {        width = availableWidth;    } elseif (widthMeasureSpec == MeasureSpec.AT_MOST) {        width = Math.min(requestedWidth, availableWidth);    } else {        width = requestedWidth;    }// ...}
  2. 布局阶段

    // DisplayPolicy.javapublicvoidlayoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames){// ...// 获取窗口的布局参数final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);// ...// 计算窗口框架    mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,            win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,            win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,            sTmpClientFrames);// ...}

4.3 布局性能优化

为了提高布局性能,Android 14的WMS引入了多种优化策略:

  1. 增量布局

    • 只对需要布局的窗口进行计算
    • 避免不必要的全量布局
  2. 异步布局

    • 将布局计算移到后台线程
    • 减少主线程的阻塞
  3. 布局缓存

    • 缓存布局计算结果
    • 避免重复计算

5. 性能优化建议

5.1 窗口层级优化

  1. 减少窗口层级

    • 避免过多的嵌套窗口
    • 使用扁平化的窗口结构
  2. 合理使用窗口类型

    • 将窗口类型设置为合适的范围
    • 避免使用过高的窗口类型导致排序问题
  3. 控制子窗口数量

    • 限制子窗口的数量
    • 避免复杂的窗口嵌套

5.2 布局性能优化

  1. 减少布局计算

    • 避免频繁的布局请求
    • 使用固定大小窗口
  2. 优化窗口更新

    • 批量更新窗口属性
    • 减少不必要的重绘
  3. 使用硬件加速

    • 启用硬件加速
    • 使用高效的渲染管道

5.3 常见问题及解决方案

  1. 窗口闪烁问题

    • 问题:窗口显示时出现闪烁
    • 解决方案:确保窗口的正确初始化,避免多次布局
  2. 窗口布局问题

    • 问题:窗口大小或位置不正确
    • 解决方案:检查布局参数,确保正确的测量和布局过程
  3. 性能问题

    • 问题:窗口操作卡顿
    • 解决方案:优化布局过程,减少不必要的计算和重绘

6. 总结

Android 14的WMS窗口层级树是一个复杂而高效的数据结构,它负责管理Android系统中的所有窗口。通过深入理解其核心机制和数据结构,我们可以更好地优化应用程序的性能和用户体验。

本文详细分析了WMS窗口层级树的结构、管理机制和布局流程,并提供了性能优化建议和常见问题的解决方案。希望这些内容对您深入理解Android窗口管理系统有所帮助。