文章目录
- 一、基础概念与体系架构
-
- [1. 简述 Window、WindowManager、WMS 三者关系与职责](#1. 简述 Window、WindowManager、WMS 三者关系与职责)
- [2. Android 中有哪些 Window 类型?应用与系统窗口区别](#2. Android 中有哪些 Window 类型?应用与系统窗口区别)
- [3. addView/updateViewLayout/removeView 流程](#3. addView/updateViewLayout/removeView 流程)
- [4. 为什么 DecorView 是 Window 根 View?与 Window 如何绑定](#4. 为什么 DecorView 是 Window 根 View?与 Window 如何绑定)
- [5. PhoneWindow 作用](#5. PhoneWindow 作用)
- [二、WindowManager 与 View 关联核心](#二、WindowManager 与 View 关联核心)
-
- [1. 同一个 WM 可添加多个 View?不同 WM 实例区别](#1. 同一个 WM 可添加多个 View?不同 WM 实例区别)
- [2. addView 中 LayoutInflater 与 WM 流程](#2. addView 中 LayoutInflater 与 WM 流程)
- [3. ViewRootImpl 核心作用 & 与 WMS 通信方式](#3. ViewRootImpl 核心作用 & 与 WMS 通信方式)
- [4. 子线程不能更新 UI 原因 & 与 ViewRootImpl 关系](#4. 子线程不能更新 UI 原因 & 与 ViewRootImpl 关系)
- [5. LayoutParams 哪些参数影响窗口展示](#5. LayoutParams 哪些参数影响窗口展示)
- [三、WMS 核心原理(大厂深度必问)](#三、WMS 核心原理(大厂深度必问))
-
- [1. WMS 如何管理窗口?Z-Order 如何计算](#1. WMS 如何管理窗口?Z-Order 如何计算)
- [2. App 与 WMS 通信方式 & Binder 作用](#2. App 与 WMS 通信方式 & Binder 作用)
- [3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token](#3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token)
- [4. AppToken 与 WindowToken 区别](#4. AppToken 与 WindowToken 区别)
- [5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应](#5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应)
- [6. 如何判断窗口可获取焦点?焦点切换逻辑](#6. 如何判断窗口可获取焦点?焦点切换逻辑)
- [四、Activity/Dialog/Toast 窗口原理](#四、Activity/Dialog/Toast 窗口原理)
-
- [1. Activity 窗口在哪个生命周期创建 & 添加](#1. Activity 窗口在哪个生命周期创建 & 添加)
- [2. Dialog 与 Activity 窗口区别?非 Activity 上下文报错原因](#2. Dialog 与 Activity 窗口区别?非 Activity 上下文报错原因)
- [3. Toast 窗口类型 & 限制 & 崩溃原因](#3. Toast 窗口类型 & 限制 & 崩溃原因)
- [4. 悬浮窗权限校验逻辑](#4. 悬浮窗权限校验逻辑)
- [5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么](#5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么)
- [五、Surface 与窗口渲染](#五、Surface 与窗口渲染)
-
- [1. Window 与 Surface 关系 & 窗口渲染流程](#1. Window 与 Surface 关系 & 窗口渲染流程)
- [2. SurfaceFlinger 作用 & 与 WMS、App 协作](#2. SurfaceFlinger 作用 & 与 WMS、App 协作)
- [3. 硬件加速 & 开启后渲染变化](#3. 硬件加速 & 开启后渲染变化)
- [4. SurfaceView、TextureView 与普通 View 区别](#4. SurfaceView、TextureView 与普通 View 区别)
- [5. invalidate/requestLayout 如何到 WMS & SF](#5. invalidate/requestLayout 如何到 WMS & SF)
- [六、Token 机制与权限校验(字节 / 阿里高频)](#六、Token 机制与权限校验(字节 / 阿里高频))
-
- [1. 为什么用 WindowToken 校验窗口合法性](#1. 为什么用 WindowToken 校验窗口合法性)
- [2. 应用后台弹窗口被拦截核心逻辑](#2. 应用后台弹窗口被拦截核心逻辑)
- [3. 不同版本对 Token、后台弹窗的改动](#3. 不同版本对 Token、后台弹窗的改动)
- [4. Application 上下文创建 Dialog 崩溃原因](#4. Application 上下文创建 Dialog 崩溃原因)
- [5. 如何绕过 Token 实现后台弹窗?系统如何修复](#5. 如何绕过 Token 实现后台弹窗?系统如何修复)
- 七、多窗口、分屏、折叠屏
-
- [1. 多窗口下 WMS 如何管理应用窗口](#1. 多窗口下 WMS 如何管理应用窗口)
- [2. 分屏下窗口尺寸、生命周期、焦点变化](#2. 分屏下窗口尺寸、生命周期、焦点变化)
- [3. 折叠屏切换时窗口重建与布局](#3. 折叠屏切换时窗口重建与布局)
- [4. 多窗口与 Activity 启动模式关系](#4. 多窗口与 Activity 启动模式关系)
- 八、异常场景与问题排查
-
- [1. WindowLeaked 场景 & 如何避免](#1. WindowLeaked 场景 & 如何避免)
- [2. 后台切回黑屏 / 白屏与窗口机制关系](#2. 后台切回黑屏 / 白屏与窗口机制关系)
- [3. 窗口动画卡顿、黑屏分析角度](#3. 窗口动画卡顿、黑屏分析角度)
- [4. 软键盘弹出挤压布局原理](#4. 软键盘弹出挤压布局原理)
- 九、大厂开放性问题(简要答案)
-
- [1. 窗口从创建到显示全流程](#1. 窗口从创建到显示全流程)
- [2. 全局悬浮窗实现要点](#2. 全局悬浮窗实现要点)
- [3. 系统窗口与应用窗口通信](#3. 系统窗口与应用窗口通信)
- [4. 优化 Activity 窗口启动速度](#4. 优化 Activity 窗口启动速度)
- [5. Android 12+ 窗口核心改动](#5. Android 12+ 窗口核心改动)
一、基础概念与体系架构
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 等
区别:
应用窗口:需要 Activity/Token 才能创建,受生命周期管理。
系统窗口:需要额外权限,不受单个 Activity 生命周期控制。
3. addView/updateViewLayout/removeView 流程
- 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 内部用 WindowState 描述每个窗口。
按 type + 层级规则 排序 Z 序。
层级:系统窗口 > 子窗口 > 应用窗口。
同类型按添加顺序、焦点、显示状态调整。
2. App 与 WMS 通信方式 & Binder 作用
答案:
通信通道:IWindowSession(每个进程一个)
窗口回调:IWindow(每个窗口一个)
Binder 作用:跨进程传递 窗口操作、尺寸、事件、生命周期。
3. WindowToken 作用?为什么 Activity/Dialog 要不同 Token
答案:
WindowToken 是窗口的身份令牌,用于权限校验。
防止恶意应用随意弹系统级窗口。
Activity 窗口使用 AppToken/ActivityRecord Token。
Dialog 作为子窗口,必须使用 宿主 Activity 的 Token。
4. AppToken 与 WindowToken 区别
答案:
AppToken:对应一个 Activity,生命周期与 Activity 绑定。
WindowToken:对应一组窗口,用于校验窗口合法性。
Activity 窗口用 AppToken,普通子窗口用 WindowToken。
5. WMS 感知窗口生命周期?Activity 与窗口生命周期对应
答案:
Activity 生命周期通过 AMS 通知 WMS。
对应关系:
onCreate:创建窗口
onResume:窗口真正 addView、显示
onPause:失去焦点
onDestroy:移除窗口
6. 如何判断窗口可获取焦点?焦点切换逻辑
答案:
焦点条件:
LayoutParams.FLAG_NOT_FOCUSABLE 为 false
窗口可见、不被完全遮挡
属于当前前台应用
切换:
触摸 / 按键 → WMS 计算顶层可焦点窗口 → 通知对应窗口获取焦点。
四、Activity/Dialog/Toast 窗口原理
1. Activity 窗口在哪个生命周期创建 & 添加
答案:
onCreate:PhoneWindow、DecorView 创建
onResume(handleResumeActivity):
调用 wm.addView,窗口真正显示到屏幕。
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 权限。
Android 6.0+ 动态申请。
Android 10+ 后台弹悬浮窗进一步受限。
WMS 会检查:类型 + 权限 + Token。
5. Dialog 依赖 Activity Window?脱离 Activity 展示要解决什么
答案:
Dialog 是子窗口,必须绑定 Activity Token。
脱离 Activity 需要:
使用 系统窗口类型
申请悬浮窗权限
自己管理生命周期,防止窗口泄漏
五、Surface 与窗口渲染
1. Window 与 Surface 关系 & 窗口渲染流程
答案:
Surface 是一块 画布(缓冲区),Window 对应一个 Surface。
渲染流程:
App 绘制 → 写入 Surface → 提交给 SurfaceFlinger → SurfaceFlinger 合成 → 屏幕显示。
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
答案:
invalidate/requestLayout → ViewRootImpl
scheduleTraversals
主线程 performTraversals
measure/layout/draw
绘制内容写入 Surface
setVisible/relayout 通知 WMS
WMS 通知 SF 合成刷新
六、Token 机制与权限校验(字节 / 阿里高频)
1. 为什么用 WindowToken 校验窗口合法性
答案:
防止恶意应用在后台随意弹窗、仿冒界面、窃取隐私。
Token 由系统分发,App 不能伪造。
只有合法 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. 折叠屏切换时窗口重建与布局
答案:
折叠 / 展开 → 屏幕尺寸变化
系统触发 configChange
默认重建 Activity
可通过 android:configChanges 避免重建,自己重布局
4. 多窗口与 Activity 启动模式关系
答案:
多窗口下,standard 等模式会在 对应窗口栈 内创建。
分屏时,新 Activity 默认在同半屏打开。
特殊启动模式(如 singleInstance)会独占一个窗口。
八、异常场景与问题排查
1. WindowLeaked 场景 & 如何避免
答案:场景:
Activity 销毁时,Dialog/Toast/ 悬浮窗未关闭
窗口仍持有 Activity 引用
避免:
onDestroy 中 dismiss Dialog
用 Application 生命周期管理全局弹窗
及时 removeView
2. 后台切回黑屏 / 白屏与窗口机制关系
答案:
Activity 被销毁后重新创建
DecorView 未完成绘制前显示窗口背景
或 Surface 未准备好
优化:设置合适背景、优化启动、防止不必要重建
3. 窗口动画卡顿、黑屏分析角度
答案:
主线程阻塞,绘制不及时
动画复杂,GPU 负载高
窗口层级过多,SF 合成压力大
Surface 创建 / 销毁延迟
4. 软键盘弹出挤压布局原理
答案:
输入法是一个系统窗口。
键盘弹出 → WMS 调整应用窗口大小
windowSoftInputMode 控制:
压缩布局
平移布局
不调整
九、大厂开放性问题(简要答案)
1. 窗口从创建到显示全流程
Activity → PhoneWindow → DecorView → ViewRootImpl → WMS → SurfaceFlinger → 屏幕。
2. 全局悬浮窗实现要点
申请悬浮窗权限
使用系统窗口类型
处理触摸、拖动、焦点
注意生命周期,防止泄漏
3. 系统窗口与应用窗口通信
Binder、AIDL、ContentProvider、广播。
4. 优化 Activity 窗口启动速度
减少布局层级
异步加载
优化绘制
避免主线程耗时
复用窗口 / 预创建 DecorView
5. Android 12+ 窗口核心改动
统一窗口类型
更严格的后台弹出限制
强化隐私权限
折叠屏 / 大屏增强