android12 WindowManagerService窗口的层级计算过程

5 阅读13分钟

WindowManagerService (WMS) 通过一个基于树形结构的“窗口容器”体系来管理所有窗口的层级。其核心计算思路是:为每个窗口计算一个最终的 Z-order 值,值越大,在屏幕上显示的位置就越靠上

核心架构:基于 WindowContainer 的树形结构

Android 12 中,所有窗口元素都继承自 WindowContainer,形成了一棵严格的树。Z-order 由子节点在父容器 mChildren 列表中的位置决定,越靠近队尾,层级越高。核心层级如下:

  • RootWindowContainer:WMS 中的顶层容器,管理所有显示屏。
  • DisplayContent:代表一个物理或逻辑显示屏。
  • DisplayArea:用于管理特定功能区域(如刘海屏、放大镜)。
  • Task:代表一个任务栈。
  • ActivityRecord / WindowToken:代表一个 Activity 或一组窗口。
  • WindowState:代表一个具体的窗口。

关键参数:mBaseLayer 与 mSubLayer

1. 基础层级 (mBaseLayer)
在 WindowState 构造时由 WindowManagerPolicy.getWindowLayerLw()根据窗口类型获取 mBaseLayer。 主要分为三大类:

  • 应用窗口 (1-99) :如 TYPE_APPLICATION
  • 子窗口 (1000-1999) :依附于父窗口,如 PopupWindow。
  • 系统窗口 (2000-2999) :如状态栏、Toast。

2. 子层级 (mSubLayer)
通过 WindowManagerPolicy.getSubWindowLayerFromTypeLw() 获取 mSubLayer。 仅用于子窗口,决定其在父窗口内部的相对顺序。值为正显示在父窗口之上,为负则在之下。

//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
//WindowState构造函数
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
        WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
        int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
        PowerManagerWrapper powerManagerWrapper) {
    super(service);
    ...
    //初始化 `InputWindowHandle`,用于接收触摸和按键事件
    mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
            mActivityRecord != null
                    ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
            getDisplayId()));
    mInputWindowHandle.setOwnerPid(s.mPid);
    ...

    //子窗口(如 PopupWindow、对话框等)
    if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
        //基于**父窗口**的层级计算而来。使用 `TYPE_LAYER_MULTIPLIER` (通常为 10000)
        //放大,加上 `TYPE_LAYER_OFFSET` (通常为 1000),为子窗口在父窗口内部预留了
        //足够的层级空间
        mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        //用于决定子窗口在**父窗口内部**的相对顺序。正值在父窗口之上,负值在之下。
        mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
        mIsChildWindow = true;

        ...
    } else {
        //对于非子窗口(如 Activity 主窗口、系统窗口)
        //获取基础层级,再乘以 `TYPE_LAYER_MULTIPLIER` 并加上偏移量。
        mBaseLayer = mPolicy.getWindowLayerLw(this)
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        //`mSubLayer` 固定为 0
        mSubLayer = 0;
        mIsChildWindow = false;
        mLayoutAttached = false;
        mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
        mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
    }
    ...
    //子窗口
    if (mIsChildWindow) {
        //将子窗口添加到父窗口的子列表中,并利用 `sWindowSubLayerComparator` 
        //这个比较器来维护子窗口在父窗口内的正确 Z-order 顺序
        //WindowContainer.addChild(this, sWindowSubLayerComparator);
        parentWindow.addChild(this, sWindowSubLayerComparator);
    }

    
}


//frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
//根据窗口类型决定基础层级mBaseLayer
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
        boolean roundedCornerOverlay) {
    /如果窗口既是圆角覆盖层,又有内部系统权限,直接返回可能的最大层级
    //这确保了屏幕圆角等系统级 UI 始终显示在最顶层,不被任何应用遮挡。
    if (roundedCornerOverlay && canAddInternalSystemWindow) {
        return getMaxWindowLayer();
    }
    //应用窗口
    if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
        return APPLICATION_LAYER;
    }

    switch (type) {
        //壁纸窗口,位于所有应用窗口之下
        case TYPE_WALLPAPER:
            return  1;
        //演示屏窗口
        case TYPE_PRESENTATION:
        case TYPE_PRIVATE_PRESENTATION:
        //分屏分隔线窗口
        case TYPE_DOCK_DIVIDER:
        //快速设置对话框窗口
        case TYPE_QS_DIALOG:
        case TYPE_PHONE:
            return  3;
        //系统级搜索窗口
        case TYPE_SEARCH_BAR:
        //语音交互启动窗口,过渡占位窗口
        case TYPE_VOICE_INTERACTION_STARTING:
            return  4;
        //语音交互会话主窗口
        case TYPE_VOICE_INTERACTION:
            return  5;
        //与系统特殊手势处理相关的系统窗口类型
        case TYPE_INPUT_CONSUMER:
            return  6;
         //系统级对话框窗口
        case TYPE_SYSTEM_DIALOG:
            return  7;
        case TYPE_TOAST:
            return  8;
        case TYPE_PRIORITY_PHONE:
            return  9;
        //悬浮窗
        case TYPE_SYSTEM_ALERT:
            return  canAddInternalSystemWindow ? 13 : 10;
        //高于普通应用窗口,低于系统级悬浮窗。
        case TYPE_APPLICATION_OVERLAY:
            return  12;
        //输入法窗口
        case TYPE_INPUT_METHOD:
            return  15;
        case TYPE_INPUT_METHOD_DIALOG:
            return  16;
            //状态栏
        case TYPE_STATUS_BAR:
            return  17;
        case TYPE_STATUS_BAR_ADDITIONAL:
            return  18;
        case TYPE_NOTIFICATION_SHADE:
            return  19;
        //状态栏的子面板
        case TYPE_STATUS_BAR_SUB_PANEL:
            return  20;
        case TYPE_KEYGUARD_DIALOG:
            return  21;
        case TYPE_VOLUME_OVERLAY:
            return  22;
        case TYPE_SYSTEM_OVERLAY:
           
            return  canAddInternalSystemWindow ? 23 : 11;
        case TYPE_NAVIGATION_BAR:
            return  24;
        case TYPE_NAVIGATION_BAR_PANEL:
           
            return  25;
        case TYPE_SCREENSHOT:
            return  26;
        case TYPE_SYSTEM_ERROR:
            return  canAddInternalSystemWindow ? 27 : 10;
        case TYPE_MAGNIFICATION_OVERLAY:
            return  28;
        case TYPE_DISPLAY_OVERLAY:
            return  29;
        case TYPE_DRAG:
            return  30;
        case TYPE_ACCESSIBILITY_OVERLAY:
            return  31;
        case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
            return 32;
        case TYPE_SECURE_SYSTEM_OVERLAY:
            return  33;
        case TYPE_BOOT_PROGRESS:
            return  34;
        case TYPE_POINTER:
            // the (mouse) pointer layer
            return  35;
        default:
            return 3;
    }
}

//根据窗口类型决定子层级
default int getSubWindowLayerFromTypeLw(int type) {
    switch (type) {
        case TYPE_APPLICATION_PANEL:
        case TYPE_APPLICATION_ATTACHED_DIALOG:
            return APPLICATION_PANEL_SUBLAYER;
        case TYPE_APPLICATION_MEDIA:
            return APPLICATION_MEDIA_SUBLAYER;
        case TYPE_APPLICATION_MEDIA_OVERLAY:
            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
        case TYPE_APPLICATION_SUB_PANEL:
            return APPLICATION_SUB_PANEL_SUBLAYER;
        case TYPE_APPLICATION_ABOVE_SUB_PANEL:
            return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
    }
    return 0;
}


计算流程:插入与分配

添加窗口时,层级计算分为两步:

第一步:插入 (addChild)
当添加新窗口时,WMS 会调用父容器的 addChild 方法,根据窗口类型、应用的 Z-order 等规则,将其插入到 mChildren 列表中的正确位置

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
        int displayId, int requestUserId, InsetsState requestedVisibility,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl[] outActiveControls) {
        ...
       //创建WindowState,这个对象维护了窗口的所有状态信息
       /WindowState构造函数:
       //计算窗口的主序 (`mBaseLayer`) 和子序 (`mSubLayer`) 的初始值
       final WindowState win = new WindowState(this, session, client, token, parentWindow,
                appOp[0], attrs, viewVisibility, session.mUid, userId,
                session.mCanAddInternalSystemWindow);
       ...

        res = ADD_OKAY;
        ...
        //将窗口与 DisplayContent 关联,并设置 SurfaceControl
        win.attach();
        //将窗口注册到 WMS 的全局映射表中
        mWindowMap.put(client.asBinder(), win);
        ...
       
        boolean imMayMove = true;
         //将窗口加入所属 `WindowToken` 的窗口列表
        //将窗口作为一个节点,添加到 `WindowContainer` 层级树中。
        //`WindowContainer` 树中的父子关系和兄弟顺序,
        //由之前计算的 `mBaseLayer` 和 `mSubLayer` 决定
        win.mToken.addWindow(win);
        //根据窗口类型,决定它应该为应用窗口提供什么样的"留白区域"(Insets)
        displayPolicy.addWindowLw(win, attrs);
        //输入法窗口处理
        if (type == TYPE_INPUT_METHOD) {
            //注册 Inset → 触发布局
            displayContent.setInputMethodWindowLocked(win);
            imMayMove = false;
        } else if (type == TYPE_INPUT_METHOD_DIALOG) {
            //调整布局
            displayContent.computeImeTarget(true /* updateImeTarget */);
            imMayMove = false;
        } else {
            ...
        }

        ...

        if (imMayMove) {
            //调整布局
            displayContent.computeImeTarget(true /* updateImeTarget */);
        }

 //计算窗口的 Z-order 层级
 //实际执行的方法,是 `win` 父容器对象的实际类型(如 `DisplayContent`)所重写的版本。
// - 如果 `win` 是子窗口,其父容器通常是 `WindowState`,就会执行 `WindowState` 的 `assignChildLayers`,负责处理子窗口的相对顺序。
//-   如果 `win` 是 Activity 主窗口,其父容器可能是 `Task` 或 `ActivityRecord`,则会  执行它们的实现,负责任务或 Activity 内部的层级管理。
//-   如果 `win` 是系统窗口(如状态栏),其父容器可能是 `DisplayContent` 或其子区域(如 `AboveAppWindowContainers`),最终会由 `DisplayContent` 的复杂逻辑来统筹
        //WindowContainer.assignChildLayers()
        win.getParent().assignChildLayers();

        ...
       
    }
    ...

    return res;
}

//将窗口加入所属 `WindowToken` 的窗口列表
void addWindow(final WindowState win) {
 //如果窗口是子窗口,直接返回
//`DisplayContent` 负责管理顶级窗口的层级。子窗口的层级由其父窗口管理,
//因此不需要也不应该被直接添加到 `DisplayContent` 的 `mChildren` 列表中。
//这体现了 `WindowContainer` 树形结构的分层管理思想。
    if (win.isChildWindow()) {
        return;
    }
    //检查 `DisplayContent` 自身的 `SurfaceControl` 是否已创建。
    //如果为空,则立即创建。
    //`DisplayContent` 作为显示屏容器,也需要拥有自己的 `Surface`。这个 
    //`Surface` 是所有子窗口的“根画布”,必须先于子窗口存在。`createSurfaceControl` 
    //会向 `SurfaceFlinger` 申请一块显示内存。
    if (mSurfaceControl == null) {
        createSurfaceControl(true /* force */);
    }
    //检查 `mChildren` 列表是否已包含该窗口
    if (!mChildren.contains(win)) {
        //并使用 `mWindowComparator` 比较器将其插入到正确的位置
        addChild(win, mWindowComparator);
        //将 WMS 的 `mWindowsChanged` 标志置为 `true`,这会触
        //发 `assignWindowLayers()` 等后续操作,重新计算所有窗口的 Z-order
        mWmService.mWindowsChanged = true;
        
    }
}

//frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
//基于比较器的插入排序算法,确保 `mChildren` 列表始终保持正确的 Z-order 顺序。
protected void addChild(E child, Comparator<E> comparator) {
   //检查子节点是否已有父容器。如果 `child` 已经有父容器且当前不是“重新设置父容器”状态
   //(`!mReparenting`),则抛出异常,防止一个节点被错误地添加到多个父容器下。
   //这维护了树形结构的单一父节点约束。
    if (!child.mReparenting && child.getParent() != null) {
        throw new IllegalArgumentException("addChild: container=" + child.getName()
                + " is already a child of container=" + child.getParent().getName()
                + " can't add to container=" + getName());
    }

    int positionToAdd = -1;
    //如果提供了比较器 (`comparator`)
    if (comparator != null) {
        final int count = mChildren.size();
        //遍历现有的 `mChildren` 列表
        for (int i = 0; i < count; i++) {
            //**新子节点的优先级应该排在当前节点之前**(即层级更低,应显示在下方)。
            if (comparator.compare(child, mChildren.get(i)) < 0) {
                positionToAdd = i;
                break;
            }
        }
    }

  
    if (positionToAdd == -1) {
        //如果没找到合适的插入点(意味着新节点优先级高于或等于所有现有节点),
        //则直接添加到列表**末尾**。在 Z-order 体系中,列表末尾代表最高层级,会显示在最
        //上面。否则,插入到找到的 `positionToAdd` 位置。
        mChildren.add(child);
    } else {
       //找到第一个满足此条件的位置,记录在 `positionToAdd` 中。
       //后续节点将依次后移,为新节点腾出空间。
        mChildren.add(positionToAdd, child);
    }
  
    //在成功将子节点加入列表后,设置其父节点引用。
    //这个顺序很重要,可以避免子类在 `setParent` 过程中因尚未加入列表而产生不一致的状态  
    child.setParent(this);
}


//WindowContainer计算窗口的 Z-order 层级
//frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void assignChildLayers() {
    assignChildLayers(getSyncTransaction());
    scheduleAnimation();
}

void assignChildLayers(Transaction t) {
    int layer = 0;
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        //递归调用:先处理子节点的子节点
        wc.assignChildLayers(t);
        //只有 `needsZBoost()` 返回 `false` 的节点才会在第一轮被分配层级。
        //`layer` 从 0 开始递增,因此第一轮分配到的层级值相对较低。
        if (!wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        //第二轮:为需要 Z 提升的节点分配层级
        //只有 `needsZBoost()` 返回 `true` 的节点才会在这一轮被分配层级。
        //`layer` 继续递增,因此这些节点会获得**比第一轮所有节点都高的层级值**。
        if (wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
}


void assignLayer(Transaction t, int layer) {
    //如果 `TransitionController` 正在播放动画,则直接返回,不执行任何层级分配。
    //动画期间层级正在被动画系统动态控制(例如窗口正在缩放或移动),此时强行修改层级
    //可能会破坏动画效果或导致画面闪烁。
    if (mWmService.mAtmService.getTransitionController().isPlaying()) return;
    //**检查是否需要更新**
    //新的绝对层级值与上次记录的层级值不同,上次设置的是**相对层级**(`assignRelativeLayer`),这意味着当前需要切换到绝对层级。
    final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
    //只有当 `mSurfaceControl` 存在(窗口已有 Surface)且层级确实发生了变化时,
    //才执行更新。
    if (mSurfaceControl != null && changed) {
        //将操作委托给了 `SurfaceAnimator.setLayer`,
        //这个 `Transaction` 对象是一个包含了一系列 `Surface` 操作(如设置层级、位置、
        //大小等)的批处理容器。当所有操作都通过 `Transaction` 准备好后,WMS 会调
        //用 `Transaction.apply()` 方法,将这一批指令**一次性提交
        //给 `SurfaceFlinger`**
        setLayer(t, layer);
        //记录当前分配的层级值,用于下次变更检测。
        mLastLayer = layer;
        //清除相对层级状态,表示当前使用的是绝对层级
        mLastRelativeToLayer = null;
    }
}


//`WindowState` 为其直接子窗口(如 PopupWindow、Dialog)分配 Z-order 层级。
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
// **`TYPE_APPLICATION_MEDIA`**(层级 -2)是**底层**,通常用于视频画面的渲染,
//作为内容的背景。
// **`TYPE_APPLICATION_MEDIA_OVERLAY`**(层级 -1)位于其上方,
//通常用于显示视频控制条(如播放/暂停按钮),覆盖在视频画面之上,但仍低于 Activity 主窗口。
public void assignChildLayers(Transaction t) {
    //初始层级:`layer` 从 `PRESERVED_SURFACE_LAYER + 1` 开始
    //(`PRESERVED_SURFACE_LAYER` 通常为 0)。注释说明,如果主窗口的 Surface 被保
    //留了(如窗口关闭但 Surface 仍存在),子窗口必须显示在保留 Surface 之上。
    int layer = PRESERVED_SURFACE_LAYER + 1;
    for (int i = 0; i < mChildren.size(); i++) {
        //遍历 `mChildren` 列表。**注意**:这里 `mChildren` 中的元素
        //是 `WindowState` 类型,代表该窗口的**直接子窗口**。
        final WindowState w = mChildren.get(i);
       
        if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) {
            if (mWinAnimator.hasSurface()) {
               //“将子窗口 `w` 的层级设置为相对于父窗口的 Surface 偏移 **-2**”。
               //也就是说,无论父窗口的最终层级是多少,子窗口都会恰好显示在它下方 2 层。
                w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -2);
            } else {
              //如果父窗口还没有 Surface(例如在窗口初始化早期),则无法建立相对层级关
              //系。此时调用 **`assignLayer(t, -2)`** ,直接为子窗口分配一个绝对层级
              //值 **-2**。由于此时父窗口的 Surface 还未创建,一个相对较低的绝对层级值
              //也能达到类似的“显示在父窗口之下”的效果。
                w.assignLayer(t, -2);
            }
        } else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
            if (mWinAnimator.hasSurface()) {
             //将子窗口 `w` 的层级设置为相对于父窗口的 Surface **偏移 -1**。
             //子窗口会显示在父窗口下方 **1 层**。
                w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -1);
            } else {
            //直接为子窗口分配一个绝对层级值 **-1**。
                w.assignLayer(t, -1);
            }
        } else {
            w.assignLayer(t, layer);
        }
        //通过递归调用 `assignChildLayers(t)`,层级分配逻辑可以从树的根节点
        //一直传递到叶子节点。
        w.assignChildLayers(t);
        //分配一个递增的 `layer` 值,从 1 开始逐渐增加
        layer++;
    }
}



第二步:分配 (assignWindowLayers)
窗口插入到 mWindows 列表后,WMS会调用 DisplayContent.assignWindowLayers()。它会从底部到顶部遍历列表,根据窗口的 mBaseLayer(基础层级)和 mSubLayer(子层级),为每个窗口计算最终的 mLastLayer 值。

//frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
void assignWindowLayers(boolean setLayoutNeeded) {
    assignChildLayers(getSyncTransaction());
    if (setLayoutNeeded) {
        setLayoutNeeded();
    }
    //触发一次动画帧调度
    scheduleAnimation();
}



//`DisplayContent` 分配 Z-order 层级。
1.  **父类(`WindowContainer`)** :定义了算法骨架 `assignChildLayers(Transaction t)`,包含了通用的层级分配逻辑(如遍历子节点、分配层级)。
2.  **子类(`DisplayContent`)** :重写了该算法,在调用父类逻辑**之前**,先插入了自己特有的业务逻辑(IME 处理)。
void assignChildLayers(SurfaceControl.Transaction t) {
    //1. 先处理 IME 的特殊层级关系
    assignRelativeLayerForIme(t, false /* forceUpdate */);
  //2. 调用父类 `WindowContainer` 的通用层级分配方法。父类方法会递归遍历所有子节点,
  //按照比较器定义的顺序为每个子节点分配层级。这是一个通用的、与具体业务无关的层级分配逻辑。
    super.assignChildLayers(t);
}


//WindowContainer计算窗口的 Z-order 层级
//frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void assignChildLayers(Transaction t) {
    int layer = 0;
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        //递归调用:先处理子节点的子节点
        wc.assignChildLayers(t);
        //只有 `needsZBoost()` 返回 `false` 的节点才会在第一轮被分配层级。
        //`layer` 从 0 开始递增,因此第一轮分配到的层级值相对较低。
        if (!wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        //第二轮:为需要 Z 提升的节点分配层级
        //只有 `needsZBoost()` 返回 `true` 的节点才会在这一轮被分配层级。
        //`layer` 继续递增,因此这些节点会获得**比第一轮所有节点都高的层级值**。
        if (wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
}

void assignLayer(Transaction t, int layer) {
    //如果 `TransitionController` 正在播放动画,则直接返回,不执行任何层级分配。
    //动画期间层级正在被动画系统动态控制(例如窗口正在缩放或移动),此时强行修改层级
    //可能会破坏动画效果或导致画面闪烁。
    if (mWmService.mAtmService.getTransitionController().isPlaying()) return;
    //**检查是否需要更新**
    //新的绝对层级值与上次记录的层级值不同,上次设置的是**相对层级**(`assignRelativeLayer`),这意味着当前需要切换到绝对层级。
    final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
    //只有当 `mSurfaceControl` 存在(窗口已有 Surface)且层级确实发生了变化时,
    //才执行更新。
    if (mSurfaceControl != null && changed) {
        //将操作委托给了 `SurfaceAnimator.setLayer`,
        //这个 `Transaction` 对象是一个包含了一系列 `Surface` 操作(如设置层级、位置、
        //大小等)的批处理容器。当所有操作都通过 `Transaction` 准备好后,WMS 会调
        //用 `Transaction.apply()` 方法,将这一批指令**一次性提交
        //给 `SurfaceFlinger`**
        setLayer(t, layer);
        //记录当前分配的层级值,用于下次变更检测。
        mLastLayer = layer;
        //清除相对层级状态,表示当前使用的是绝对层级
        mLastRelativeToLayer = null;
    }
}

总的来说,通过引入 WindowContainer 树形结构,将窗口层级管理从“平铺排序”演进为“树形管理”,逻辑更清晰,也更好地支持了多窗口和复杂功能。