WMS

作者: msg00 | 来源:发表于2019-03-10 16:33 被阅读0次

Window Tree

Window Tree

WMS责任主要是负责收集各个窗口的数据,比如透明度,层级值,位置参数,大小等,然后将窗口的这些参数都传给Surface层去渲染;
WMS通过创建一个类似树形结构,来管理所有的窗口,下图为Window Tree简单介绍


11.jpg

Window Tree如何建立

AMS和WMS关系极其密切,基本上每一种数据结构都与之有所对应,不同点在与AMS关心的最小粒度是Activity,而WMS关心的最小粒度是窗口;所以AppWindowToken包含AppWindowToken的构建时机顺序都是根据AMS决定的,而AppWindowToken以下的部分就是完全由WMS来控制.
虽然AppWindowToken创建时机和顺序都是AMS决定的;但是每个AppWindowToken对应着一个Activity,了解它是很有必要的,所以整个WMS数的构建从AppWindowToken开始说起[WindowToken暂时不分析]:

AppWindowToken创建时机

从startActivity()到Activity.onCreate()方法,大致我分了三步[Android系统是非常繁琐,整个过程所要做的事情非常之多]

  1. 启动一个Activity的时候,会首先查看对应的进程是否启动,没启动就先启动对应的进程
  2. 然后创建Activity对应的AppWindowToken,同时添加进WMS树中
  3. 最后是大家熟悉的Activity的onCreate等;
    注意这个时候Activity对应的窗口[WindowState]并没有添加进来即AppWindowToken并没有对应的child;
WindowState创建时机

接着上一个流程来说,在Activity的onCreate时候Activity已经创建好了对应的View树[更准确的说是setContentView],View数的树顶是一个DecorView,此时DecorView处于游离状态,对于开发者来说,我们如果想要添加一个窗口需要做些什么呢,没错就是通过WindowManager.addView(decorView, lp); Android系统同样也是这样操作,时机就是回调Activity.onResume之前.
所以创建WindowState的源头是WindowManager.addView(decorView, lp)方法,而真正创建WindowState的是在WMS.addWindow方法
WMS.addWindow方法大概做了3件事

  1. 找到属于该窗口的屏幕[DisplayContent]
  2. 找到属于该窗口的AppWindowToken
  3. 创建WindowState并且存入AppWindowToken中即添加到WMS树中
    这里其实是有两种情况: 1. 如果WindowState是Dialog或者Activity等应用窗口则根据WindowState的mBaseLayer从小到大的顺序添加到AppWindowToken中,如果是PopupWindow等子窗口,则不会添加到AppWindowToken,而是根据WindowState的mSubLayer从小到大的顺序添加进WindowState中,因为此处是Activity的窗口所以直接是添加到AppWindowToken中

至此Window Tree分支创建过程大致分析完毕,开发者可通过调用一个有一个接口来丰富Window Tree.
强烈建议自已分析一下WindowManager.addView(decorView, lp)这个方法,这个过程包含了很多必要的知识点比如View Tree的测量布局绘制,View树对外的代理官ViewRootImpl的创建,为什么PopupWindow的context不能使用Application而是要使用Activity的等等等;

Window层级处理

Android窗口类型

窗口类型分为三种
应用窗口: 如Activity, Dialog
子窗口: PopupWindow
系统窗口: 系统弹窗等

WindowState属性 mBaseLayer ; mSubLayer ; mLayer

每个WindowState都有三个属性 mBaseLayer ; mSubLayer ; mLayer;
mBaseLayer,mSubLayer都是由WindowManager.LayoutParam中的type决定,系统窗口和应用窗口的mSubLayer=0,type决定mBaseLayer;子窗口的mBaseLayer值对应着父窗口的mBaseLayer,而type决定着mSubLayer;
mLayer是通过整合所有窗口计算出来的,详见下面窗口的层级处理;

    if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
        // The multiplier here is to reserve space for multiple
        mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; // 应用窗口之间和系统窗口之间都是预留了很大的空间的,目的在于后续层级处理的时候预留插入的位置
        mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
        mIsChildWindow = true;
        parentWindow.addChild(this, sWindowSubLayerComparator);
    } else {
        mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        mSubLayer = 0;
        mIsChildWindow = false;

显然系统窗口的mBaseLayer是大于应用窗口;对于子窗口来说它是依附与父窗口的,可以在父窗口的下面也可以在父窗口的上层,这取决于mSubLayer的正负值

Android 8.0 层级处理

因为Window Tree已经有顺序了,所以只需要按照顺序遍历所有WindowState,然后根据mBaseLayer进行累加并赋值给mLayer
遍历的源头来自WindowLayersController.assignWindowLayers; 累加规则在WindowLayersController.mAssignWindowLayersConsumer;

WindowLayersController.assignWindowLayers 部分代码

    displayContent.forAllWindows(mAssignWindowLayersConsumer, false /* traverseTopToBottom */); //开始遍历
    adjustSpecialWindows(); //调整特殊层级位置

WindowLayersController.mAssignWindowLayersConsumer 部分代码

    int oldLayer = w.mLayer;
    if (w.mBaseLayer == mCurBaseLayer) {
        mCurLayer += WINDOW_LAYER_MULTIPLIER;   // WINDOW_LAYER_MULTIPLIER
    } else {    
        mCurBaseLayer = mCurLayer = w.mBaseLayer;
    }
    assignAnimLayer(w, mCurLayer);

    collectSpecialWindows(w) 收集一些特殊的窗口,然后调整层级位置

有些窗口比较特殊,它的层级需要根据其他窗口而定,比如输入法窗口,它是必须高于应用窗口的, 所以在adjustSpecialWindows中会调整输入法窗口的mLayer值,这也是为什么每个层级之间都需要预留位置;

最终WMS还是会遍历整个Window Tree,将每个WindowState对应的层级数据交付给与之对应的WindowSurfaceController中,由WindowSurfaceController再交给Surface层
WMS是以树的形式管理WindowState[Window Tree],而Surface层没有树结构,只是通过WindowState的mLayer来确定Surface的位置

Android 9.0 层级处理

Android 9.0 有一个比较大的变动在于将窗口动画移动到Surface层处理,避免卡顿;有兴趣可以看看Here
所以Android9.0 中已经没有WindowLayersController.java了;取而代之的是有层级概念的SurfaceControl[即Surface Tree结构如图],这样surface层就可以通过按照顺序遍历这颗树即可获取到Surface位置
单从层级的角度来看,这种结构方便动态更改:如果需要调整某个层级,就比较简单不需要提前预留位置,直接可以通过设置assignRelativeLayer,添加一个新的分支,同时还可以在这个新分支做更多的处理

222.jpg

本文只是非常粗略的描述了WMS的一部分,Android系统非常庞大且复杂,所以不能过于深入细节,而是把握整体,了解这样做的好处以及缺点,本人也能力有限,如果文章中有错误,可以指出,互相探讨,互相学习,谢谢.

相关文章

网友评论

      本文标题:WMS

      本文链接:https://www.haomeiwen.com/subject/tvtppqtx.html