Files
mkdocs/docs/android面试/系统原理/WMS面试.md
2026-01-16 14:54:07 +08:00

22 KiB
Raw Blame History

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