# WMS窗口常见面试题

  

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

  

## 目录

  

- [基础概念类](#基础概念类)

- [架构原理类](#架构原理类)

- [窗口管理类](#窗口管理类)

- [源码分析类](#源码分析类)

- [性能优化类](#性能优化类)

- [问题排查类](#问题排查类)

- [多窗口相关](#多窗口相关)

  

---

  

## 基础概念类

  

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

  

**答案：**

  

WMS（Window Manager Service）是Android窗口系统的核心服务，运行在system_server进程中。

  

**主要职责：**

  

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

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

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

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

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

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

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

  

```java

// 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() (服务端)

```

  

```java

// 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`：应用基础窗口

  

2. **子窗口（SUB_WINDOW）**

   - `TYPE_APPLICATION_PANEL`：应用面板

   - `TYPE_APPLICATION_SUB_PANEL`：应用子面板

   - `TYPE_APPLICATION_ATTACHED_DIALOG`：附加对话框

  

3. **系统窗口（SYSTEM_WINDOW）**

   - `TYPE_STATUS_BAR`：状态栏

   - `TYPE_NAVIGATION_BAR`：导航栏

   - `TYPE_SYSTEM_ALERT`：系统警告窗口

   - `TYPE_TOAST`：Toast窗口

   - `TYPE_APPLICATION_OVERLAY`：悬浮窗（需要权限）

  

**层级关系（Z-Order）：**

  

```

系统窗口（最高）

    ↓

应用窗口（中等）

    ↓

子窗口（最低）

```

  

```java

// 窗口类型定义

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. **WindowManagerService**：WMS主类，管理所有窗口

2. **WindowState**：窗口状态，表示一个窗口的所有信息

3. **DisplayContent**：显示内容，管理一个显示设备上的所有窗口

4. **WindowToken**：窗口令牌，用于窗口分组和权限控制

5. **WindowAnimator**：窗口动画控制器

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

  

```java

// 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

                               └──> 更新布局

```

  

**关键代码：**

  

```java

// 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维护窗口列表，按层级排序

  

**层级计算：**

  

```java

// 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等

  

```java

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. **显示配置**：管理显示设备的分辨率、方向等

  

```java

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销毁时，所有关联窗口都会被移除

  

```java

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方法流程：**

  

```java

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. 处理窗口动画

  

**执行流程：**

  

```java

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并显示

```

  

**关键代码：**

  

```java

// 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. **使用硬件加速**：启用硬件加速提升绘制性能

  

```java

// 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. **避免同时多个动画**：减少并发动画数量

  

```java

// 使用硬件加速动画

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**：分析窗口创建和布局流程

  

```bash

# 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正确管理

  

```java

// 正确的窗口管理

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. **焦点管理**：管理两个窗口的焦点切换

  

```java

// 分屏窗口布局

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. **管理生命周期**：及时移除窗口

  

```java

// 创建悬浮窗

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