Files
mkdocs/docs/技术面试问题回答.md
2026-01-16 14:58:56 +08:00

33 KiB
Raw Blame History

技术面试问题回答

一、Framework开发经验相关

Q1: 请介绍一下你的Framework开发经验主要涉及哪些方面

A: 我拥有4年Framework深度开发经验主要专注于Android系统框架与中间件开发。具体包括

  • 系统核心服务深入理解AMS、PKMS、PMS、Input、DPM等核心服务的运行机制和实现原理
  • 窗口系统精通WMS、WMShell、View系统熟悉多窗口场景分屏、浮窗、自由窗等的绘制原理
  • Binder通信深入理解Binder机制熟悉系统服务间通信原理
  • 系统功能:熟悉权限管理、通知系统、系统升级、分屏、多屏协同等功能的实现机制
  • 企业级中间件参与过2个企业级中间件框架的开发与维护具备框架设计与架构能力

Q2: 能详细说说Android系统启动流程吗

A: Android系统启动流程主要包括以下几个阶段

  1. Bootloader阶段加载Linux内核
  2. Kernel启动初始化硬件驱动启动init进程
  3. Init进程解析init.rc启动Zygote进程和ServiceManager
  4. Zygote进程预加载类和资源fork出SystemServer进程
  5. SystemServer启动各类系统服务AMS、WMS、PKMS等
  6. Launcher启动系统服务就绪后启动Launcher用户可见

在整个过程中我重点关注AMS、WMS等核心服务的启动顺序和依赖关系以及它们如何协同工作。

Q3: 你提到熟悉Binder机制能说说Binder的工作原理吗

A: Binder是Android的进程间通信机制主要特点

  • 一次拷贝通过mmap实现数据只需拷贝一次效率高
  • 安全性:基于内核驱动,有完善的权限验证机制
  • 架构采用C/S架构包含Client、Server、ServiceManager、Binder驱动四部分

工作流程:

  1. Server向ServiceManager注册服务
  2. Client通过ServiceManager获取服务代理
  3. Client调用代理方法通过Binder驱动传递到Server
  4. Server处理请求并返回结果

在实际开发中我经常需要自定义Binder服务理解AIDL的生成机制以及如何优化Binder调用的性能。

二、系统稳定性与问题定位

Q4: 如何定位和解决ANR问题

A: ANR定位我通常采用以下步骤

  1. 日志分析:查看/data/anr/traces.txt,定位主线程阻塞位置
  2. 工具分析使用Systrace、Perfetto分析主线程执行时间线
  3. 常见原因:
    • 主线程执行耗时操作网络、数据库、文件IO
    • 死锁或锁竞争
    • 系统服务响应慢如AMS、WMS

解决方案:

  • 耗时操作移到子线程(线程池、协程)
  • 优化数据库查询,使用索引
  • 避免主线程持有锁时间过长
  • 对于系统服务问题需要分析Framework层代码

Q5: 如何排查内存泄漏问题?

A: 内存泄漏排查流程:

  1. 工具检测使用LeakCanary、MATMemory Analyzer Tool进行检测
  2. 分析堆转储:查看对象引用链,找出泄漏路径
  3. 常见场景:
    • 静态变量持有Context/Activity引用
    • 监听器未解注册BroadcastReceiver、EventBus等
    • 内部类持有外部类引用Handler、Thread等
    • 单例模式持有Context

预防措施:

  • 使用WeakReference持有Context
  • 及时解注册监听器
  • Handler使用静态内部类+WeakReference
  • 定期进行内存分析

Q6: 遇到过冻屏、死机问题吗?如何定位?

A: 遇到过,这类问题通常比较复杂,我的定位思路:

  1. 日志收集抓取logcat、kernel log、tombstone等
  2. 分析关键信息:
    • 冻屏:检查主线程是否阻塞,是否有死锁
    • 死机查看kernel panic信息分析硬件/驱动问题
  3. 使用工具:
    • Systrace分析CPU调度
    • Perfetto分析系统整体状态
    • 使用adb shell dumpsys分析各服务状态

实际案例曾遇到一个冻屏问题通过Systrace发现是WMS在窗口切换时发生死锁最终通过优化锁的粒度解决。

三、性能优化经验

Q7: 你在性能优化方面有哪些经验?

A: 性能优化我主要从以下几个方面入手:

系统级优化:

  • CPU调度了解系统调度机制优化线程优先级和CPU亲和性
  • 内存优化:减少内存分配,使用对象池,优化数据结构
  • I/O优化使用异步IO批量操作减少文件读写次数

应用层优化:

  • 启动优化减少Application初始化时间延迟加载非关键组件
  • 布局优化减少布局层级使用ConstraintLayout避免过度绘制
  • 网络优化:请求合并,使用缓存,压缩数据

工具使用:

  • 使用Perfetto、Systrace分析性能瓶颈
  • 使用Profiler监控CPU、内存、网络使用情况
  • 使用StrictMode检测主线程耗时操作

Q8: 如何优化应用启动速度?

A: 启动优化策略:

  1. Application优化

    • 延迟初始化非关键组件(使用懒加载)
    • 将初始化任务放到子线程或异步执行
    • 使用启动器模式,控制初始化顺序
  2. 首屏优化:

    • 减少首屏布局复杂度
    • 使用ViewStub延迟加载
    • 预加载关键数据
  3. 技术手段:

    • 使用App Startup库统一管理初始化
    • 使用Trace API标记启动流程
    • 分析启动时间线,找出瓶颈

实际效果在某个项目中通过优化将启动时间从3.5秒降低到1.8秒。

四、架构设计与项目经验

Q9: 你在架构设计方面有哪些经验?

A: 架构设计经验:

应用层架构:

  • 熟练掌握MVC、MVP、MVVM架构模式根据项目特点选择合适架构
  • 组件化开发:将业务模块解耦,实现模块独立开发和测试
  • 接口设计:定义清晰的模块间接口,降低耦合度

Framework层架构

  • 参与过2个企业级中间件框架的开发负责核心模块设计
  • 熟悉系统服务架构,理解服务注册、发现、调用机制
  • 模块解耦:通过接口抽象、依赖注入等方式实现模块解耦

设计原则:

  • 单一职责原则
  • 开闭原则
  • 依赖倒置原则
  • 关注点分离

Q10: 能介绍一下你参与的大型项目吗?

A: 我参与过多个大型项目,主要包括:

Framework层项目

  • 企业级中间件框架:负责核心服务模块的设计与开发,支持多业务线接入
  • 系统定制化项目:参与系统服务的定制化开发,优化系统性能和稳定性

应用层项目:

  • 电商App负责核心购物流程、支付模块开发处理高并发场景
  • 社交即时通讯App负责消息推送、音视频通话等核心功能
  • 工具类App涉及多个垂直领域的工具应用

在这些项目中,我主要负责:

  • 架构设计与技术选型
  • 核心模块开发与性能优化
  • 复杂问题排查与解决
  • 代码review和技术分享

五、复杂问题解决能力

Q11: 能分享一个你解决过的复杂技术问题吗?

A: 案例:多窗口场景下的内存泄漏问题

问题描述:

在分屏场景下应用退出后内存持续增长最终导致OOM。

排查过程:

  1. 使用MAT分析堆转储发现大量Window对象未释放
  2. 通过Systrace分析发现WMS在窗口销毁时未正确清理
  3. 深入Framework代码发现是窗口状态机在特定场景下未正确转换

解决方案:

  • 在应用层确保Activity正确调用onDestroy及时释放资源
  • 在Framework层修复窗口状态机的状态转换逻辑确保窗口正确销毁
  • 添加监控:增加窗口泄漏检测机制,及时发现问题

结果: 问题彻底解决,内存使用恢复正常,并建立了预防机制。

Q12: 如何快速定位和解决线上Crash问题

A: Crash问题处理流程

  1. 信息收集:

    • 收集Crash堆栈、设备信息、系统版本
    • 查看用户操作路径,复现问题
  2. 问题分析:

    • 分析堆栈信息,定位崩溃位置
    • 检查是否为空指针、数组越界、类型转换等常见问题
    • 查看相关代码变更历史
  3. 解决方案:

    • 添加空值检查、边界检查
    • 使用try-catch捕获异常
    • 对于Framework层问题需要深入分析系统服务
  4. 预防措施:

    • 完善单元测试和集成测试
    • 使用Crash监控平台如Firebase Crashlytics
    • 代码review时重点关注异常处理

六、技术深度与学习能力

Q13: 你是如何保持技术更新的?

A: 技术学习方式:

  1. 源码阅读:

    • 定期阅读Android Framework源码理解系统实现原理
    • 关注Google官方文档和AOSP更新
  2. 技术社区:

    • 关注技术博客、GitHub优秀项目
    • 参与技术会议和分享
  3. 实践总结:

    • 在项目中实践新技术
    • 总结问题解决经验,形成知识沉淀
  4. 工具使用:

    • 学习使用新的调试工具如Perfetto
    • 关注性能分析工具的发展

Q14: 对于Android新版本特性你是如何学习和应用的

A: 学习新版本特性的方法:

  1. 官方文档:

    • 第一时间阅读Google官方发布说明
    • 关注新API和废弃API的变化
  2. 实践验证:

    • 在测试项目中验证新特性
    • 分析新特性的实现原理
  3. 兼容性处理:

    • 考虑向后兼容性
    • 使用版本适配库如AndroidX
  4. 团队分享:

    • 将新特性应用到实际项目
    • 在团队内部分享学习心得

七、团队协作与项目管理

Q15: 在团队协作中,你是如何保证代码质量的?

A: 代码质量保障措施:

  1. 代码规范:

    • 遵循团队代码规范
    • 使用代码检查工具Lint、Checkstyle
  2. Code Review

    • 认真review他人代码提出改进建议
    • 接受他人review持续改进
  3. 测试:

    • 编写单元测试和集成测试
    • 进行充分的自测
  4. 文档:

    • 编写清晰的代码注释
    • 维护技术文档

Q16: 你如何平衡开发效率和代码质量?

A: 平衡策略:

  1. 技术选型:

    • 选择成熟稳定的技术方案,避免过度设计
    • 使用合适的框架和工具,提高开发效率
  2. 代码复用:

    • 抽取公共组件,避免重复开发
    • 建立组件库,提高复用率
  3. 迭代优化:

    • 先实现功能,再逐步优化
    • 定期重构,保持代码质量
  4. 工具辅助:

    • 使用IDE插件提高编码效率
    • 使用CI/CD自动化测试和部署

总结

以上是我基于10年Android开发经验在Framework层和应用层开发、系统稳定性保障、性能优化、架构设计等方面的技术积累。我具备解决复杂技术问题的能力能够从系统层面思考问题提供最优解决方案。同时我注重团队协作能够将技术经验分享给团队共同提升技术水平。

WMS窗口常见面试题

本文档整理了Android WMSWindow Manager Service窗口管理相关的常见面试题涵盖基础概念、架构原理、源码分析、问题排查等多个方面。

目录


基础概念类

Q1: 什么是WMS它的主要职责是什么

答案:

WMSWindow Manager Service是Android窗口系统的核心服务运行在system_server进程中。

主要职责:

  1. 窗口管理:管理所有窗口的创建、显示、销毁等生命周期

  2. 窗口层级管理维护窗口的Z-Order顺序决定窗口的显示优先级

  3. 布局计算:计算窗口的位置、大小和可见区域

  4. 输入事件分发:将触摸、按键等输入事件分发给正确的窗口

  5. 窗口动画:管理窗口的显示、隐藏、切换等动画效果

  6. 屏幕旋转:处理屏幕方向变化时的窗口布局调整

  7. 多显示支持:支持多个显示设备的窗口管理


// WMS是系统服务在SystemServer中启动

public class SystemServer {

    private void startOtherServices(...) {

        WindowManagerService wm = WindowManagerService.main(...);

        ServiceManager.addService(Context.WINDOW_SERVICE, wm);

    }

}

Q2: WMS与WindowManager、WindowManagerGlobal的关系是什么

答案:

这三者的关系如下:

  1. WindowManager应用层接口开发者使用的API

  2. WindowManagerGlobal应用层实现管理ViewRootImpl和窗口会话

  3. WindowManagerService:系统服务,实际管理窗口的服务端

调用流程:


应用层WindowManager.addView()

    ↓

WindowManagerGlobal.addView()

    ↓

ViewRootImpl.setView()

    ↓

IWindowSession.addToDisplay() (Binder调用)

    ↓

WMS.addWindow() (服务端)


// WindowManager接口

public interface WindowManager extends ViewManager {

    void addView(View view, ViewGroup.LayoutParams params);

    void removeView(View view);

    void updateViewLayout(View view, ViewGroup.LayoutParams params);

}

  

// WindowManagerGlobal实现

public final class WindowManagerGlobal {

    public void addView(View view, ViewGroup.LayoutParams params, ...) {

        ViewRootImpl root = new ViewRootImpl(view.getContext(), display);

        root.setView(view, wparams, panelParentView);

    }

}

  

// WMS服务端

public class WindowManagerService {

    public int addWindow(Session session, IWindow client, ...) {

        // 实际窗口管理逻辑

    }

}

Q3: 窗口类型有哪些?它们的层级关系是什么?

答案:

窗口类型:

  1. 应用窗口APPLICATION

   - TYPE_APPLICATION普通Activity窗口

   - TYPE_APPLICATION_STARTING:启动窗口

   - TYPE_BASE_APPLICATION:应用基础窗口

  1. 子窗口SUB_WINDOW

   - TYPE_APPLICATION_PANEL:应用面板

   - TYPE_APPLICATION_SUB_PANEL:应用子面板

   - TYPE_APPLICATION_ATTACHED_DIALOG:附加对话框

  1. 系统窗口SYSTEM_WINDOW

   - TYPE_STATUS_BAR:状态栏

   - TYPE_NAVIGATION_BAR:导航栏

   - TYPE_SYSTEM_ALERT:系统警告窗口

   - TYPE_TOASTToast窗口

   - TYPE_APPLICATION_OVERLAY:悬浮窗(需要权限)

层级关系Z-Order


系统窗口(最高)

    ↓

应用窗口(中等)

    ↓

子窗口(最低)


// 窗口类型定义

public static class LayoutParams {

    // 应用窗口1000-1999

    public static final int TYPE_APPLICATION = 2;

    public static final int TYPE_APPLICATION_STARTING = 3;

    // 子窗口1000-1999

    public static final int TYPE_APPLICATION_PANEL = 1000;

    // 系统窗口2000-2999

    public static final int TYPE_STATUS_BAR = 2000;

    public static final int TYPE_SYSTEM_ALERT = 2003;

    public static final int TYPE_TOAST = 2005;

    public static final int TYPE_APPLICATION_OVERLAY = 2038;

}


架构原理类

Q4: WMS的架构是怎样的包含哪些核心组件

答案:

WMS架构分层


┌─────────────────────────────────┐

│  应用层(客户端)                  │

│  Activity/WindowManager          │

└──────────────┬──────────────────┘

               │ Binder IPC

┌──────────────▼──────────────────┐

│  系统服务层(服务端)              │

│  WindowManagerService            │

│  ├── WindowState                 │

│  ├── DisplayContent              │

│  ├── WindowToken                 │

│  └── WindowAnimator              │

└──────────────┬──────────────────┘

               │

┌──────────────▼──────────────────┐

│  显示层                          │

│  SurfaceFlinger                 │

└─────────────────────────────────┘

核心组件:

  1. WindowManagerServiceWMS主类管理所有窗口

  2. WindowState:窗口状态,表示一个窗口的所有信息

  3. DisplayContent:显示内容,管理一个显示设备上的所有窗口

  4. WindowToken:窗口令牌,用于窗口分组和权限控制

  5. WindowAnimator:窗口动画控制器

  6. WindowStateAnimator:单个窗口的动画状态


// WindowState窗口状态

class WindowState {

    final WindowManagerService mService;

    final WindowToken mToken;

    final WindowManager.LayoutParams mAttrs;

    final DisplayContent mDisplayContent;

    SurfaceControl mSurfaceControl;

    // 窗口属性

    int mLayer;  // 层级

    Rect mFrame; // 位置和大小

    boolean mVisible; // 是否可见

}

Q5: 窗口添加的完整流程是什么?

答案:

窗口添加流程:


1. Activity.attach()

   └──> 创建PhoneWindow

2. Activity.onCreate()

   └──> setContentView()

       └──> PhoneWindow.setContentView()

           └──> 创建DecorView

3. Activity.onResume()

   └──> Activity.makeVisible()

       └──> WindowManager.addView()

           └──> WindowManagerGlobal.addView()

               └──> 创建ViewRootImpl

                   └──> ViewRootImpl.setView()

                       └──> IWindowSession.addToDisplay()

                           └──> WMS.addWindow()

                               ├──> 创建WindowState

                               ├──> 创建Surface

                               └──> 更新布局

关键代码:


// 1. Activity创建窗口

public final void attach(...) {

    mWindow = new PhoneWindow(this, window, activityConfigCallback);

    mWindow.setWindowManager(

        (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),

        mToken, mComponent.flattenToString(),

        (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

}

  

// 2. WMS添加窗口

public int addWindow(Session session, IWindow client, ...) {

    // 权限检查

    if (!checkCallingPermission(...)) {

        return WindowManagerGlobal.ADD_PERMISSION_DENIED;

    }

    // 创建WindowState

    WindowState win = new WindowState(this, session, client, ...);

    // 添加到DisplayContent

    DisplayContent displayContent = getDisplayContent(displayId);

    displayContent.addWindow(win);

    // 创建Surface

    win.createSurfaceControl();

    // 更新布局

    performLayoutAndPlaceSurfacesLocked();

    return WindowManagerGlobal.ADD_OKAY;

}

Q6: WMS如何管理窗口的Z-Order层级

答案:

Z-Order管理机制

  1. 基础层级由窗口类型决定TYPE值

  2. 层级调整:通过WindowState.mLayer动态计算

  3. 层级排序DisplayContent维护窗口列表按层级排序

层级计算:


// WMS计算窗口层级

void assignWindowLayers(DisplayContent displayContent) {

    int baseLayer = 0;

    // 1. 系统窗口:最高层级

    for (WindowState win : systemWindows) {

        win.mLayer = baseLayer + win.mAttrs.type;

    }

    // 2. 应用窗口:中等层级

    for (WindowState win : applicationWindows) {

        win.mLayer = baseLayer + win.mAttrs.type;

    }

    // 3. 子窗口:最低层级(相对于父窗口)

    for (WindowState win : childWindows) {

        win.mLayer = win.mParentWindow.mLayer + win.mAttrs.type;

    }

    // 4. 按层级排序

    displayContent.sortWindowsByLayer();

}

影响层级的因素:

  • 窗口类型TYPE

  • 窗口标志FLAG

  • 窗口动画状态

  • 窗口可见性


窗口管理类

Q7: WindowState的作用是什么它包含哪些关键信息

答案:

WindowState的作用

WindowState是WMS中表示一个窗口状态的核心类包含了窗口的所有信息。

关键信息:

  1. 窗口属性LayoutParams、类型、标志等

  2. 窗口状态:可见性、焦点状态、动画状态等

  3. 窗口位置Frame、可见区域、裁剪区域等

  4. Surface信息SurfaceControl、Surface等

  5. 窗口关系父窗口、子窗口、Token等


class WindowState {

    // 窗口属性

    final WindowManager.LayoutParams mAttrs;

    final WindowToken mToken;

    final DisplayContent mDisplayContent;

    // 窗口状态

    boolean mVisible;

    boolean mHasSurface;

    boolean mIsAnimating;

    // 窗口位置

    Rect mFrame;           // 窗口位置和大小

    Rect mVisibleFrame;     // 可见区域

    Rect mContentFrame;    // 内容区域

    // Surface

    SurfaceControl mSurfaceControl;

    Surface mSurface;

    // 窗口关系

    WindowState mParentWindow;

    ArrayList<WindowState> mChildWindows;

    // 层级

    int mLayer;

}

Q8: DisplayContent的作用是什么它如何管理窗口

答案:

DisplayContent的作用

DisplayContent表示一个显示设备上的所有窗口内容管理该显示设备上的窗口栈、布局和显示。

主要功能:

  1. 窗口管理:维护该显示设备上的所有窗口

  2. 窗口栈管理维护窗口的Z-Order顺序

  3. 布局计算:计算窗口的位置和大小

  4. 显示配置:管理显示设备的分辨率、方向等


class DisplayContent {

    final int mDisplayId;

    final Display mDisplay;

    // 窗口列表

    final WindowList mWindows = new WindowList();

    // 窗口栈

    final ArrayList<TaskStack> mStacks = new ArrayList<>();

    // 显示配置

    Configuration mDisplayConfiguration;

    // 添加窗口

    void addWindow(WindowState win) {

        mWindows.add(win);

        assignWindowLayers();

    }

    // 布局计算

    void performLayout() {

        for (WindowState win : mWindows) {

            computeWindowFrame(win);

        }

    }

}

Q9: WindowToken的作用是什么为什么需要WindowToken

答案:

WindowToken的作用

WindowToken是窗口的令牌用于

  1. 窗口分组:将属于同一应用的窗口分组

  2. 权限控制控制哪些窗口可以添加到Token

  3. 窗口关联关联Activity、Service等组件

为什么需要WindowToken

  1. 安全性:防止其他应用随意添加窗口到你的应用

  2. 窗口管理:统一管理同一组件的所有窗口

  3. 生命周期Token销毁时所有关联窗口都会被移除


class WindowToken {

    final IBinder token;  // Token标识

    final int windowType; // 窗口类型

    final String name;    // Token名称

    // 关联的窗口列表

    final ArrayList<WindowState> windows = new ArrayList<>();

    // 添加窗口

    void addWindow(WindowState win) {

        windows.add(win);

    }

    // 移除窗口

    void removeWindow(WindowState win) {

        windows.remove(win);

        if (windows.isEmpty()) {

            // Token可以销毁

        }

    }

}


源码分析类

Q10: WMS的addWindow方法做了哪些事情

答案:

addWindow方法流程


public int addWindow(Session session, IWindow client, ...) {

    // 1. 权限检查

    if (!checkCallingPermission(...)) {

        return WindowManagerGlobal.ADD_PERMISSION_DENIED;

    }

    // 2. 参数验证

    if (attrs.type < FIRST_APPLICATION_WINDOW ||

        attrs.type > LAST_APPLICATION_WINDOW) {

        // 系统窗口需要特殊权限

    }

    // 3. 获取或创建WindowToken

    WindowToken token = getWindowToken(attrs.token);

    if (token == null) {

        // 创建新Token

        token = new WindowToken(...);

    }

    // 4. 创建WindowState

    WindowState win = new WindowState(this, session, client, token, ...);

    // 5. 添加到DisplayContent

    DisplayContent displayContent = getDisplayContent(displayId);

    displayContent.addWindow(win);

    // 6. 创建Surface

    win.createSurfaceControl();

    // 7. 更新布局

    performLayoutAndPlaceSurfacesLocked();

    return WindowManagerGlobal.ADD_OKAY;

}

关键步骤:

  1. 权限检查:检查是否有权限添加该类型窗口

  2. Token管理获取或创建WindowToken

  3. 创建WindowState:创建窗口状态对象

  4. 添加到DisplayContent:将窗口添加到对应的显示设备

  5. 创建Surface创建窗口的Surface用于绘制

  6. 更新布局:重新计算所有窗口的布局

Q11: performLayoutAndPlaceSurfacesLocked方法的作用是什么

答案:

方法作用:

performLayoutAndPlaceSurfacesLocked是WMS的核心布局方法负责

  1. 计算所有窗口的位置和大小

  2. 分配窗口的层级

  3. 更新Surface的位置和大小

  4. 处理窗口动画

执行流程:


void performLayoutAndPlaceSurfacesLocked() {

    // 1. 遍历所有显示设备

    for (DisplayContent displayContent : mDisplayContents) {

        // 2. 计算显示配置

        displayContent.computeScreenConfiguration();

        // 3. 应用窗口策略

        applyWindowPolicy(displayContent);

        // 4. 计算窗口位置和大小

        for (WindowState win : displayContent.mWindows) {

            computeWindowFrame(win);

        }

        // 5. 分配窗口层级

        assignWindowLayers(displayContent);

        // 6. 更新Surface

        for (WindowState win : displayContent.mWindows) {

            if (win.mHasSurface) {

                updateSurface(win);

            }

        }

        // 7. 处理窗口动画

        displayContent.mAnimator.updateWindowsLocked();

    }

}

Q12: WMS如何与SurfaceFlinger交互

答案:

交互流程:


WMS

  ├──> 创建SurfaceControl

  ├──> 设置Surface属性位置、大小、层级

  └──> 通过SurfaceControl与SurfaceFlinger通信

       └──> SurfaceFlinger合成Surface并显示

关键代码:


// WMS创建Surface

class WindowState {

    void createSurfaceControl() {

        mSurfaceControl = new SurfaceControl.Builder()

            .setName(mWindowTag)

            .setBufferSize(mFrame.width(), mFrame.height())

            .setFormat(PixelFormat.TRANSLUCENT)

            .build();

        mSurface = new Surface(mSurfaceControl);

    }

    void updateSurface() {

        // 设置Surface位置和大小

        mSurfaceControl.setPosition(mFrame.left, mFrame.top);

        mSurfaceControl.setSize(mFrame.width(), mFrame.height());

        // 设置Surface层级

        SurfaceControl.Transaction t = new SurfaceControl.Transaction();

        t.setLayer(mSurfaceControl, mLayer);

        t.apply();

    }

}


性能优化类

Q13: 如何优化窗口的创建和显示性能?

答案:

优化策略:

  1. 减少窗口数量:避免创建过多窗口

  2. 延迟创建:非关键窗口延迟创建

  3. 复用窗口:复用已有的窗口

  4. 优化布局:减少布局层级和复杂度

  5. 使用硬件加速:启用硬件加速提升绘制性能


// 1. 延迟创建窗口

Handler.postDelayed(() -> {

    createWindow();

}, 100);

  

// 2. 复用窗口

if (mWindow == null) {

    mWindow = createWindow();

} else {

    updateWindow(mWindow);

}

  

// 3. 启用硬件加速

<activity android:hardwareAccelerated="true" />

Q14: 窗口动画对性能有什么影响?如何优化?

答案:

影响:

  1. CPU占用动画计算消耗CPU

  2. GPU占用动画渲染消耗GPU

  3. 帧率下降:复杂动画可能导致掉帧

优化方法:

  1. 简化动画:使用简单的动画效果

  2. 使用硬件加速利用GPU加速动画

  3. 减少动画时长:缩短动画时间

  4. 避免同时多个动画:减少并发动画数量


// 使用硬件加速动画

ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);

animator.setDuration(300);

animator.setInterpolator(new AccelerateDecelerateInterpolator());

animator.start();


问题排查类

Q15: 如何排查窗口显示异常的问题?

答案:

排查步骤:

  1. 检查窗口状态:使用adb shell dumpsys window

  2. 检查Surface状态查看Surface是否创建成功

  3. 检查布局查看窗口的Frame是否正确

  4. 检查层级查看窗口的Layer是否正确

  5. 使用Systrace:分析窗口创建和布局流程


# 1. 查看窗口信息

adb shell dumpsys window windows

  

# 2. 查看窗口层级

adb shell dumpsys window displays

  

# 3. 使用Systrace分析

python systrace.py -t 10 -o trace.html wm

Q16: 窗口泄漏如何排查和解决?

答案:

排查方法:

  1. 检查WindowManager引用:确保及时移除窗口

  2. 检查生命周期确保在onDestroy中移除窗口

  3. 使用LeakCanary:检测窗口泄漏

  4. 检查WindowToken确保Token正确管理


// 正确的窗口管理

class MyActivity extends Activity {

    private View floatingView;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        // 创建悬浮窗

        createFloatingWindow();

    }

    @Override

    protected void onDestroy() {

        super.onDestroy();

        // 必须移除窗口

        if (floatingView != null) {

            WindowManager wm = getWindowManager();

            wm.removeView(floatingView);

            floatingView = null;

        }

    }

}


多窗口相关

Q17: 分屏模式是如何实现的?

答案:

分屏实现原理:

  1. 任务栈管理每个分屏窗口对应一个TaskStack

  2. 窗口布局WMS计算每个窗口的位置和大小

  3. 输入事件分发:根据触摸位置分发到对应窗口

  4. 焦点管理:管理两个窗口的焦点切换


// 分屏窗口布局

void layoutSplitScreenWindows(DisplayContent displayContent) {

    // 计算分屏窗口大小

    Rect primaryFrame = new Rect(0, 0, screenWidth / 2, screenHeight);

    Rect secondaryFrame = new Rect(screenWidth / 2, 0, screenWidth, screenHeight);

    // 设置主窗口位置

    primaryWindow.mFrame = primaryFrame;

    // 设置次窗口位置

    secondaryWindow.mFrame = secondaryFrame;

}

Q18: 悬浮窗Overlay Window如何实现

答案:

实现步骤:

  1. 申请权限SYSTEM_ALERT_WINDOW权限

  2. 设置窗口类型TYPE_APPLICATION_OVERLAY

  3. 创建窗口使用WindowManager添加窗口

  4. 管理生命周期:及时移除窗口


// 创建悬浮窗

private void createOverlayWindow() {

    // 1. 检查权限

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

        if (!Settings.canDrawOverlays(this)) {

            // 请求权限

            requestOverlayPermission();

            return;

        }

    }

    // 2. 创建窗口参数

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(

        WindowManager.LayoutParams.WRAP_CONTENT,

        WindowManager.LayoutParams.WRAP_CONTENT,

        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,

        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,

        PixelFormat.TRANSLUCENT

    );

    // 3. 创建视图

    View overlayView = LayoutInflater.from(this)

        .inflate(R.layout.overlay_window, null);

    // 4. 添加窗口

    WindowManager wm = getSystemService(Context.WINDOW_SERVICE);

    wm.addView(overlayView, params);

}


总结

WMS窗口面试题主要涵盖

  1. 基础概念WMS作用、窗口类型、层级关系

  2. 架构原理WMS架构、窗口添加流程、Z-Order管理

  3. 窗口管理WindowState、D