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 }