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

3 阅读18分钟

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

源码根目录: ~/aosp15/


目录


1. 整体架构概览

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

核心类职责

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

2. 完整调用链路

[应用进程]
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

@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

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {

步骤1: 参数校验

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: 参数处理

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

// 如果是子窗口,查找关联的父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

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

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {

步骤1: 设置mView和属性

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: 请求首次布局

// 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() 实现:

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

步骤3: 创建InputChannel

InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    inputChannel = new InputChannel();
}

步骤4: IPC调用添加Window

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 ...
}

关键参数说明:

参数方向说明
mWindowinIWindow Binder对象,WMS通过它回调客户端
mWindowAttributesin窗口类型、flags、大小等布局参数
getHostVisibility()inView的当前可见性
mDisplay.getDisplayId()in目标显示屏ID
userIdin用户ID(多用户支持)
inputChannelout输入事件通道
mTempInsetsout当前Insets状态
mTempControlsoutInsets源控制
attachedFrameout父窗口的附加帧
compatScaleout兼容性缩放因子

步骤5: 错误码处理

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

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 跨进程调用

┌───────────────────┐                       ┌───────────────────┐
│    应用进程        │                       │   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

@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行代码。

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: 前置准备 & 权限检查

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获取、重复添加检查。

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。

    WindowToken token = displayContent.getWindowToken(
            hasParent ? parentWindow.mAttrs.token : attrs.token);

分支逻辑:

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时核心代码:

    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已存在 — 应用窗口验证:

    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校验

    // 创建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构造函数6.2/6.3节


Step 5: InputChannel & 注册到WindowMap

    // 打开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/层级更新

    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: 输出参数填充 & 返回

    // 方向/配置更新
    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

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

字段初始化

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);

窗口层级计算

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窗口或壁纸窗口(特殊浮动层)

动画器和子窗口添加

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

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

完整权限检查逻辑:

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

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

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

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)WindowTokenWMS.addWindowToken() 调用
系统窗口 (无预注册Token)WindowTokenWMS.addWindow() 中创建
壁纸窗口WallpaperWindowTokenWMS.addWindowToken()
WindowContext窗口WindowToken (fromClientToken=true)WMS.addWindow() 中创建

7.3 WMS.addWindowToken()

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

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_WINDOW1应用窗口起始值
TYPE_BASE_APPLICATION1基础应用窗口(底层)
TYPE_APPLICATION2标准应用窗口
TYPE_APPLICATION_STARTING3应用启动窗口(Splash Screen)
TYPE_DRAWN_APPLICATION4已绘制的应用窗口
LAST_APPLICATION_WINDOW99应用窗口结束值

8.2 子窗口 (1000-1999)

常量说明
FIRST_SUB_WINDOW1000子窗口起始值
TYPE_APPLICATION_PANEL1000应用面板
TYPE_APPLICATION_MEDIA1001应用媒体
TYPE_APPLICATION_SUB_PANEL1002应用子面板
TYPE_APPLICATION_ATTACHED_DIALOG1003附属对话框
TYPE_APPLICATION_MEDIA_OVERLAY1004媒体覆盖层
TYPE_APPLICATION_ABOVE_SUB_PANEL1005子面板上方的面板
LAST_SUB_WINDOW1999子窗口结束值

8.3 系统窗口 (2000-2999)

常量说明
FIRST_SYSTEM_WINDOW2000系统窗口起始值
TYPE_STATUS_BAR2000状态栏
TYPE_SEARCH_BAR2001搜索栏
TYPE_PHONE2002电话窗口
TYPE_SYSTEM_ALERT2003系统警报
TYPE_KEYGUARD2004锁屏
TYPE_TOAST2005Toast
TYPE_SYSTEM_OVERLAY2006系统覆盖层
TYPE_PRIORITY_PHONE2007优先电话
TYPE_SYSTEM_DIALOG2008系统对话框
TYPE_KEYGUARD_DIALOG2009锁屏对话框
TYPE_SYSTEM_ERROR2010系统错误
TYPE_INPUT_METHOD2011输入法
TYPE_INPUT_METHOD_DIALOG2012输入法对话框
TYPE_WALLPAPER2013壁纸
TYPE_STATUS_BAR_PANEL2014状态栏面板
TYPE_SECURE_SYSTEM_OVERLAY2015安全系统覆盖层
TYPE_DRAG2016拖拽覆盖层
TYPE_STATUS_BAR_SUB_PANEL2017状态栏子面板
TYPE_POINTER2018指针
TYPE_NAVIGATION_BAR2019导航栏
TYPE_VOLUME_OVERLAY2020音量覆盖层
TYPE_BOOT_PROGRESS2021启动进度
TYPE_INPUT_CONSUMER2022输入消费者
TYPE_NAVIGATION_BAR_PANEL2024导航栏面板
TYPE_DISPLAY_OVERLAY2026显示覆盖层
TYPE_MAGNIFICATION_OVERLAY2027放大覆盖层
TYPE_PRIVATE_PRESENTATION2030私有Presentation
TYPE_VOICE_INTERACTION2031语音交互
TYPE_ACCESSIBILITY_OVERLAY2032无障碍覆盖层
TYPE_VOICE_INTERACTION_STARTING2033语音交互启动窗口
TYPE_DOCK_DIVIDER2034分屏分割线
TYPE_QS_DIALOG2035快速设置对话框
TYPE_SCREENSHOT2036截图
TYPE_PRESENTATION2037Presentation
TYPE_APPLICATION_OVERLAY2038应用覆盖层 (SYSTEM_ALERT_WINDOW)
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY2039无障碍放大覆盖层
TYPE_NOTIFICATION_SHADE2040通知栏
TYPE_STATUS_BAR_ADDITIONAL2041附加状态栏
LAST_SYSTEM_WINDOW2999系统窗口结束值

9. 错误码与返回值

9.1 错误码

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

常量含义触发场景
ADD_OKAY0添加成功
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无效DisplayDisplay不存在或无权访问
ADD_INVALID_TYPE-10无效窗口类型WindowContext类型不匹配 / TYPE_STATUS_BAR_PANEL
ADD_INVALID_USER-11无效用户跨用户添加时用户验证失败

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

常量含义
ADD_FLAG_IN_TOUCH_MODE0x1当前处于触摸模式
ADD_FLAG_APP_VISIBLE0x2应用可见
ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS0x4始终消费系统栏

9.3 客户端异常映射

// 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 关键成员

字段类型说明
mSessionSession所属的客户端Session
mClientIWindow客户端Binder代理
mTokenWindowToken所属的WindowToken
mDisplayContentDisplayContent所属的DisplayContent
mActivityRecordActivityRecord关联的Activity(可能为null)
mAttrsWindowManager.LayoutParams窗口布局参数
mBaseLayerint基础Z序层级
mSubLayerint子窗口Z序偏移
mIsChildWindowboolean是否为子窗口
mLayoutAttachedboolean是否布局附加到父窗口
mIsImWindowboolean是否为IME窗口
mIsWallpaperboolean是否为壁纸窗口
mIsFloatingLayerboolean是否为浮动层
mWinAnimatorWindowStateAnimator窗口动画器
mInputChannelInputChannel服务端输入通道
mViewVisibilityintView可见性

10.2 WindowToken 关键成员

字段类型说明
windowTypeint窗口类型
mDisplayContentDisplayContent关联的DisplayContent
mPersistOnEmptyboolean无子窗口时是否保留
mOwnerCanManageAppTokensboolean所有者是否可管理App Token
mRoundedCornerOverlayboolean是否圆角覆盖层
mFromClientTokenboolean是否来自客户端Token (WindowContext)
mOptionsBundle选项
mSurfaceControlSurfaceControlSurface控制

10.3 WMS 关键容器

字段类型说明
mWindowMapHashMap<IBinder, WindowState>IWindow Binder → WindowState 映射
mGlobalLockWindowManagerGlobalLockWMS全局锁
mDisplayReadybooleanDisplay是否初始化完成
mPolicyWindowManagerPolicy窗口策略 (PhoneWindowManager)
mHH主线程Handler

11. 时序图

 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()
     │                              │

附录: 源码文件索引

文件路径
WindowManagerImplframeworks/base/core/java/android/view/WindowManagerImpl.java
WindowManagerGlobalframeworks/base/core/java/android/view/WindowManagerGlobal.java
ViewRootImplframeworks/base/core/java/android/view/ViewRootImpl.java
IWindowSessionframeworks/base/core/java/android/view/IWindowSession.aidl
IWindowframeworks/base/core/java/android/view/IWindow.aidl
Sessionframeworks/base/services/core/java/com/android/server/wm/Session.java
WindowManagerServiceframeworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
WindowStateframeworks/base/services/core/java/com/android/server/wm/WindowState.java
WindowTokenframeworks/base/services/core/java/com/android/server/wm/WindowToken.java
DisplayPolicyframeworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
DisplayContentframeworks/base/services/core/java/com/android/server/wm/DisplayContent.java
PhoneWindowManagerframeworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
WindowStateAnimatorframeworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java