Android Framework-WMS-层级结构树

面试被面试官WMS问的道心破碎,抓紧翻出来我多年前的笔记补补WMS基础了。

wms的层级树

使用 adb shell dumpsys activity containers 可以看到层级树结构

shell 复制代码
➜  ~ adb shell
redfin:/ $ dumpsys activity containers
ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)
ROOT type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
  #0 Display 0 name="内置屏幕" type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][1080,2340] bounds=[0,0][1080,2340]
   #2 Leaf:36:36 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #1 WindowToken{4c74f5b android.os.BinderProxy@7b57e6a} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 e6cb3f8 ScreenDecorOverlayBottom type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #0 WindowToken{1079adc android.os.BinderProxy@9bb34f} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 39427e5 ScreenDecorOverlay type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
   #1 HideDisplayCutout:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #0 OneHanded:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #1 FullscreenMagnification:33:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 Leaf:33:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 Leaf:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
   #0 WindowedMagnification:0:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #6 HideDisplayCutout:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 OneHanded:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #2 FullscreenMagnification:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 Leaf:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #1 Leaf:28:28 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 FullscreenMagnification:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 Leaf:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #5 Leaf:24:25 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #1 WindowToken{9ae296d android.os.BinderProxy@3fa0d84} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 71509a2 pip-dismiss-overlay type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 WindowToken{4aa27f4 android.os.BinderProxy@49e7b06} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 f578b1d NavigationBar0 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #4 HideDisplayCutout:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 OneHanded:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 FullscreenMagnification:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 Leaf:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #3 OneHanded:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 FullscreenMagnification:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 Leaf:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 WindowToken{ec72a3e android.os.BinderProxy@8c27dc0} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #0 3a0109f NotificationShade type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #2 HideDisplayCutout:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 OneHanded:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 FullscreenMagnification:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 Leaf:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #1 OneHanded:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #0 FullscreenMagnification:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 Leaf:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 WindowToken{1ff17bb android.os.BinderProxy@d208db5} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #0 87a44d8 StatusBar type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
    #0 HideDisplayCutout:0:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
     #1 OneHanded:2:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #1 ImePlaceholder:15:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 ImeContainer type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #0 WindowToken{ec7930c android.os.Binder@48ec8e0} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
         #0 f7e2abe InputMethod type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 FullscreenMagnification:2:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #1 Leaf:3:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #0 WindowToken{5cc70f android.os.BinderProxy@eba41ed} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
         #0 9d7d070 ShellDropTarget type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #6 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
         #0 Task=10 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
          #0 ActivityRecord{b80f2a6 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t10} type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
           #0 2dcc518 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #5 Task=50 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
         #0 ActivityRecord{c94e9e4 u0 com.android.dialer/.main.impl.MainActivity t50} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
          #0 715cee5 com.android.dialer/com.android.dialer.main.impl.MainActivity type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #4 Task=31 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #3 Task=32 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #2 Task=33 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #1 Task=34 type=undefined mode=split-screen-primary override-mode=split-screen-primary requested-bounds=[0,0][1080,1162] bounds=[0,0][1080,1162]
        #0 Task=35 type=undefined mode=split-screen-secondary override-mode=split-screen-secondary requested-bounds=[0,1190][1080,2340] bounds=[0,1190][1080,2340]
     #0 OneHandedBackgroundPanel:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
      #0 OneHanded:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 FullscreenMagnification:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #0 Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
         #0 WallpaperWindowToken{ee59505 token=android.os.Binder@374087c} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
          #0 fcd2dd2 com.android.systemui.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]

怎么理解WMS的层级树呢?

说真的,我自己去看dump出来的层技树我都眼晕,尤其对不好行数的话,直接就翻白眼了。 我学习这部分是拿个纸板挡着挨个看。 最底部是0,然后#0 代表 就是那个孩子, #2 就有俩孩子 ,然后看空格找自己的孩子 很像python

Leaf 叶子。leaf 36 :36 第一个36 就是层级是36 第二个36 是到36 也就说我只占了36一层,有的34:35 就代表 要了34-35两层。

可以看出,Wallpaper处于0-1层节点,Activity处于DefaultTaskDisplayArea也就是第2层,InputMethod处于13-14层,StatusBar处于15层,NotificationShade处于17层,NavigationBar0处于24-25层

值越大越往上,简单来说可以理解为0-36层的帧布局(方便理解),放置的时候往对应层级放。壁纸在最下层 然后普通activity在上面, 状态栏就高很多了。

相关类

  • RootWindowContainer: 最顶层的管理者,根窗口容器,树的根是它。通过它遍历寻找,可以找到窗口树上的窗口。它的孩子是DisplayContent。 给可以直接持有窗口的自己或它的孩子定义了一些公共的方法和属性,像RootWindowContainerDisplayContentDisplayAreaDisplayArea.TokensTaskDisplayAreaTaskActivityRecordWindowTokenWindowState都是直接或间接的继承该类。
  • DisplayContent: 该类是对应着显示屏幕的,Android是支持多屏幕的,所以可能存在多个DisplayContent对象。上图只画了一个对象的结构,其他对象的结构也是和画的对象的结构是相似的。
  • DisplayArea: 该类是对应着显示屏幕下面的,代表一组窗口合集,具有多个子类,如Tokens,TaskDisplayArea等
  • TaskDisplayArea:它为DisplayContent的孩子,对应着窗口层次的第2层。第2层作为应用层,看它的定义:int APPLICATION_LAYER = 2,应用层的窗口是处于第2层。TaskDisplayArea的孩子是Task类,其实它的孩子类型也可以是TaskDisplayArea。而Task的孩子则可以是ActivityRecord,也可以是Task
  • Tokens:代表专门包含WindowTokens的容器,它的孩子是WindowToken,而WindowToken的孩子则为WindowState对象。WindowState是对应着一个窗口的。   ImeContainer:它是输入法窗口的容器,它的孩子是WindowToken类型。WindowToken的孩子为WindowState类型,而WindowState类型则对应着输入法窗口。
  • Task: 代表着一个节点,就是咱们说的栈。它的孩子可以是Task,也可以是ActivityRecord类型。
  • ActivityRecord: :是对应着应用进程中的Activity的。ActivityRecord是继承WindowToken的,它的孩子类型为WindowState
  • WindowStateWindowState是对应着一个窗口的.

比如 如下 FullscreenMagnification2-14 但是#1站了3:14,那 DefaultTaskDisplayArea 就剩下 2了,

这里好奇比如有些 FullscreenMagnification 为什么会占据 2-14 层 是因为他作用主要是放大镜,拖动的时候 可能会在需要方法的层级进行显示,所以需要跨层。(我特地查的)

shell 复制代码
 #0 FullscreenMagnification:2:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #1 Leaf:3:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #0 WindowToken{39faa68 android.os.BinderProxy@2588e77} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
         #0 768e27c ShellDropTarget type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
       #0 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
        #8 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
js 复制代码
//个人理解基类 可以找到父亲 也知道自己儿子 
//子节点的list顺序代表就是z轴的层级显示顺序,list尾巴在比list的头的z轴层级要高。
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
   private WindowContainer<WindowContainer> mParent = null;
   protected final WindowList<E> mChildren = new WindowList<E>();
}

//这个是根节点, DisplayContent 可以理解为屏幕  DisplayListener 负责监听屏幕的添加和移除 和变化
class RootWindowContainer extends WindowContainer<DisplayContent>
        implements DisplayManager.DisplayListener {}

层级构建的原理

java 复制代码
 private final SurfaceSession mSession = new SurfaceSession();

DisplayContent(Display display, RootWindowContainer root) {
  //省略
   //构建 SurafaceControl
     final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
                .setOpaque(true)
                .setContainerLayer()
                .setCallsite("DisplayContent");
        mSurfaceControl = b.setName("Root").setContainerLayer().build();

  //instantiate 会调用到默认实现 DefaultProvider 在 DisplayAreaPolicy里面
  //前面说倒 TaskDisplayArea:它为DisplayContent的孩子,对应着窗口层次的第2层。
 mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
                mWmService, this /* content */, this /* root */, mImeWindowsContainer);
  
final List<DisplayArea<? extends WindowContainer>> areas =
                mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
        final DisplayArea<?> area = areas.size() == 1 ? areas.get(0) : null;
}
  
  • instantiate 的作用
java 复制代码
//services/core/java/com/android/server/wm/DisplayAreaPolicy.java
static final class DefaultProvider implements DisplayAreaPolicy.Provider {
        @Override
        public DisplayAreaPolicy instantiate(WindowManagerService wmService,
                DisplayContent content, RootDisplayArea root,
                DisplayArea.Tokens imeContainer) {
           //先构建了一个 叫DefaultTaskDisplayArea  我们再dumpus 里面也能找到对应层级
            final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
                    "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
          //构建了一个集合
            final List<TaskDisplayArea> tdaList = new ArrayList<>();
          //添加默认的defaultTaskDisplayArea 也就吧 DefaultTaskDisplayArea 加进去了
            tdaList.add(defaultTaskDisplayArea);

          //构建一个 HierarchyBuilder 
            final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
           
            rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
           //是否信任
            if (content.isTrusted()) {
                //看下这里面构建了什么
                configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
            }

             //把添加完 层级设置为root
            return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
        }}
java 复制代码
 private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
                WindowManagerService wmService, DisplayContent content) {
            
   //构建了WindowedMagnification 0:31
            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                   
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());
      //如果是默认屏幕
            if (content.isDefaultDisplay) {
               //构建 HideDisplayCutout
                rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
                        FEATURE_HIDE_DISPLAY_CUTOUT)
                        .all()
                        .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
                                TYPE_NOTIFICATION_SHADE)
                        .build())
                     //添加 OneHandedBackgroundPanel 0:1
                        .addFeature(new Feature.Builder(wmService.mPolicy,
                                "OneHandedBackgroundPanel",
                                FEATURE_ONE_HANDED_BACKGROUND_PANEL)
                                .upTo(TYPE_WALLPAPER)
                                .build())
                     //添加 OneHanded
                        .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                                .build());
            }
            rootHierarchy
                 //添加FullscreenMagnification
                    .addFeature(new Feature.Builder(wmService.mPolicy, 
                                                    "FullscreenMagnification",
                            FEATURE_FULLSCREEN_MAGNIFICATION)
                            .all()
                            .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,
                                    TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,
                                    TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                            .build())
              //添加 ImePlaceholder 15:16
                    .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
                            FEATURE_IME_PLACEHOLDER)
                            .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
                            .build());
        }



HierarchyBuilder addFeature(DisplayAreaPolicyBuilder.Feature feature) {
            mFeatures.add(feature);
            return this;
        }

总结:添加了 一堆Feature进了 rootHierarchymFeatures 里面。分别是

  • WindowedMagnification

  • HideDisplayCutout

  • OneHandedBackgroundPanel

  • OneHanded

  • FullscreenMagnification

  • ImePlaceholder

    合计6个

configureTrustedHierarchyBuilder 方法里我们看到添加了我们很眼熟的 WindowedMagnificationImePlaceholder 等 但是我们看到如all()except()等方法,看下对应方法

java 复制代码
//services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

  default int getMaxWindowLayer() {
        return 36;
    }

 Builder(WindowManagerPolicy policy, String name, int id) {
                mPolicy = policy;
                mName = name;
                mId = id;
                mLayers = new boolean[mPolicy.getMaxWindowLayer() + 1];
            
//all 就是0-36全都是true
Builder all() {
                Arrays.fill(mLayers, true);
                return this;
            }
   
     //and 就是 传入的这些为true 
    Builder and(int... types) {
                for (int i = 0; i < types.length; i++) {
                    int type = types[i];
                    set(type, true);
                }
                return this;
            }
   //except这些我不要
    Builder except(int... types) {
                for (int i = 0; i < types.length; i++) {
                    int type = types[i];
                    set(type, false);
                }
                return this;
            }

   
   //这个比较麻烦 我们需要追下代码   -> getWindowLayerFromTypeLw()
   //看完 getWindowLayerFromTypeLw 我们理解
   //我们传入的 返回的层级之前都得是true 然后我是true
     Builder upTo(int typeInclusive) {
                final int max = layerFromType(typeInclusive, false);
                for (int i = 0; i < max; i++) {
                    mLayers[i] = true;
                }
                set(typeInclusive, true);
                return this;
            }
   
   //set 最后也会调用到getWindowLayerFromTypeLw
     private void set(int type, boolean value) {
                mLayers[layerFromType(type, true)] = value;
                if (type == TYPE_APPLICATION_OVERLAY) {
                    mLayers[layerFromType(type, true)] = value;
                    mLayers[layerFromType(TYPE_SYSTEM_ALERT, false)] = value;
                    mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false)] = value;
                    mLayers[layerFromType(TYPE_SYSTEM_ERROR, false)] = value;
                }
            }
   
   default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
            boolean roundedCornerOverlay) {
         //我们传入了false 肯定不走这个
        if (roundedCornerOverlay && canAddInternalSystemWindow) {
            return getMaxWindowLayer();
        }
  //大于1 小于 99 返回  APPLICATION_LAYER 为2 
        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:
            case TYPE_DOCK_DIVIDER:
            case TYPE_QS_DIALOG:
            case TYPE_PHONE:
                return  3;
            case TYPE_SEARCH_BAR:
            case TYPE_VOICE_INTERACTION_STARTING:
                return  4;
            case TYPE_VOICE_INTERACTION:
               
                return  5;
            case TYPE_INPUT_CONSUMER:
                return  6;
            case TYPE_SYSTEM_DIALOG:
                return  7;
            case TYPE_TOAST:
                
                return  8;
            case TYPE_PRIORITY_PHONE:
             
                return  9;
            case TYPE_SYSTEM_ALERT:
            
                return  canAddInternalSystemWindow ? 13 : 10;
            case TYPE_APPLICATION_OVERLAY:
                return  12;
            case TYPE_INPUT_METHOD:
               
                return  15;
            case TYPE_INPUT_METHOD_DIALOG:
               
                return  16;
            case TYPE_STATUS_BAR:
                return  17;
            case TYPE_STATUS_BAR_ADDITIONAL:
                return  18;
            case TYPE_NOTIFICATION_SHADE:
                return  19;
            case TYPE_STATUS_BAR_SUB_PANEL:
                return  20;
            case TYPE_KEYGUARD_DIALOG:
                return  21;
            case TYPE_VOLUME_OVERLAY:
              
                return  22;
            case TYPE_SYSTEM_OVERLAY:
              
                return  canAddInternalSystemWindow ? 23 : 11;
            case TYPE_NAVIGATION_BAR:
                
                return  24;
            case TYPE_NAVIGATION_BAR_PANEL:
                
                return  25;
            case TYPE_SCREENSHOT:
               
                return  26;
            case TYPE_SYSTEM_ERROR:
               
                return  canAddInternalSystemWindow ? 27 : 10;
            case TYPE_MAGNIFICATION_OVERLAY:
                
                return  28;
            case TYPE_DISPLAY_OVERLAY:
              
                return  29;
            case TYPE_DRAG:
               
                return  30;
            case TYPE_ACCESSIBILITY_OVERLAY:
               
                return  31;
            case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
                return 32;
            case TYPE_SECURE_SYSTEM_OVERLAY:
                return  33;
            case TYPE_BOOT_PROGRESS:
                return  34;
            case TYPE_POINTER:
              
                return  35;
            default:
                Slog.e("WindowManager", "Unknown window type: " + type);
                return 3;
        }
    }
   
   //在构建的时候 第36 默认是被占据的
    private boolean mExcludeRoundedCorner = true;
    Feature build() {
                if (mExcludeRoundedCorner) {
                  
                    mLayers[mPolicy.getMaxWindowLayer()] = false;
                }
      //主要这里把 mLayers 赋值给了 mWindowLayers
                return new Feature(mName, mId, mLayers.clone(), mNewDisplayAreaSupplier);
            }

理解完这些 我们回看

java 复制代码
/**
upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)   返回了32 
 除了 getWindowLayerFromTypeLw 里查到 TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY 是 32  所以32就不支持
 所以 WindowedMagnification占据了  0-31
**/
            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                   
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());

//看下 OneHanded 
/*
*
   首先 0-36我都要, getWindowLayerFromTypeLw 查一下   24和 25 我不要
   我们在dump 出来的数据里也可以看到  OneHanded 没有24和25  但是为什么没有36 我不都全都要了么
   因为build里面 36是false
 
**/
ddFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
                                .build());


/**
在看下 HideDisplayCutout
 首先   首先 0-36我都要  其实 我不要  24  25  19  17
 所以他的层级是 0-16 ,18,20-23, 26-31,32-35  在日志中可以查看到
**/
                rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
                        FEATURE_HIDE_DISPLAY_CUTOUT)
                        .all()
                        .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
                                TYPE_NOTIFICATION_SHADE)
                        .build())

我们知道添加了这些层级 那么他们是怎么排布出来的

DisplayAreaPolicyBuilder().build(); 到这步代码的时候我们已经知道 rootHierarchy 有一堆Future 但是只是添加进去了,还没有排序

js 复制代码
//services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

  private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =
            new ArrayList<>();
Result build(WindowManagerService wmService) {
        validate();

        //mRootHierarchyBuilder就是我们添加了一堆Future  是HierarchyBuilder 
        mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);
        List<RootDisplayArea> displayAreaGroupRoots = new ArrayList<>(
                mDisplayAreaGroupHierarchyBuilders.size());
        for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
            HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
            hierarchyBuilder.build();
            displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
        }
        // Use the default function if it is not specified otherwise.
        if (mSelectRootForWindowFunc == null) {
            mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction(
                    mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
        }
        return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
                mSelectRootForWindowFunc);
    }

看下 HierarchyBuilderbuild

js 复制代码
//https://blog.csdn.net/qq_34211365/article/details/122349862  

private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
            final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;
     //前面说过 //36+1 =37
            final int maxWindowLayerCount = policy.getMaxWindowLayer() + 1;
     //搞个数组长度37
            final DisplayArea.Tokens[] displayAreaForLayer =
                    new DisplayArea.Tokens[maxWindowLayerCount];
           //搞个map 为上面的几个大爷构建做好准备
            final Map<Feature, List<DisplayArea<WindowContainer>>> featureAreas =
                    new ArrayMap<>(mFeatures.size()); 
           //configureTrustedHierarchyBuilder 里mFeatures 里面添加了 等 遍历到到集合里
            for (int i = 0; i < mFeatures.size(); i++) {//每个Feature下面都挂了个集合
                featureAreas.put(mFeatures.get(i), new ArrayList<>());
            }


              //搞个 PendingArea 数组 37长度 PendingArea 可以理解为链表那种我知道自己父亲和儿子是谁
            PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
          /**
           PendingArea(Feature feature, int minLayer, PendingArea parent) {
            mMinLayer = minLayer;//最低层级
            mFeature = feature;//不解释
            mParent = parent;//父亲
        }**/
           
        //搞个空的  给所有的future 当root节点用
            final PendingArea root = new PendingArea(null, 0, null);
           //当前塞满了root
            Arrays.fill(areaForLayer, root);

            //获取mFeatures的长度 
            final int size = mFeatures.size();
     //写到这里了
            for (int i = 0; i < size; i++) {
                 //遍历
                final Feature feature = mFeatures.get(i);
                PendingArea featureArea = null;
              //37 因为小于其实是0-36
                for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                  //上面构建的时候 如果 对应的feature 包含对应层级则为true 比如0-18, 20-21 则19是false 其他是true
                    if (feature.mWindowLayers[layer]) {
                         //第一次肯定为null, 如果他的父亲  不等于 当前节点
                        if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
                             //构建一个 PendingArea 父亲是areaForLayer 的当前areaForLayer[layer] 当其实null
                            featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
                          //  当前位置的mChildren 添加 该 PendingArea
                            areaForLayer[layer].mChildren.add(featureArea);
                        }
                       //将featureArea 放到该位置 
                        areaForLayer[layer] = featureArea;
                    } else {
                        
                        featureArea = null;
                    }
                }
            }
     /****
     
      PendingArea(Feature feature, int minLayer, PendingArea parent) {
            mMinLayer = minLayer;
            mFeature = feature;
            mParent = parent;
        }
     
     到这里是怎么回事呢, android 里面每一层都会挂满叶子 Leaf , 我们在构建的时候 先添加的WindowedMagnification 所以他在mFeatures的前面,我们回看一下 mFeatures 里面一共加了6个Features  , 进入layer 这个循环的时候,  WindowedMagnification是0-31,那么areaForLayer 这个36长度的数组,第0位就被创建了一个 PendingArea 0 并塞入进去了,然后
      现在的情况就是   areaForLayer[0]-->PendingArea0 {   父亲是root , 层级是0, feature 是  WindowedMagnification}
     
      然后将areaForLayer 当前0 位置的 mChildren 将 该PendingArea 加进去
      然后areaForLayer 的第0 为 就是  PendingArea 0
      第一圈结束 就相当于   然后areaForLayer[0]  == PendingArea0 {   父亲是root , 层级是0, feature 是  WindowedMagnification} 
       依次类推
       直到32 不符合了 那这里areaForLayer[32]=null 到36都是null
       比如 到了 在看下 HideDisplayCutout

       0-36我都要  不要  24  25  19  17
       第0 个 我要, 然后构建 PendingArea 但是 areaForLayer 现在第0位置已经塞进去 一个了,是 WindowedMagnification 那一圈赛进去的, 这里的节点  就是
上次 存进去的  , 加入到 该节点的   mChildren 里面然后将      areaForLayer[layer] 换位HideDisplayCutout 新构建的节点
这么跑到32就导致 所有节点虽然都变更了,但是 自己的父节点都是上次的节点
到33了 新节点 没被WindowedMagnification 占据 ,那么最高层的节点就归属于HideDisplayCutout
可以理解为先到先得,晚的都得认上次站坑的人 当爹


     **/
      

       
            PendingArea leafArea = null;
            int leafType = LEAF_TYPE_TOKENS;//设置为token
     
            //这里主要是挂载 在每个节点
            for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                int type = typeOfLayer(policy, layer);//要么容器 要么叶子类型 除了输入法和app 都返回token类型
             
                //  符合三种条件都会在对应角标下挂载新的节点,大体理解就是该节点哪怕被其他类型站了 ,我就挂载在他下面, 
                if (leafArea == null || leafArea.mParent != areaForLayer[layer]
                        || type != leafType) {
                  // 创建 PendingArea 标识不是feature  将父节点 也就是标feature加入
                  //这里会给每一个节点上面都挂一个 LEAF_TYPE_TOKENS类型的节点
                    leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);
                    areaForLayer[layer].mChildren.add(leafArea);//加入feature下
                    leafType = type; 
                    //但是如果是输入法和app 就会特殊处理一下
                    if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
  //areaForLayer[layer] 就是父节点
                        addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);//针对app节点做了处理  会直接挂载到DefaultTaskDisplayArea下面
                        addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
                                displayAreaGroupHierarchyBuilders);
                        leafArea.mSkipTokens = true;
                    } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {

                        leafArea.mExisting = mImeContainer;//针对输入做了特殊处理 DisplayArea.Tokens
                        leafArea.mSkipTokens = true;//他俩都会mSkipTokens=true
                    }
                }
                leafArea.mMaxLayer = layer;
            }
       
            root.computeMaxLayer();

           //到这里才将displayAreaForLayer 挂载到 根节点 也就是我们看到的root
           //在该方法内部对根据level 进行了重新排序
            root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);

             //添加完成通知可以使用
            mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
        }

//根据类型返回 对应参数 app 和输入法都返回 LEAF_TYPE_IME_CONTAINERS 其他为token
private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
            if (layer == APPLICATION_LAYER) {//app
                return LEAF_TYPE_TASK_CONTAINERS;
            } 
  else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)
                    || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) {
                return LEAF_TYPE_IME_CONTAINERS;
            } else {
                return LEAF_TYPE_TOKENS;
            }
        }


//添加app  都会会挂载到 DefaultTaskDisplayArea 下
  private void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {
            final int count = mTaskDisplayAreas.size();
            for (int i = 0; i < count; i++) {
           
                PendingArea leafArea =
                        new PendingArea(null /* feature */, APPLICATION_LAYER, parentPendingArea);
                leafArea.mExisting = mTaskDisplayAreas.get(i);// DefaultTaskDisplayArea->TaskDisplayArea
                leafArea.mMaxLayer = APPLICATION_LAYER;
                parentPendingArea.mChildren.add(leafArea);
            }
        }



 private void addDisplayAreaGroupsToApplicationLayer(
                DisplayAreaPolicyBuilder.PendingArea parentPendingArea,
                @Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
              //因为displayAreaGroupHierarchyBuilders 我看了半天没发现赋值的地方是个null 就直接返回了
            if (displayAreaGroupHierarchyBuilders == null) {
                return;
            }
            final int count = displayAreaGroupHierarchyBuilders.size();
            for (int i = 0; i < count; i++) {
                DisplayAreaPolicyBuilder.PendingArea
                        leafArea = new DisplayAreaPolicyBuilder.PendingArea(
                        null /* feature */, APPLICATION_LAYER, parentPendingArea);
                leafArea.mExisting = displayAreaGroupHierarchyBuilders.get(i).mRoot;
                leafArea.mMaxLayer = APPLICATION_LAYER;//这是2
                parentPendingArea.mChildren.add(leafArea);
            }
        }

看下instantiateChildren 做了什么

java 复制代码
// 参数分别为 mRoot, displayAreaForLayer, 0, featureAreas
void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer,
                int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) {
           //先根据里面的最小的mMinLayer 小到大进行排序
            mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));
              //遍历
            for (int i = 0; i < mChildren.size(); i++) {
                 //获取对应节点
                final PendingArea child = mChildren.get(i);
              //调用createArea 先去看下
                final DisplayArea area = child.createArea(parent, areaForLayer);
                if (area == null) {
                   //如果是null 就继续转
                    continue;
                }
                //root 添加 添加到 mChildren  并且 设置父类为root 这里如果是输入法 就是 ImeContainer
               //这个addChild的时候 会有各自的实现 父类是WindowContainer,子类task和TaskDisplayear 有各自的实现
              parent.addChild(area, WindowContainer.POSITION_TOP);
                if (child.mFeature != null) {
                    areas.get(child.mFeature).add(area);
                }
              //子节点也去遍历挂载
                child.instantiateChildren(area, areaForLayer, level + 1, areas);
            }
        }
js 复制代码
 @Nullable
        private DisplayArea createArea(DisplayArea<DisplayArea> parent,
                DisplayArea.Tokens[] areaForLayer) {
            if (mExisting != null) {//输入法和app 不是null 输入法是DisplayArea.Tokens类型
                if (mExisting.asTokens() != null) {//输入法是token 进入  
                    fillAreaForLayers(mExisting.asTokens(), areaForLayer);
                }
              //app 返回 DefaultTaskDisplayArea  输入法返回 ImeContainer
                return mExisting;
            }
            if (mSkipTokens) {
                return null;
            }
            DisplayArea.Type type;
            if (mMinLayer > APPLICATION_LAYER) {
                type = DisplayArea.Type.ABOVE_TASKS;
            } else if (mMaxLayer < APPLICATION_LAYER) {
                type = DisplayArea.Type.BELOW_TASKS;
            } else {
                type = DisplayArea.Type.ANY;
            }
            if (mFeature == null) {
              //如果没有层级,默认就是叶子Leaf +层级 现在看只有36:36是null 的剩下都被人占据了
                final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
                        "Leaf:" + mMinLayer + ":" + mMaxLayer);
                fillAreaForLayers(leaf, areaForLayer);
                return leaf;
            } else {
                return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,
                        mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);
            }
        }
js 复制代码
//services/core/java/com/android/server/wm/TaskDisplayArea.java 
void addChild(WindowContainer child, int position) {
        if (child.asTaskDisplayArea() != null) {
            
            super.addChild(child, position);
        } else if (child.asTask() != null) {
            addChildTask(child.asTask(), position);
        } else {
            throw new IllegalArgumentException(
                    "TaskDisplayArea can only add Task and TaskDisplayArea, but found "
                            + child);
        }
    }

最终app类都会挂载到 DefaultTaskDisplayArea 下 , 输入类都挂载到 mImeContainer 下。

第一个循环 挂载的时候 ,保证了0-36层 挨个都挂载上对应的 feature , 比如WindowedMagnification 是0-31 那么转他的时候,areaForLayer 的0-31都是WindowedMagnification 然后剩下的是 32-35 是 HideDisplayCutout ,但是HideDisplayCutout 人 1-31的也要,进循环里判断 创建一个 新的 节点 父亲变为WindowedMagnification,然后将 HideDisplayCutout 放在1-31上,但是已经形成了一个链表,这么转圈下来,6个层级跑完,虽然最后的已经变了,但是 每个节点都找到了自己的对应位置。你可以理解为 按照最新的6个层级, 最后添加的层级 如果需要该层级,则会挂载在最下面,他的父亲是上个占据该层级的Future. 第二个循环比较好理解, 比如 FullscreenMagnification(F1) 占 1-12 ImePlaceholder (F2)占据了13-14 他们挂在OneHanded (F3)1-14下

那么第一次leafAreanull, 进来 在 0位置 下面挂一个叶子节点 ,该节点父亲是F1 , 第二次进来 不是null, 父亲一样,类别一样,那么就不用挂在 直到循环到F2的时候,相当于 F1 下面挂了个Lefa,F2 下面也挂了一个Leaf。 然后如果是输入法或者app 则这里在mExistingmSkipTokens 做了处理 然后取出最大的层级 35 调用 instantiateChildren的时候 一层层的 将组装好的数据,一层层从0到36 罗列下来, 在 createArea 中 ,输入法和app 不会创建叶子,会直接挂载到对应的层级上, 其他类型会创建一个 DisplayArea 挂载上去。有名字的会将名字和层级挂载上去,没名字的 就叫Leaf.

其他应用挂载之前必须构建一个windowToken ,都挂载在token下。

总结

层级树的加载逻辑代码,筒子们不要记也不要费心看,我看这部分代码的时候,感觉脑子都不够用了(主要我脑子内存小)。 大体上知道,对应类型的window 会挂载到对应的层级上,实在感觉理解难受的,就理解为0-36层帧布局, 为了保证从上到下看起来没问题,对应的会挂载到对应的帧布局上。 问你就说 Activity 的对应Task 挂载在 DefaultTaskDisplayArea 下就可以了。 然后摸着不存在的胡子,微笑看着对象,表现出一种这种简单问题还问我?装个大大的B。

相关推荐
alexhilton13 小时前
面向开发者的系统设计:像建筑师一样思考
android·kotlin·android jetpack
CYRUS_STUDIO1 天前
用 Frida 控制 Android 线程:kill 命令、挂起与恢复全解析
android·linux·逆向
CYRUS_STUDIO1 天前
Frida 实战:Android JNI 数组 (jobjectArray) 操作全流程解析
android·逆向
用户091 天前
Gradle Cache Entries 深度探索
android·java·kotlin
循环不息优化不止1 天前
安卓 View 绘制机制深度解析
android
叽哥1 天前
Kotlin学习第 9 课:Kotlin 实战应用:从案例到项目
android·java·kotlin
雨白2 天前
Java 线程通信基础:interrupt、wait 和 notifyAll 详解
android·java
诺诺Okami2 天前
Android Framework-Launcher-UI和组件
android
潘潘潘2 天前
Android线程间通信机制Handler介绍
android