android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer第二节

Android R WindowManagerService模块(1) WMS整体架构及启动过程 DisplayArea是Android R上新添加的容器,目的就是将复杂的窗口层级管理简单化、低耦合。 而在树结构中,各个容器结构如下: 可以看到,在树结构中,根节点为RootWindowContainer,叶子节点为WindowState。 正是通过这种结构,WMS中将系统中所有的窗口显示管理得井井有条,并将所有窗口以Surface的形式送到SurfacaFlinger中进行合成和显示。 2.WMS启动流程 接下来我们看下WMS的启动过程。WindowManagerService没有继承与Syste. 阅读详情
AI摘要

文章详细介绍了Android系统中DisplayContent如何启动层级树的构建,通过分析DisplayContent、Feature、PendingArea和DisplayArea等概念,展示了层级结构从源码层面是如何组织的,包括窗口类型的层级转换、Feature的构建以及最终树形结构的生成过程。

接着上一节课学习,我们已经清楚的知道了层级结构应该怎么看,根据dumpsys的输出可以完美复原出层级结构树,也理解了结构树对于层级结构的控制作用。但还没有从源码部分对这个结构树进行一个分析,即分析生成这个结构树的源码部分。

1、DisplayContent中启动层级树的构建

    /**
     * Create new {@link DisplayContent} instance, add itself to the root window container and
     * initialize direct children.
     * @param display May not be null.
     * @param root {@link RootWindowContainer}
     */
    DisplayContent(Display display, RootWindowContainer root) {
        super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);
        
    //ignore
    //实际调用这里surface相关图层配置,因为显示东西都需要Surfaceflinger
        configureSurfaces(pendingTransaction);
    //ignore
    }
    private void configureSurfaces(Transaction transaction) {
     //ignore

        if (mDisplayAreaPolicy == null) {
            // Setup the policy and build the display area hierarchy.
            // Build the hierarchy only after creating the surface so it is reparented correctly
            //实际调用这里进行DisplayArea构建
            mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
                    mWmService, this /* content */, this /* root */,
                    mImeWindowsContainer);
        }
//ignore
    }

结下来调用是实现类DefaultProvider的instantiate
frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicy.java

 public DisplayAreaPolicy instantiate(WindowManagerService wmService,
                DisplayContent content, RootDisplayArea root,
                DisplayArea.Tokens imeContainer) {
                //创建特殊的TaskDisplayArea,这里我们前面讲过它是专门来装Activity相关的容器
            final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
                    "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
            final List<TaskDisplayArea> tdaList = new ArrayList<>();
            tdaList.add(defaultTaskDisplayArea);

            // Define the features that will be supported under the root of the whole logical
            // display. The policy will build the DisplayArea hierarchy based on this.
            final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
            // Set the essential containers (even if the display doesn't support IME).
 //这里同时setImeContainer进行输入法直接容器设置           
 rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
            if (content.isTrusted()) {//主屏幕肯定进入,也是构成层级关键
                // Only trusted display can have system decorations.
                configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
            }

             return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
        }

上面可以看出主要有以下部分
1、构建HierarchyBuilder对象
2、准备TaskDisplayArea
3、准备好imeContainer
4、识别屏幕情况,进入configureTrustedHierarchyBuilder
5、配置完成进入build
先看configureTrustedHierarchyBuilder

private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
                WindowManagerService wmService, DisplayContent content) {
            // WindowedMagnification should be on the top so that there is only one surface
            // to be magnified.
            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());
            if (content.isDefaultDisplay) {
                // Only default display can have cutout.
                // See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.
                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())
                        .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                                FEATURE_ONE_HANDED)
                                .all()
                                .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL,
                                        TYPE_SECURE_SYSTEM_OVERLAY)
                                .build());
            }
            rootHierarchy
                    .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())
                    .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
                            FEATURE_IME_PLACEHOLDER)
                            .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
                            .build());
        }
    }

看到这个大家是否觉得这些名字和dumpsys的很熟悉,对的其实就是这里设置的这些Feature名字
先来看Feature类:

    /**
     * A feature that requires {@link DisplayArea DisplayArea(s)}.
     */
    static class Feature {
        private final String mName;
        private final int mId;
        private final boolean[] mWindowLayers;
        private final NewDisplayAreaSupplier mNewDisplayAreaSupplier;

        private Feature(String name, int id, boolean[] windowLayers,
                NewDisplayAreaSupplier newDisplayAreaSupplier) {
            mName = name;
            mId = id;
            mWindowLayers = windowLayers;
            mNewDisplayAreaSupplier = newDisplayAreaSupplier;
        }
           //注意这里排除36层
     Feature build() {
                if (mExcludeRoundedCorner) {
                    // Always put the rounded corner layer to the top most layer.
                    mLayers[mPolicy.getMaxWindowLayer()] = false;
                }
                return new Feature(mName, mId, mLayers.clone(), mNewDisplayAreaSupplier);
            }

首先Feature代表的是DisplayArea的一个特征,可以根据Feature来对不同的DisplayArea进行划分。
mName:这个Feature的名字,如上面的“WindowedMagnification”,“HideDisplayCutout”之类的,后续DisplayArea层级结构建立起来后,每个DisplayArea的名字用的就是当前DisplayArea对应的那个Feature的名字。
mId:Feature的ID,如上面的FEATURE_WINDOWED_MAGNIFICATION和FEATURE_HIDE_DISPLAY_CUTOUT,虽说是Feature的ID,因为Feature又是DisplayArea的特征
mWindowLayers:代表了这个DisplayArea可以包含哪些层级对应的窗口,后续会分析到。
看看其中一个Feature:

   rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
                    FEATURE_WINDOWED_MAGNIFICATION)
                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                    .build());
//typeInclusive代表一个windowType,一般可以通过windowType获取对应的windowLayer,获取方法layerFromType,upTo代表逻辑就是把层级范围到typeInclusive
  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 that the feature does not apply to the given window types.
             */
             //简单说就是把人家types排除
            Builder except(int... types) {
                for (int i = 0; i < types.length; i++) {
                    int type = types[i];
                    set(type, false);
                }
                return this;
            }
            //留下types
             Builder and(int... types) {
                for (int i = 0; i < types.length; i++) {
                    int type = types[i];
                    set(type, true);
                }
                return this;
            }
             private int layerFromType(int type, boolean internalWindows) {
                return mPolicy.getWindowLayerFromTypeLw(type, internalWindows);
            }

这里调用了getWindowLayerFromTypeLw来实现窗口类型到层级数的转化:

 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_DIALOG:
                return  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
                // in a higher layer than TYPE_APPLICATION_OVERLAY.
                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;
            case TYPE_SYSTEM_OVERLAY:
                // the on-screen volume indicator and controller shown when the user
                // changes the device volume
                return  canAddInternalSystemWindow ? 23 : 10;
            case TYPE_NAVIGATION_BAR:
                // the navigation bar, if available, shows atop most things
                return  24;
            case TYPE_NAVIGATION_BAR_PANEL:
                // some panels (e.g. search) need to show on top of the navigation bar
                return  25;
            case TYPE_SCREENSHOT:
                // screenshot selection layer shouldn't go above system error, but it should cover
                // navigation bars at the very least.
                return  26;
            case TYPE_SYSTEM_ERROR:
                // system-level error dialogs
                return  canAddInternalSystemWindow ? 27 : 9;
            case TYPE_MAGNIFICATION_OVERLAY:
                // used to highlight the magnified portion of a display
                return  28;
            case TYPE_DISPLAY_OVERLAY:
                // used to simulate secondary display devices
                return  29;
            case TYPE_DRAG:
                // the drag layer: input for drag-and-drop is associated with this window,
                // which sits above all other focusable windows
                return  30;
            case TYPE_ACCESSIBILITY_OVERLAY:
                // overlay put by accessibility services to intercept user interaction
                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:
                // the (mouse) pointer layer
                return  35;
            default:
                Slog.e("WindowManager", "Unknown window type: " + type);
                return 3;
        }
    }
 

看到上面是不是看到和我们熟悉的窗口类型,如TYPE_WALLPAPER,TYPE_NAVIGATION_BAR等,其实他们都是有固定的一个层级的。即windowType的值并不是真正层级数目,都是需要通过这个方法进行转化才是真正层级数

那么我们再回到addFeature部分,通过以上的层级获取及相关upTo方法后我们可以得出各个Feature的一个层级情况

Feature名字 层级情况
WindowedMagnification 0-31
HideDisplayCutout 0-14 16 18-23 26-35
OneHanded 0-23 26-32 34-35
FullscreenMagnification 0-12 15-23 26-27 29-31 33-35
ImePlaceholder 13-14

也就是每个Feature对应层级已经清楚了
再接下来就要进入正式的树构建了
frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

Result build(WindowManagerService wmService) {
        validate();

        // Attach DA group roots to screen hierarchy before adding windows to group hierarchies.
        mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);//关键的进行build
       //ignore
        return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
                mSelectRootForWindowFunc, mSelectTaskDisplayAreaFunc);
    }

来看看build方法:

 /**
         * Builds the {@link DisplayArea} hierarchy below root. And adds the roots of those
         * {@link HierarchyBuilder} as children.
         */
        private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
//ignore
            PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
            //搞默认的PendingArea作为root部分
            final PendingArea root = new PendingArea(null, 0, null); 
            //给areaForLayer填满都是默认new PendingArea(null, 0, null); 
            Arrays.fill(areaForLayer, root);
		       //创建features相关的树
            // Create DisplayAreas to cover all defined features.
            final int size = mFeatures.size();
            for (int i = 0; i < size; i++) {
                // Traverse the features with the order they are defined, so that the early defined
                // feature will be on the top in the hierarchy.
                final Feature feature = mFeatures.get(i);
                PendingArea featureArea = null;
                for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                    if (feature.mWindowLayers[layer]) {
                        // This feature will be applied to this window layer.
                        //
                        // We need to find a DisplayArea for it:
                        // We can reuse the existing one if it was created for this feature for the
                        // previous layer AND the last feature that applied to the previous layer is
                        // the same as the feature that applied to the current layer (so they are ok
                        // to share the same parent DisplayArea).
                        if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
                            // No suitable DisplayArea:
                            // Create a new one under the previous area (as parent) for this layer.
                            featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
                            areaForLayer[layer].mChildren.add(featureArea);
                        }
                        areaForLayer[layer] = featureArea;
                    } else {
                        // This feature won't be applied to this window layer. If it needs to be
                        // applied to the next layer, we will need to create a new DisplayArea for
                        // that.
                        featureArea = null;
                    }
                }
            }
					//创建叶子相关
            // Create Tokens as leaf for every layer.
            PendingArea leafArea = null;
            int leafType = LEAF_TYPE_TOKENS;
            for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                int type = typeOfLayer(policy, layer);
                // Check whether we can reuse the same Tokens with the previous layer. This happens
                // if the previous layer is the same type as the current layer AND there is no
                // feature that applies to only one of them.
                if (leafArea == null || leafArea.mParent != areaForLayer[layer]
                        || type != leafType) {
                    // Create a new Tokens for this layer.
                    leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);
                    areaForLayer[layer].mChildren.add(leafArea);
                    leafType = type;
                    if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
                        // We use the passed in TaskDisplayAreas for task container type of layer.
                        // Skip creating Tokens even if there is no TDA.
                        addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
                        addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
                                displayAreaGroupHierarchyBuilders);
                        leafArea.mSkipTokens = true;
                    } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
                        // We use the passed in ImeContainer for ime container type of layer.
                        // Skip creating Tokens even if there is no ime container.
                        leafArea.mExisting = mImeContainer;
                        leafArea.mSkipTokens = true;
                    }
                }
                leafArea.mMaxLayer = layer;
            }
            root.computeMaxLayer();//会计算出每个节点最大layer值

            // We built a tree of PendingAreas above with all the necessary info to represent the
            // hierarchy, now create and attach real DisplayAreas to the root.
            root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);//这里会对把PendingArea生成DisplayArea

            // Notify the root that we have finished attaching all the DisplayAreas. Cache all the
            // feature related collections there for fast access.
            mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
        }

这里主要分两个部分,逻辑稍微难理解:

1、根据上面的几个Feature的配置来构造

 // Create DisplayAreas to cover all defined features.
            final int size = mFeatures.size();
            for (int i = 0; i < size; i++) {//针对5个Feature进行遍历,按照add先后顺序,意味最先add在最顶层
                // Traverse the features with the order they are defined, so that the early defined
                // feature will be on the top in the hierarchy.
                final Feature feature = mFeatures.get(i);
                PendingArea featureArea = null;
                for (int layer = 0; layer < maxWindowLayerCount; layer++) {
                    if (feature.mWindowLayers[layer]) {
                        // This feature will be applied to this window layer.
                        //
                        // We need to find a DisplayArea for it:
                        // We can reuse the existing one if it was created for this feature for the
                        // previous layer AND the last feature that applied to the previous layer is
                        // the same as the feature that applied to the current layer (so they are ok
                        // to share the same parent DisplayArea).
                        //条件1:如果featureArea为空,一般每个Feature第一次进入都为null
                        //条件2:如果featureArea不为空,featureArea的父节点不一样,即如果兄弟层级featureArea的父节点是同一个那就不需要新创建
                        if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
                            // No suitable DisplayArea:
                            // Create a new one under the previous area (as parent) for this layer.
                            featureArea = new PendingArea(feature, layer, areaForLayer[layer]);//以areaForLayer[layer]为父节点创建一个新的节点
                            areaForLayer[layer].mChildren.add(featureArea);//老容器节点添加新节点
                        }
                        areaForLayer[layer] = featureArea;//更新当前layer的容器节点变成新的PendingArea
                    } else {
                        // This feature won't be applied to this window layer. If it needs to be
                        // applied to the next layer, we will need to create a new DisplayArea for
                        // that.
                        //如果这一层不支持显示,那么就把featureArea设置为null
                        featureArea = null;
                    }
                }
            }

那么我们来一个个Feature进行分析进行树图绘制:

Feature名字 层级情况
WindowedMagnification 0-31
第一个Feature从0层就需要创建PeadingArea,父节点是Root:0:0,一直到31都是共用一个Parent
![在这里插入图片描述](https://img-blog.csdnimg.cn/60c03fca26f9436cb34ae5ac63a70452.png

(注意这里其实还没有最大层级,因为还没有对最大层级进行计算,这个要到最后才会结算,这里为了方便写的)
HideDisplayCutout 0-14 16 18-23 26-35
到达第二个Feature开始从0时候肯定新建一个PendingArea,他的0-31层,父节点就会变成WindowedMagnification:0:31
在这里插入图片描述
因为32-35层上一个Feature并没有覆盖
OneHanded 0-23 26-32 34-35
在这里插入图片描述

FullscreenMagnification 0-12 15-23 26-27 29-31 33-35
在这里插入图片描述

ImePlaceholder 13-14
在这里插入图片描述

2、Feature构造完成也要对应的一些特殊的进行配置,除了TaskDisplayArea和ImeContainer特殊外,其他的给每个后面都给个Tokens

这个部分较为简单一些,基于上面已经根据Feature构建的树统一需要加上一个Tokens节点,但是要除去TaskDisplayArea和ImeContainer的两个部分

 // Create Tokens as leaf for every layer.
            PendingArea leafArea = null;
            int leafType = LEAF_TYPE_TOKENS;//统一初始中为LEAF_TYPE_TOKENS
            for (int layer = 0; layer < maxWindowLayerCount; layer++) {//遍历36层
                int type = typeOfLayer(policy, layer);//获取每层的type是什么
                // Check whether we can reuse the same Tokens with the previous layer. This happens
                // if the previous layer is the same type as the current layer AND there is no
                // feature that applies to only one of them.
                //条件1针对leafArea空,或者leafArea本身不和这个layer共用一个父节点
                //条件2针对属于TYPE_INPUT_METHOD  APPLICATION_LAYER特殊处理
                if (leafArea == null || leafArea.mParent != areaForLayer[layer]
                        || type != leafType) {
                    // Create a new Tokens for this layer.
                    //以下代码相应想给每一层都挂载一个PendingArea
                    leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);//创建新的PendingArea,并挂载到areaForLayer[layer]下面
                    areaForLayer[layer].mChildren.add(leafArea);
                    leafType = type;
                    if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
                    //APPLICATION_LAYER单独处理,就是前面设置过的TaskDisplayArea
                        // We use the passed in TaskDisplayAreas for task container type of layer.
                        // Skip creating Tokens even if there is no TDA.
                        addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);//设置本身已经设置过的TaskDisplayArea单独处理
                        addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
                                displayAreaGroupHierarchyBuilders);
                        leafArea.mSkipTokens = true;//设置跳过
                    } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
                        // We use the passed in ImeContainer for ime container type of layer.
                        // Skip creating Tokens even if there is no ime container.
                        leafArea.mExisting = mImeContainer;//设置本身已经设置过的mImeContainer
                        leafArea.mSkipTokens = true;//设置跳过
                    }
                }
                leafArea.mMaxLayer = layer;
            }
            //根据层级获取type,这里只对特殊的APPLICATION_LAYER和TYPE_INPUT_METHOD有特殊,其他都是LEAF_TYPE_TOKENS
            private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
              if (layer == APPLICATION_LAYER) {
                  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;
              }
          }
           /** Adds all {@link TaskDisplayArea} to the application layer. */
          private void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {
              final int count = mTaskDisplayAreas.size();//这里一般等于1
              for (int i = 0; i < count; i++) {
                  PendingArea leafArea =
                          new PendingArea(null /* feature */, APPLICATION_LAYER, parentPendingArea);//创建新的APPLICATION_LAYER的PendingArea,并挂载到parentPendingArea下面
                  leafArea.mExisting = mTaskDisplayAreas.get(i);//和前面IME一样把容器设置进去
                  leafArea.mMaxLayer = APPLICATION_LAYER;//设置最大Layer
                  parentPendingArea.mChildren.add(leafArea);//添加为父节点的孩子
              }
          }
      }
  

上面代码执行完成后基本Pending树就构造完成,但这个时候还是PendingArea还不是真正DisplayArea,而且当前根节点只是个Root:0:0,根本不是我们DisplayContent,继续看build还剩下以下几步

 root.computeMaxLayer();//会计算出每个节点最大layer值

 // We built a tree of PendingAreas above with all the necessary info to represent the
 // hierarchy, now create and attach real DisplayAreas to the root.
 root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);//这里会对把PendingArea生成DisplayArea,这里的参数mRoot就是我们的DisplayContent,root是Root:0:0这个PendingArea

这里重点看看 root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);

  void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer,
912                  int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) {
913              mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));
914              for (int i = 0; i < mChildren.size(); i++) {
915                  final PendingArea child = mChildren.get(i);
916                  final DisplayArea area = child.createArea(parent, areaForLayer);
                     //这里可能create出来为null情况,比如前面说的ImeContainer,和DefaultTaskDisplayArea
917                  if (area == null) {
918                      // TaskDisplayArea and ImeContainer can be set at different hierarchy, so it can
919                      // be null.
920                      continue;
921                  }
922                  parent.addChild(area, WindowContainer.POSITION_TOP);//把返回的area设置为Child
923                  if (child.mFeature != null) {
924                      areas.get(child.mFeature).add(area);//同时也放入一下Feature集合
925                  }
926                  child.instantiateChildren(area, areaForLayer, level + 1, areas);//迭代子节点
927              }
928          }
929  
930          @Nullable
931          private DisplayArea createArea(DisplayArea<DisplayArea> parent,
932                  DisplayArea.Tokens[] areaForLayer) {
933              if (mExisting != null) {//Ime和DefaultTaskDisplayArea可以进入,针对已经存在mExisting直接使用它返回
934                  if (mExisting.asTokens() != null) {//判断是否属于Tokens类型,其实就是ImeContainer
935                      // Store the WindowToken container for layers
936                      fillAreaForLayers(mExisting.asTokens(), areaForLayer);//给对应覆盖的层级都需要赋值为mExisting
937                  }
938                  return mExisting;//返回之前设置的
939              }
940              if (mSkipTokens) {//如果被设置了跳过的直接返回null
941                  return null;
942              }
943              DisplayArea.Type type;
944              if (mMinLayer > APPLICATION_LAYER) {
945                  type = DisplayArea.Type.ABOVE_TASKS;
946              } else if (mMaxLayer < APPLICATION_LAYER) {
947                  type = DisplayArea.Type.BELOW_TASKS;
948              } else {
949                  type = DisplayArea.Type.ANY;
950              }
951              if (mFeature == null) {
952                  final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
953                          "Leaf:" + mMinLayer + ":" + mMaxLayer);//构造对应Tokens
954                  fillAreaForLayers(leaf, areaForLayer);//给对应覆盖的层级都需要赋值为leaf
955                  return leaf;
956              } else {
957                  return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,
958                          mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);//这里一般是构造对应DisplayArea
959              }
960          }

对于代码都给予了详细注释,这里就只做个总结:
1、根据窗口层级37层,每一层进行遍历,挂载一个新的叶子TOKENS节点,规则和前面Feature一样,如果同一个父亲则不需要新生成
2、针对TYPE_INPUT_METHOD APPLICATION_LAYER需要进行特殊处理

那么综上其实可以得出以下图(红色的Leaf就是新添加的,还有ImeContainer和DefaultTaskDisplayArea):

在这里插入图片描述

Android12 - WMS之WindowContainer树(DisplayArea) 同一个Feature,相邻的Layer所生成的结点相同且共用,比如对于WindowedMagnification这个Feature,0~31 Layer所对应的结点都是[WindowedMagnification, 0, root]将task加入到TaskDisplayArea。如图示表格,按每个Layer所对应的列从上到下,最上面的为根结点root,上面的结点为下面节点的结点点,下面的节点被加入到上面结点的mChildren属性列表中。每个layer的值代表该layer在Z轴中的顺序,值越大的越靠上。 阅读详情

相关推荐

Android WindowContainer窗口结构

窗口是根据显示屏幕来管理,每个显示屏幕的窗口层级分为37层,0-36层。每层可以放置多个窗口,上层窗口覆盖下面的。要理解窗口的结构,需要学习下WindowContainer、RootWindowContainer、DisplayContent、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowStateWindowContainer等类。

薛文旺 1507

android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer

官方注释: 给可以直接持有窗口的自己或它的孩子定义了一些公共的方法和属性,像RootWindowContainer、DisplayContent、DisplayArea、DisplayArea.Tokens、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState都是直接或间接的继承该类。 这里面主要的重要要成员变量就是mParent和mChildren,一个代表父节点一个代表子节点,而且子节点的list顺序代表就是z轴的层级显示顺序,list尾

learnframework的博客 8806

Android进阶——WMS与AMS浅析

1.简介 可以毫不夸张的说,Android的framework层主要是由WMS、AMS还有View所构成,这三个模块穿插交互在整个framework中,掌握了它们之间的关系和每一个逻辑步骤,你对framework的了解至少有百分之五十 AMS是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要。 在没有深入了解AMS与WMS前,对它俩负责的功能一直很模糊,一直搞不清区别。所以在深入

Yawn 6961

3【Android 12】DisplayArea层级结构

DisplayArea类的继承关系,之前已经分析过,这里用一张简单的类图总结:既然DisplayContent是作为其代表的屏幕的DisplayArea层级结构的根节点,那么从DisplayContent出发,看一下这棵以DisplayContent为根节点的DisplayArea树是如何生成的。 在DisplayContent的构造方法中,调用DisplayAreaPolicy.Provider.instantiate方法,去初始化一个DisplayArea层级结构。DisplayAreaPolicy.P

ukynho的博客 4139

C#与发那科机器人通信实战:从SDK配置到机械臂控制

本文详细介绍了如何使用C#与发那科机器人进行通信,从SDK配置到机械臂控制的完整实战流程。内容包括环境准备、通信连接建立、机械臂运动控制、异常处理与状态监控,以及高级功能实战,帮助开发者快速掌握工业机器人编程技术。

weixin_42524276的博客 459

Arcgis 10.3 与 ArcGIS Engine 10.3 安装与破解

Arcgis 10.3 与 ArcGIS Engine 10.3 安装与破解

weixin_52127098的博客 4725

安卓12窗口层次: DisplayArea树

DisplayArea树 DisplayArea树示意图 DisplayArea概念 DisplayArea树的所有节点都继承于DisplayArea,而DisplayArea继承于WindowContainer,因此每一个节点都是一个container。DisplayArea代表了屏幕的显示区域,该显示区域是从Z值来看的,即在不同的layer上创建不同的DisplayArea。如果一个DisplayArea有子元素,那么代表该DisplayArea从Z轴上还是可分的。 DisplayContent代表一

jieliaoyuan8279的博客 9946

自适应陷波器的原理与实现

x(t)是叠加有两个频率干扰信号的输入信号,s(t)是需要保留的有用信号,在输入信号中,我们只知道频率w1和w2,但不知道信号的幅度A和相位θ,自适应陷波器可以估计两个未知的幅度和相位值,这需要我们提供两路相互正交的单频信号,如cos(w1t)、sin(w1t),通过调整其权值,从而合成出与干扰信号完全相同的信号A1cos(w1t+θ1),从而实现干扰信号的滤除。采用LMS算法,在保证不损失其他有用信号的情况下,有效地抑制输入信号中某一频率的干扰,如需滤除多个频率,只需要增加相应的输入信号。

Melkiades2333的博客 6888

2【Android 12】WindowContainer类

在代码搜索WindowContainer的继承关系,可以得到:除了不参与WindowContainer层级结构的WindowingLayerContainer之外,其他类都在本文有提及,用类图总结为:然后,将我们上面分析各个WindowContainer类时提供的说明图进行关联,可以得到:得到了一个简略版的WindowContainer层级结构图,这个并不真实反映手机的情况,因为这是按照我们上面的分析拼凑出的一张图,但是可以作为参考。

ukynho的博客 1万+

整车电检工艺流程

本文是笔者在从事汽车行业智能制造领域过程,对于整车电检工艺流程的理解与总结。

qq_40664711的博客 1万+

自动驾驶大模型---小米&华科的ORION端到端方案

本文介绍了小米汽车与华中科技大学联合开发的ORION自动驾驶端到端方案。该框架创新性地将视觉语言模型(VLM)与自动驾驶系统结合,包含QT-Former特征提取模块、大语言模型(LLM)推理模块和生成式规划器三大核心组件。通过视觉感知与语言理解的深度融合,ORION能更准确地理解人类指令并生成合理轨迹,同时提升系统的可解释性。实验证明,该方案在准确性、泛化能力和决策透明度方面均有显著优势。ORION框架为自动驾驶技术提供了新思路,有望推动行业向更安全、智能的方向发展。

智能汽车人的博客 2005

Android 12系统源码_窗口管理(四)窗口令牌WindowToken和窗口状态WindowState

通过Android12系统源码认识Android系统的窗口层级树

AfinalStone的专栏 2419

【WRF数据介绍第一期】静态地理数据介绍及下载

WRF数据介绍第一期:静态地理数据介绍及下载

WW、forever的博客 4812

android系统开发之AMS和WMS

提示:AMS和WMS是安卓系统层的核心服务,对于安卓系统层开发人员来说,必须掌握它们的工作原理和使用方法。

shengjiaxin的博客 1600

C#实现网络寻路(附完整源码)

C#实现网络寻路(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 423

Android Audio录音——AudioRecord回声消除(九)

在语音通话或录音场景中,回声(Acoustic Echo)通常是指说话的声音从对方的扬声器播放出来,又被对方的麦克风拾取,然后有被传回来,导致我们听到了自己延迟了一段时间的重复声音。

小旭的专栏 1404

【Android 13源码分析】WindowContainer窗口层级-3-实例分析

在安卓源码的设计中,将将屏幕分为了37层,不同的窗口将在不同的层级中显示。对这一块的概念以及相关源码做了详细分析,整理出以下几篇。当前为第三篇,以应用窗口和系统窗口2大类型窗口的挂载为例介绍窗口是如何挂载到层级树中的。这篇看完对AOSP中整个窗口树就有了比较完整的了解。

隔壁小王的博客 2052

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

android认识窗口

这里我按照自己的理解画了一下Android架构图,主要是对看下Framework这块:顶层是基于ApplicationFramework层的Apps层,ApplicationFramework是运行在App进程的Framework代码,如四大组件,各种Manager。在这一层,屏幕上的一块显示区域,典型代表是Activity,但是Activity毕竟是一个综合性比较强的概念,具体到内容显示这块还是由Window类负责,Window则是容纳View对象的容器。

Rainman博的专栏 832

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Android 12 - WMS 层级结构 && DisplayAreaGroup 引入

1. 简介 在 Android 窗口管理中,所有的窗口都是以树形数据结构进行组织管理的,认知这棵 WMS 的树有助于我们理解窗口的管理和显示,同时,WMS 的层级也决定了其在 SurfaceFlinger 的层级结构,这恰恰决定了它的显示规则。 2. WMS 顶层层级构建 在 Android 12 中,所有窗口树形管理都继基于 WindowContainer, 每个 WindowContainer 都有一个父节点和若干个子节点,我们先看看框架中 WindowContainer 都有哪些类型: RootW

HansChen的博客 6846

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Android T 窗口层级其三 —— 层级结构树添加窗口

DisplayArea层级结构中的每一个DisplayArea,都包含着一个层级值范围,这个层级值范围表明了这个DisplayArea可以容纳哪些类型的窗口。每种窗口类型,都可以通过WindowManagerPolicy.getWindowLayerFromTypeLw方法,返回一个相应的层级值。尚未添加窗口的层级结构树,如图。这里我们根据上面的代码,以及。的信息简单画出如下树形图。

yimelancholy的博客 3493

android12 displayArea学习

上图所示流程为冷启动activity的场景,在ATMS的视角下,会完成activityRecord和Task的创建,并把Task放到taskDisplayArea下面,把activityRecord放到Task下面。第五步,设置root节点为DisplayContent,同时从root节点开始,遍历所有子节点,创建DisplayArea,同时也创建对应的DisplayArea的surface。第三步,根据先前设置的feature数量,遍历所有Layer,根据具体规则创建每一层的pendingArea。

lizhenjun114的专栏 1925

Android Framework(一)WMS窗口层级树及构建流程

.....// 打印的name@OverridedumpChildrenNames的实现在WindowContainer的父类ConfigurationContainer中i >= 0;--i) {// 打印 # 加角标可以看到从RootWindowContainer开始递归打印。这也就是dump到的窗口容器层级树的内容。比如最开始的RootWindowContainer::getName返回的内容就是 “ROOT”。

芸兮的博客 4173

Android14 WMS AMS 窗口层级结构生成过程解析

我们从 DisplayContent 的构造函数出发,看一下这棵以 DisplayContent 为根节点的 DisplayArea 树是如何生成的。

chuyouyinghe的专栏 727

WindowManagerService 初始化构建(3)

之前我们看了WMS和一些数据结构,WMS就是通过WindowContainer的一些子类构建一个树结构,来管理所有的窗口的,其中比较重要的ActivityRecord对应app创建的Activity,WindowState则表示最终的窗口。这篇文章我们来看一下WMS初始化过程,了解一下WMS是怎么构造这个树结构的。

起司锅仔的博客 1027
上一篇: android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer
下一篇: android 13 WMS/AMS系统开发-窗口层级相关SurfaceFlinger图层创建 第三节
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值