AOSP15 WMS/AMS系统开发 - WindowManagerService addWindow详解

基于 AOSP 15 (Android 15) 源码分析

源码根目录: ~/aosp15/


目录

  • [1. 整体架构概览](#1. 整体架构概览 "#1-%E6%95%B4%E4%BD%93%E6%9E%B6%E6%9E%84%E6%A6%82%E8%A7%88")
  • [2. 完整调用链路](#2. 完整调用链路 "#2-%E5%AE%8C%E6%95%B4%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF")
  • [3. 客户端侧详细流程](#3. 客户端侧详细流程 "#3-%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BE%A7%E8%AF%A6%E7%BB%86%E6%B5%81%E7%A8%8B")
    • [3.1 WindowManagerImpl.addView()](#3.1 WindowManagerImpl.addView() "#31-windowmanagerimpladdview")
    • [3.2 WindowManagerGlobal.addView()](#3.2 WindowManagerGlobal.addView() "#32-windowmanagerglobaladdview")
    • [3.3 ViewRootImpl.setView()](#3.3 ViewRootImpl.setView() "#33-viewrootimplsetview")
    • [3.4 IWindowSession.addToDisplayAsUser()](#3.4 IWindowSession.addToDisplayAsUser() "#34-iwindowsessionaddtodisplayasuser")
  • [4. Binder IPC 跨进程调用](#4. Binder IPC 跨进程调用 "#4-binder-ipc-%E8%B7%A8%E8%BF%9B%E7%A8%8B%E8%B0%83%E7%94%A8")
  • [5. 服务端侧详细流程](#5. 服务端侧详细流程 "#5-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E4%BE%A7%E8%AF%A6%E7%BB%86%E6%B5%81%E7%A8%8B")
    • [5.1 Session.addToDisplayAsUser()](#5.1 Session.addToDisplayAsUser() "#51-sessionaddtodisplayasuser")
    • [5.2 WindowManagerService.addWindow()](#5.2 WindowManagerService.addWindow() "#52-windowmanagerserviceaddwindow")
    • [5.3 WindowState 构造函数](#5.3 WindowState 构造函数 "#53-windowstate-%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0")
    • [5.4 WindowToken.addWindow()](#5.4 WindowToken.addWindow() "#54-windowtokenaddwindow")
  • [6. 关键辅助类分析](#6. 关键辅助类分析 "#6-%E5%85%B3%E9%94%AE%E8%BE%85%E5%8A%A9%E7%B1%BB%E5%88%86%E6%9E%90")
    • [6.1 DisplayPolicy.checkAddPermission()](#6.1 DisplayPolicy.checkAddPermission() "#61-displaypolicycheckaddpermission")
    • [6.2 DisplayPolicy.validateAddingWindowLw()](#6.2 DisplayPolicy.validateAddingWindowLw() "#62-displaypolicyvalidateaddingwindowlw")
    • [6.3 DisplayPolicy.adjustWindowParamsLw()](#6.3 DisplayPolicy.adjustWindowParamsLw() "#63-displaypolicyadjustwindowparamslw")
  • [7. WindowToken 创建与管理](#7. WindowToken 创建与管理 "#7-windowtoken-%E5%88%9B%E5%BB%BA%E4%B8%8E%E7%AE%A1%E7%90%86")
  • [8. 窗口类型定义](#8. 窗口类型定义 "#8-%E7%AA%97%E5%8F%A3%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89")
  • [9. 错误码与返回值](#9. 错误码与返回值 "#9-%E9%94%99%E8%AF%AF%E7%A0%81%E4%B8%8E%E8%BF%94%E5%9B%9E%E5%80%BC")
  • [10. 关键数据结构](#10. 关键数据结构 "#10-%E5%85%B3%E9%94%AE%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84")
  • [11. 时序图](#11. 时序图 "#11-%E6%97%B6%E5%BA%8F%E5%9B%BE")

1. 整体架构概览

scss 复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                          应用进程 (App Process)                      │
│                                                                     │
│  ┌───────────────────┐  ┌────────────────────┐  ┌───────────────┐   │
│  │ WindowManagerImpl │─▶│ WindowManagerGlobal│─▶│  ViewRootImpl │   │
│  └───────────────────┘  └────────────────────┘  └───────┬───────┘   │
│                                                         │           │
│                             IWindowSession (AIDL/Binder)│           │
└─────────────────────────────────────────────────────────┼───────────┘
                                                          │ IPC
┌─────────────────────────────────────────────────────────┼───────────┐
│                      system_server  进程                 │           │
│                                                         │           │
│  ┌───────────┐  ┌───────────────────────┐  ┌────────────▼─────────┐ │
│  │  Session  │─▶│ WindowManagerService  │─▶│      WindowState     │ │
│  └───────────┘  └──────────┬────────────┘  └──────────────────────┘ │
│                            │                                        │
│                 ┌──────────▼──────────┐                             │
│                 │     WindowToken     │                             │
│                 └─────────────────────┘                             │
└─────────────────────────────────────────────────────────────────────┘

核心类职责

类名 职责
WindowManagerImpl 应用层WindowManager实现,对外暴露addView/removeView接口
WindowManagerGlobal 进程级单例,管理所有View/ViewRootImpl/LayoutParams
ViewRootImpl View树根节点,负责布局、绘制、与WMS通信
IWindowSession AIDL接口,客户端与服务端的会话通道
Session IWindowSession的服务端实现,每个进程一个
WindowManagerService 系统窗口管理服务,窗口的最终管理者和仲裁者
WindowState 窗口在WMS中的状态表示
WindowToken 窗口令牌,一组相关窗口的容器
DisplayContent 显示屏内容,管理一个Display上的所有窗口
DisplayPolicy 显示策略,负责窗口权限验证和参数调整

2. 完整调用链路

scss 复制代码
[应用进程]
WindowManagerImpl.addView(view, params)
  │
  ▼
WindowManagerGlobal.addView(view, params, display, parentWindow, userId)
  │  ├── 参数校验
  │  ├── 创建 ViewRootImpl
  │  └── 添加到全局列表 mViews/mRoots/mParams
  ▼
ViewRootImpl.setView(view, attrs, panelParentView, userId)
  │  ├── 设置 mView、复制 attrs
  │  ├── requestLayout() 请求首次布局
  │  ├── 创建 InputChannel
  │  └── mWindowSession.addToDisplayAsUser() ── IPC  ──┐
  │                                                    │
[system_server]                                        │ Binder
  │                                                    │
  ▼                                                    │
Session.addToDisplayAsUser(...)  ◀─────────────────────┘
  │
  ▼
WindowManagerService.addWindow(session, client, attrs, ...)
  │
  ├── Step 1:  权限检查 checkAddPermission()
  ├── Step 2:  子窗口处理 & DisplayContent校验
  ├── Step 3:  基础校验 (重复添加 / 用户验证 / Presentation)
  ├── Step 4:  WindowToken 查找/创建  ← 核心逻辑
  ├── Step 5:  创建 WindowState & DisplayPolicy校验
  ├── Step 6:  InputChannel & 注册到WindowMap
  ├── Step 7:  添加到Token & 特殊窗口处理
  ├── Step 8:  焦点 / IME / 层级 / 输入更新
  └── Step 9:  输出参数填充 & 返回

3. 客户端侧详细流程

3.1 WindowManagerImpl.addView()

文件 : frameworks/base/core/java/android/view/WindowManagerImpl.java:156

java 复制代码
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyTokens(params);
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
            mContext.getUserId());
}

说明 : 应用层入口方法,实现了 ViewManager 接口。

  • applyTokens(params) --- 处理Window token相关的参数,将Activity/Window的token设置到LayoutParams中
  • mParentWindow --- 如果是子WindowManager(如 window.getWindowManager()),此处为父窗口
  • mContext.getUserId() --- 传入当前用户ID,支持多用户

3.2 WindowManagerGlobal.addView()

文件 : frameworks/base/core/java/android/view/WindowManagerGlobal.java:350

java 复制代码
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {

步骤1: 参数校验

java 复制代码
if (view == null) {
    throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
    throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
    throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}

步骤2: 参数处理

java 复制代码
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
    // 子窗口:由父窗口调整布局参数(设置token等)
    parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
    // 非子窗口:检查是否启用硬件加速
    if (context != null
            && (context.getApplicationInfo().flags
            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
        wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
    }
}

步骤3: 查找父View和创建ViewRootImpl

java 复制代码
// 如果是子窗口,查找关联的父View
if (wparams.type >= FIRST_SUB_WINDOW && wparams.type <= LAST_SUB_WINDOW) {
    for (int i = 0; i < count; i++) {
        if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
            panelParentView = mViews.get(i);
        }
    }
}

// 检查是否为无窗口Session (SurfaceControlViewHost)
IWindowSession windowlessSession = null;
if (wparams.token != null && panelParentView == null) {
    for (int i = 0; i < mWindowlessRoots.size(); i++) {
        ViewRootImpl maybeParent = mWindowlessRoots.get(i);
        if (maybeParent.getWindowToken() == wparams.token) {
            windowlessSession = maybeParent.getWindowSession();
            break;
        }
    }
}

// 创建 ViewRootImpl
if (windowlessSession == null) {
    root = new ViewRootImpl(view.getContext(), display);
} else {
    root = new ViewRootImpl(view.getContext(), display,
            windowlessSession, new WindowlessWindowLayout());
}

步骤4: 添加到全局列表并调用setView

java 复制代码
view.setLayoutParams(wparams);

mViews.add(view);       // 保存View引用
mRoots.add(root);       // 保存ViewRootImpl引用
mParams.add(wparams);   // 保存LayoutParams

try {
    root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
    // BadTokenException / InvalidDisplayException → 清理
    final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
    if (viewIndex >= 0) {
        removeViewLocked(viewIndex, true);
    }
    throw e;
}

三个全局列表:

  • mViews: ArrayList<View> --- 所有已添加的View
  • mRoots: ArrayList<ViewRootImpl> --- 所有ViewRootImpl
  • mParams: ArrayList<WindowManager.LayoutParams> --- 所有布局参数

3.3 ViewRootImpl.setView()

文件 : frameworks/base/core/java/android/view/ViewRootImpl.java:1496

java 复制代码
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {

步骤1: 设置mView和属性

java 复制代码
synchronized (this) {
    if (mView == null) {
        mView = view;  // 保存View引用

        mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
        mFallbackEventHandler.setView(view);
        mWindowAttributes.copyFrom(attrs);  // 复制布局参数
        if (mWindowAttributes.packageName == null) {
            mWindowAttributes.packageName = mBasePackageName;
        }

        attrs = mWindowAttributes;
        // ... 硬件加速、表面Insets、兼容性信息处理 ...
        mAdded = true;

步骤2: 请求首次布局

java 复制代码
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();

重要: 在添加Window之前先请求布局,确保第一次relayout时View树已准备好。

requestLayout() 实现:

java 复制代码
@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();      // 检查是否在UI线程
        mLayoutRequested = true;
        scheduleTraversals();  // 调度performTraversals()
    }
}

步骤3: 创建InputChannel

java 复制代码
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    inputChannel = new InputChannel();
}

步骤4: IPC调用添加Window

java 复制代码
try {
    mOrigWindowType = mWindowAttributes.type;
    mAttachInfo.mRecomputeGlobalAttributes = true;
    collectViewAttributes();
    adjustLayoutParamsForCompatibility(mWindowAttributes, ...);
    controlInsetsForCompatibility(mWindowAttributes);

    Rect attachedFrame = new Rect();
    final float[] compatScale = { 1f };
    res = mWindowSession.addToDisplayAsUser(
            mWindow,               // IWindow 客户端Binder对象
            mWindowAttributes,     // 窗口布局参数
            getHostVisibility(),   // 宿主可见性
            mDisplay.getDisplayId(), // 目标Display ID
            userId,                // 用户ID
            mInsetsController.getRequestedVisibleTypes(), // 请求可见的Insets类型
            inputChannel,          // 输入通道 (out)
            mTempInsets,           // Insets状态 (out)
            mTempControls,         // Insets控制 (out)
            attachedFrame,         // 附加帧 (out)
            compatScale            // 兼容性缩放 (out)
    );
    // ... 处理返回的attachedFrame和compatScale ...
}

关键参数说明:

参数 方向 说明
mWindow in IWindow Binder对象,WMS通过它回调客户端
mWindowAttributes in 窗口类型、flags、大小等布局参数
getHostVisibility() in View的当前可见性
mDisplay.getDisplayId() in 目标显示屏ID
userId in 用户ID(多用户支持)
inputChannel out 输入事件通道
mTempInsets out 当前Insets状态
mTempControls out Insets源控制
attachedFrame out 父窗口的附加帧
compatScale out 兼容性缩放因子

步骤5: 错误码处理

java 复制代码
if (res < WindowManagerGlobal.ADD_OKAY) {
    // ... 清理 ...
    switch (res) {
        case ADD_BAD_APP_TOKEN:        // -1: Token无效
        case ADD_BAD_SUBWINDOW_TOKEN:  // -2: 子窗口Token无效
            throw new WindowManager.BadTokenException(
                    "Unable to add window -- token " + attrs.token
                    + " is not valid; is your activity running?");
        case ADD_NOT_APP_TOKEN:        // -3: 非应用Token
            throw new WindowManager.BadTokenException(...);
        case ADD_APP_EXITING:          // -4: 应用正在退出
            throw new WindowManager.BadTokenException(...);
        case ADD_DUPLICATE_ADD:        // -5: 重复添加
            throw new WindowManager.BadTokenException(...);
        case ADD_STARTING_NOT_NEEDED:  // -6: 不需要启动窗口
            return;  // 静默忽略
        case ADD_MULTIPLE_SINGLETON:   // -7: 单例窗口重复
            throw new WindowManager.BadTokenException(...);
        case ADD_PERMISSION_DENIED:    // -8: 权限拒绝
            throw new WindowManager.BadTokenException(...);
        case ADD_INVALID_DISPLAY:      // -9: 无效Display
            throw new WindowManager.InvalidDisplayException(...);
        case ADD_INVALID_TYPE:         // -10: 无效窗口类型
            throw new WindowManager.InvalidDisplayException(...);
        case ADD_INVALID_USER:         // -11: 无效用户
            throw new WindowManager.BadTokenException(...);
    }
}

3.4 IWindowSession.addToDisplayAsUser()

文件 : frameworks/base/core/java/android/view/IWindowSession.aidl:58

aidl 复制代码
int addToDisplayAsUser(
    IWindow window,
    in WindowManager.LayoutParams attrs,
    in int viewVisibility,
    in int layerStackId,      // displayId
    in int userId,
    int requestedVisibleTypes,
    out InputChannel outInputChannel,
    out InsetsState insetsState,
    out InsetsSourceControl.Array activeControls,
    out Rect attachedFrame,
    out float[] sizeCompatScale
);

IWindowSession 还提供了另外两个添加方法:

方法 说明
addToDisplay() 不指定userId,使用调用者的userId
addToDisplayAsUser() 指定userId,支持多用户
addToDisplayWithoutInputChannel() 不创建输入通道,用于不需要输入的窗口

4. Binder IPC 跨进程调用

scss 复制代码
┌───────────────────┐                       ┌───────────────────┐
│    应用进程        │                       │   system_server   │
│                   │                       │                   │
│  mWindowSession ──┼─── Binder Proxy ────▶ │  Session (Stub)   │
│  (IWindowSession) │                       │                   │
│                   │                       │  mWindowMap ──────│──▶ WindowState
│  mWindow ─────────┼─── Binder Proxy ────▶ │  (IWindow Binder) │
│  (IWindow.Stub)   │                       │                   │
│                   │◀─── Binder Proxy ─────│  回调IWindow方法   │
│                   │     (resized等)       │  (resized,        │
│                   │                       │   insetsChanged等)│
└───────────────────┘                       └───────────────────┘

双向通信:

  • 客户端 → 服务端 : 通过 IWindowSession 接口(add、relayout、remove等操作)
  • 服务端 → 客户端 : 通过 IWindow 接口(resized、insetsControlChanged、dispatchAppVisibility等回调)

5. 服务端侧详细流程

5.1 Session.addToDisplayAsUser()

文件 : frameworks/base/services/core/java/com/android/server/wm/Session.java:247

java 复制代码
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
        float[] outSizeCompatScale) {
    return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
            requestedVisibleTypes, outInputChannel, outInsetsState, outActiveControls,
            outAttachedFrame, outSizeCompatScale);
}

说明 : Session是IWindowSession的服务端实现,每个客户端进程对应一个Session实例。它直接委托给 WindowManagerService.addWindow()


5.2 WindowManagerService.addWindow()

文件 : frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java:1527

这是整个添加Window流程的核心方法,包含约430行代码。

java 复制代码
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
        int displayId, int requestUserId, @InsetsType int requestedVisibleTypes,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
        float[] outSizeCompatScale) {

Step 1: 前置准备 & 权限检查

java 复制代码
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();  // 切换为系统身份
final int type = attrs.type;

int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
        appOp, displayId);
if (res != ADD_OKAY) {
    return res;
}

委托给 PhoneWindowManager.checkAddPermission(),按窗口类型检查不同权限(系统窗口需 INTERNAL_SYSTEM_WINDOW,应用覆盖层需 SYSTEM_ALERT_WINDOW AppOps等)。详见 6.1节


Step 2: synchronized块 --- 前置校验

进入全局锁后依次进行:Display就绪检查、Session存活检查、子窗口处理、DisplayContent获取、重复添加检查。

java 复制代码
synchronized (mGlobalLock) {
    if (!mDisplayReady) throw new IllegalStateException("Display has not been initialialized");
    if (session.isClientDead()) return ADD_APP_EXITING;

    // 子窗口: 查找父窗口,验证不能嵌套
    if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
        parentWindow = windowForClientLocked(null, attrs.token, false);
        if (parentWindow == null) return ADD_BAD_SUBWINDOW_TOKEN;
        if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW) return ADD_BAD_SUBWINDOW_TOKEN;
    }

    // DisplayContent获取 & 访问验证
    final DisplayContent displayContent = parentWindow != null
            ? parentWindow.mDisplayContent
            : getDisplayContentOrCreate(displayId, attrs.token);
    if (displayContent == null || !displayContent.hasAccess(session.mUid)) {
        return ADD_INVALID_DISPLAY;
    }

    // 重复添加检查
    if (mWindowMap.containsKey(client.asBinder())) return ADD_DUPLICATE_ADD;

Step 3: WindowToken查找/创建 --- 核心逻辑

这是addWindow中最关键的步骤,决定窗口归属哪个Token。

java 复制代码
    WindowToken token = displayContent.getWindowToken(
            hasParent ? parentWindow.mAttrs.token : attrs.token);

分支逻辑:

css 复制代码
Token是否已存在?
├── Token == null(不存在)
│   ├── 检查权限: unprivilegedAppCanCreateTokenWith()
│   ├── 有父窗口 → 共享父窗口Token: parentWindow.mToken
│   ├── 有WindowContext监听器 → new WindowToken.Builder(...).setFromClientToken(true).build()
│   └── 其他 → new WindowToken.Builder(...).build()
│
└── Token != null(已存在)→ 按窗口类型验证
    ├── TYPE_APPLICATION (1~99)
    │   ├── token.asActivityRecord() == null → ADD_NOT_APP_TOKEN
    │   ├── activity.getParent() == null → ADD_APP_EXITING
    │   └── TYPE_APPLICATION_STARTING → 检查是否已有StartingWindow
    ├── TYPE_INPUT_METHOD / TYPE_WALLPAPER / TYPE_VOICE_INTERACTION → 验证token.windowType
    └── 其他系统窗口 + token是ActivityRecord → 创建新Token

Token为null时核心代码:

java 复制代码
    if (token == null) {
        if (!unprivilegedAppCanCreateTokenWith(...)) return ADD_BAD_APP_TOKEN;
        if (hasParent) {
            token = parentWindow.mToken;  // 子窗口共享父窗口Token
        } else if (mWindowContextListenerController.hasListener(windowContextToken)) {
            token = new WindowToken.Builder(this, binder, type)
                    .setDisplayContent(displayContent)
                    .setFromClientToken(true).setOptions(options).build();
        } else {
            final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
            token = new WindowToken.Builder(this, binder, type)
                    .setDisplayContent(displayContent).build();
        }
    }

Token已存在 --- 应用窗口验证:

java 复制代码
    else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
        activity = token.asActivityRecord();
        if (activity == null) return ADD_NOT_APP_TOKEN;
        if (activity.getParent() == null) return ADD_APP_EXITING;
    }

Step 4: 创建WindowState & DisplayPolicy校验

java 复制代码
    // 创建WindowState
    final WindowState win = new WindowState(this, session, client, token, parentWindow,
            appOp[0], attrs, viewVisibility, session.mUid, userId,
            session.mCanAddInternalSystemWindow);

    // DisplayPolicy参数调整 (强制系统覆盖层不可聚焦/不可触摸等)
    displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
    attrs.flags = sanitizeFlagSlippery(attrs.flags, ...);
    attrs.inputFeatures = sanitizeInputFeatures(attrs.inputFeatures, ...);
    win.setRequestedVisibleTypes(requestedVisibleTypes);

    // DisplayPolicy最终验证 (TRUSTED_OVERLAY权限、系统UI权限等)
    res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
    if (res != ADD_OKAY) return res;

详见 [5.3节 WindowState构造函数](#5.3节 WindowState构造函数 "#53-windowstate-%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0") 和 6.2/6.3节


Step 5: InputChannel & 注册到WindowMap

java 复制代码
    // 打开InputChannel (创建服务端/客户端输入通道对)
    if (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
        win.openInputChannel(outInputChannel);
    }

    // --- 从此不允许失败 ---

    // Toast窗口: 同UID限制 + 超时隐藏
    if (type == TYPE_TOAST) {
        if (!displayContent.canAddToastWindowForUid(callingUid)) return ADD_DUPLICATE_ADD;
        mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
                win.mAttrs.hideTimeoutMilliseconds);
    }

    // 注册到全局映射
    win.mSession.onWindowAdded(win);
    mWindowMap.put(client.asBinder(), win);       // IBinder → WindowState
    win.initAppOpsState();
    win.setHiddenWhileSuspended(mPmInternal.isPackageSuspended(...));

openInputChannel 内部逻辑:InputChannel.openInputChannelPair() 创建配对通道 → 服务端注册到 InputManager → 客户端通道通过out参数传回。


Step 6: 添加到Token & 焦点/IME/层级更新

java 复制代码
    win.mToken.addWindow(win);                    // 添加到WindowToken的子节点
    displayPolicy.addWindowLw(win, attrs);        // 通知DisplayPolicy

    // 特殊窗口类型处理
    if (type == TYPE_APPLICATION_STARTING && activity != null) {
        activity.attachStartingWindow(win);
    } else if (type == TYPE_INPUT_METHOD) {
        displayContent.setInputMethodWindowLocked(win);
    } else if (type == TYPE_WALLPAPER) {
        displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
    }

    // 焦点更新
    boolean focusChanged = false;
    if (win.canReceiveKeys()) {
        focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, false);
    }

    // IME目标计算 & 层级分配 & 输入窗口更新
    if (imMayMove) displayContent.computeImeTarget(true);
    win.getParent().assignChildLayers();
    if (focusChanged) displayContent.getInputMonitor().setInputFocusLw(...);
    displayContent.getInputMonitor().updateInputWindowsLw(false);

Step 7: 输出参数填充 & 返回

java 复制代码
    // 方向/配置更新
    if (win.isVisibleRequestedOrAdding() && displayContent.updateOrientation()) {
        displayContent.sendNewConfiguration();
    }

    // 填充输出参数
    win.fillInsetsState(outInsetsState, true);
    getInsetsSourceControls(win, outActiveControls);
    if (win.mLayoutAttached) {
        outAttachedFrame.set(win.getParentWindow().getFrame());
    } else {
        outAttachedFrame.set(0, 0, -1, -1);
    }
    outSizeCompatScale[0] = win.getCompatScaleForClient();

}  // end synchronized
Binder.restoreCallingIdentity(origId);
return res;

5.3 WindowState 构造函数

文件 : frameworks/base/services/core/java/com/android/server/wm/WindowState.java:1098

java 复制代码
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
        WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
        int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {

字段初始化

java 复制代码
super(service);
mTmpTransaction = service.mTransactionFactory.get();
mSession = s;                              // 所属Session
mClient = c;                               // IWindow客户端Binder
mAppOp = appOp;                            // AppOps操作码
mToken = token;                            // 所属WindowToken
mDisplayContent = token.mDisplayContent;   // 所属DisplayContent
mActivityRecord = mToken.asActivityRecord(); // 关联的Activity(可能为null)
mOwnerUid = ownerId;
mShowUserId = showUserId;
mWindowId = new WindowId(this);
mAttrs.copyFrom(a);                        // 复制布局参数
mViewVisibility = viewVisibility;
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;

// 输入窗口句柄
mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
        mActivityRecord != null
                ? mActivityRecord.getInputApplicationHandle(false) : null,
        getDisplayId()));
mInputWindowHandle.setFocusable(false);
mInputWindowHandle.setOwnerPid(s.mPid);
mInputWindowHandle.setOwnerUid(s.mUid);
mInputWindowHandle.setName(getName());
mInputWindowHandle.setPackageName(mAttrs.packageName);
mInputWindowHandle.setLayoutParamsType(mAttrs.type);

窗口层级计算

java 复制代码
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
    // 子窗口: 基于父窗口的层级
    mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
            * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
    mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
    mIsChildWindow = true;
    mLayoutAttached = (mAttrs.type != TYPE_APPLICATION_ATTACHED_DIALOG);
    mIsImWindow = (parentWindow.mAttrs.type == TYPE_INPUT_METHOD
            || parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG);
    mIsWallpaper = (parentWindow.mAttrs.type == TYPE_WALLPAPER);
} else {
    // 非子窗口: 基于自身类型
    mBaseLayer = mPolicy.getWindowLayerLw(this)
            * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
    mSubLayer = 0;
    mIsChildWindow = false;
    mLayoutAttached = false;
    mIsImWindow = (mAttrs.type == TYPE_INPUT_METHOD
            || mAttrs.type == TYPE_INPUT_METHOD_DIALOG);
    mIsWallpaper = (mAttrs.type == TYPE_WALLPAPER);
}
mIsFloatingLayer = mIsImWindow || mIsWallpaper;

层级计算规则:

  • mBaseLayer = 窗口类型对应的层级 × TYPE_LAYER_MULTIPLIER(10000) + TYPE_LAYER_OFFSET(1000)
  • mSubLayer = 子窗口相对于父窗口的偏移层级
  • mIsFloatingLayer = IME窗口或壁纸窗口(特殊浮动层)

动画器和子窗口添加

java 复制代码
mWinAnimator = new WindowStateAnimator(this);
mWinAnimator.mAlpha = a.alpha;

mRequestedWidth = UNSPECIFIED_LENGTH;
mRequestedHeight = UNSPECIFIED_LENGTH;
mLayer = 0;
mOverrideScale = mWmService.mAtmService.mCompatModePackages.getCompatScale(
        mAttrs.packageName, s.mUid);
updateGlobalScale();

// 子窗口直接添加到父窗口
if (mIsChildWindow) {
    parentWindow.addChild(this, sWindowSubLayerComparator);
}

5.4 WindowToken.addWindow()

文件 : frameworks/base/services/core/java/com/android/server/wm/WindowToken.java:330

java 复制代码
void addWindow(final WindowState win) {
    ProtoLog.d(WM_DEBUG_FOCUS,
            "addWindow: win=%s Callers=%s", win, Debug.getCallers(5));

    if (win.isChildWindow()) {
        // 子窗口已经添加到父窗口了,不需要再添加到Token
        return;
    }
    // 如果Token还没有SurfaceControl,创建一个
    if (mSurfaceControl == null) {
        createSurfaceControl(true /* force */);
        reassignLayer(getSyncTransaction());
    }
    // 将WindowState添加为Token的子节点
    if (!mChildren.contains(win)) {
        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);
        addChild(win, mWindowComparator);
        mWmService.mWindowsChanged = true;
    }
}

说明: WindowToken继承自WindowContainer,使用树形结构管理其下的所有WindowState。每个WindowToken在SurfaceFlinger中对应一个Layer节点。


6. 关键辅助类分析

6.1 DisplayPolicy.checkAddPermission()

文件 : frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java:3150

完整权限检查逻辑:

scss 复制代码
checkAddPermission(type, isRoundedCornerOverlay, packageName, appOp, displayId)
│
├── 圆角覆盖层 → 检查 INTERNAL_SYSTEM_WINDOW 权限
│
├── 类型有效性检查 → 不是有效的应用/子/系统窗口类型 → ADD_INVALID_TYPE
│
├── 非系统窗口 (type < 2000) → ADD_OKAY (由WMS进一步验证)
│
├── 非系统警报窗口类型
│   ├── TYPE_TOAST → appOp = OP_TOAST_WINDOW, ADD_OKAY
│   ├── TYPE_ACCESSIBILITY_OVERLAY → appOp = OP_CREATE_ACCESSIBILITY_OVERLAY
│   ├── TYPE_INPUT_METHOD/WALLPAPER/PRESENTATION/VOICE_INTERACTION等 → ADD_OKAY
│   └── 其他 → 检查 INTERNAL_SYSTEM_WINDOW 权限
│
└── 系统警报窗口类型 (isSystemAlertWindowType)
    ├── appOp = OP_SYSTEM_ALERT_WINDOW
    ├── 系统进程 (SYSTEM_UID) → ADD_OKAY
    ├── targetSdk >= O 且非 TYPE_APPLICATION_OVERLAY → 检查 INTERNAL_SYSTEM_WINDOW
    ├── 检查 SYSTEM_APPLICATION_OVERLAY 权限
    ├── 虚拟设备所有者 + CREATE_VIRTUAL_DEVICE → ADD_OKAY
    └── AppOps 检查
        ├── MODE_ALLOWED → ADD_OKAY
        ├── MODE_IGNORED → ADD_OKAY (但窗口会被隐藏)
        ├── MODE_ERRORED → targetSdk < M ? ADD_OKAY : ADD_PERMISSION_DENIED
        └── 默认 → 检查 SYSTEM_ALERT_WINDOW 权限

6.2 DisplayPolicy.validateAddingWindowLw()

文件 : frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java:1057

验证窗口添加的最终策略:

java 复制代码
int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
    // TRUSTED_OVERLAY 需要 INTERNAL_SYSTEM_WINDOW 权限
    if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
        mContext.enforcePermission(INTERNAL_SYSTEM_WINDOW, ...);
    }
    // INTERCEPT_GLOBAL_DRAG_AND_DROP 需要 Task权限
    if ((attrs.privateFlags & PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP) != 0) {
        ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy");
    }

    // 系统UI权限 (虚拟设备所有者用 CREATE_VIRTUAL_DEVICE,否则用 STATUS_BAR_SERVICE)
    final String systemUiPermission = ...;

    switch (attrs.type) {
        case TYPE_STATUS_BAR:           // 需要系统UI权限,单例检查
        case TYPE_NOTIFICATION_SHADE:   // 需要系统UI权限,单例检查
        case TYPE_NAVIGATION_BAR:       // 需要系统UI权限,单例检查
        case TYPE_NAVIGATION_BAR_PANEL:
        case TYPE_STATUS_BAR_ADDITIONAL:
        case TYPE_STATUS_BAR_SUB_PANEL:
        case TYPE_VOICE_INTERACTION_STARTING:
            mContext.enforcePermission(systemUiPermission, ...);
            break;
        case TYPE_STATUS_BAR_PANEL:
            return ADD_INVALID_TYPE;    // 此类型已废弃
    }

    // providedInsets 需要系统UI权限 (Recents组件除外)
    if (attrs.providedInsets != null) {
        if (!mService.mAtmService.isCallerRecents(callingUid)) {
            mContext.enforcePermission(systemUiPermission, ...);
        }
    }
    return ADD_OKAY;
}

6.3 DisplayPolicy.adjustWindowParamsLw()

文件 : frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java:950

在WindowState创建后,调整窗口参数:

窗口类型 调整内容
TYPE_SYSTEM_OVERLAY / TYPE_SECURE_SYSTEM_OVERLAY 强制设置 FLAG_NOT_FOCUSABLE + FLAG_NOT_TOUCHABLE
TYPE_WALLPAPER 设置 layoutInDisplayCutoutMode = ALWAYS
TYPE_TOAST 限制超时时间,设置 FLAG_NOT_TOUCHABLE
TYPE_BASE_APPLICATION 全屏非透明窗口不允许 fitInsets
系统警报窗口 (SAW) alpha > 最大遮挡透明度时降级
所有窗口 清理不受限手势排除标志

7. WindowToken 创建与管理

7.1 WindowToken.Builder

文件 : frameworks/base/services/core/java/com/android/server/wm/WindowToken.java:828

java 复制代码
static class Builder {
    private final WindowManagerService mService;
    private final IBinder mToken;         // Token的Binder标识
    @WindowType private final int mType;  // 窗口类型

    private boolean mPersistOnEmpty;      // 空Token是否保留
    private DisplayContent mDisplayContent; // 关联的DisplayContent
    private boolean mOwnerCanManageAppTokens; // 是否可管理App Token
    private boolean mRoundedCornerOverlay;    // 是否圆角覆盖层
    private boolean mFromClientToken;         // 是否来自客户端Token
    @Nullable private Bundle mOptions;        // 选项

    // setter方法 (返回this以支持链式调用)
    Builder setPersistOnEmpty(boolean);
    Builder setDisplayContent(DisplayContent);
    Builder setOwnerCanManageAppTokens(boolean);
    Builder setRoundedCornerOverlay(boolean);
    Builder setFromClientToken(boolean);
    Builder setOptions(Bundle);

    WindowToken build() {
        return new WindowToken(mService, mToken, mType, mPersistOnEmpty,
                mDisplayContent, mOwnerCanManageAppTokens, mRoundedCornerOverlay,
                mFromClientToken, mOptions);
    }
}

7.2 Token创建时机

场景 Token类型 创建者
Activity窗口 ActivityRecord (继承WindowToken) AMS创建Task/Activity时
系统窗口 (有预注册Token) WindowToken WMS.addWindowToken() 调用
系统窗口 (无预注册Token) WindowToken WMS.addWindow() 中创建
壁纸窗口 WallpaperWindowToken WMS.addWindowToken()
WindowContext窗口 WindowToken (fromClientToken=true) WMS.addWindow() 中创建

7.3 WMS.addWindowToken()

文件 : frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java:2850

java 复制代码
public void addWindowToken(@NonNull IBinder binder, int type, int displayId,
        @Nullable Bundle options) {
    if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
        throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
    }
    synchronized (mGlobalLock) {
        final DisplayContent dc = getDisplayContentOrCreate(displayId, null);
        if (dc == null) { return; }
        if (dc.getWindowToken(binder) != null) { return; }  // 已存在

        if (type == TYPE_WALLPAPER) {
            new WallpaperWindowToken(this, binder, true, dc, true, options);
        } else {
            new WindowToken.Builder(this, binder, type)
                    .setDisplayContent(dc)
                    .setPersistOnEmpty(true)     // 空Token也保留
                    .setOwnerCanManageAppTokens(true)
                    .setOptions(options)
                    .build();
        }
    }
}

8. 窗口类型定义

文件 : frameworks/base/core/java/android/view/WindowManager.java

8.1 应用窗口 (1-99)

常量 说明
FIRST_APPLICATION_WINDOW 1 应用窗口起始值
TYPE_BASE_APPLICATION 1 基础应用窗口(底层)
TYPE_APPLICATION 2 标准应用窗口
TYPE_APPLICATION_STARTING 3 应用启动窗口(Splash Screen)
TYPE_DRAWN_APPLICATION 4 已绘制的应用窗口
LAST_APPLICATION_WINDOW 99 应用窗口结束值

8.2 子窗口 (1000-1999)

常量 说明
FIRST_SUB_WINDOW 1000 子窗口起始值
TYPE_APPLICATION_PANEL 1000 应用面板
TYPE_APPLICATION_MEDIA 1001 应用媒体
TYPE_APPLICATION_SUB_PANEL 1002 应用子面板
TYPE_APPLICATION_ATTACHED_DIALOG 1003 附属对话框
TYPE_APPLICATION_MEDIA_OVERLAY 1004 媒体覆盖层
TYPE_APPLICATION_ABOVE_SUB_PANEL 1005 子面板上方的面板
LAST_SUB_WINDOW 1999 子窗口结束值

8.3 系统窗口 (2000-2999)

常量 说明
FIRST_SYSTEM_WINDOW 2000 系统窗口起始值
TYPE_STATUS_BAR 2000 状态栏
TYPE_SEARCH_BAR 2001 搜索栏
TYPE_PHONE 2002 电话窗口
TYPE_SYSTEM_ALERT 2003 系统警报
TYPE_KEYGUARD 2004 锁屏
TYPE_TOAST 2005 Toast
TYPE_SYSTEM_OVERLAY 2006 系统覆盖层
TYPE_PRIORITY_PHONE 2007 优先电话
TYPE_SYSTEM_DIALOG 2008 系统对话框
TYPE_KEYGUARD_DIALOG 2009 锁屏对话框
TYPE_SYSTEM_ERROR 2010 系统错误
TYPE_INPUT_METHOD 2011 输入法
TYPE_INPUT_METHOD_DIALOG 2012 输入法对话框
TYPE_WALLPAPER 2013 壁纸
TYPE_STATUS_BAR_PANEL 2014 状态栏面板
TYPE_SECURE_SYSTEM_OVERLAY 2015 安全系统覆盖层
TYPE_DRAG 2016 拖拽覆盖层
TYPE_STATUS_BAR_SUB_PANEL 2017 状态栏子面板
TYPE_POINTER 2018 指针
TYPE_NAVIGATION_BAR 2019 导航栏
TYPE_VOLUME_OVERLAY 2020 音量覆盖层
TYPE_BOOT_PROGRESS 2021 启动进度
TYPE_INPUT_CONSUMER 2022 输入消费者
TYPE_NAVIGATION_BAR_PANEL 2024 导航栏面板
TYPE_DISPLAY_OVERLAY 2026 显示覆盖层
TYPE_MAGNIFICATION_OVERLAY 2027 放大覆盖层
TYPE_PRIVATE_PRESENTATION 2030 私有Presentation
TYPE_VOICE_INTERACTION 2031 语音交互
TYPE_ACCESSIBILITY_OVERLAY 2032 无障碍覆盖层
TYPE_VOICE_INTERACTION_STARTING 2033 语音交互启动窗口
TYPE_DOCK_DIVIDER 2034 分屏分割线
TYPE_QS_DIALOG 2035 快速设置对话框
TYPE_SCREENSHOT 2036 截图
TYPE_PRESENTATION 2037 Presentation
TYPE_APPLICATION_OVERLAY 2038 应用覆盖层 (SYSTEM_ALERT_WINDOW)
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY 2039 无障碍放大覆盖层
TYPE_NOTIFICATION_SHADE 2040 通知栏
TYPE_STATUS_BAR_ADDITIONAL 2041 附加状态栏
LAST_SYSTEM_WINDOW 2999 系统窗口结束值

9. 错误码与返回值

9.1 错误码

文件 : frameworks/base/core/java/android/view/WindowManagerGlobal.java:124

常量 含义 触发场景
ADD_OKAY 0 添加成功 ---
ADD_BAD_APP_TOKEN -1 应用Token无效 非特权应用尝试创建应用窗口Token
ADD_BAD_SUBWINDOW_TOKEN -2 子窗口Token无效 子窗口的父窗口不存在或本身是子窗口
ADD_NOT_APP_TOKEN -3 非应用Token 应用窗口使用了非ActivityRecord的Token
ADD_APP_EXITING -4 应用正在退出 Activity已退出或Session客户端已死亡
ADD_DUPLICATE_ADD -5 重复添加 同一IWindow已添加 / 同一UID已有Toast
ADD_STARTING_NOT_NEEDED -6 不需要启动窗口 StartingWindow不再需要
ADD_MULTIPLE_SINGLETON -7 单例窗口重复 StatusBar/NavigationBar已存在
ADD_PERMISSION_DENIED -8 权限被拒绝 缺少必要的系统权限
ADD_INVALID_DISPLAY -9 无效Display Display不存在或无权访问
ADD_INVALID_TYPE -10 无效窗口类型 WindowContext类型不匹配 / TYPE_STATUS_BAR_PANEL
ADD_INVALID_USER -11 无效用户 跨用户添加时用户验证失败

9.2 返回标志位(与ADD_OKAY按位或)

常量 含义
ADD_FLAG_IN_TOUCH_MODE 0x1 当前处于触摸模式
ADD_FLAG_APP_VISIBLE 0x2 应用可见
ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS 0x4 始终消费系统栏

9.3 客户端异常映射

java 复制代码
// ViewRootImpl.setView() 中的错误码处理
switch (res) {
    case ADD_BAD_APP_TOKEN:       // → WindowManager.BadTokenException
    case ADD_BAD_SUBWINDOW_TOKEN: // → WindowManager.BadTokenException
    case ADD_NOT_APP_TOKEN:       // → WindowManager.BadTokenException
    case ADD_APP_EXITING:         // → WindowManager.BadTokenException
    case ADD_DUPLICATE_ADD:       // → WindowManager.BadTokenException
    case ADD_MULTIPLE_SINGLETON:  // → WindowManager.BadTokenException
    case ADD_PERMISSION_DENIED:   // → WindowManager.BadTokenException
    case ADD_INVALID_USER:        // → WindowManager.BadTokenException
    case ADD_STARTING_NOT_NEEDED: // → 静默返回 (不抛异常)
    case ADD_INVALID_DISPLAY:     // → WindowManager.InvalidDisplayException
    case ADD_INVALID_TYPE:        // → WindowManager.InvalidDisplayException
}

10. 关键数据结构

10.1 WindowState 关键成员

字段 类型 说明
mSession Session 所属的客户端Session
mClient IWindow 客户端Binder代理
mToken WindowToken 所属的WindowToken
mDisplayContent DisplayContent 所属的DisplayContent
mActivityRecord ActivityRecord 关联的Activity(可能为null)
mAttrs WindowManager.LayoutParams 窗口布局参数
mBaseLayer int 基础Z序层级
mSubLayer int 子窗口Z序偏移
mIsChildWindow boolean 是否为子窗口
mLayoutAttached boolean 是否布局附加到父窗口
mIsImWindow boolean 是否为IME窗口
mIsWallpaper boolean 是否为壁纸窗口
mIsFloatingLayer boolean 是否为浮动层
mWinAnimator WindowStateAnimator 窗口动画器
mInputChannel InputChannel 服务端输入通道
mViewVisibility int View可见性

10.2 WindowToken 关键成员

字段 类型 说明
windowType int 窗口类型
mDisplayContent DisplayContent 关联的DisplayContent
mPersistOnEmpty boolean 无子窗口时是否保留
mOwnerCanManageAppTokens boolean 所有者是否可管理App Token
mRoundedCornerOverlay boolean 是否圆角覆盖层
mFromClientToken boolean 是否来自客户端Token (WindowContext)
mOptions Bundle 选项
mSurfaceControl SurfaceControl Surface控制

10.3 WMS 关键容器

字段 类型 说明
mWindowMap HashMap<IBinder, WindowState> IWindow Binder → WindowState 映射
mGlobalLock WindowManagerGlobalLock WMS全局锁
mDisplayReady boolean Display是否初始化完成
mPolicy WindowManagerPolicy 窗口策略 (PhoneWindowManager)
mH H 主线程Handler

11. 时序图

scss 复制代码
 App Process                  system_server (WMS)
     │                              │
     │  WindowManagerImpl.addView() │
     │──────────────────────────────│
     │  WindowManagerGlobal.addView()
     │    ├── 参数校验
     │    ├── new ViewRootImpl()
     │    └── root.setView()
     │          ├── mView = view
     │          ├── requestLayout()
     │          ├── new InputChannel()
     │          │
     │          │  mWindowSession.addToDisplayAsUser()
     │──────────────────────────────▶
     │          │                    │  Session.addToDisplayAsUser()
     │          │                    │    │
     │          │                    │  WMS.addWindow()
     │          │                    │    ├── 1. mPolicy.checkAddPermission()
     │          │                    │    ├── 2. 子窗口处理
     │          │                    │    ├── 3. DisplayContent获取
     │          │                    │    ├── 4. 重复添加检查
     │          │                    │    ├── 5. Presentation处理
     │          │                    │    ├── 6. 用户ID验证
     │          │                    │    ├── 7. WindowToken查找/创建
     │          │                    │    ├── 8. 类型验证
     │          │                    │    ├── 9. new WindowState()
     │          │                    │    │     ├── 字段初始化
     │          │                    │    │     ├── 层级计算
     │          │                    │    │     └── 子窗口添加
     │          │                    │    ├── 10. adjustWindowParamsLw()
     │          │                    │    ├── 11. validateAddingWindowLw()
     │          │                    │    ├── 12. openInputChannel()
     │          │                    │    ├── 13. Toast超时处理
     │          │                    │    ├── 14. WindowContext处理
     │          │                    │    ├── 15. mWindowMap.put()
     │          │                    │    ├── 16. token.addWindow()
     │          │                    │    ├── 17. 特殊窗口处理
     │          │                    │    ├── 18. updateFocusedWindowLocked()
     │          │                    │    ├── 19. computeImeTarget()
     │          │                    │    ├── 20. assignChildLayers()
     │          │                    │    ├── 21. updateInputWindowsLw()
     │          │                    │    └── 22. 填充输出参数
     │          │                    │
     │◀──────────────────────────────│
     │  res (int)                    │
     │    ├── ADD_OKAY = 0           │
     │    ├── ADD_FLAG_* (按位或)    │
     │    └── 或负数错误码            │
     │                              │
     │  错误码处理 / 正常流程继续      │
     │  handleInsetsControlChanged()
     │  computeFrames()
     │  setFrame()
     │                              │

附录: 源码文件索引

文件 路径
WindowManagerImpl frameworks/base/core/java/android/view/WindowManagerImpl.java
WindowManagerGlobal frameworks/base/core/java/android/view/WindowManagerGlobal.java
ViewRootImpl frameworks/base/core/java/android/view/ViewRootImpl.java
IWindowSession frameworks/base/core/java/android/view/IWindowSession.aidl
IWindow frameworks/base/core/java/android/view/IWindow.aidl
Session frameworks/base/services/core/java/com/android/server/wm/Session.java
WindowManagerService frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
WindowState frameworks/base/services/core/java/com/android/server/wm/WindowState.java
WindowToken frameworks/base/services/core/java/com/android/server/wm/WindowToken.java
DisplayPolicy frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
DisplayContent frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
PhoneWindowManager frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
WindowStateAnimator frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
相关推荐
爱吃牛肉的大老虎2 小时前
MySQL优化之系统表分析SQL
android·sql·mysql
Fate_I_C2 小时前
实战案例:用 Kotlin 重写一个 Java Android 工具类
android·java·kotlin
Fate_I_C2 小时前
Kotlin 特有语法糖
android·开发语言·kotlin
Fate_I_C2 小时前
Kotlin 为什么是 Android 开发的首选语言
android·开发语言·kotlin
黄林晴2 小时前
Android CLI 来了!终端一键建项目、控模拟器、给 Agent 喂官方规范
android
常利兵2 小时前
Kotlin 助力 Android 启动“大提速”
android·开发语言·kotlin
撩得Android一次心动2 小时前
Android DataBinding 全面解析【源码篇2】
android·源码·android jetpack·databinding
守月满空山雪照窗2 小时前
图形 API 体系解析:Android Vulkan / OpenGL 与主流图形 API 对比
android