Ahao's Technical Blog Ahao's Technical Blog
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
  • 008.核心系统服务
  • 009.输入系统
  • 010.开发工具
  • Vulkan
  • OpenGL
  • Skia
  • 001.语法相关
  • 002.Android相关
  • 003.Linux相关
  • 004.环境配置
  • 001.Java
  • 002.Kotlin
  • 003.C/C++
  • 004.脚本类
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

阿豪讲Framework

不积跬步无以至千里
首页
  • 001.基础篇
  • 002.玩转AOSP篇
  • 003.学穿Binder篇
  • 004.基础组件篇
  • 005.系统启动过程分析
  • 006.Hal开发入门与实践
  • 007.显示系统
  • 008.核心系统服务
  • 009.输入系统
  • 010.开发工具
  • Vulkan
  • OpenGL
  • Skia
  • 001.语法相关
  • 002.Android相关
  • 003.Linux相关
  • 004.环境配置
  • 001.Java
  • 002.Kotlin
  • 003.C/C++
  • 004.脚本类
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 基础篇

  • 玩转AOSP篇

  • 学穿Binder篇

  • 基础组件篇

  • 系统启动过程分析

  • Hal开发入门与实践

  • 显示系统

    • 窗口显示过程全流程分析1
      • 1. 理解窗口
      • 2. 窗口的操作接口
      • 3. WindowManager.LayoutParams 作用与核心成员解析
        • 3.1 作用
        • 3.2 核心成员变量解析
      • 4. 窗口添加过程整体分析
        • 4.1 WindowManager 初始化过程分析
        • 4.2 添加窗口过程分析
        • 相关 Trace 分析
    • 显示疑难问题分析基础
  • 核心系统服务

  • 输入系统

  • 开发工具

  • Framework
  • 显示系统
ahao
2026-02-02
目录

窗口显示过程全流程分析1

# 窗口显示过程全流程分析1

本文基于 aosp android-16.0.0_r4 版本分析。

很久很久以前,没有 AI 辅助,为了降低源码阅读难度,一直把整个显示系统进行拆解(app gui/hwui wms sf)分析,但是拆解后,总是有一种盲人摸象的感觉。要融汇贯通,掌握整体的架构思维,还是得的基于实际上层场景进行全流程分析!

这个系列会很长很长,通过上层不同的窗口操作场景(窗口显示移除,窗口动画,StartingWindow,分屏,小窗等等),贯穿 app gui/hwui wms sf 每个细节,梳理出 Framework 中,显示系统的整个流程,为成为一名 Android 显示全栈工程师打好基础。

本文关注以下两点:

  • 窗口(Window)的概念
  • 窗口(Window)添加与显示的整体流程,梳理出关键流程和后续需要重点分析的要点。

# 1. 理解窗口

从 App 开发者的角度看:

  • 一个 Activity 是窗口
  • 一个 Dialog/PopupWindow 是一个窗口,是其所在 Activity 窗口的子窗口
  • 一个悬浮窗是一个窗口,比如播放视频的小窗,微信视频通话的小窗

从系统源码的角度看:

  • 在 App 端,使用 ViewRootImpl + View 树来描述和抽象一个窗口,很多文章里说 PhoneWindow(继承自 Window)是窗口的抽象,我觉得 PhoneWindow 是一个管理中间层。
  • 在 WMS 源码中使用 WindowContainer 的子类组成的树结构,来组织和管理所有的窗口。
  • 在 SF 源码中使用 LayerHierarchy 组成的树结构,来组织和管理所有的窗口。

# 2. 窗口的操作接口

这里给出一个悬浮窗显示的 Demo,用于相关接口学习:https://github.com/yuandaimaahao/FloatingWindow

无论哪种窗口,都是通过:

  1. WindowManager.LayoutParams 描述窗口的类型,大小,层级,位置与特性等
  2. WindowManager.addView 添加窗口
  3. WindowManager.removeView 移除窗口

# 3. WindowManager.LayoutParams 作用与核心成员解析

# 3.1 作用

    // frameworks/base/core/java/android/view/WindowManager.java
    public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
1
2
  • WindowManager.LayoutParams 是 Android 窗口系统中最重要的参数类,它继承自 ViewGroup.LayoutParams,用于描述窗口的所有属性配置,包括位置、大小、类型、行为、显示效果等。
  • LayoutParams 作为一个 Parcelable 对象,可以通过 Binder 传递给 WindowManagerService,是APP 与 WMS 通信的重要数据结构。

# 3.2 核心成员变量解析

  • 位置与尺寸
成员 类型 说明
x int 窗口 X 坐标偏移(配合 gravity 使用)
y int 窗口 Y 坐标偏移(配合 gravity 使用)
width int 窗口宽度(继承自父类)
height int 窗口高度(继承自父类)
gravity int 窗口在屏幕中的对齐方式(如 Gravity.CENTER)
horizontalMargin float 水平边距(百分比)
verticalMargin float 垂直边距(百分比)

WindowManager.LayoutParams 中的 x,y 成员是令人迷惑的点,往往会搞不清楚对应的坐标系,实际上,x y 的含义随 Gravity 变化而变化。

Gravity 设置 x 的含义 y 的含义
TOP \| LEFT 距离左边缘的像素 距离顶部边缘的像素
TOP \| CENTER_HORIZONTAL 相对中心的偏移(正数向右) 距离顶部边缘的像素
CENTER_VERTICAL \| LEFT 距离左边缘的像素 相对中心的偏移(正数向下)
CENTER 相对中心的偏移 相对中心的偏移
  • 窗口类型(type)

Android 根据窗口的 type 将窗口分为三大类:

  1. 应用窗口 (Application Windows)
  2. 子窗口 (Sub-Windows)
  3. 系统窗口 (System Windows)

窗口的 type 由 WindowManager.LayoutParams.type 属性决定。

  • 应用窗口 (Application Windows)是最常见的窗口类型,对应于我们平常写的 Activity。

    • 层级范围:1 ~ 99
    • 特点:必须依赖于 Activity 存在。当 Activity 销毁时,对应的应用窗口也会被销毁。
    • 常见类型:
      • TYPE_BASE_APPLICATION (1):所有 Activity 的基础窗口。
      • TYPE_APPLICATION (2):普通应用程序窗口。
  • 子窗口 (Sub-Windows)不能单独存在,必须依附于一个父窗口(通常是应用窗口)。

    • 层级范围:1000 ~ 1999
    • 特点:随父窗口的生命周期变化,父窗口关闭,子窗口也会关闭。
    • 常见类型:
      • TYPE_APPLICATION_PANEL (1002):依附于 Activity 的面板,例如常见的 Dialog(对话框)。
      • TYPE_APPLICATION_MEDIA (1001):用于视频播放等媒体显示。
      • TYPE_APPLICATION_SUB_PANEL (1005):比如 PopupWindow(下拉弹窗)。
  • 系统窗口 (System Windows)不需要对应具体的 Activity,它们可以显示在所有应用窗口之上。

    • 层级范围:2000 ~ 2999
    • 特点:权限较高,通常用于系统状态栏、Toast、或者应用内的全局悬浮窗。添加此类窗口通常需要申请特殊权限。
    • 常见类型:
      • TYPE_STATUS_BAR (2000):系统的状态栏。
      • TYPE_TOAST (2005):系统提示信息(Toast)。
      • TYPE_APPLICATION_OVERLAY (2038):这是目前(Android 8.0/API 26 及以后)开发悬浮窗最常用且推荐的类型。它替代了旧版本中被废弃的 TYPE_PHONE 或 TYPE_SYSTEM_ALERT。

容易忽略的一点:

  • type 值的大小与窗口的高低没有绝对的依赖关系,并不是 type 越大,窗口的纵向层级就一定越高。
  • 窗口的 type 在 WMS 端中,通过 WindowManagerPolicy.getWindowLayerFromTypeLw 方法转换为一个整型值,转换后的值决定了窗口的高低。

小结:

类别 范围 说明 常见类型
应用窗口 1-99 普通应用窗口 TYPE_BASE_APPLICATION(1), TYPE_APPLICATION(2)
子窗口 1000-1999 依附于父窗口 TYPE_APPLICATION_PANEL(1000), TYPE_APPLICATION_MEDIA(1001)
系统窗口 2000-2999 系统特殊窗口 TYPE_STATUS_BAR(2000), TYPE_TOAST(2005), TYPE_INPUT_METHOD(2011)
  • 窗口标志(flags)

flags 是一个位掩码字段,控制窗口的各种行为:

        // /frameworks/base/core/java/android/view/WindowManager.java
        /** Window flag: as long as this window is visible to the user, allow
         *  the lock screen to activate while the screen is on.  */
        public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;

        /** Window flag: everything behind this window will be dimmed.
         *  Use {@link #dimAmount} to control the amount of dim. */
        public static final int FLAG_DIM_BEHIND        = 0x00000002;

        /** Window flag: this window won't ever get key input focus */
        public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
        // .......
1
2
3
4
5
6
7
8
9
10
11
12

常用 flags 一览:

Flag 值 作用
FLAG_DIM_BEHIND 0x02 窗口后面变暗(配合 dimAmount)
FLAG_NOT_FOCUSABLE 0x08 窗口不获取焦点
FLAG_NOT_TOUCHABLE 0x10 窗口不接收触摸事件(穿透)
FLAG_NOT_TOUCH_MODAL 0x20 窗口外的触摸事件传递给后面窗口
FLAG_KEEP_SCREEN_ON 0x80 保持屏幕常亮
FLAG_LAYOUT_IN_SCREEN 0x100 窗口可布局到整个屏幕
FLAG_FULLSCREEN 0x400 全屏模式(隐藏状态栏)
FLAG_SECURE 0x2000 禁止截屏/录屏
FLAG_SHOW_WHEN_LOCKED 0x80000 锁屏时显示
FLAG_TURN_SCREEN_ON 0x200000 显示时点亮屏幕
FLAG_HARDWARE_ACCELERATED 0x1000000 启用硬件加速
  • 软键盘模式(softInputMode)
        /**
         * Desired operating mode for any soft input area.  May be any combination
         * of:
         *
         * <ul>
         * <li> One of the visibility states
         * {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED},
         * {@link #SOFT_INPUT_STATE_HIDDEN}, {@link #SOFT_INPUT_STATE_ALWAYS_HIDDEN},
         * {@link #SOFT_INPUT_STATE_VISIBLE}, or {@link #SOFT_INPUT_STATE_ALWAYS_VISIBLE}.
         * <li> One of the adjustment options
         * {@link #SOFT_INPUT_ADJUST_UNSPECIFIED}, {@link #SOFT_INPUT_ADJUST_RESIZE},
         * {@link #SOFT_INPUT_ADJUST_PAN}, or {@link #SOFT_INPUT_ADJUST_NOTHING}.
         * </ul>
         *
         *
         * <p>This flag can be controlled in your theme through the
         * {@link android.R.attr#windowSoftInputMode} attribute.</p>
         */
        @SoftInputModeFlags
        public int softInputMode;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

由两部分组成:

状态控制:

值 说明
SOFT_INPUT_STATE_HIDDEN 默认隐藏键盘
SOFT_INPUT_STATE_VISIBLE 默认显示键盘
SOFT_INPUT_STATE_ALWAYS_HIDDEN 总是隐藏

调整模式:

值 说明
SOFT_INPUT_ADJUST_RESIZE 调整窗口大小(已废弃)
SOFT_INPUT_ADJUST_PAN 平移窗口内容
SOFT_INPUT_ADJUST_NOTHING 不做任何调整
  • 窗口标识(token)
        // 4176:4180:/home/zzh0838/Project/lineage23/frameworks/base/core/java/android/view/WindowManager.java
        /**
         * Identifier for this window.  This will usually be filled in for
         * you.
         */
        public IBinder token = null;
1
2
3
4
5
6
  • 应用窗口:token 必须是 Activity 的 token
  • 子窗口:token 必须是父窗口的 token
  • 系统窗口:通常为 null 或特定 token
  • 显示效果
成员 类型 说明
format int 像素格式(PixelFormat.TRANSLUCENT 等)
alpha float 窗口整体透明度(0.0~1.0)
dimAmount float 背景变暗程度(配合 FLAG_DIM_BEHIND)
screenBrightness float 屏幕亮度覆盖
windowAnimations int 窗口动画资源 ID
rotationAnimation int 旋转动画类型

  • 其他重要成员
成员 说明
packageName 窗口所属包名
screenOrientation 屏幕方向
preferredRefreshRate 首选刷新率
layoutInDisplayCutoutMode 刘海屏布局模式
privateFlags 系统内部使用的私有标志
surfaceInsets Surface 内边距

# 4. 窗口添加过程整体分析

Demo 中,窗口显示的核心代码如下:

    // WindowManager 初始化
    private WindowManager windowManager;
    windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

    // 添加窗口
    private void showFloatingWindow() {
        if (floatingView != null) {
            return;
        }

        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        floatingView = inflater.inflate(R.layout.floating_window, null);

        Button btnClose = floatingView.findViewById(R.id.btn_close_floating);
        btnClose.setOnClickListener(v -> hideFloatingWindow());

        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
        );

        params.gravity = Gravity.TOP;
        params.x = 0;
        params.y = 0;
        // 通过 windowAnimations 设置窗口的进入和退出动画
        params.windowAnimations = R.style.FloatingWindowAnimation;

        windowManager.addView(floatingView, params);
        isFloatingWindowShowing = true;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 4.1 WindowManager 初始化过程分析

App 中 WindowManager 获取的代码:

private WindowManager windowManager;
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
1
2

getSystemService 实现在 Activity 中:

    // frameworks/base/core/java/android/app/Activity.java
    private WindowManager mWindowManager;
    
    @Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        if (getBaseContext() == null) {
            throw new IllegalStateException(
                    "System services not available to Activities before onCreate()");
        }

        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        return super.getSystemService(name);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这里针对 WINDOW_SERVICE SEARCH_SERVICE 类型的服务做了缓存,我们的 App 中获取到的是缓存的 Service。

在 Activity 的显示过程中,会首次去获取 WINDOW_SERVICE,并将获取的结果缓存到 Activity.mWindowManager 中去:

    // frameworks/base/core/java/android/app/Activity.java
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
            IBinder shareableActivityToken, IBinder initialCallerInfoAccessToken) {
        // ......
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        // .....
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

getSystemService 实现如下:

    // frameworks/base/core/java/android/view/ContextThemeWrapper.java
    @Override
    public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
            }
            return mInflater;
        }
        return getBaseContext().getSystemService(name);
    }
1
2
3
4
5
6
7
8
9
10
11

接着调用 ContextImpl 的 getSystemService 方法:

// /frameworks/base/core/java/android/app/ContextImpl.java
    @Override
    public Object getSystemService(String name) {
        if (vmIncorrectContextUseEnabled()) {
            // Check incorrect Context usage.
            if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
                final String errorMessage = "Tried to access visual service "
                        + SystemServiceRegistry.getSystemServiceClassName(name)
                        + " from a non-visual Context:" + getOuterContext();
                final String message = "WindowManager should be accessed from Activity or other "
                        + "visual Context. Use an Activity or a Context created with "
                        + "Context#createWindowContext(int, Bundle), which are adjusted to "
                        + "the configuration and visual bounds of an area on screen.";
                final Exception exception = new IllegalAccessException(errorMessage);
                StrictMode.onIncorrectContextUsed(message, exception);
                Log.e(TAG, errorMessage + " " + message, exception);
            }
        }
        return SystemServiceRegistry.getSystemService(this, name);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

SystemServiceRegistry 的静态块中:

// /frameworks/base/core/java/android/app/SystemServiceRegistry.java
 static {
        // ......
        registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
        // ......
 }

    private static <T> void registerService(@NonNull String serviceName,
            @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
        SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

SystemServiceRegistry.getSystemService 的实现如下:

// /frameworks/base/core/java/android/app/SystemServiceRegistry.java

    /**
     * Gets a system service from a given context.
     * @hide
     */
    public static Object getSystemService(@NonNull ContextImpl ctx, String name) {
        // 拿到静态块中注册的 CachedServiceFetcher
        final ServiceFetcher<?> fetcher = getSystemServiceFetcher(name); 
        if (fetcher == null) {
            return null;
        }
        // 通过 CachedServiceFetcher 获取 Service
        final Object ret = fetcher.getService(ctx);
        if (sEnableServiceNotFoundWtf && ret == null) {
            // Some services do return null in certain situations, so don't do WTF for them.
            switch (name) {
                case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
                case Context.APP_PREDICTION_SERVICE:
                case Context.INCREMENTAL_SERVICE:
                case Context.ETHERNET_SERVICE:
                case Context.CONTEXTHUB_SERVICE:
                case Context.VIRTUALIZATION_SERVICE:
                case Context.VIRTUAL_DEVICE_SERVICE:
                    return null;
                case Context.VCN_MANAGEMENT_SERVICE:
                    if (!hasSystemFeatureOpportunistic(ctx,
                            PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
                        return null;
                    }
                    break;
                case Context.SEARCH_SERVICE:
                    // Wear device does not support SEARCH_SERVICE so we do not print WTF here
                    if (hasSystemFeatureOpportunistic(ctx, PackageManager.FEATURE_WATCH)) {
                        return null;
                    }
                    break;
                case Context.APPWIDGET_SERVICE:
                    if (!hasSystemFeatureOpportunistic(ctx, PackageManager.FEATURE_APP_WIDGETS)) {
                        return null;
                    }
                    break;
                case Context.TEXT_SERVICES_MANAGER_SERVICE:
                    if (android.server.Flags.removeTextService()
                            && hasSystemFeatureOpportunistic(ctx, PackageManager.FEATURE_WATCH)) {
                        return null;
                    }
                    break;
            }
            Slog.wtf(TAG, "Manager wrapper not available: " + name);
            return null;
        }
        return ret;
    }

    private static ServiceFetcher<?> getSystemServiceFetcher(String name) {
        if (name == null) {
            return null;
        }
        final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        if (fetcher == null) {
            if (sEnableServiceNotFoundWtf) {
                Slog.wtf(TAG, "Unknown manager requested: " + name);
            }
            return null;
        }
        return fetcher;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

拿到 WINDOW_SERVICE 对应的 CachedServiceFetcher,然后调用 CachedServiceFetcher.getService 方法:

// /frameworks/base/core/java/android/app/SystemServiceRegistry.java

   static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;

        CachedServiceFetcher() {
            // Note this class must be instantiated only by the static initializer of the
            // outer class (SystemServiceRegistry), which already does the synchronization,
            // so bare access to sServiceCacheSize is okay here.
            mCacheIndex = sServiceCacheSize++;
        }

        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache; // ContextImpl 中的缓存
            final int[] gates = ctx.mServiceInitializationStateArray; // 保存服务的状态
            boolean interrupted = false;

            T ret = null;

            for (;;) {
                boolean doInitialize = false;
                synchronized (cache) {
                    // Return it if we already have a cached instance.
                    T service = (T) cache[mCacheIndex];
                    if (service != null) {
                        ret = service;  // 如果缓存中有,直接返回
                        break; // exit the for (;;)
                    }

                    // If we get here, there's no cached instance.

                    // Grr... if gate is STATE_READY, then this means we initialized the service
                    // once but someone cleared it.
                    // We start over from STATE_UNINITIALIZED.
                    // Similarly, if the previous attempt returned null, we'll retry again.
                    if (gates[mCacheIndex] == ContextImpl.STATE_READY
                            || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
                        gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
                    }

                    // It's possible for multiple threads to get here at the same time, so
                    // use the "gate" to make sure only the first thread will call createService().

                    // At this point, the gate must be either UNINITIALIZED or INITIALIZING.
                    if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
                        doInitialize = true;
                        gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
                    }
                }

                if (doInitialize) {
                    // Only the first thread gets here.

                    T service = null;
                    @ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
                    try {
                        // This thread is the first one to get here. Instantiate the service
                        // *without* the cache lock held.
                        service = createService(ctx); // 缓存中没有,则初始化具体的 Service
                        newState = ContextImpl.STATE_READY;

                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);

                    } finally {
                        synchronized (cache) {
                            cache[mCacheIndex] = service;  // 缓存起来
                            gates[mCacheIndex] = newState;
                            cache.notifyAll();
                        }
                    }
                    ret = service;
                    break; // exit the for (;;)
                }
                // The other threads will wait for the first thread to call notifyAll(),
                // and go back to the top and retry.
                synchronized (cache) { // 针对多线程做处理
                    // Repeat until the state becomes STATE_READY or STATE_NOT_FOUND.
                    // We can't respond to interrupts here; just like we can't in the "doInitialize"
                    // path, so we remember the interrupt state here and re-interrupt later.
                    while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
                        try {
                            // Clear the interrupt state.
                            interrupted |= Thread.interrupted();
                            cache.wait();
                        } catch (InterruptedException e) {
                            // This shouldn't normally happen, but if someone interrupts the
                            // thread, it will.
                            Slog.w(TAG, "getService() interrupted");
                            interrupted = true;
                        }
                    }
                }
            }
            if (interrupted) {
                Thread.currentThread().interrupt();
            }
            return ret;
        }

        public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;

        // Services that explicitly use a Context can never be fetched without one.
        public final boolean supportsFetchWithoutContext() {
            return false;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

小结:

  • 我们获取到的具体类型是 WindowManagerImpl,首次获取时会初始化这个对象。
  • 首次获取后,WindowManagerImpl 对象会被缓存到 ContextImpl.mServiceCache 中
  • Activity 中也做了缓存(WindowManager mWindowManager),后续我们在 Activity 中获取到的都是这个缓存

# 4.2 添加窗口过程分析

windowManager.addView(floatingView, params);
1
    // frameworks/base/core/java/android/view/WindowManagerImpl.java
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        fallbackWindowTypeIfNeeded(params, view);
        applyTokens(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }
1
2
3
4
5
6
7
8
9
10

WindowManagerGlobal 是一个单例类,接着调用 WindowManagerGlobal.addView:

// frameworks/base/core/java/android/view/WindowManagerImpl.java
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        // java16 的新语法
        if (!(params instanceof WindowManager.LayoutParams wparams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final Context context = view.getContext();
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            if (context != null
                    && (context.getApplicationInfo().flags
                    & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        if (context != null && wparams.type > LAST_APPLICATION_WINDOW) {
            final TypedArray styles = context.obtainStyledAttributes(R.styleable.Window);
            if (PhoneWindow.isOptingOutEdgeToEdgeEnforcement(
                    context.getApplicationInfo(), true /* local */, styles)) {
                wparams.privateFlags |= PRIVATE_FLAG_OPT_OUT_EDGE_TO_EDGE;
            }
            styles.recycle();
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            IWindowSession windowlessSession = null;
            // If there is a parent set, but we can't find it, it may be coming
            // from a SurfaceControlViewHost hierarchy.
            if (wparams.token != null && panelParentView == null) {
                for (int i = 0; i < mWindowlessRoots.size(); i++) {
                    ViewRootImpl maybeParent = mWindowlessRoots.get(i);
                    if (maybeParent.getWindowToken() == wparams.token) {
                        windowlessSession = maybeParent.getWindowSession();
                        break;
                    }
                }
            }

            if (windowlessSession == null) {
                // 初始化 ViewRootImpl
                root = new ViewRootImpl(view.getContext(), display);
            } else {
                root = new ViewRootImpl(view.getContext(), display,
                        windowlessSession, new WindowlessWindowLayout());
            }

            view.setLayoutParams(wparams);

            // 缓存起来
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
                // 核心步骤
                root.setView(view, wparams, panelParentView, userId);
                mWindowViewsListenerGroup.accept(getWindowViews());
            } catch (RuntimeException e) {
                Log.e(TAG, "Couldn't add view: " + view, e);
                final int viewIndex = (index >= 0) ? index : (mViews.size() - 1);
                // BadTokenException or InvalidDisplayException, clean up.
                if (viewIndex >= 0) {
                    removeViewLocked(viewIndex, true);
                }
                throw e;
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

核心要点:

  • 初始化一个 ViewRootImpl 对象,接着调用 ViewRootImpl.setView
  • 把 View,ViewRootImpl,ViewGroup.LayoutParams 缓存到 mViews,mRoots 和 mParams 中

接着看 ViewRootImpl.setView,这是最核心的部分。

setView() 是 View 系统与 WindowManagerService 建立连接的核心入口,负责完成窗口注册、Surface 准备、输入通道建立等关键工作。

  • setView 整体执行流程图
setView(view, attrs, panelParentView, userId)
        │
        ├─→ 【阶段1】初始化基础状态
        │
        ├─→ 【阶段2】配置硬件加速与兼容性
        │
        ├─→ 【阶段3】requestLayout() - 调度首次布局(异步过程,在下次 Vsync-app 信号到来时执行)
        │
        ├─→ 【阶段4】addToDisplayAsUser() - 远程调用到 WMS 注册窗口
        │
        ├─→ 【阶段5】处理添加结果与错误
        │
        ├─→ 【阶段6】建立输入事件通道
        │
        └─→ 【阶段7】构建输入事件处理管道
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 阶段 1:初始化基础状态
synchronized (this) {
    if (mView == null) {    // 确保只设置一次
        mView = view;       // 保存根 View 引用
        
        mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
        // `FallbackEventHandler` 是**按键事件的兜底处理器**,当 View 树没有消费某些特殊按键时,由它来处理系统级别的按键功能。
        mFallbackEventHandler.setView(view); 
        // 复制窗口属性
        mWindowAttributes.copyFrom(attrs);
        if (mWindowAttributes.packageName == null) {
            mWindowAttributes.packageName = mBasePackageName;
        }
        attrs = mWindowAttributes;
        setTag();
        mFpsTraceName = "FPS of " + getTitle();
        mLargestViewTraceName = "Largest view percentage(per hundred) of " + getTitle();

        if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
            & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
            && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
                Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
            }
        // 保存客户端原始 flags
        mClientWindowLayoutFlags = attrs.flags;
        adjustLayoutInDisplayCutoutMode(attrs);
        setAccessibilityFocus(null, null);        
        // 处理 RootViewSurfaceTaker(如 SurfaceView 需要直接管理 Surface)
        // SurfaceView 单独来分析?
        if (view instanceof RootViewSurfaceTaker) {
            mSurfaceHolderCallback = ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
            if (mSurfaceHolderCallback != null) {
                mSurfaceHolder = new TakenSurfaceHolder();
                mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                mSurfaceHolder.addCallback(mSurfaceHolderCallback);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

关键操作:

  • 保存根 View 引用到 mView
  • 复制并保存窗口属性
  • 处理 Surface 接管请求
  • 阶段 2:配置硬件加速与兼容性
// 计算 Surface Insets(用于阴影绘制)
if (!attrs.hasManualSurfaceInsets) {
    attrs.setSurfaceInsets(view, false, true);
}

// 获取兼容性信息(用于老应用适配)
// 这个兼容性不太懂
CompatibilityInfo compatibilityInfo = mDisplay.getDisplayAdjustments().getCompatibilityInfo();
mTranslator = compatibilityInfo.getTranslator();

// 启用硬件加速(除非应用自己持有 Surface)
if (mSurfaceHolder == null) {
    enableHardwareAcceleration(attrs);
    final boolean useMTRenderer = MT_RENDERER_AVAILABLE
            && mAttachInfo.mThreadedRenderer != null;
    if (mUseMTRenderer != useMTRenderer) {
        endDragResizing();
        mUseMTRenderer = useMTRenderer;
    }
}

// 兼容性转换处理
boolean restore = false;
if (mTranslator != null) {
    mSurface.setCompatibilityTranslator(mTranslator);
    restore = true;
    attrs.backup();
    mTranslator.translateWindowLayout(attrs);
}
if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);

// 设置 AttachInfo
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;

// 当前是子窗口的情况:保存父窗口 Token
if (panelParentView != null) {
    mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

关键操作:

  • 启用硬件加速(enableHardwareAcceleration)
  • 配置兼容性转换器
  • 初始化 AttachInfo 共享信息
  • 阶段 3:调度首次布局
 int res; /* = WindowManagerImpl.ADD_OKAY; */
requestLayout(); //这里会向 Choreographer 注册一个 Runnable,在下次 Vsync-app 到来时回调 Runnable,用于窗口的布局操作

// 创建输入通道(用于接收触摸/按键事件)
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    inputChannel = new InputChannel();
}

mForceDecorViewVisibility = (mWindowAttributes.privateFlags
        & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
1
2
3
4
5
6
7
8
9
10
11
12

关键点:

  • requestLayout() 会向 Choreographer 注册一个 Runnable,在下次 Vsync-app 到来是回调 Runnable,Runnable 中会触发 scheduleTraversals(),调度首次测量/布局/绘制,需要注意的是,该操作是在后续的 addToDisplayAsUser 之后

  • 创建空的 InputChannel,稍后由 WMS 填充

  • 阶段 4:Binder 远程调用注册窗口 - addToDisplayAsUser()

这是最核心的步骤:

                // 只有 DecorView 实现了 RootViewSurfaceTaker
                // inset 部分做详细分析
                if (mView instanceof RootViewSurfaceTaker) {
                    // 在窗口尚未 attach 时,把“提前调用的 insets API”交给真正的 InsetsController
                    PendingInsetsController pendingInsetsController =
                            ((RootViewSurfaceTaker) mView).providePendingInsetsController();
                     // 把 PendingInsetsController 里攒下来的操作,replay 到 ViewRootImpl 的 mInsetsController 上
                    if (pendingInsetsController != null) {
                        pendingInsetsController.replayAndAttach(mInsetsController);
                    }
                }
                if (mView instanceof DecorView) {
                    mWindowAttributes.privateFlags |= PRIVATE_FLAG_APP_PROGRESS_GENERATION_ALLOWED;
                }

                // TODO(b/395054309): Replace with calls to LayoutParams#setSystemApplicationOverlay
                //  in next API bump
                if (com.android.media.projection.flags.Flags.recordingOverlay()
                        && mWindowAttributes.type == TYPE_APPLICATION_OVERLAY
                        && hasSystemApplicationOverlayAppOp()) {
                    mWindowAttributes.privateFlags |= PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY;
                }

                // 用于在客户端(ViewRootImpl)与系统服务(WindowManagerService)之间传递窗口布局结果的容器类。它作为 IWindowSession.addToDisplayAsUser() 和 relayout() 的 out 参数,WMS 会填充它并返回给客户端。
                final WindowRelayoutResult addResult = new WindowRelayoutResult(
                        new ClientWindowFrames(),       // 窗口帧信息
                        new MergedConfiguration(),      // 合并后的配置
                        mTempInsets,                    // Insets 状态
                        new InsetsSourceControl.Array()); // Insets 控制对象数组
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    adjustLayoutParamsForCompatibility(mWindowAttributes,
                            mInsetsController.getAppearanceControlled(),
                            mInsetsController.isBehaviorControlled());
                    controlInsetsForCompatibility(mWindowAttributes);

                    // 核心,WMS 会填充 addResult
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibleTypes(), inputChannel, addResult);
                    if (mTranslator != null) {
                        mTranslator.translateRectInScreenToAppWindow(
                                addResult.frames.attachedFrame);
                    }
                    // 使用返回的结果
                    mTmpFrames.attachedFrame = addResult.frames.attachedFrame; 
                    mTmpFrames.compatScale = addResult.frames.compatScale;
                    mInvCompatScale = 1f / addResult.frames.compatScale;
                    mSeqId = Math.max(addResult.syncSeqId, mSeqId);
                    if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                        Trace.instant(Trace.TRACE_TAG_VIEW, mTag + " setView id=" + mSeqId);
                    }
                } catch (RemoteException | RuntimeException e) {
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  • addToDisplayAsUser 发起远程调用,WMS 添加窗口,返回窗口相关的信息

  • 后续利用返回的信息计算窗口的布局

  • 阶段 5:处理添加结果与错误

                // 处理 Insets 控制
                handleInsetsControlChanged(mTempInsets, addResult.activeControls);
                final InsetsState state = mInsetsController.getState();
                final Rect displayCutoutSafe = mTempRect;
                state.getDisplayCutoutSafe(displayCutoutSafe);
                // 计算窗口 frame
                final WindowConfiguration winConfig = getCompatWindowConfiguration();
                mWindowLayout.computeFrames(mWindowAttributes, state,
                        displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
                        UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
                        mInsetsController.getRequestedVisibleTypes(), 1f /* compactScale */,
                        mTmpFrames);
                // 最终计算出窗口的位置,保存到 ViewRootImpl.mWinFrame 中
                setFrame(mTmpFrames.frame, true /* withinRelayout */);
                registerBackCallbackOnWindow();
                if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                if (res < WindowManagerGlobal.ADD_OKAY) {
                    mAttachInfo.mRootView = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    // 错误处理:检查返回码
                    switch (res) {
                       // ......
                    }
                    throw new RuntimeException(
                            "Unable to add window -- unknown error code " + res);
                }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

常见错误原因:

错误码 原因
ADD_BAD_APP_TOKEN Activity 已销毁或 Token 无效
ADD_PERMISSION_DENIED 缺少创建该类型窗口的权限
ADD_DUPLICATE_ADD 窗口已经添加过
ADD_INVALID_DISPLAY 指定的显示器不存在
  • 分发 inset 信息

  • 利用 wms 返回的信息,计算窗口位置

  • 阶段 6:建立输入事件通道

// 创建输入事件接收器
if (inputChannel != null) {
    // InputQueue 回调(可选)
    if (mInputQueueCallback != null) {
        mInputQueue = new InputQueue();
        mInputQueueCallback.onInputQueueCreated(mInputQueue);
    }
    
    //  创建 WindowInputEventReceiver
    // 它在 Native 层监听 InputChannel 的 socket
    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                Looper.myLooper(), mAttachInfo.mThreadedRenderer);

    // Update unbuffered request when set the root view.
    mUnbufferedInputSource = mView.mUnbufferedInputSource;
}
    // 输入延迟追踪(可选)
    if (ENABLE_INPUT_LATENCY_TRACKING && mAttachInfo.mThreadedRenderer != null) {
        InputMetricsListener listener = new InputMetricsListener();
        mHardwareRendererObserver = new HardwareRendererObserver(
                listener, listener.data, mHandler, true);
        mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
    }
    
    mUnbufferedInputSource = mView.mUnbufferedInputSource;
}

//  建立 View 与 ViewRootImpl 的父子关系
view.assignParent(this);

// 从返回结果获取触摸模式和可见性
mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  • 阶段 7:构建输入事件处理管道
// 构建输入事件处理责任链(Input Pipeline)
CharSequence counterSuffix = attrs.getTitle();

mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
        "aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
        "aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
        "aq:native-pre-ime:" + counterSuffix);

mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;

mAdded = true;

// 启用/禁用动画
if (!mRemoved || !mAppVisible) {
    AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

输入事件处理链:

输入事件 → WindowInputEventReceiver
               │
               ▼
┌─────────────────────────────────────────────────────────────┐
│  NativePreImeInputStage    ← mFirstInputStage               │
│           ↓                                                  │
│  ViewPreImeInputStage      → view.dispatchKeyEventPreIme()  │
│           ↓                                                  │
│  ImeInputStage             → 输入法处理                      │
│           ↓                                                  │
│  EarlyPostImeInputStage    ← mFirstPostImeInputStage        │
│           ↓                                                  │
│  NativePostImeInputStage   → Native 层处理                   │
│           ↓                                                  │
│  ViewPostImeInputStage     → view.dispatchKeyEvent()        │
│           ↓                                                  │
│  SyntheticInputStage       → 合成事件(如轨迹球转方向键)    │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

后续在输入部分详细分析阶段 7、8

  • 小结

相关类结构如下:

20260202162045

整体流程如下:

WindowManagerGlobal.addView()
        │
        ▼
ViewRootImpl.setView(view, attrs, panelParentView, userId)
        │
        ├─→ 1. mView = view                         // 保存根 View
        │
        ├─→ 2. mWindowAttributes.copyFrom(attrs)    // 复制窗口属性
        │
        ├─→ 3. enableHardwareAcceleration()         // 启用硬件加速
        │
        ├─→ 4. mAttachInfo 初始化                   // 设置共享信息
        │
        ├─→ 5. requestLayout()                      // 布局操作,异步过程,实际在最后执行(下次 Vsync-app 到达时)
        │
        ├─→ 6. new InputChannel()                   // 创建输入通道
        │
        ├─→ 7. mWindowSession.addToDisplayAsUser()  // 注册窗口
        │       │
        │       └─→ WMS 创建 WindowState、分配 Surface
        │
        ├─→ 8. 处理返回结果 / 错误检查
        │
        ├─→ 9. handleInsetsControlChanged()         // 处理 Insets
        │
        ├─→ 10. computeFrames() setFrame()          // 计算和设置窗口 frame
        │
        ├─→ 11. new WindowInputEventReceiver()      // 创建输入接收器
        │
        ├─→ 12. view.assignParent(this)             // 建立父子关系
        │
        └─→ 13. 构建 InputStage 责任链              // 输入处理管道
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

后续我们需要深入分析的几个点:

  • enableHardwareAcceleration,HWUI 启动硬件加速
  • App 端输入通道的建立,这个需要结合输入系统一起分析
  • addToDisplayAsUser 注册窗口,WMS 中的流程
  • handleInsetsControlChanged,Inset 的分发
  • computeFrames() setFrame(),计算和设置窗口 frame
  • 兼容性的处理

# 相关 Trace 分析

20260202164428

026.AIDL Hal 开发指南10 —— AIDL HAL 的升级
显示疑难问题分析基础

← 026.AIDL Hal 开发指南10 —— AIDL HAL 的升级 显示疑难问题分析基础→

最近更新
01
004.Vulkan绘制一个三角形3——初始化过程分析2
02-03
02
002.Vulkan绘制一个三角形1——概述
02-03
03
003.Vulkan绘制一个三角形2——初始化过程分析1
02-03
更多文章>
Theme by Vdoing | Copyright © 2020-2026 AHao Framework | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式