基于 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>--- 所有已添加的ViewmRoots: ArrayList<ViewRootImpl>--- 所有ViewRootImplmParams: 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 |