WMS层级修改与原理简单分析

记录一个WMS的问题,如何修改或者添加一个WMS的层级

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
            PowerManagerWrapper powerManagerWrapper) {
  if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.
            mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
            mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
            } else {
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.
            mBaseLayer = mPolicy.getWindowLayerLw(this)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
            mSubLayer = 0;
            }

可以看到这里有个baseLayer这个属性,了解WMS的应该知道WindowState是什么东西

这个mbaseLayer的值 最终会调用到 mPolicy.getWindowLayerLw 

 default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
            boolean roundedCornerOverlay) {
        // Always put the rounded corner layer to the top most.
        if (roundedCornerOverlay && canAddInternalSystemWindow) {
            return getMaxWindowLayer();
        }
        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
            return APPLICATION_LAYER;
        }

        switch (type) {
            case TYPE_WALLPAPER:
                // wallpaper is at the bottom, though the window manager may move it.
                return  1;
            case TYPE_PRESENTATION:
            case TYPE_PRIVATE_PRESENTATION:
            case TYPE_DOCK_DIVIDER:
            case TYPE_QS_DIALOG:
            case TYPE_PHONE:
                return  3;
            case TYPE_SEARCH_BAR:
                return  4;
            case TYPE_INPUT_CONSUMER:
                return  5;
            case TYPE_SYSTEM_DIALOGreturn  6;
            case TYPE_TOAST:
                // toasts and the plugged-in battery thing
                return  7;
            case TYPE_PRIORITY_PHONE:
                // SIM errors and unlock.  Not sure if this really should be in a high layer.
                return  8;
            case TYPE_SYSTEM_ALERT:
                // like the ANR / app crashed dialogs
                // Type is deprecated for non-system apps. For system apps, this type should be
                //  return  canAddInternalSystemWindow ? 12 : 9;
            case TYPE_APPLICATION_OVERLAY:
                return  11;
            case TYPE_INPUT_METHOD:
                // on-screen keyboards and other such input method user interfaces go here.
                return  13;
            case TYPE_INPUT_METHOD_DIALOG:
                // on-screen keyboards and other such input method user interfaces go here.
                return  14;
             case TYPE_STATUS_BAR:
                return  15;
            case TYPE_STATUS_BAR_ADDITIONAL:
                return  16;
            case TYPE_NOTIFICATION_SHADE:
                return  17;
            case TYPE_STATUS_BAR_SUB_PANEL:
                return  18;
            case TYPE_KEYGUARD_DIALOG:
                return  19;
            case TYPE_VOICE_INTERACTION_STARTING:
                return  20;
            case TYPE_VOICE_INTERACTION: // voice interaction layer should show above the lock screen.
                return  21;
            case TYPE_VOLUME_OVERLAY:
                // the on-screen volume indicator and controller shown when the user
                // changes the device volume
                return  22;
           。。。。省略

如果你需要新增一个层级很高的类型那么就新增一个新的参数即可新增一个新的层级

当然还需要跟APP对应起来

但是问题来了,WMS的baseLayer我去看了一下似乎没有直接跟SurfaceContorl关联起来,SurfaceContorl的setLayer没有直接set这个baseLayer

那么WMS的渲染层级到底怎么设置的??SurfaceContorl 跟这个baseLayer到底有什么关系?

其实这个baseLayer只是一个相对位置,并不是surfaceControl的真实位置,如果你dumpsurface

并不会dump到我们新增的window位置

WMS的排序是通过排序,而这个排序是当前这个window在集合里的位置

窗口次序的调整时机应该是有新窗口被添加或是旧的窗口被移除,不管是什么类型的窗口被添加到wms中都是走addWindow方法

final boolean suspended = mPmInternal.isPackageSuspended(win.getOwningPackage(),
                    UserHandle.getUserId(win.getOwningUid()));
            win.setHiddenWhileSuspended(suspended);
            final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
            final AppWindowToken aToken = token.asAppWindowToken();
            if (type == TYPE_APPLICATION_STARTING && aToken != null) {
                aToken.startingWindow = win;
                if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
                        + " startingWindow=" + win);
            }
            boolean imMayMove = true;
            win.mToken.addWindow(win);
            if (type == TYPE_INPUT_METHOD) {
                win.mGivenInsetsPending = true;
                setInputMethodWindowLocked(win);
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                displayContent.computeImeTarget(true /* updateImeTarget */);
                imMayMove = false;
            } else {
                if (type == TYPE_WALLPAPER) {         displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
                    // If there is currently a wallpaper being shown, and
                    // the base layer of the new window is below the current
                    // layer of the target window, then adjust the wallpaper.
                    // This is to avoid a new window being placed between the
                    // wallpaper and its target.
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }

这个地方有两个关键点
win.mToken.addWindow(win);添加到windowContainer中,此时会导致容器中的其他窗口位置会发生变化

WindowToken.java
void addWindow(final WindowState win) {
        if (DEBUG_FOCUS) Slog.d(TAG_WM,
                "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
        if (win.isChildWindow()) {//如果是子窗口,应该添加到父窗口的容器中
            // Child windows are added to their parent windows.
            return;
        }
        if (!mChildren.contains(win)) {//如果WindowContainer中没有添加过
            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
            addChild(win, mWindowComparator);
            mService.mWindowsChanged = true;
            // TODO: Should we also be setting layout needed here and other places?
        }
    }
 WindowContainer.java
 protected void addChild(E child, Comparator 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);
        }
        onChildAdded(child);
        // Set the parent after we've actually added a child in case a subclass depends on this.
        child.setParent(this);
    }
    //自定义的Comparator
    private final Comparator mWindowComparator =
            (WindowState newWindow, WindowState existingWindow) -> {
        final WindowToken token = WindowToken.this;
        if (newWindow.mToken != token) {//如果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;
    };
    protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
            WindowState existingWindow) {
        // New window is considered greater if it has a higher or equal base layer.
        return newWindow.mBaseLayer >= existingWindow.mBaseLayer;//比较baseLayer值
    }

这里完成了在集合里的排序,可是跟surfaceControl怎么关联上的?

 public void assignChildLayers(Transaction t) {
        // The surface of the main window might be preserved. So the child window on top of the main
        // window should be also on top of the preserved surface.
        int layer = PRESERVED_SURFACE_LAYER + 1;
        for (int i = 0; i < mChildren.size(); i++) {
            final WindowState w = mChildren.get(i);

            // APPLICATION_MEDIA_OVERLAY needs to go above APPLICATION_MEDIA
            // while they both need to go belelow the main window. However the
            // relative layering of multiple APPLICATION_MEDIA/OVERLAY has never
            // been defined and so we can use static layers and leave it that way.
            if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) {
                if (mWinAnimator.hasSurface()) {
                    w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -2);
                } else {
                    w.assignLayer(t, -2);
                }
  } else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
                if (mWinAnimator.hasSurface()) {
                    w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -1);
                } else {
                    w.assignLayer(t, -1);
                }
            } else {
                w.assignLayer(t, layer);
            }
            w.assignChildLayers(t);
            layer++;
        }
    } 在这里进行layer++ 

最终会走到

WindowContainer::assignLayer
    void assignLayer(Transaction t, int layer) {
        // Don't assign layers while a transition animation is playing
        // TODO(b/173528115): establish robust best-practices around z-order fighting.
        if (!mTransitionController.canAssignLayers(this)) return;
        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
        if (mSurfaceControl != null && changed) {
            setLayer(t, layer);
            mLastLayer = layer;
            mLastRelativeToLayer = null;
        }
    } 

这个            setLayer(t, layer);方法会最终setSurfaceControl的Layer层级

    protected void setLayer(Transaction t, int layer) {
        if (mSurfaceFreezer.hasLeash()) {
            // When the freezer has created animation leash parent for the window, set the layer
            // there instead.
            mSurfaceFreezer.setLayer(t, layer);
        } else {
            // Route through surface animator to accommodate that our surface control might be
            // attached to the leash, and leash is attached to parent container.
            mSurfaceAnimator.setLayer(t, layer);
        }
    }

所以最终就会给到surfacecontrol

验证 在 getWindowLayerFromTypeLw新增36 mBaseLayer=361000 通过dump可以拿到

 Window #2 Window{a06b8bf u0 com.example.myapplication}:
    mDisplayId=0 rootTaskId=1 mSession=Session{5f8e963 10870:u0a10173} mClient=android.os.BinderProxy@9ff5e19
    mOwnerUid=10173 showForAllUsers=true package=com.example.myapplication appop=NONE
    mAttrs={(0,0)(2000000000x2000000000) gr=CENTER sim={adjust=pan} ty=TYPE_AUTO_CALL fmt=TRANSLUCENT
      fl=NOT_FOCUSABLE HARDWARE_ACCELERATED
      pfl=USE_BLAST INSET_PARENT_FRAME_BY_IME
      bhv=DEFAULT
      fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}
    Requested w=3511296 h=3511296 mLayoutSeq=407
    mBaseLayer=361000 mSubLayer=0    mToken=WindowToken{bcdede type=2101 android.os.BinderProxy@9ff5e19}
    mViewVisibility=0x0 mHaveFrame=true mObscured=false
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    mFullConfiguration={1.0 ?mcc0mnc [zh_CN_#Hans] ldltr sw1440dp w2560dp h1154dp 160dpi xlrg long land car finger -keyb/v/h dpad/v winConfig={ mBounds=Rect(0, 0 - 2560, 1440) mAppBounds=Rect(0, 0 - 2560, 1296) mMaxBounds=Rect(0, 0 - 2560, 1440) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.1160 fontWeightAdjustment=0}
    mLastReportedConfiguration={1.0 ?mcc0mnc [zh_CN_#Hans] ldltr sw1440dp w2560dp h1154dp 160dpi xlrg long land car finger -keyb/v/h dpad/v winConfig={ mBounds=Rect(0, 0 - 2560, 1440) mAppBounds=Rect(0, 0 - 2560, 1296) mMaxBounds=Rect(0, 0 - 2560, 1440) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} s.1160 fontWeightAdjustment=0}
    mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
    Frames: parent=[0,0][2560,1440] display=[0,0][2560,1440] frame=[0,0][2560,1440] last=[0,0][2560,1440] insetsChanged=false
     surface=[0,0][0,0]
    WindowStateAnimator{65e1e17 }:
      mSurface=Surface(name=)/@0xd8137cb
      Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0)  transform=(1.0, 0.0, 0.0, 1.0)
      mDrawState=HAS_DRAWN       mLastHidden=false
      mEnterAnimationPending=false      mSystemDecorRect=[0,0][0,0]
    mForceSeamlesslyRotate=false seamlesslyRotate: pending=null    isOnScreen=true
    isVisible=true
    keepClearAreas: restricted=[], unrestricted=[]
    mPrepareSyncSeqId=0

你可能感兴趣的:(android)