美文网首页Androidandroid WMS有关
WindowManagerService架构剖析之窗口分组与分层

WindowManagerService架构剖析之窗口分组与分层

作者: 码上就说 | 来源:发表于2018-07-17 21:50 被阅读269次

    WindowManagerService工作方式

    《WindowManagerService架构剖析之addWindow流程》
    《WindowManagerService架构剖析之窗口分组与分层》
    《WindowManagerService架构剖析之token分析》

    一、Window介绍

    Window定义了Android中顶层的显示系统和行为规则,Android中的View都是以Window为模板,都是附在WIndow上,从Activity中setContentView(...)中就可以看出Window以及PhoneWindow(Window的子类)就是Android显示层级的最顶层(这里说的最顶层不是显示在最上层,只是说这个Window是整个UI显示的基础)

    2.1 Window 类型

    每个Window都有type,就是窗口类型,我们在WMS中addWindow的时候会根据当前的窗口类型采取相应的策略。通常而言,窗口分为3类:窗口类型定义在WindowManager.java

    2.1.1 系统窗口类型
            public static final int FIRST_SYSTEM_WINDOW     = 2000;
    //显示状态栏,被放置在屏幕最上方,其他的window都在它的下方
            public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
    //searchbar的window,只能有一个。
            public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
    //接电话的界面的window
            public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
    //系统警告类的window,例如一些电量警告等等
            public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
    //屏保窗口
            public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
    //toast窗口
            public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
            public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
            public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
            public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
            public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
            public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
            public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
            public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
            public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
            public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
            public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
            public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;
            public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
            public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
            public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
            public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
            public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
            public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;
            public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
            public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
            public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
            public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
            public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
            public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
            public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
            public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
            public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;
            public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;
            public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
            public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;
            public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;
            public static final int LAST_SYSTEM_WINDOW      = 2999;
    

    系统窗口类型在2000 ~ 2999,随便找一个系统窗口类型赋值的地方,如下:

    BaseErrorDialog.java
    class BaseErrorDialog extends AlertDialog {
        public BaseErrorDialog(Context context) {
            super(context, com.android.internal.R.style.Theme_Dialog_AppError);
            getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    //......
            getWindow().setAttributes(attrs);
        }
    }
    
    2.1.2.应用窗口类型
    WindowManager.java
            //作为普通应用程序窗口类型的开始
            public static final int FIRST_APPLICATION_WINDOW = 1;
            //作为所有应用程序的基础窗口
            public static final int TYPE_BASE_APPLICATION   = 1;
            //一个普通的应用程序窗口,当前的token一定要设置成Activity的token,表明当前的window是有归属的
            public static final int TYPE_APPLICATION        = 2;
            //特殊的应用程序窗口,用于程序启动的时候显示,当程序可以显示window之前使用这个window来显示一些东西
            public static final int TYPE_APPLICATION_STARTING = 3;
            //在应用程序显示之前,使用此标识来表明windowManager会等待这个window绘制完毕
            public static final int TYPE_DRAWN_APPLICATION = 4;
            //应用程序窗口类型的结束
            public static final int LAST_APPLICATION_WINDOW = 99;
    

    应用窗口类型在1~99找到应用窗口类型赋值的地方:根据上一篇文章对应用窗口启动过程的分析来看,如下:

    ActivityThread.java
    final void handleResumeActivity(IBinder token,
                boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    //......
            r = performResumeActivity(token, clearHide, reason);
    //......
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
    //......
            wm.addView(decor, l);
    //......
    }
    
    2.1.3 子窗口类型
    WindowManager.java
            public static final int FIRST_SUB_WINDOW = 1000;
    //一个应用程序顶部的panel,显示在依附的window上面
            public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
    //显示media的window,显示在依附的window下面
            public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
    //一个子panel,显示在依附的window上面,并且也显示在任何其他TYPE_APPLICATION_PANEL类型的window上面
            public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
            public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
            public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;
            public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
            public static final int LAST_SUB_WINDOW = 1999;
    

    子窗口类型在1000~1999,通常所说的popupwindow就是子窗口,看一下赋值的例子。

    PopupWindow.java
    public class PopupWindow {
            private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
            protected final WindowManager.LayoutParams createPopupLayoutParams(IBinder token) {
    //......
                    p.type = mWindowLayoutType;
    //......
                    return p;
            }
            private void invokePopup(WindowManager.LayoutParams p) {
    //......
                      mWindowManager.addView(decorView, p);
    //......
        }
    }
    

    问题:Dialog是子窗口吗?2.2 Window 分组会分析这个问题。
    小结:
    1.type越小,越在上面,但是window的层级不单单是这个决定的,下面会详细分析。
    2.type只能在这个范围之内,不在此范围,报错。

    PhoneWindowManager.java
    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
            int type = attrs.type;
            if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
                    || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
                    || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
                return WindowManagerGlobal.ADD_INVALID_TYPE;
            }
    //......
        }
    

    2.2 Window 分组

    学习Window分组之前,建议先看一下《WindowManagerService架构剖析之token分析》https://www.jianshu.com/p/23bce4f5f8ea 这样理解起来容易一些。
    这篇文章分析了一个道理:token,AMS-ActivityRecord中appToken,Window中mAppToken,WMS中的windowToken都代表同一个token,这个token就是标识window是否属于同一分组。
    为什么这么说?光说不行,我们用源码分析一下就知道了。还是要扯到WMS中的addWindow方法,这个方法太重要了,这些天看这个代码,每次都有新的体会,每次理解都深刻一点。这次我们剔掉不重要的代码,只看关键部分。

    WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                InputChannel outInputChannel) {
    //......
          final WindowState win = new WindowState(this, session, client, token, parentWindow,
                        appOp[0], seq, attrs, viewVisibility, session.mUid,
                        session.mCanAddInternalSystemWindow);
    //......
          win.mToken.addWindow(win);
    //......
    }
    

    WindowState就是windowManager中的窗口,一个WindowState表示一个window,一个WindowState持有一个WindowToken对象(mToken),这个WindowToken对象就是AMS中传入的appToken,但是这个addWindow是什么意思?

    WindowToken.java
    protected final WindowList<E> mChildren = new WindowList<E>(); //step1:
    void addWindow(final WindowState win) {
            if (win.isChildWindow()) {  //step2:
                return;
            }
            if (!mChildren.contains(win)) {  //step3:
                addChild(win, mWindowComparator);
                mService.mWindowsChanged = true;
            }
        }
    
    private final Comparator<WindowState> mWindowComparator =
                (WindowState newWindow, WindowState existingWindow) -> {
            final WindowToken token = WindowToken.this;
            if (newWindow.mToken != token) {
                throw new IllegalArgumentException("newWindow=" + newWindow
                        + " is not a child of token=" + token);
            }
    
            if (existingWindow.mToken != token) {
                throw new IllegalArgumentException("existingWindow=" + existingWindow
                        + " is not a child of token=" + token);
            }
    
            return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
        };
    

    1.mChildren列表就是当前window存储的子window列表
    2.如果当前创建的window已经是子window,那么表示已经添加过了,不需要重复添加,直接return
    3.如果当前window的存储的子window列表中没有child,则addChild
    4.WindowToken 继承 WindowContainer
    5.比较的原则是什么:比较两个window的mBaseLayer,至于什么是mBaseLayer,2.3 Window层级 会介绍。
    6.mWindowComparator里面也能看出来,如果newWindow和existingWindow的token不一样,是不能比较的,直接throw异常了。

    WindowContainer.java
    protected void addChild(E child, Comparator<E> comparator) {
            if (child.getParent() != null) {
                throw new IllegalArgumentException("addChild: container=" + child.getName()
                        + " is already a child of container=" + child.getParent().getName()
                        + " can't add to container=" + getName());
            }
    
            int positionToAdd = -1;
            if (comparator != null) {
                final int count = mChildren.size();
                for (int i = 0; i < count; i++) {
                    if (comparator.compare(child, mChildren.get(i)) < 0) {
                        positionToAdd = i;
                        break;
                    }
                }
            }
    
            if (positionToAdd == -1) {
                mChildren.add(child);
            } else {
                mChildren.add(positionToAdd, child);
            }
            // Set the parent after we've actually added a child in case a subclass depends on this.
            child.setParent(this);
        }
    

    这段代码十分简单,找到当前child在mChildren列表中的位置(排序算法),然后将child插入相应的位置,保证插入child之后mChildren也是按序排列的。
    当前window和child window列表都持有同一个token,这个token标识当前window同一分组。

    现在可以分析2.1小节提出的问题了,Dialog是子窗口类型吗?


    Dialog-addView.jpg

    关键的点有:
    1.getAttributes

    Window.java
    private final WindowManager.LayoutParams mWindowAttributes =
            new WindowManager.LayoutParams();
    public final WindowManager.LayoutParams getAttributes() {
            return mWindowAttributes;
        }
    
    WindowManager.java
    public LayoutParams() {
                super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                type = TYPE_APPLICATION;
                format = PixelFormat.OPAQUE;
            }
    

    有点意思了,当前的Dialog的window type是TYPE_APPLICATION,上面的窗口类型介绍了这是应用程序的窗口类型。说明这个Dialog是属于应用程序窗口的一种。
    2.adjustLayoutParamsForSubWindow

    Window.java
    void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
            CharSequence curTitle = wp.getTitle();
            if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                if (wp.token == null) {
                    View decor = peekDecorView();
                    if (decor != null) {
                        wp.token = decor.getWindowToken();
                    }
                }
    //......
            } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
                    wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
    //......
            } else {
                if (wp.token == null) {
                    wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
                }
    //......
            }
    //......
            if (mHardwareAccelerated ||
                    (mWindowAttributes.flags & FLAG_HARDWARE_ACCELERATED) != 0) {
                wp.flags |= FLAG_HARDWARE_ACCELERATED;
            }
        }
    

    这个函数别看很长,但是对我们而言,有用的只有几行:
    if (wp.token == null) {
    wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
    }
    说明这个是直接使用mContainer.mAppToken,而这个mContainer,就是Dialog基于的Activity,这个明确了。
    小结:
    1.Dialog不是子窗口,是应用窗口的一种。
    2.Dialog和它基于的Activity公用同一个token,说明它们是属于同一组。

    PopupWindow就是名副其实的子窗口类型的,这里暂且不展开讲解,PopupWindow的token获取和Dialog还有不同,大家感兴趣可以去看下。(根据PopupWindow的锚点Window确定)。


    Window分组.jpg

    2.3 Window 层级

    前面铺垫了这么多,又是分组又是token比较,其实已经讲了一些mBaseLayer相关的知识了,这时候Windiw分层已经呼之欲出了。所谓分层,就是显示的时候有上下次序,上面的window会覆盖下面的window,我们需要知道哪些window应该放在上面,依据是什么?这是本小节探讨的问题。
    window之所以要分层级,因为我们看到的手机直观上是二维的,但是实际上是一个三维的显示过程,就像一个三维的坐标系一样。


    Window层级图 (1).jpg

    还是要讲WMS-addWindow,这个地方太重要了,添加窗口的时候就应该确定好了窗口的层级,显示的时候才可以根据当前的层级来确定window应该在哪一层显示。
    前面我们讨论过WindowState对象对应Window,那么WindowState中肯定有标识当前window层级的变量和计算当前window层级的方法。WMS-addWindow中构造了一个WindowState对象。

    WindowState.java
    final int mBaseLayer;
    final int mSubLayer;
    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
               WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
               int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
    //......
            mToken = token;
    //......
            mWindowId = new WindowId(this);
    //......
            if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
    //......
                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;
                mLayoutAttached = false;
    //......
            }
    //......
        }
    

    这段我们我们可以抽取出下面的信息:
    1.WindowState构造的时候初始化当前的mBaseLayer和mSubLayer,这两个参数应该是决定z-order的两个因素,单还有没有其他的因素,暂时不得而知。
    2.mBaseLayer在window策略中定义了决定其计算的函数,mSubLayer只有当前window是子窗口的时候才会计算,否则直接初始化0
    PhoneWindowManager实现WindowManagerPolicy接口。

    WindowManagerPolicy.java
    default int getWindowLayerLw(WindowState win) {
            return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
        }
    
    default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
            if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                return APPLICATION_LAYER;
            }
    
            switch (type) {
                case TYPE_WALLPAPER:
                    return  1;
                case TYPE_PRESENTATION:
                case TYPE_PRIVATE_PRESENTATION:
                    return  APPLICATION_LAYER;
                case TYPE_DOCK_DIVIDER:
                    return  APPLICATION_LAYER;
                case TYPE_QS_DIALOG:
                    return  APPLICATION_LAYER;
                case TYPE_PHONE:
                    return  3;
        //......
                case TYPE_BOOT_PROGRESS:
                    return  32;
                case TYPE_POINTER:
                    return  33;
                default:
                    return APPLICATION_LAYER;
            }
        }
    
    default int getSubWindowLayerFromTypeLw(int type) {
            switch (type) {
                case TYPE_APPLICATION_PANEL:
                case TYPE_APPLICATION_ATTACHED_DIALOG:
                    return APPLICATION_PANEL_SUBLAYER;
                case TYPE_APPLICATION_MEDIA:
                    return APPLICATION_MEDIA_SUBLAYER;
                case TYPE_APPLICATION_MEDIA_OVERLAY:
                    return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
                case TYPE_APPLICATION_SUB_PANEL:
                    return APPLICATION_SUB_PANEL_SUBLAYER;
                case TYPE_APPLICATION_ABOVE_SUB_PANEL:
                    return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
            }
            return 0;
        }
    

    baseLayer这儿实际上就是映射windowType到相应的到1~33区间,这个baseLayer会在后续计算真正window层级的时候用到。可见WindowState构造函数中只是粗略确定当前的baseLayer和subLayer,后面肯定还会根据这两个基础参数计算出最终的层级。
    1.mBaseLayer是基础序,当前窗口类型确定的情况下,基础序是不变的。依附与同一个parent 窗口的 子窗口的mBaseLayer是相同的。
    2.mSubLayer就是比较相同分组下的子窗口的序,简称子序。从代码上来看,mSubLayer的区间是-2~3
    计算的公式是:
    3.windowType越大,z-order不一定最大,因为windowType在计算过程中被重新映射了,上面就是映射的过程。

    mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                        * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
    static final int TYPE_LAYER_MULTIPLIER = 10000;
    static final int TYPE_LAYER_OFFSET = 1000;
    

    从这个计算公式来讲,只要parentWindow类型不同,那么mBaseLayer决定的大区间肯定是不同的,保证了每个windowType决定的mBaseLayer都会有相当大的缓冲区间,切不会出现不同windowType相等的情况。
    接下来还有两个最终的步骤:

    WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                InputChannel outInputChannel) {
    //......
          final WindowState win = new WindowState(this, session, client, token, parentWindow,
                        appOp[0], seq, attrs, viewVisibility, session.mUid,
                        session.mCanAddInternalSystemWindow);
    //......
          win.mToken.addWindow(win);
    //......
          displayContent.assignWindowLayers(false /* setLayoutNeeded */);
    //......
    }
    

    1.win.mToken.addWindow(win);
    这个函数其实在2.2 Window分组的时候已经详细分析过,这个方法的主要作用就是讲当前的放入有序windowList数组中正确的位置。根据token找到归属的window列表,就是将window分组完成。
    2.displayContent.assignWindowLayers(false /* setLayoutNeeded */);
    这个方法非常关键,这是计算z-order值的过程,这个方法执行完成之后,z-order最终确定,z-order越大,表明window层级越在上面。下面看看详细的计算过程。


    z-order计算调用过程.jpg

    真正的计算过程代码如下:

    WindowLayersController.java
    private final Consumer<WindowState> mAssignWindowLayersConsumer = w -> {
            boolean layerChanged = false;
    
            int oldLayer = w.mLayer;
    //step1:
            if (w.mBaseLayer == mCurBaseLayer) {
                mCurLayer += WINDOW_LAYER_MULTIPLIER;
            } else {
                mCurBaseLayer = mCurLayer = w.mBaseLayer;
            }
    //step2:
            assignAnimLayer(w, mCurLayer);
    //step3:
            if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
                layerChanged = true;
                mAnyLayerChanged = true;
            }
    //step4:
            if (w.mAppToken != null) {
                mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
                        w.mWinAnimator.mAnimLayer);
            }
            if (mImeTarget != null && w.mBaseLayer == mImeTarget.mBaseLayer) {
                mHighestLayerInImeTargetBaseLayer = Math.max(mHighestLayerInImeTargetBaseLayer,
                        w.mWinAnimator.mAnimLayer);
            }
            if (w.getAppToken() != null && StackId.isResizeableByDockedStack(w.getStackId())) {
                mHighestDockedAffectedLayer = Math.max(mHighestDockedAffectedLayer,
                        w.mWinAnimator.mAnimLayer);
            }
    //step5:
            collectSpecialWindows(w);
    
            if (layerChanged) {
                w.scheduleAnimationIfDimming();
            }
        };
    

    这个是使用了java8推出的函数式编程:java.util.function.Consumer接口。注册的接口在合适的时机accept(...)一下,触发一下要执行的函数,这种写法符合lambda规则,代码看上去比较简洁。
    step1:如果当前window和之前的window是同一类型的,为了以示区分,后一个窗口+5,偏移一下,标识区别。如果不是同一类型,那么更新一下mCurBaseLayer和mCurLayer
    step2:更新动画层的layer,动画显示的时候,该窗口的层级会有变化。
    step3:当前的层级有变化或者动画层级有变化,置位标识值,后面会用到。
    step4:同时更新当前应用最高层级、IME最高层级、常驻栏最高层级
    step5:如果当前的window是特殊窗口,将他们放入特定的数组中,这儿没有更新layer
    1.这儿为什么没有遍历windowList?
    整个accept(...)回调就在windowList的遍历中,此回调值计算单个window的最终layer
    2.更新之后的layer,会通过setLayer将计算好的z-order值更新到SurfaceFlinger中,进而确定Surface的次序。

    接下来准备分析一下窗口大小计算、窗口动画等等。

    相关文章

      网友评论

        本文标题:WindowManagerService架构剖析之窗口分组与分层

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