【Android面试】窗口机制专题

文章目录

一、基础概念与体系架构

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值