Android WindowManagerService--03:整体架构及启动过程

本文转载自:Android R WindowManagerService模块(1) WMS整体架构及启动过程

本文基于Android 11.0源码分析

前言

  Android系统中,WindowManagerService(以下简称WMS)负责一切窗口的管理,窗口可以理解为屏幕上的各种显示区域,如状态栏、Activity、锁屏等对于WMS来说,都是一个具体的窗口实例。从这篇文章开始,将会对WindowManagerService模块进行整理总结。WMS的职责可以简单总结为下图:

WMS04.PNG

1.WMS架构

  在WindowManagerService中,以容器+树结构的形式对窗口进行管理,最顶层容器为ConfigurationContainer,它是所有容器的父容器,各个容器继承关系如下:

WMS05.PNG

上图中包含了WMS中的所有容器,各个子容器含义如下:

  1. ConfigurationContainer:最顶层容器,定义了多个Configuration对象,以及提供了用来组织各容器层级的公共逻辑;

  2. WindowProcessController:用于和AMS中的ProcessRecord进行通讯,当ProcessRecord中对应用进程作出调整后,通过WindowProcessController和WM进行通信;

  3. WindowContainer:作为可以保存窗口类的父类,定义了用于操作窗口的所有公共方法;

  4. RootWindowContainer:窗口容器在树结构中的根节点;

  5. DisplayContent:作为RootWindowContainer的子节点,用于管理同一个逻辑屏的窗口;

  6. DisplayChildWindowContainer:DisplayContent中的所有子节点的父类;

  7. NonAppWindowContainers:继承于DisplayChildWindowContainer,主要保存非来自应用的WindowToken;

  8. WindowContainers:只包含一个子节点——DisplayArea.Root,大部门窗口都会保存在这个容器中;

  9. DisplayArea:用于对DisplayContent中的节点进行分组管理,主要分为了三类;

  10. DisplayArea.Root:DisplayArea的子类,该容器作为DisplayContent中最顶层的显示区域,用来保存Tokens、TaskDisplayArea、ImeContainer容器;

  11. TaskDisplayArea:DisplayArea的子类,此类容器用于管理Task;

  12. TaskDisplayArea.Tokens:DisplayArea的子类,该容器用来保存正常窗口的WindowToken;

  13. ImeContainer:Tokens的子类,该容器用来保存IME窗口的WindowToken;

  14. Task:用来保存ActivityRecord,即我们常说的"任务";

  15. ActivityStack:Task的子类,用来管理处于同一个栈的Activity,特殊栈可以保存Task;

  16. WindowToken:用来管理窗口,多个窗口可以被一个WindowToken进行管理;

  17. ActivityRecord:继承于WindowToken,表示ActivityStack中的一个Activity实例;

  18. WallpaperWindowToken:继承于WindowToken,壁纸窗口比较特殊,因此由WallpaperWindowToken进行管理;

  19. WindowState:窗口对象实例。

DisplayArea是Android R上新添加的容器,目的就是将复杂的窗口层级管理简单化、低耦合。

  而在树结构中,各个容器结构如下:

WMS06.PNG

可以看到,在树结构中,根节点为RootWindowContainer,叶子节点为WindowState。 正是通过这种结构,WMS中将系统中所有的窗口显示管理得井井有条,并将所有窗口以Surface的形式送到SurfacaFlinger中进行合成和显示。

2.WMS启动流程

  接下来我们看下WMS的启动过程。WindowManagerService没有继承与SystemService,而是直接继承了IWindowManager.Stub接口,因此启动过程中,和SytemService的启动有区别。在system_server中,通过以下这些操作完成了WMS的启动:

// frameworks/base/services/java/com/android/server/SystemServer.java

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
            // 2.1 创建WMS
            wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
            // 2.2 进行初始化
            wm.onInitReady();
            // 2.3 设置InputCallback接口
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            // 2.4 进行Display配置更新
            wm.displayReady();
            // 2.5 系统启动完成
            wm.systemReady();
            // 2.6 计算Configuration
        final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
        DisplayMetrics metrics = new DisplayMetrics();
        context.getDisplay().getMetrics(metrics);
        context.getResources().updateConfiguration(config, metrics);
    }

注:上面筛选出wm相关的操作,下面对这些操作分别进行分析。

2.1 WMS#main()创建WMS对象

  在执行main()方法后,最终会在android.display线程去创建WMS的实例:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm) {
        return main(context, im, showBootMsgs, onlyCore, policy, atm,
                SurfaceControl.Transaction::new, Surface::new, SurfaceControl.Builder::new);
    }

    /**
     * Creates and returns an instance of the WindowManagerService. This call allows the caller
     * to override factories that can be used to stub native calls during test.
     */
    @VisibleForTesting
    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
        // DisplayThread就是android.display线程
        // runWithScissors的执行会导致system_server线程等待android.display执行完再进行下一步操作。
        DisplayThread.getHandler().runWithScissors(() ->
                sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
                        atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0);
        return sInstance;
    }
------------------------
    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
            ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<Surface> surfaceFactory,
            Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
        ......

        // Tranaction对象
        mTransaction = mTransactionFactory.get();

        // 创建WindowAnimator对象
        mAnimator = new WindowAnimator(this);
        // 创建RootWindowContainer对象
        mRoot = new RootWindowContainer(this);
        // 创建WindowSurfacePlacer对象
        mWindowPlacerLocked = new WindowSurfacePlacer(this);
        // 创建TaskSnapshotController对象
        mTaskSnapshotController = new TaskSnapshotController(this);
        // 创建DisplayWindowListenerController对象
        mDisplayNotificationController = new DisplayWindowListenerController(this);
        ......
        // 创建SurfaceAnimationRunner对象
        mSurfaceAnimationRunner = new SurfaceAnimationRunner(mTransactionFactory,
                mPowerManagerInternal);
        // 创建TaskPositioningController
        mTaskPositioningController = new TaskPositioningController(
                this, mInputManager, mActivityTaskManager, mH.getLooper());
        // 创建DragDropController对象
        mDragDropController = new DragDropController(this, mH.getLooper());
        // 创建EmbeddedWindowController
        mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
        // 创建 DisplayAreaPolicy.Provider对象
        mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
                mContext.getResources());
        .....
    }

构造方法中,创建了WMS所用到的多个对象。

2.2 WMS#onInitReady()对Policy进行初始化

  接下来执行onInitReady()方法进行初始化:

 // frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    public void onInitReady() {
        initPolicy();//初始化policy

        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
        createWatermark();
        showEmulatorDisplayOverlayIfNeeded();
    }
-------------------------------------
    private void initPolicy() {
        UiThread.getHandler().runWithScissors(new Runnable() {
            @Override
            public void run() {
                WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
                mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
            } // android.ui线程
        }, 0);
    }

在android.ui线程中调用WindowManagerPolicy#init()方法进行初始化,其中WindowManagerPolicy就是SystemServer.java中WindowManagerService.main()方法传进来的PhoneWindowManager。

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    public void init(Context context, IWindowManager windowManager,
            WindowManagerFuncs windowManagerFuncs) {
        mContext = context;
        mWindowManager = windowManager;
        mWindowManagerFuncs = windowManagerFuncs;
        ......
    }

这个方法中做了大量的初始化操作。PhoneWindowManager继承于WindowManagerPolicy,是WMS中管理窗口过程中的一个策略类,窗口的显示、事件的派发等都受到PhoneWindowManager中的策略影响。mWindowManager和mWindowManagerFuncs都是WMS对象本身。

  这里的initPolicy()方法最终执行在android.ui线程中,并且也是使用runWithScissors,所以中和前面的两个线程,有如下的线程执行关系:

WMS07.png

initPolicy方法和此前讲的WMS的main方法的实现类似,它的具体实现在PhoneWindowManager(PWM)中。PWM的init方法运行在”android.ui”线程中,它的优先级要高于initPolicy方法所在的”android.display”线程,因此”android.display”线程要等PWM的init方法执行完毕后,处于等待状态的”android.display”线程才会被唤醒从而继续执行下面的代码:WMS.displayRead()。

2.3 IMS#setWindowManagerCallbacks()设置InputCallback回调

  这个方法用来向IMS中设置InputManagerCallback回调:

// frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

    public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
        mWindowManagerCallbacks = callbacks;
    }

InputManagerCallback对象在WMS加载时完成创建:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    // 创建InputManagerCallback对象
    final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);
------------------------------
    public InputManagerCallback getInputManagerCallback() {
        return mInputManagerCallback;
    }

InputManagerCallback接口用于接受IMS中的回调,如input事件派发过程中发生的ANR等,就是通过该接口向WMS中传递。

2.4 WMS#displayReady()更新DisplayContent配置

  这个方法用来进行Display相关配置的第一次更新:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public void displayReady() {
        synchronized (mGlobalLock) {
            if (mMaxUiWidth > 0) {
                mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
            }
            applyForcedPropertiesForDefaultDisplay();
            // 告知WindowAnimator初始化完成
            mAnimator.ready();
            // 表示Display准备完成
            mDisplayReady = true;
            // Reconfigure all displays to make sure that forced properties and
            // DisplayWindowSettings are applied.
            // 更新Configuration
            mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_TOUCHSCREEN);
        }

        try {
            // 更新Configuration
            mActivityTaskManager.updateConfiguration(null);
        } catch (RemoteException e) {
        }
    }

这里通过DisplayContent#reconfigureDisplayLocked()更新DisplayContent相关配置。

2.5 WMS#systemReady()方法

  这个方法的执行,表示system_server启动完成,WMS中会分别执行其他组件的systemReady()方法:

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    public void systemReady() {
        // 系统
        mSystemReady = true;
        // PhoneWindowManager
        mPolicy.systemReady();
        // 执行DisplayPolicy#systemReady
        mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
        mTaskSnapshotController.systemReady();
        mHasWideColorGamutSupport = queryWideColorGamutSupport();
        mHasHdrSupport = queryHdrSupport();
        UiThread.getHandler().post(mSettingsObserver::loadSettings);
        IVrManager vrManager = IVrManager.Stub.asInterface(
                ServiceManager.getService(Context.VR_SERVICE));
        if (vrManager != null) {
            try {
                final boolean vrModeEnabled = vrManager.getVrModeState();
                synchronized (mGlobalLock) {
                    vrManager.registerListener(mVrStateCallbacks);
                    if (vrModeEnabled) {
                        mVrModeEnabled = vrModeEnabled;
                        mVrStateCallbacks.onVrStateChanged(vrModeEnabled);
                    }
                }
            } catch (RemoteException e) {
                // Ignore, we cannot do anything if we failed to register VR mode listener
            }
        }
    }

2.6 WMS#computeNewConfiguration()

  这个方法是启动过程中执行的最后一个方法,用来更新全局配置状态:

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public Configuration computeNewConfiguration(int displayId) {
        synchronized (mGlobalLock) {
            return computeNewConfigurationLocked(displayId);
        }
    }

    private Configuration computeNewConfigurationLocked(int displayId) {
        if (!mDisplayReady) {
            return null;
        }
        final Configuration config = new Configuration();
        final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
        displayContent.computeScreenConfiguration(config);
        return config;
    }

在该方法中,会根据逻辑屏id,获得对应的DisplayContent对象来进行配置的更新,并在更新完成后,设置给对应Context的Resource对象。 关于DisplayContent中的更新配置更新流程,会在之后的文章中结合具体场景详细说明。

  经过以上几个步骤,WMS启动完成。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容