Android WMS架构俯视图:WindowContainer树形组合模式-理论基础+实践结果

Android WMS架构:WindowContainer树形组合模式

1,理论基础:
https://www.jianshu.com/p/7f98f566f830
《设计模式的艺术软件开发人员内功修炼之道》读书笔记十一
第11章树形结构的处理——组合模式

2,实践结果:
https://blog.csdn.net/shensky711/article/details/121530510
Android 12 - WMS 层级结构 && DisplayAreaGroup 引入

在这里插入图片描述

基于Android R分析:WMS&ATMS架构俯视图

WMS: WindowManagerService
AMS: ActivityManagerService
ATMS: ActivityTaskManagerService
WMS&ATMS架构俯视图:
------------------------------------------------------------------------------
 客户端  | Session会话  |  服务器   |   (内存中的)数据库
------------------------------------------------------------------------------
 App应用    -请求服务->    WMS&ATMS   -增删改查Container-> XxxWindowContainer
------------------------------------------------------------------------------

WindowContainer容器相关类。
分析方法:
方法一: 
通过 dumpsys activity activities 和
dumpsys activity containers 查看容器层级关系:
例如:
Display #0 
    Stack #13: type=standard mode=fullscreen
      * Task{a983a94 #13
        * Hist #0: ActivityRecord{a3670a5
   Stack #1: type=home mode=fullscreen
     * Task{f09c4d #5
       * Hist #0: ActivityRecord{d8e5ed9

今天通过另一种方法分析WindowContainer容器相关类。
容器类就是一种盛放东西的容器。
面向对象的编程中,容器类就是盛放对象的容器。
为了方便管理,WindowContainer容器类就引入了父子关系进行来管理。
就把放在容器类中的对象叫做子对象。
该容器类的对象称为父对象。
进而可以理解为,容器就是存放数据的地方,类似数据库,
就有增删改查的操作。
所以, WindowContainer类 中有如下方法:
addChild()
removeChild()
removeImmediately()
setParent()

进而可知,其他从WindowContainer类派生出的类,也会有
或最起码会有addChild()的操作或使用。

WindowContainer相关容器类父子关系
---------------------------------------------------
       父             |            子
---------------------------------------------------
 RootWindowContainer   ->   DisplayContent
---------------------------------------------------
 DisplayContent        ->   DisplayArea.Root
---------------------------------------------------
 DisplayArea.Root      ->   TaskDisplayArea
---------------------------------------------------
 TaskDisplayArea       ->   ActivityStack
---------------------------------------------------
 ActivityStack         ->   Task
 ---------------------------------------------------
 Task                  ->   ActivityRecord
 ---------------------------------------------------
 Task                  ->   WindowToken|WindowState
 ---------------------------------------------------


基于Android S分析:

grep -r "extends DisplayArea|extends WindowContainer|" --include *.java --color

WindowContainer容器相关类。
分析方法:
方法一: 
通过 dumpsys activity activities 和
dumpsys activity containers 查看容器层级关系:
例如:
Display #0
  RootTask #11: type=standard mode=fullscreen
    * Task{8dba6e1 #11
        Hist #0: ActivityRecord{9f50330
  RootTask #1: type=home mode=fullscreen
    * Task{6be5100 #10
        Hist #0: ActivityRecord{a8effa2

今天通过另一种方法分析WindowContainer容器相关类。
容器类就是一种盛放东西的容器。
面向对象的编程中,容器类就是盛放对象的容器。
为了方便管理,WindowContainer容器类就引入了父子关系进行来管理。
就把放在容器类中的对象叫做子对象。
该容器类的对象称为父对象。
进而可以理解为,容器就是存放数据的地方,类似数据库,
就有增删改查的操作。
所以, WindowContainer类 中有如下方法:
addChild()
removeChild()
removeImmediately()
setParent()

进而可知,其他从WindowContainer类派生出的类,也会有
或最起码会有addChild()的操作或使用。

109  /**
110   * Defines common functionality for classes that can hold windows directly or through their
111   * children in a hierarchy form.
112   * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
113   * changes are made to this class.
114   */
115  class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
116          implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {



506      /**
507       * Adds the input window container has a child of this container in order based on the input
508       * comparator.
509       * @param child The window container to add as a child of this window container.
510       * @param comparator Comparator to use in determining the position the child should be added to.
511       *                   If null, the child will be added to the top.
512       */
513      @CallSuper
514      protected void addChild(E child, Comparator<E> comparator) {
515          if (!child.mReparenting && child.getParent() != null) {
516              throw new IllegalArgumentException("addChild: container=" + child.getName()
517                      + " is already a child of container=" + child.getParent().getName()
518                      + " can't add to container=" + getName());
519          }
520  
521          int positionToAdd = -1;
522          if (comparator != null) {
523              final int count = mChildren.size();
524              for (int i = 0; i < count; i++) {
525                  if (comparator.compare(child, mChildren.get(i)) < 0) {
526                      positionToAdd = i;
527                      break;
528                  }
529              }
530          }
531  
532          if (positionToAdd == -1) {
533              mChildren.add(child);
534          } else {
535              mChildren.add(positionToAdd, child);
536          }
537  
538          // Set the parent after we've actually added a child in case a subclass depends on this.
539          child.setParent(this);
540      }
541  
542      /** Adds the input window container has a child of this container at the input index. */
543      @CallSuper
544      void addChild(E child, int index) {
545          if (!child.mReparenting && child.getParent() != null) {
546              throw new IllegalArgumentException("addChild: container=" + child.getName()
547                      + " is already a child of container=" + child.getParent().getName()
548                      + " can't add to container=" + getName()
549                      + "\n callers=" + Debug.getCallers(15, "\n"));
550          }
551  
552          if ((index < 0 && index != POSITION_BOTTOM)
553                  || (index > mChildren.size() && index != POSITION_TOP)) {
554              throw new IllegalArgumentException("addChild: invalid position=" + index
555                      + ", children number=" + mChildren.size());
556          }
557  
558          if (index == POSITION_TOP) {
559              index = mChildren.size();
560          } else if (index == POSITION_BOTTOM) {
561              index = 0;
562          }
563  
564          mChildren.add(index, child);
565  
566          // Set the parent after we've actually added a child in case a subclass depends on this.
567          child.setParent(this);
568      }





基于Android S分析:
现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。

RootWindowContainer容器类的addChild()的相关代码分析

RootWindowContainer容器类盛放的东西是DisplayContent
即:管理的子类对象是DisplayContent


调试命令:
dumpsys activity containers
dumpsys activity activities

175  /** Root {@link WindowContainer} for the device. */
176  public class RootWindowContainer extends WindowContainer<DisplayContent>
177          implements DisplayManager.DisplayListener {

RootWindowContainer 实现了 DisplayManager.DisplayListener 所以,
在onDisplayAdded(), onDisplayRemoved()和onDisplayChanged()方法中,
能监听到显示器的变化状态,来做相应处理。


在WindowManagerService类的构造函数中创建的:mRoot
1231          mRoot = new RootWindowContainer(this);


SystemServer.java
startOtherServices()
  mActivityManagerService.setWindowManager(wm);
->
ActivityManagerService.java
setWindowManager()
  mActivityTaskManager.setWindowManager(wm);
->
ActivityTaskManagerService.java
955      public void setWindowManager(WindowManagerService wm) {
956          synchronized (mGlobalLock) {
957              mWindowManager = wm;
958              mRootWindowContainer = wm.mRoot;
959              mTempConfig.setToDefaults();
960              mTempConfig.setLocales(LocaleList.getDefault());
961              mConfigurationSeq = mTempConfig.seq = 1;
962              mRootWindowContainer.onConfigurationChanged(mTempConfig);
963              mLockTaskController.setWindowManager(wm);
964              mTaskSupervisor.setWindowManager(wm);
965              mRootWindowContainer.setWindowManager(wm);
966          }
967      }
->

1356      void setWindowManager(WindowManagerService wm) {
1357          mWindowManager = wm;
1358          mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
1359          mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
1360          mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
1361  
1362          final Display[] displays = mDisplayManager.getDisplays();
1363          for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {
1364              final Display display = displays[displayNdx];
1365              final DisplayContent displayContent = new DisplayContent(display, this);
1366              addChild(displayContent, POSITION_BOTTOM);
1367              if (displayContent.mDisplayId == DEFAULT_DISPLAY) {
1368                  mDefaultDisplay = displayContent;
1369              }
1370          }
1371          calculateDefaultMinimalSizeOfResizeableTasks();
1372  
1373          final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();
1374          defaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
1375          positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,
1376                  false /* includingParents */);
1377      }


1424      /**
1425       * Get an existing instance of {@link DisplayContent} or create new if there is a
1426       * corresponding record in display manager.
1427       */
1428      // TODO: Look into consolidating with getDisplayContent()
1429      @Nullable
1430      DisplayContent getDisplayContentOrCreate(int displayId) {
1431          DisplayContent displayContent = getDisplayContent(displayId);
1432          if (displayContent != null) {
1433              return displayContent;
1434          }
1435          if (mDisplayManager == null) {
1436              // The system isn't fully initialized yet.
1437              return null;
1438          }
1439          final Display display = mDisplayManager.getDisplay(displayId);
1440          if (display == null) {
1441              // The display is not registered in DisplayManager.
1442              return null;
1443          }
1444          // The display hasn't been added to ActivityManager yet, create a new record now.
1445          displayContent = new DisplayContent(display, this);
1446          addChild(displayContent, POSITION_BOTTOM);
1447          return displayContent;
1448      }


RootWindowContainer 实现了 DisplayManager.DisplayListener的方法:
2597      @Override
2598      public void onDisplayAdded(int displayId) {
2599          if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display added displayId=" + displayId);
2600          synchronized (mService.mGlobalLock) {
2601              final DisplayContent display = getDisplayContentOrCreate(displayId);
2602              if (display == null) {
2603                  return;
2604              }
2605              // Do not start home before booting, or it may accidentally finish booting before it
2606              // starts. Instead, we expect home activities to be launched when the system is ready
2607              // (ActivityManagerService#systemReady).
2608              if (mService.isBooted() || mService.isBooting()) {
2609                  startSystemDecorations(display.mDisplayContent);
2610              }
2611          }
2612      }

2614      private void startSystemDecorations(final DisplayContent displayContent) {
              // 当连接显示器时,启动该显示器上的home桌面
2615          startHomeOnDisplay(mCurrentUser, "displayAdded", displayContent.getDisplayId());
2616          displayContent.getDisplayPolicy().notifyDisplayReady();
2617      }

2619      @Override
2620      public void onDisplayRemoved(int displayId) {
2621          if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display removed displayId=" + displayId);
2622          if (displayId == DEFAULT_DISPLAY) {
2623              throw new IllegalArgumentException("Can't remove the primary display.");
2624          }
2625  
2626          synchronized (mService.mGlobalLock) {
2627              final DisplayContent displayContent = getDisplayContent(displayId);
2628              if (displayContent == null) {
2629                  return;
2630              }
2631  
2632              displayContent.remove();
2633          }
2634      }
2635  
2636      @Override
2637      public void onDisplayChanged(int displayId) {
2638          if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display changed displayId=" + displayId);
2639          synchronized (mService.mGlobalLock) {
2640              final DisplayContent displayContent = getDisplayContent(displayId);
2641              if (displayContent != null) {
2642                  displayContent.onDisplayChanged();
2643              }
2644          }
2645      }

dumpsys activity containers

ActivityTaskManagerService.java
3809      void dumpActivityContainersLocked(PrintWriter pw) {
3810          pw.println("ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)");
3811          mRootWindowContainer.dumpChildrenNames(pw, " ");
3812          pw.println(" ");
3813      }
->
ConfigurationContainer.java
684      /**
685       * Dumps the names of this container children in the input print writer indenting each
686       * level with the input prefix.
687       */
688      public void dumpChildrenNames(PrintWriter pw, String prefix) {
689          final String childPrefix = prefix + " ";
690          pw.println(getName()
691                  + " type=" + activityTypeToString(getActivityType())
692                  + " mode=" + windowingModeToString(getWindowingMode())
693                  + " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode())
694                  + " requested-bounds=" + getRequestedOverrideBounds().toShortString()
695                  + " bounds=" + getBounds().toShortString());
696          for (int i = getChildCount() - 1; i >= 0; --i) {
697              final E cc = getChildAt(i);
698              pw.print(childPrefix + "#" + i + " ");
699              cc.dumpChildrenNames(pw, childPrefix);
700          }
701      }
->
RootWindowContainer.java
1287      @Override
1288      String getName() {
1289          return "ROOT";
1290      }

DisplayContent.java
3205      String getName() {
3206          return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
3207      }


基于Android S分析:
现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。

DisplayContent容器类的addChild()的相关代码分析

DisplayContent集成RootDisplayArea,管理子DisplayArea
DisplayContent容器类盛放的东西是: 
即:管理的子类对象是 DisplayArea
通过adb shell dumpsys activity containers
查看DisplayContent管理的子类对象比较多。
其中有个子类对象是:TaskDisplayArea

245  /**
246   * Utility class for keeping track of the WindowStates and other pertinent contents of a
247   * particular Display.
248   */
249  class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {

WindowManagerService.java
1366          mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
1367                  mContext.getResources());
->
DisplayAreaPolicy.java

1377      DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
1378          return mDisplayAreaPolicyProvider;
1379      }
->
183          static Provider fromResources(Resources res) {
184              String name = res.getString(
185                      com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider);
186              if (TextUtils.isEmpty(name)) {
187                  return new DisplayAreaPolicy.DefaultProvider();
188              }
                 ...
197          }

91      /** Provider for platform-default display area policy. */
92      static final class DefaultProvider implements DisplayAreaPolicy.Provider {
93          @Override
94          public DisplayAreaPolicy instantiate(WindowManagerService wmService,
95                  DisplayContent content, RootDisplayArea root,
96                  DisplayArea.Tokens imeContainer) {
97              final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
98                      "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
99              final List<TaskDisplayArea> tdaList = new ArrayList<>();
100              tdaList.add(defaultTaskDisplayArea);
101  
102              // Define the features that will be supported under the root of the whole logical
103              // display. The policy will build the DisplayArea hierarchy based on this.
104              final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
105              // Set the essential containers (even if the display doesn't support IME).
106              rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
107              if (content.isTrusted()) {
108                  // Only trusted display can have system decorations.
109                  configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
110              }
111  
112              // Instantiate the policy with the hierarchy defined above. This will create and attach
113              // all the necessary DisplayAreas to the root.
114              return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
115          }
->
DisplayContent.java
1030          // Setup the policy and build the display area hierarchy.
1031          mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
1032                  mWmService, this /* content */, this /* root */, mImeWindowsContainer);



addWindowToken() 添加系统类型窗口
IWindowManager.aidl
WindowManagerInternal.java
addWindowToken()
->
WindowManagerService.java
addWindowToken()
 new WindowToken.Builder(this, binder, type)
         .setDisplayContent(dc)
         .setPersistOnEmpty(true)
         .setOwnerCanManageAppTokens(true)
         .setOptions(options)
         .build();
->
WindowToken.java
WindowToken() {
  dc.addWindowToken(token, this);
}
->
DisplayContent.java
1097      void addWindowToken(IBinder binder, WindowToken token) {
1098          final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);
1099          if (dc != null) {
1100              // We currently don't support adding a window token to the display if the display
1101              // already has the binder mapped to another token. If there is a use case for supporting
1102              // this moving forward we will either need to merge the WindowTokens some how or have
1103              // the binder map to a list of window tokens.
1104              throw new IllegalArgumentException("Can't map token=" + token + " to display="
1105                      + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
1106          }
1107          if (binder == null) {
1108              throw new IllegalArgumentException("Can't map token=" + token + " to display="
1109                      + getName() + " binder is null");
1110          }
1111          if (token == null) {
1112              throw new IllegalArgumentException("Can't map null token to display="
1113                      + getName() + " binder=" + binder);
1114          }
1115  
1116          mTokenMap.put(binder, token);
1117  
1118          if (token.asActivityRecord() == null) {
1119              // Set displayContent for non-app token to prevent same token will add twice after
1120              // onDisplayChanged.
1121              // TODO: Check if it's fine that super.onDisplayChanged of WindowToken
1122              //  (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned.
1123              token.mDisplayContent = this;
1124              // Add non-app token to container hierarchy on the display. App tokens are added through
1125              // the parent container managing them (e.g. Tasks).
1126              final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
1127              da.addChild(token);
1128          }
1129      }




RootDisplayArea

35  /**
36   * Root of a {@link DisplayArea} hierarchy. It can be either the {@link DisplayContent} as the root
37   * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the
38   * logical display.
39   */
40  class RootDisplayArea extends DisplayArea.Dimmable {
41  
42      /** {@link Feature} that are supported in this {@link DisplayArea} hierarchy. */
43      List<DisplayAreaPolicyBuilder.Feature> mFeatures;
44  
45      /**
46       * Mapping from policy supported {@link Feature} to list of {@link DisplayArea} created to cover
47       * all the window types that the {@link Feature} will be applied to.
48       */
49      Map<Feature, List<DisplayArea<WindowContainer>>> mFeatureToDisplayAreas;
50  
51      /** Mapping from window layer to {@link DisplayArea.Tokens} that holds windows on that layer. */
52      private DisplayArea.Tokens[] mAreaForLayer;
53  
54      /** Whether the hierarchy has been built. */
55      private boolean mHasBuiltHierarchy;


76      /**
77       * Places the IME container below this root, so that it's bounds and config will be updated to
78       * match the root.
79       */
80      void placeImeContainer(DisplayArea.Tokens imeContainer) {
81          final RootDisplayArea previousRoot = imeContainer.getRootDisplayArea();
82  
83          List<Feature> features = mFeatures;
84          for (int i = 0; i < features.size(); i++) {
85              Feature feature = features.get(i);
86              if (feature.getId() == FEATURE_IME_PLACEHOLDER) {
87                  List<DisplayArea<WindowContainer>> imeDisplayAreas =
88                          mFeatureToDisplayAreas.get(feature);
89                  if (imeDisplayAreas.size() != 1) {
90                      throw new IllegalStateException("There must be exactly one DisplayArea for the "
91                              + "FEATURE_IME_PLACEHOLDER");
92                  }
93  
94                  previousRoot.updateImeContainerForLayers(null /* imeContainer */);
95                  imeContainer.reparent(imeDisplayAreas.get(0), POSITION_TOP);
96                  updateImeContainerForLayers(imeContainer);
97                  return;
98              }
99          }
100          throw new IllegalStateException(
101                  "There is no FEATURE_IME_PLACEHOLDER in this root to place the IME container");
102      }



50  /**
51   * Container for grouping WindowContainer below DisplayContent.
52   *
53   * DisplayAreas are managed by a {@link DisplayAreaPolicy}, and can override configurations and
54   * can be leashed.
55   *
56   * DisplayAreas can contain nested DisplayAreas.
57   *
58   * DisplayAreas come in three flavors, to ensure that windows have the right Z-Order:
59   * - BELOW_TASKS: Can only contain BELOW_TASK DisplayAreas and WindowTokens that go below tasks.
60   * - ABOVE_TASKS: Can only contain ABOVE_TASK DisplayAreas and WindowTokens that go above tasks.
61   * - ANY: Can contain any kind of DisplayArea, and any kind of WindowToken or the Task container.
62   *
63   * @param <T> type of the children of the DisplayArea.
64   */
65  public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {



DisplayArea.java
613      /**
614       * DisplayArea that can be dimmed.
615       */
616      static class Dimmable extends DisplayArea<DisplayArea> {


533      /**
534       * DisplayArea that contains WindowTokens, and orders them according to their type.
535       */
536      public static class Tokens extends DisplayArea<WindowToken> {

DisplayAreaPolicyBuilder

46  /**
47   * A builder for instantiating a complex {@link DisplayAreaPolicy}
48   *
49   * <p>Given a set of features (that each target a set of window types), it builds the necessary
50   * {@link DisplayArea} hierarchy.
51   *
52   * <p>Example:
53   *
54   * <pre class="prettyprint">
55   *      // Build root hierarchy of the logical display.
56   *      DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
57   *          new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
58   *              // Feature for targeting everything below the magnification overlay
59   *              .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
60   *                             "WindowedMagnification", FEATURE_WINDOWED_MAGNIFICATION)
61   *                             .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
62   *                             .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
63   *                             // Make the DA dimmable so that the magnify window also mirrors the
64   *                             // dim layer
65   *                             .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
66   *                             .build())
67   *              .setImeContainer(imeContainer)
68   *              .setTaskDisplayAreas(rootTdaList);
69   *
70   *      // Build root hierarchy of first and second DisplayAreaGroup.
71   *      RootDisplayArea firstRoot = new RootDisplayArea(wmService, "FirstRoot", FEATURE_FIRST_ROOT);
72   *      DisplayAreaPolicyBuilder.HierarchyBuilder firstGroupHierarchy =
73   *          new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot)
74   *              // (Optional) .addFeature(...)
75   *              .setTaskDisplayAreas(firstTdaList);
76   *
77   *      RootDisplayArea secondRoot = new RootDisplayArea(wmService, "SecondRoot",
78   *          FEATURE_REAR_ROOT);
79   *      DisplayAreaPolicyBuilder.HierarchyBuilder secondGroupHierarchy =
80   *          new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot)
81   *              // (Optional) .addFeature(...)
82   *              .setTaskDisplayAreas(secondTdaList);
83   *
84   *      // Define the function to select root for window to attach.
85   *      BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc =
86   *                (windowToken, options) -> {
87   *                    if (options == null) {
88   *                        return root;
89   *                    }
90   *                    // OEMs need to define the condition.
91   *                    if (...) {
92   *                        return firstRoot;
93   *                    }
94   *                    if (...) {
95   *                        return secondRoot;
96   *                    }
97   *                    return root;
98   *                };
99   *
100   *      return new DisplayAreaPolicyBuilder()
101   *                .setRootHierarchy(rootHierarchy)
102   *                .addDisplayAreaGroupHierarchy(firstGroupHierarchy)
103   *                .addDisplayAreaGroupHierarchy(secondGroupHierarchy)
104   *                .setSelectRootForWindowFunc(selectRootForWindowFunc)
105   *                .build(wmService, content);
106   * </pre>
107   *
108   * This builds a policy with the following hierarchy:
109   * <pre class="prettyprint">
110   *      - RootDisplayArea (DisplayContent)
111   *          - WindowedMagnification
112   *              - DisplayArea.Tokens (Wallpapers can be attached here)
113   *              - TaskDisplayArea
114   *              - RootDisplayArea (FirstRoot)
115   *                  - DisplayArea.Tokens (Wallpapers can be attached here)
116   *                  - TaskDisplayArea
117   *                  - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
118   *                  - DisplayArea.Tokens (windows above IME can be attached here)
119   *              - RootDisplayArea (SecondRoot)
120   *                  - DisplayArea.Tokens (Wallpapers can be attached here)
121   *                  - TaskDisplayArea
122   *                  - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
123   *                  - DisplayArea.Tokens (windows above IME can be attached here)
124   *              - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
125   *              - ImeContainers
126   *              - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY can be
127   *                                    attached here)
128   *          - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up can be attached
129   *                                here)
130   * </pre>
131   * When a {@link WindowToken} of Wallpaper needs to be attached, the policy will call the OEM
132   * defined {@link #mSelectRootForWindowFunc} to get a {@link RootDisplayArea}. It will then place
133   * the window to the corresponding {@link DisplayArea.Tokens} under the returned root
134   * {@link RootDisplayArea}.
135   */
136  class DisplayAreaPolicyBuilder {
137  
138      /**
139       * Key to specify the {@link RootDisplayArea} to attach the window to. Should be used by the
140       * function passed in from {@link #setSelectRootForWindowFunc(BiFunction)}
141       */
142      static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id";
143  
144      @Nullable private HierarchyBuilder mRootHierarchyBuilder;
145      private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =
146              new ArrayList<>();
147  


375      /**
376       *  Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
377       * {@link RootDisplayArea}
378       */
379      static class HierarchyBuilder {
380          private static final int LEAF_TYPE_TASK_CONTAINERS = 1;
381          private static final int LEAF_TYPE_IME_CONTAINERS = 2;
382          private static final int LEAF_TYPE_TOKENS = 0;
383  
384          private final RootDisplayArea mRoot;
385          private final ArrayList<DisplayAreaPolicyBuilder.Feature> mFeatures = new ArrayList<>();
386          private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList<>();
387          @Nullable
388          private DisplayArea.Tokens mImeContainer;


727      static class Result extends DisplayAreaPolicy {
728          final List<RootDisplayArea> mDisplayAreaGroupRoots;
729          final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
730          private final TaskDisplayArea mDefaultTaskDisplayArea;

750          @Override
751          public void addWindow(WindowToken token) {
752              DisplayArea.Tokens area = findAreaForToken(token);
753              area.addChild(token);
754          }



858          @Nullable
859          private DisplayArea createArea(DisplayArea<DisplayArea> parent,
860                  DisplayArea.Tokens[] areaForLayer) {
861              if (mExisting != null) {
862                  if (mExisting.asTokens() != null) {
863                      // Store the WindowToken container for layers
864                      fillAreaForLayers(mExisting.asTokens(), areaForLayer);
865                  }
866                  return mExisting;
867              }
868              if (mSkipTokens) {
869                  return null;
870              }
871              DisplayArea.Type type;
872              if (mMinLayer > APPLICATION_LAYER) {
873                  type = DisplayArea.Type.ABOVE_TASKS;
874              } else if (mMaxLayer < APPLICATION_LAYER) {
875                  type = DisplayArea.Type.BELOW_TASKS;
876              } else {
877                  type = DisplayArea.Type.ANY;
878              }
879              if (mFeature == null) {
880                  final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
881                          "Leaf:" + mMinLayer + ":" + mMaxLayer);
882                  fillAreaForLayers(leaf, areaForLayer);
883                  return leaf;
884              } else {
885                  return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,
886                          mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);
887              }
888          }


static class Result extends DisplayAreaPolicy {

     static class Feature {



在DisplayAreaPolicyBuilder.java中,Result继承DisplayAreaPolicy
static class Result extends DisplayAreaPolicy {

46  /**
47   * Policy that manages {@link DisplayArea}.
48   */
49  public abstract class DisplayAreaPolicy {
50      protected final WindowManagerService mWmService;
51  
52      /**
53       * The {@link RootDisplayArea} of the whole logical display. All {@link DisplayArea}s must be
54       * (direct or indirect) descendants of this area.
55       */
56      protected final RootDisplayArea mRoot;
57  
58      /**
59       * Constructs a new {@link DisplayAreaPolicy}
60       *
61       * @param wmService the window manager service instance
62       * @param root the root display area under which the policy operates
63       */
64      protected DisplayAreaPolicy(WindowManagerService wmService, RootDisplayArea root) {
65          mWmService = wmService;
66          mRoot = root;
67      }
68  
69      /**
70       * Called to ask the policy to attach the given {@link WindowToken} to the {@link DisplayArea}
71       * hierarchy.
72       *
73       * <p>This must attach the token to {@link #mRoot} (or one of its descendants).
74       */
75      public abstract void addWindow(WindowToken token);





 
91      /** Provider for platform-default display area policy. */
92      static final class DefaultProvider implements DisplayAreaPolicy.Provider {
93          @Override
94          public DisplayAreaPolicy instantiate(WindowManagerService wmService,
95                  DisplayContent content, RootDisplayArea root,
96                  DisplayArea.Tokens imeContainer) {
97              final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
98                      "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
99              final List<TaskDisplayArea> tdaList = new ArrayList<>();
100              tdaList.add(defaultTaskDisplayArea);
101  
102              // Define the features that will be supported under the root of the whole logical
103              // display. The policy will build the DisplayArea hierarchy based on this.
104              final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
105              // Set the essential containers (even if the display doesn't support IME).
106              rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
107              if (content.isTrusted()) {
108                  // Only trusted display can have system decorations.
109                  configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
110              }
111  
112              // Instantiate the policy with the hierarchy defined above. This will create and attach
113              // all the necessary DisplayAreas to the root.
114              return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
115          }
116  
117          private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
118                  WindowManagerService wmService, DisplayContent content) {
119              // WindowedMagnification should be on the top so that there is only one surface
120              // to be magnified.
121              rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
122                      FEATURE_WINDOWED_MAGNIFICATION)
123                      .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
124                      .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
125                      // Make the DA dimmable so that the magnify window also mirrors the dim layer.
126                      .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
127                      .build());
128              if (content.isDefaultDisplay) {
129                  // Only default display can have cutout.
130                  // See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.
131                  rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
132                          FEATURE_HIDE_DISPLAY_CUTOUT)
133                          .all()
134                          .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
135                                  TYPE_NOTIFICATION_SHADE)
136                          .build())
137                          .addFeature(new Feature.Builder(wmService.mPolicy,
138                                  "OneHandedBackgroundPanel",
139                                  FEATURE_ONE_HANDED_BACKGROUND_PANEL)
140                                  .upTo(TYPE_WALLPAPER)
141                                  .build())
142                          .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
143                                  FEATURE_ONE_HANDED)
144                                  .all()
145                                  .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
146                                  .build());
147              }
148              rootHierarchy
149                      .addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",
150                              FEATURE_FULLSCREEN_MAGNIFICATION)
151                              .all()
152                              .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,
153                                      TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,
154                                      TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
155                              .build())
156                      .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
157                              FEATURE_IME_PLACEHOLDER)
158                              .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
159                              .build());
160          }
161      }
162  


DisplayAreaOrganizerController

291      /**
292       * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}.
293       */
294      private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
295              int taskDisplayAreaFeatureId) {

291      /**
292       * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}.
293       */
294      private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
295              int taskDisplayAreaFeatureId) {
296          final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,
297                  root.mWmService, name, taskDisplayAreaFeatureId, true /* createdByOrganizer */);
298  
299          // Find the top most DA that can contain Task (either a TDA or a DisplayAreaGroup).
300          final DisplayArea topTaskContainer = root.getItemFromDisplayAreas(da -> {
301              if (da.mType != ANY) {
302                  return null;
303              }
304  
305              final RootDisplayArea rootDA = da.getRootDisplayArea();
306              if (rootDA == root || rootDA == da) {
307                  // Either it is the top TDA below the root or it is a DisplayAreaGroup.
308                  return da;
309              }
310              return null;
311          });
312          if (topTaskContainer == null) {
313              throw new IllegalStateException("Root must either contain TDA or DAG root=" + root);
314          }
315  
316          // Insert the TaskDisplayArea as the top Task container.
317          final WindowContainer parent = topTaskContainer.getParent();
318          final int index = parent.mChildren.indexOf(topTaskContainer) + 1;
319          parent.addChild(taskDisplayArea, index);
320  
321          return taskDisplayArea;
322      }

基于Android S分析:
现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。

TaskDisplayArea容器类的addChild()的相关代码分析

TaskDisplayArea盛放的东西是:
App应用类型窗口的Task
是app window containers

调试命令:
dumpsys activity containers
dumpsys activity activities

DisplayAreaOrganizerController.java
createTaskDisplayArea()

72  /**
73   * {@link DisplayArea} that represents a section of a screen that contains app window containers.
74   *
75   * The children can be either {@link Task} or {@link TaskDisplayArea}.
76   */
77  final class TaskDisplayArea extends DisplayArea<WindowContainer> {


348      @Override
349      void addChild(WindowContainer child, int position) {
350          if (child.asTaskDisplayArea() != null) {
351              if (DEBUG_ROOT_TASK) {
352                  Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this);
353              }
354              super.addChild(child, position);
355          } else if (child.asTask() != null) {
356              addChildTask(child.asTask(), position);
357          } else {
358              throw new IllegalArgumentException(
359                      "TaskDisplayArea can only add Task and TaskDisplayArea, but found "
360                              + child);
361          }
362      }
363  
364      private void addChildTask(Task task, int position) {
365          if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
366  
367          addRootTaskReferenceIfNeeded(task);
368          position = findPositionForRootTask(position, task, true /* adding */);
369  
370          super.addChild(task, position);
371          if (mPreferredTopFocusableRootTask != null
372                  && task.isFocusable()
373                  && mPreferredTopFocusableRootTask.compareTo(task) < 0) {
374              // Clear preferred top because the adding focusable task has a higher z-order.
375              mPreferredTopFocusableRootTask = null;
376          }
377          mAtmService.updateSleepIfNeededLocked();
378          onRootTaskOrderChanged(task);
379      }


1067      /**
1068       * When two level tasks are required for given windowing mode and activity type, returns an
1069       * existing compatible root task or creates a new one.
1070       * For one level task, the candidate task would be reused to also be the root task or create
1071       * a new root task if no candidate task.
1072       *
1073       * @param windowingMode The windowing mode the root task should be created in.
1074       * @param activityType  The activityType the root task should be created in.
1075       * @param onTop         If true the root task will be created at the top of the display,
1076       *                      else at the bottom.
1077       * @param candidateTask The possible task the activity might be launched in. Can be null.
1078       * @param sourceTask    The task requesting to start activity. Used to determine which of the
1079       *                      adjacent roots should be launch root of the new task. Can be null.
1080       * @param options       The activity options used to the launch. Can be null.
1081       * @param launchFlags   The launch flags for this launch.
1082       * @return The root task to use for the launch.
1083       * @see #getRootTask(int, int)
1084       */
1085      Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
1086              @Nullable Task candidateTask, @Nullable Task sourceTask,
1087              @Nullable ActivityOptions options, int launchFlags) {
1088          // Need to pass in a determined windowing mode to see if a new root task should be created,
1089          // so use its parent's windowing mode if it is undefined.
1090          if (!alwaysCreateRootTask(
1091                  windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(),
1092                  activityType)) {
1093              Task rootTask = getRootTask(windowingMode, activityType);
1094              if (rootTask != null) {
1095                  return rootTask;
1096              }
1097          } else if (candidateTask != null) {
1098              final Task rootTask = candidateTask;
1099              final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
1100              final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options,
1101                      sourceTask, launchFlags);
1102  
1103              if (launchRootTask != null) {
1104                  if (rootTask.getParent() == null) {
1105                      launchRootTask.addChild(rootTask, position);
1106                  } else if (rootTask.getParent() != launchRootTask) {
1107                      rootTask.reparent(launchRootTask, position);
1108                  }
1109              } else if (rootTask.getDisplayArea() != this || !rootTask.isRootTask()) {
1110                  if (rootTask.getParent() == null) {
1111                      addChild(rootTask, position);
1112                  } else {
1113                      rootTask.reparent(this, onTop);
1114                  }
1115              }
1116              // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
1117              if (candidateTask.getWindowingMode() != windowingMode) {
1118                  candidateTask.setWindowingMode(windowingMode);
1119              }
1120              return rootTask;
1121          }
1122          return new Task.Builder(mAtmService)
1123                  .setWindowingMode(windowingMode)
1124                  .setActivityType(activityType)
1125                  .setOnTop(onTop)
1126                  .setParent(this)
1127                  .setSourceTask(sourceTask)
1128                  .setActivityOptions(options)
1129                  .setLaunchFlags(launchFlags)
1130                  .build();
1131      }


254  class Task extends WindowContainer<WindowContainer> {


          @Override
1721      void addChild(WindowContainer child, int index) {
1722          // If this task had any child before we added this one.
1723          boolean hadChild = hasChild();
1724          // getActivityType() looks at the top child, so we need to read the type before adding
1725          // a new child in case the new child is on top and UNDEFINED.
1726          final int activityType = getActivityType();
1727  
1728          index = getAdjustedChildPosition(child, index);
1729          super.addChild(child, index);
1730  
1731          ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
1732  
1733          // A rootable task that is now being added to be the child of an organized task. Making
1734          // sure the root task references is keep updated.
1735          if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
1736              getDisplayArea().addRootTaskReferenceIfNeeded((Task) child);
1737          }
1738  
1739          // Make sure the list of display UID allowlists is updated
1740          // now that this record is in a new task.
1741          mRootWindowContainer.updateUIDsPresentOnDisplay();
1742  
1743          final ActivityRecord r = child.asActivityRecord();
1744          if (r == null) return;
1745  
1746          r.inHistory = true;
1747  
1748          // Only set this based on the first activity
1749          if (!hadChild) {
1750              if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
1751                  // Normally non-standard activity type for the activity record will be set when the
1752                  // object is created, however we delay setting the standard application type until
1753                  // this point so that the task can set the type for additional activities added in
1754                  // the else condition below.
1755                  r.setActivityType(ACTIVITY_TYPE_STANDARD);
1756              }
1757              setActivityType(r.getActivityType());
1758              isPersistable = r.isPersistable();
1759              mCallingUid = r.launchedFromUid;
1760              mCallingPackage = r.launchedFromPackage;
1761              mCallingFeatureId = r.launchedFromFeatureId;
1762              // Clamp to [1, max].
1763              maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1764                      ActivityTaskManager.getMaxAppRecentsLimitStatic());
1765          } else {
1766              // Otherwise make all added activities match this one.
1767              r.setActivityType(activityType);
1768          }
1769  
1770          updateEffectiveIntent();
1771      }
1772  
1773      void addChild(ActivityRecord r) {
1774          addChild(r, Integer.MAX_VALUE /* add on top */);
1775      }


7569      void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) {
7570          Task task = child.asTask();
7571          try {
7572              if (task != null) {
7573                  task.setForceShowForAllUsers(showForAllUsers);
7574              }
7575              // We only want to move the parents to the parents if we are creating this task at the
7576              // top of its root task.
7577              addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/);
7578          } finally {
7579              if (task != null) {
7580                  task.setForceShowForAllUsers(false);
7581              }
7582          }
7583      }

7689      /**
7690       * Put a Task in this root task. Used for adding only.
7691       * When task is added to top of the root task, the entire branch of the hierarchy (including
7692       * root task and display) will be brought to top.
7693       * @param child The child to add.
7694       * @param position Target position to add the task to.
7695       */
7696      private void addChild(WindowContainer child, int position, boolean moveParents) {
7697          // Add child task.
7698          addChild(child, null);
7699  
7700          // Move child to a proper position, as some restriction for position might apply.
7701          positionChildAt(position, child, moveParents /* includingParents */);
7702      }



Task创建

Activity 生命周期状态
adb shell cmd window logging enable-text WM_DEBUG_STATES

adb shell cmd window logging enable-text WM_DEBUG_TASKS

adb shell cmd window logging enable-text WM_DEBUG_IME

adb shell cmd window logging enable-text WM_DEBUG_ADD_REMOVE

adb shell cmd window logging enable-text WM_DEBUG_WINDOW_ORGANIZER


Task.java
new Task.Builder()
reuseOrCreateTask()



基于Android S分析:
现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。

ActivityRecord容器类的addChild()的相关代码分析

ActivityRecord extends WindowToken
WindowToken extends WindowContainer<WindowState>

ActivityRecord容器盛放的东西是:
WindowState

调试命令:
dumpsys activity containers
dumpsys activity activities
dumpsys window


364  /**
365   * An entry in the history task, representing an activity.
366   */
367  public final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {


3625      @Override
3626      void addWindow(WindowState w) {
3627          super.addWindow(w);
3628  
3629          boolean gotReplacementWindow = false;
3630          for (int i = mChildren.size() - 1; i >= 0; i--) {
3631              final WindowState candidate = mChildren.get(i);
3632              gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
3633          }
3634  
3635          // if we got a replacement window, reset the timeout to give drawing more time
3636          if (gotReplacementWindow) {
3637              mWmService.scheduleWindowReplacementTimeouts(this);
3638          }
3639          checkKeyguardFlagsChanged();
3640      }


3642      @Override
3643      void removeChild(WindowState child) {
3644          if (!mChildren.contains(child)) {
3645              // This can be true when testing.
3646              return;
3647          }
3648          super.removeChild(child);
3649          checkKeyguardFlagsChanged();
3650          updateLetterboxSurface(child);
3651      }
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值