文章目录
一、基础概念与体系架构
1. 简述 Window、WindowManager、WMS 三者关系与职责
答案:
Window:抽象类,代表一个窗口,是 View 的容器。具体实现是 PhoneWindow。
WindowManager:应用层接口,继承自 ViewManager,负责 添加、更新、删除窗口,是 App 与 WMS 交互的入口。
WMS(WindowManagerService):系统服务,运行在 system_server,负责所有窗口的管理、层级、尺寸、焦点、动画、显示排序。
关系:App 通过 WindowManager 跨进程通信(Binder)请求 WMS,WMS 真正决策窗口怎么显示

2. Android 中有哪些 Window 类型?应用与系统窗口区别 *
答案:窗口类型分三大类:
应用窗口:TYPE_BASE_APPLICATION、TYPE_APPLICATION(Activity 默认)
子窗口:TYPE_APPLICATION_PANEL(Dialog、PopupWindow),必须依附于主窗口
系统窗口:TYPE_STATUS_BAR、TYPE_TOAST、TYPE_SYSTEM_ALERT 等,输入法/悬浮窗/Toast/状态栏
区别:
应用窗口:需要 Activity/Token 才能创建,受生命周期管理。
系统窗口:需要额外权限,不受单个 Activity 生命周期控制。
3. addView/updateViewLayout/removeView 流程
App 层 WindowManager → WMS → Surface → SurfaceFlinger → 屏幕渲染
- addView
创建 ViewRootImpl
建立与 WMS 的连接
向 WMS 注册窗口,申请 Surface
开始首次 measure/layout/draw - updateViewLayout
更新 LayoutParams
请求 WMS 重新布局窗口
触发 requestLayout - removeView
销毁 Surface
向 WMS 注销窗口
解除 ViewRoot 与 View 的关联
处理窗口泄漏检查
4. 为什么 DecorView 是 Window 根 View?与 Window 如何绑定
答案:
DecorView 是 Activity/Window 界面的 最顶层 View,包含标题栏 + 内容布局。
它是 Window 唯一直接持有的 View。
绑定:
Activity 启动时,PhoneWindow 会创建 DecorView,并通过 setContentView 将布局添加到 DecorView 的 content 容器中。
5. PhoneWindow 作用
答案:
Window 的唯一系统实现类。
内部管理 DecorView、标题栏、背景、事件分发、输入法等。
是 Activity 和 WindowManager 之间的桥梁。
二、WindowManager 与 View 关联核心
1. 同一个 WM 可添加多个 View?不同 WM 实例区别
答案:
同一个 WindowManager 可以添加多个 View,每个 View 对应一个窗口。
每个 WindowManager 实例绑定一个 Context(Activity/Application)。
Activity 的 WM 会携带 Activity Token,Application 没有,所以不能直接弹 Dialog。
2. addView 中 LayoutInflater 与 WM 流程
答案:
LayoutInflater 把 xml 解析成 View 树
调用 WindowManager.addView(view, params)
内部创建 ViewRootImpl
ViewRootImpl 负责与 WMS 通信、创建 Surface、触发绘制
3. ViewRootImpl 核心作用 & 与 WMS 通信方式
答案:核心作用:
每个窗口对应一个 ViewRootImpl
管理 measure、layout、draw
管理 输入事件分发
管理 Surface 与渲染
管理 与 WMS 的通信
ViewRootImpl 是在 DecorView 被添加到 WindowManager 时创建的;实际创建时机在 Activity 的 onResume() 之后
通信:通过 Binder 接口 IWindowSession 与 WMS 通信。
4. 子线程不能更新 UI 原因 & 与 ViewRootImpl 关系
答案:
ViewRootImpl 里有 mThread 检查,记录创建时的线程(主线程)。
requestLayout/invalidate 最终会走到 checkThread()。
子线程更新会抛出 CalledFromWrongThreadException。
本质: UI 操作非线程安全,系统用单线程检查强制约束。
5. LayoutParams 哪些参数影响窗口展示
答案:
type:窗口类型(决定层级、权限)
width/height:宽高
gravity:对齐方式
flags:FLAG_NOT_FOCUSABLE、FLAG_NOT_TOUCHABLE 等
format:像素格式
dimAmount:背景灰度
token:窗口令牌(权限校验)
三、WMS 核心原理(大厂深度必问)
1. WMS 如何管理窗口?Z-Order 如何计算
WMS 运行在 SystemServer,通过层级树 + WindowState + WindowToken管理所有窗口生命周期与布局;Z‑Order = mBaseLayer + mSubLayer,由窗口类型决定 base、子窗口在父窗口 base 上叠加 sub,layer 越大越靠前。
2. App 与 WMS 通信方式 & Binder 作用
App 与 WMS 全程通过 Binder IPC 通信:App 端 WindowManager → IWindowManager/IWindowSession 代理 → WMS;WMS 通过 IWindow 回调 App;Binder 作用是跨进程通道、远程调用、数据传输、权限校验、事件回调、全局窗口管控。
3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token
答案:
WindowToken 是窗口的身份令牌,用于权限校验。
防止恶意应用随意弹系统级窗口。
Activity 窗口使用 AppToken/ActivityRecord Token。
Dialog 作为子窗口,必须使用 宿主 Activity 的 Token。
4. AppToken 与 WindowToken 区别
- 先有 ActivityToken,后有 WindowToken
AMS 创建 Activity → 分配 ActivityToken → 告知 WMS → WMS 依据它创建对应 WindowToken。
- 绑定关系
WindowToken 内部持有 ActivityToken 引用,实现组件层 ↔ 窗口层双向绑定。
- 职责划分
ActivityToken:管页面、生命周期、任务栈(AMS 层面)
WindowToken:管窗口、层级、显示、事件(WMS 层面)
- 为什么必须分开设计
职责解耦:AMS 只管组件生命周期,WMS 只管窗口绘制显示,互不侵入。
多窗口常见适配:一个 Activity 可以开多个窗口,一个 ActivityToken 对应多个 WindowState,共用一个 WindowToken。
系统窗口区分:状态栏、Toast、输入法无 Activity,直接使用独立 WindowToken,不需要 ActivityToken。
5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应关系
Activity 的生命周期由 AMS(ActivityManagerService) 管理,窗口生命周期由 WMS 管理,二者通过 WindowManager 桥接,同步触发但分属不同模块

6. 如何判断窗口可获取焦点?焦点切换逻辑
- 焦点条件:LayoutParams.FLAG_NOT_FOCUSABLE 为true,窗口可见,不被完全遮挡,属于当前前台应用
- 切换:触摸 / 按键 → WMS 计算顶层可焦点窗口 → 通知对应窗口获取焦点。
- 同一时间只有一个窗口拥有焦点
- 焦点永远给最顶层的符合条件的窗口
- 子窗口优先于父窗口
四、Activity/Dialog/Toast 窗口原理
1. Activity 窗口在哪个生命周期创建 & 添加
Activity 窗口在 onCreate 中完成创建并提交添加请求,onResume 阶段由 WMS 完成显示与焦点分配。
但 addView 真正被系统调用的位置是:ActivityThread 的 handleResumeActivity 方法中,在 onResume 执行完成之后。
2. Dialog 与 Activity 窗口区别?非 Activity 上下文报错原因
Dialog 是 子窗口,必须依附 Activity 窗口。
Activity 窗口有 AppToken,Dialog 使用宿主 Token。
用 Application 等无 Token 的 Context:
系统校验 Token 失败 → 抛出 WindowManager.BadTokenException。
3. Toast 窗口类型 & 限制 & 崩溃原因
- 类型:TYPE_TOAST(系统窗口)
- 限制:
自动超时消失
高版本无法自定义 Toast
后台弹出受限 - 常见崩溃:
Toast 持有 Activity 引用导致销毁时窗口泄漏
7.1 以下 Toast 内部 TN 类 Binder 泄漏导致崩溃
4. 悬浮窗权限校验逻辑
- 系统窗口类型需要 SYSTEM_ALERT_WINDOW 权限
- 6.0 前:声明即用,无需授权
- 6.0 后:不能动态申请,只能跳设置让用户手动开
- WMS 会检查:类型 + 权限 + Token
5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么
Dialog 是子窗口,必须绑定 Activity Token。
- 脱离 Activity 需要:
使用 系统窗口类型
申请悬浮窗权限
自己管理生命周期,防止窗口泄漏
五、Surface 与窗口渲染
1. Window 与 Surface 关系 & 窗口渲染流程
Surface 是一块 画布(缓冲区),Window 对应一个 Surface。
渲染流程:
- Activity 创建 PhoneWindow、DecorView,构建 View 视图树
- 绑定 Activity WindowToken,向 WMS 注册窗口属性
- handleResumeActivity 执行 addView,正式请求添加窗口
- WMS 向 SurfaceFlinger 申请分配 Surface 绘图缓冲区
- 应用侧通过 Choreographer 监听 VSync 垂直同步信号
- VSync 信号抵达 → Choreographer 统一调度渲染任务
- 触发 View 三大流程:测量 → 布局 → 绘制 (由ViewRootImpl执行)
- 绘制完成,提交 Surface 帧数据
- SurfaceFlinger 对所有窗口 Surface 分层排序、图层混合合成
- 交由 HWComposer 硬件合成,最终刷新屏幕完成显示
2. SurfaceFlinger 作用 & 与 WMS、App 协作
SurfaceFlinger:系统合成服务,负责 所有图层混合、合成、送显。
WMS 告诉 SF 窗口位置、大小、层级。
App 往 Surface 里写数据。
SF 按 Z 序合成所有窗口,输出到屏幕。
3. 硬件加速 & 开启后渲染变化
硬件加速:使用 GPU 绘制 View。
变化:
绘制性能大幅提升
绘制模型变成 显示列表(DisplayList)
部分 API 不兼容或行为改变
4. SurfaceView、TextureView 与普通 View 区别
普通 View:共享同一个 Surface,在主线程绘制。
SurfaceView:独立 Surface,可子线程绘制,效率高,但不支持动画、平移旋转。
TextureView:有独立缓冲,但挂载在应用窗口中,支持变换、动画。

5. invalidate/requestLayout 如何到 WMS & SF
- requestLayout():触发 measure + layout 重新测量布局,不走 draw
- invalidate():只触发 draw 重绘,不重新测量布局
view.requestLayout()
→ 上报 ViewRootImpl
→ 注册 Choreographer 监听 VSync
→ VSync 到来执行 measure + layout
→ 窗口尺寸/位置变更 → 跨进程通知 WMS 更新窗口属性
→ 可选触发draw写入Surface
→ 提交缓冲区 → SF合成渲染上屏
view.invalidate()
→ 标记脏区域 → 上报 ViewRootImpl
→ 等待VSync → 仅执行draw绘制
→ 内容写入Surface缓冲区
→ 直接提交帧数据给SF合成显示
→ 不通知WMS修改窗口布局信息
六、Token 机制与权限校验
1. 为什么用 WindowToken 校验窗口合法性
防止恶意应用在后台随意弹窗、仿冒界面、窃取隐私。
Token 由系统分发,App 不能伪造。
只有合法 Token 才能创建对应级别窗口。
不同应用、不同进程窗口拥有不同 WindowToken,WMS 依靠 Token 做进程隔离,禁止跨进程随意依附弹窗,保障系统界面安全。
2. 应用后台弹窗口被拦截核心逻辑
高版本 Android 限制后台应用弹出覆盖层窗口。
WMS 检查:
应用是否在前台
是否有特殊权限
窗口类型是否允许后台显示
无权限则拒绝 addView。
3. 不同版本对 Token、后台弹窗的改动
Android 6.0:悬浮窗动态权限
Android 8.0:Toast 改用 TYPE_TOAST,禁止自定义 Toast
Android 10/11:严格限制后台悬浮窗、后台弹出 Activity
整体趋势:越来越严,越安全
4. Application 上下文创建 Dialog 崩溃原因
Application Context 没有 Activity Token。
Dialog 是子窗口,必须依附带 Token 的 Activity 窗口。
WMS 校验 Token 为空 → 直接抛异常。
5. 如何绕过 Token 实现后台弹窗?系统如何修复
- 早期利用 系统漏洞 / 反射 伪造 Token。
- 利用 TYPE_SYSTEM_ALERT 等系统窗口。
系统修复:
严格权限
严格 Token 校验
后台弹出限制
高版本无法通用绕过
七、多窗口、分屏、折叠屏
1. 多窗口下 WMS 如何管理应用窗口
WMS 为每个窗口分配 固定区域。
每个应用视为独立窗口栈。
焦点、输入、尺寸单独管理。
生命周期与正常 Activity 略有区别(如不总是 onStop)。
2. 分屏下窗口尺寸、生命周期、焦点变化
尺寸:按分屏比例重新 layout
生命周期:不会正常走 onStop,保持 resumed
焦点:同一时间只有一个窗口获焦
3. 折叠屏切换时窗口重建与布局
折叠屏切换时,硬件传感器通知 DisplayManager → AMS 判定配置变更 → WMS 重新计算窗口大小并 relayout → 应用默认重建 Activity,或通过 configChanges 动态 resize → ViewRootImpl 在 VSync 驱动下重新 measure/layout/draw → SurfaceFlinger 合成新屏幕图层并上屏。
核心是配置变更触发窗口重建 / 重布局,VSync+Choreographer 保障渲染时序,同时需适配铰链与大屏布局。
4. 多窗口与 Activity 启动模式关系
多窗口下,standard 等模式会在 对应窗口栈 内创建。
分屏时,新 Activity 默认在同半屏打开。
特殊启动模式(如 singleInstance)会独占一个窗口。
八、异常场景与问题排查
1. WindowLeaked 场景 & 如何避免
- 场景:
Activity 销毁时,Dialog/Toast/ 悬浮窗未关闭
窗口仍持有 Activity 引用 - 避免:
onDestroy 中 dismiss Dialog
用 Application 生命周期管理全局弹窗
及时 removeView
2. 后台切回黑屏 / 白屏与窗口机制关系
Activity 被销毁后重新创建
DecorView 未完成绘制前显示窗口背景
或 Surface 未准备好
- 白屏:Activity主题 windowBackground 底色先显示,布局还未渲染
- 黑屏:Surface 未就绪,无画布内容,系统默认黑色画布填充
3. 窗口动画卡顿、黑屏分析角度
- 动画卡顿

- 动画黑屏

**窗口动画卡顿:**从主线程阻塞、视图绘制过重、频繁窗口重布局 IPC 耗时、Surface 渲染缓冲不足、SF 合成压力、VSync 时序不同步六大角度分析。
动画过程黑屏:核心是Surface 销毁重建时序不同步、窗口可见早于视图绘制、WindowToken 失效挂载异常、配置变更重建中断渲染、顶层窗口抢占遮挡导致画面断层缺失。
4. 软键盘弹出挤压布局原理
输入法是一个系统窗口。
键盘弹出 → WMS 调整应用窗口大小
windowSoftInputMode 控制:
压缩布局
平移布局
不调整
九、大厂开放性问题
1. 窗口从创建到显示全流程
Activity → PhoneWindow → DecorView → ViewRootImpl → WMS → SurfaceFlinger → 屏幕。
2. 全局悬浮窗实现要点
申请悬浮窗权限
使用系统窗口类型
处理触摸、拖动、焦点
注意生命周期,防止泄漏
3. 系统窗口与应用窗口通信
Binder、AIDL、ContentProvider、广播。
4. 优化 Activity 窗口启动速度
减少布局层级
异步加载
优化绘制
避免主线程耗时
复用窗口 / 预创建 DecorView
1万+

被折叠的 条评论
为什么被折叠?



