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: WindowManagerServiceAMS: ActivityManagerServiceATMS: ActivityTaskManagerServiceWMS&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 --colorWindowContainer容器相关类。分析方法:方法一: 通过 dumpsys activity activities 和dumpsys activity containers 查看容器层级关系:例如:Display #0RootTask #11: type=standard mode=fullscreen* Task{8dba6e1 #11Hist #0: ActivityRecord{9f50330RootTask #1: type=home mode=fullscreen* Task{6be5100 #10Hist #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 their111 * children in a hierarchy form.112 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime113 * changes are made to this class.114 */115class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>116implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {506/**507 * Adds the input window container has a child of this container in order based on the input508 * 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@CallSuper514protected void addChild(E child, Comparator<E> comparator) {515if (!child.mReparenting && child.getParent() != null) {516throw new IllegalArgumentException("addChild: container=" + child.getName()517+ " is already a child of container=" + child.getParent().getName()518+ " can't add to container=" + getName());519}520521int positionToAdd = -1;522if (comparator != null) {523final int count = mChildren.size();524for (int i = 0; i < count; i++) {525if (comparator.compare(child, mChildren.get(i)) < 0) {526positionToAdd = i;527break;528}529}530}531532if (positionToAdd == -1) {533mChildren.add(child);534} else {535mChildren.add(positionToAdd, child);536}537538// Set the parent after we've actually added a child in case a subclass depends on this.539child.setParent(this);540}541542/** Adds the input window container has a child of this container at the input index. */543@CallSuper544void addChild(E child, int index) {545if (!child.mReparenting && child.getParent() != null) {546throw 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}551552if ((index < 0 && index != POSITION_BOTTOM)553|| (index > mChildren.size() && index != POSITION_TOP)) {554throw new IllegalArgumentException("addChild: invalid position=" + index555+ ", children number=" + mChildren.size());556}557558if (index == POSITION_TOP) {559index = mChildren.size();560} else if (index == POSITION_BOTTOM) {561index = 0;562}563564mChildren.add(index, child);565566// Set the parent after we've actually added a child in case a subclass depends on this.567child.setParent(this);568}
基于Android S分析:现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。RootWindowContainer容器类的addChild()的相关代码分析RootWindowContainer容器类盛放的东西是DisplayContent即:管理的子类对象是DisplayContent调试命令:dumpsys activity containersdumpsys activity activities175/** Root {@link WindowContainer} for the device. */176public class RootWindowContainer extends WindowContainer<DisplayContent>177implements DisplayManager.DisplayListener {RootWindowContainer 实现了 DisplayManager.DisplayListener 所以,在onDisplayAdded(), onDisplayRemoved()和onDisplayChanged()方法中,能监听到显示器的变化状态,来做相应处理。在WindowManagerService类的构造函数中创建的:mRoot1231mRoot = new RootWindowContainer(this);SystemServer.javastartOtherServices()mActivityManagerService.setWindowManager(wm);->ActivityManagerService.javasetWindowManager()mActivityTaskManager.setWindowManager(wm);->ActivityTaskManagerService.java955public void setWindowManager(WindowManagerService wm) {956synchronized (mGlobalLock) {957mWindowManager = wm;958mRootWindowContainer = wm.mRoot;959mTempConfig.setToDefaults();960mTempConfig.setLocales(LocaleList.getDefault());961mConfigurationSeq = mTempConfig.seq = 1;962mRootWindowContainer.onConfigurationChanged(mTempConfig);963mLockTaskController.setWindowManager(wm);964mTaskSupervisor.setWindowManager(wm);965mRootWindowContainer.setWindowManager(wm);966}967}->1356void setWindowManager(WindowManagerService wm) {1357mWindowManager = wm;1358mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);1359mDisplayManager.registerDisplayListener(this, mService.mUiHandler);1360mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);13611362final Display[] displays = mDisplayManager.getDisplays();1363for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {1364final Display display = displays[displayNdx];1365final DisplayContent displayContent = new DisplayContent(display, this);1366addChild(displayContent, POSITION_BOTTOM);1367if (displayContent.mDisplayId == DEFAULT_DISPLAY) {1368mDefaultDisplay = displayContent;1369}1370}1371calculateDefaultMinimalSizeOfResizeableTasks();13721373final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();1374defaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP);1375positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,1376false /* includingParents */);1377}1424/**1425 * Get an existing instance of {@link DisplayContent} or create new if there is a1426 * corresponding record in display manager.1427 */1428// TODO: Look into consolidating with getDisplayContent()1429@Nullable1430DisplayContent getDisplayContentOrCreate(int displayId) {1431DisplayContent displayContent = getDisplayContent(displayId);1432if (displayContent != null) {1433return displayContent;1434}1435if (mDisplayManager == null) {1436// The system isn't fully initialized yet.1437return null;1438}1439final Display display = mDisplayManager.getDisplay(displayId);1440if (display == null) {1441// The display is not registered in DisplayManager.1442return null;1443}1444// The display hasn't been added to ActivityManager yet, create a new record now.1445displayContent = new DisplayContent(display, this);1446addChild(displayContent, POSITION_BOTTOM);1447return displayContent;1448}RootWindowContainer 实现了 DisplayManager.DisplayListener的方法:2597@Override2598public void onDisplayAdded(int displayId) {2599if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display added displayId=" + displayId);2600synchronized (mService.mGlobalLock) {2601final DisplayContent display = getDisplayContentOrCreate(displayId);2602if (display == null) {2603return;2604}2605// Do not start home before booting, or it may accidentally finish booting before it2606// starts. Instead, we expect home activities to be launched when the system is ready2607// (ActivityManagerService#systemReady).2608if (mService.isBooted() || mService.isBooting()) {2609startSystemDecorations(display.mDisplayContent);2610}2611}2612}2614private void startSystemDecorations(final DisplayContent displayContent) {// 当连接显示器时,启动该显示器上的home桌面2615startHomeOnDisplay(mCurrentUser, "displayAdded", displayContent.getDisplayId());2616displayContent.getDisplayPolicy().notifyDisplayReady();2617}2619@Override2620public void onDisplayRemoved(int displayId) {2621if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display removed displayId=" + displayId);2622if (displayId == DEFAULT_DISPLAY) {2623throw new IllegalArgumentException("Can't remove the primary display.");2624}26252626synchronized (mService.mGlobalLock) {2627final DisplayContent displayContent = getDisplayContent(displayId);2628if (displayContent == null) {2629return;2630}26312632displayContent.remove();2633}2634}26352636@Override2637public void onDisplayChanged(int displayId) {2638if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display changed displayId=" + displayId);2639synchronized (mService.mGlobalLock) {2640final DisplayContent displayContent = getDisplayContent(displayId);2641if (displayContent != null) {2642displayContent.onDisplayChanged();2643}2644}2645}
dumpsys activity containersActivityTaskManagerService.java3809void dumpActivityContainersLocked(PrintWriter pw) {3810pw.println("ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)");3811mRootWindowContainer.dumpChildrenNames(pw, " ");3812pw.println(" ");3813}->ConfigurationContainer.java684/**685 * Dumps the names of this container children in the input print writer indenting each686 * level with the input prefix.687 */688public void dumpChildrenNames(PrintWriter pw, String prefix) {689final String childPrefix = prefix + " ";690pw.println(getName()691+ " type=" + activityTypeToString(getActivityType())692+ " mode=" + windowingModeToString(getWindowingMode())693+ " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode())694+ " requested-bounds=" + getRequestedOverrideBounds().toShortString()695+ " bounds=" + getBounds().toShortString());696for (int i = getChildCount() - 1; i >= 0; --i) {697final E cc = getChildAt(i);698pw.print(childPrefix + "#" + i + " ");699cc.dumpChildrenNames(pw, childPrefix);700}701}->RootWindowContainer.java1287@Override1288String getName() {1289return "ROOT";1290}DisplayContent.java3205String getName() {3206return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";3207}
基于Android S分析:现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。DisplayContent容器类的addChild()的相关代码分析DisplayContent集成RootDisplayArea,管理子DisplayAreaDisplayContent容器类盛放的东西是: 即:管理的子类对象是 DisplayArea通过adb shell dumpsys activity containers查看DisplayContent管理的子类对象比较多。其中有个子类对象是:TaskDisplayArea245/**246 * Utility class for keeping track of the WindowStates and other pertinent contents of a247 * particular Display.248 */249class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {WindowManagerService.java1366mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(1367mContext.getResources());->DisplayAreaPolicy.java1377DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {1378return mDisplayAreaPolicyProvider;1379}->183static Provider fromResources(Resources res) {184String name = res.getString(185com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider);186if (TextUtils.isEmpty(name)) {187return new DisplayAreaPolicy.DefaultProvider();188} ...197}91/** Provider for platform-default display area policy. */92static final class DefaultProvider implements DisplayAreaPolicy.Provider {93@Override94public DisplayAreaPolicy instantiate(WindowManagerService wmService,95DisplayContent content, RootDisplayArea root,96DisplayArea.Tokens imeContainer) {97final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,98"DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);99final List<TaskDisplayArea> tdaList = new ArrayList();100tdaList.add(defaultTaskDisplayArea);101102// Define the features that will be supported under the root of the whole logical103// display. The policy will build the DisplayArea hierarchy based on this.104final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);105// Set the essential containers (even if the display doesn't support IME).106rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);107if (content.isTrusted()) {108// Only trusted display can have system decorations.109configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);110}111112// Instantiate the policy with the hierarchy defined above. This will create and attach113// all the necessary DisplayAreas to the root.114return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);115}->DisplayContent.java1030// Setup the policy and build the display area hierarchy.1031mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(1032mWmService, this /* content */, this /* root */, mImeWindowsContainer);addWindowToken() 添加系统类型窗口IWindowManager.aidlWindowManagerInternal.javaaddWindowToken()->WindowManagerService.javaaddWindowToken() new WindowToken.Builder(this, binder, type) .setDisplayContent(dc) .setPersistOnEmpty(true) .setOwnerCanManageAppTokens(true) .setOptions(options) .build();->WindowToken.javaWindowToken() {dc.addWindowToken(token, this);}->DisplayContent.java1097void addWindowToken(IBinder binder, WindowToken token) {1098final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);1099if (dc != null) {1100// We currently don't support adding a window token to the display if the display1101// already has the binder mapped to another token. If there is a use case for supporting1102// this moving forward we will either need to merge the WindowTokens some how or have1103// the binder map to a list of window tokens.1104throw new IllegalArgumentException("Can't map token=" + token + " to display="1105+ getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);1106}1107if (binder == null) {1108throw new IllegalArgumentException("Can't map token=" + token + " to display="1109+ getName() + " binder is null");1110}1111if (token == null) {1112throw new IllegalArgumentException("Can't map null token to display="1113+ getName() + " binder=" + binder);1114}11151116mTokenMap.put(binder, token);11171118if (token.asActivityRecord() == null) {1119// Set displayContent for non-app token to prevent same token will add twice after1120// onDisplayChanged.1121// TODO: Check if it's fine that super.onDisplayChanged of WindowToken1122//(WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned.1123token.mDisplayContent = this;1124// Add non-app token to container hierarchy on the display. App tokens are added through1125// the parent container managing them (e.g. Tasks).1126final DisplayArea.Tokens da = findAreaForToken(token).asTokens();1127da.addChild(token);1128}1129}
RootDisplayArea35/**36 * Root of a {@link DisplayArea} hierarchy. It can be either the {@link DisplayContent} as the root37 * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the38 * logical display.39 */40class RootDisplayArea extends DisplayArea.Dimmable {4142/** {@link Feature} that are supported in this {@link DisplayArea} hierarchy. */43List<DisplayAreaPolicyBuilder.Feature> mFeatures;4445/**46 * Mapping from policy supported {@link Feature} to list of {@link DisplayArea} created to cover47 * all the window types that the {@link Feature} will be applied to.48 */49Map<Feature, List<DisplayArea<WindowContainer>>> mFeatureToDisplayAreas;5051/** Mapping from window layer to {@link DisplayArea.Tokens} that holds windows on that layer. */52private DisplayArea.Tokens[] mAreaForLayer;5354/** Whether the hierarchy has been built. */55private boolean mHasBuiltHierarchy;76/**77 * Places the IME container below this root, so that it's bounds and config will be updated to78 * match the root.79 */80void placeImeContainer(DisplayArea.Tokens imeContainer) {81final RootDisplayArea previousRoot = imeContainer.getRootDisplayArea();8283List<Feature> features = mFeatures;84for (int i = 0; i < features.size(); i++) {85Feature feature = features.get(i);86if (feature.getId() == FEATURE_IME_PLACEHOLDER) {87List<DisplayArea<WindowContainer>> imeDisplayAreas =88mFeatureToDisplayAreas.get(feature);89if (imeDisplayAreas.size() != 1) {90throw new IllegalStateException("There must be exactly one DisplayArea for the "91+ "FEATURE_IME_PLACEHOLDER");92}9394previousRoot.updateImeContainerForLayers(null /* imeContainer */);95imeContainer.reparent(imeDisplayAreas.get(0), POSITION_TOP);96updateImeContainerForLayers(imeContainer);97return;98}99}100throw 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 and54 * 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 */65public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {DisplayArea.java613/**614 * DisplayArea that can be dimmed.615 */616static class Dimmable extends DisplayArea<DisplayArea> {533/**534 * DisplayArea that contains WindowTokens, and orders them according to their type.535 */536public static class Tokens extends DisplayArea<WindowToken> {DisplayAreaPolicyBuilder46/**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 necessary50 * {@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 overlay59 *.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 the64 * // dim layer65 * .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 *- WindowedMagnification112 *- DisplayArea.Tokens (Wallpapers can be attached here)113 *- TaskDisplayArea114 *- RootDisplayArea (FirstRoot)115 *- DisplayArea.Tokens (Wallpapers can be attached here)116 *- TaskDisplayArea117 *- 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 *- TaskDisplayArea122 *- 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 *- ImeContainers126 *- DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY can be127 *attached here)128 *- DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up can be attached129 *here)130 * </pre>131 * When a {@link WindowToken} of Wallpaper needs to be attached, the policy will call the OEM132 * defined {@link #mSelectRootForWindowFunc} to get a {@link RootDisplayArea}. It will then place133 * the window to the corresponding {@link DisplayArea.Tokens} under the returned root134 * {@link RootDisplayArea}.135 */136class DisplayAreaPolicyBuilder {137138/**139 * Key to specify the {@link RootDisplayArea} to attach the window to. Should be used by the140 * function passed in from {@link #setSelectRootForWindowFunc(BiFunction)}141 */142static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id";143144@Nullable private HierarchyBuilder mRootHierarchyBuilder;145private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =146new ArrayList();147375/**376 *Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a377 * {@link RootDisplayArea}378 */379static class HierarchyBuilder {380private static final int LEAF_TYPE_TASK_CONTAINERS = 1;381private static final int LEAF_TYPE_IME_CONTAINERS = 2;382private static final int LEAF_TYPE_TOKENS = 0;383384private final RootDisplayArea mRoot;385private final ArrayList<DisplayAreaPolicyBuilder.Feature> mFeatures = new ArrayList();386private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList();387@Nullable388private DisplayArea.Tokens mImeContainer;727static class Result extends DisplayAreaPolicy {728final List<RootDisplayArea> mDisplayAreaGroupRoots;729final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;730private final TaskDisplayArea mDefaultTaskDisplayArea;750@Override751public void addWindow(WindowToken token) {752DisplayArea.Tokens area = findAreaForToken(token);753area.addChild(token);754}858@Nullable859private DisplayArea createArea(DisplayArea<DisplayArea> parent,860DisplayArea.Tokens[] areaForLayer) {861if (mExisting != null) {862if (mExisting.asTokens() != null) {863// Store the WindowToken container for layers864fillAreaForLayers(mExisting.asTokens(), areaForLayer);865}866return mExisting;867}868if (mSkipTokens) {869return null;870}871DisplayArea.Type type;872if (mMinLayer > APPLICATION_LAYER) {873type = DisplayArea.Type.ABOVE_TASKS;874} else if (mMaxLayer < APPLICATION_LAYER) {875type = DisplayArea.Type.BELOW_TASKS;876} else {877type = DisplayArea.Type.ANY;878}879if (mFeature == null) {880final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,881"Leaf:" + mMinLayer + ":" + mMaxLayer);882fillAreaForLayers(leaf, areaForLayer);883return leaf;884} else {885return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,886mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);887}888}static class Result extends DisplayAreaPolicy { static class Feature {
在DisplayAreaPolicyBuilder.java中,Result继承DisplayAreaPolicystatic class Result extends DisplayAreaPolicy {46/**47 * Policy that manages {@link DisplayArea}.48 */49public abstract class DisplayAreaPolicy {50protected final WindowManagerService mWmService;5152/**53 * The {@link RootDisplayArea} of the whole logical display. All {@link DisplayArea}s must be54 * (direct or indirect) descendants of this area.55 */56protected final RootDisplayArea mRoot;5758/**59 * Constructs a new {@link DisplayAreaPolicy}60 *61 * @param wmService the window manager service instance62 * @param root the root display area under which the policy operates63 */64protected DisplayAreaPolicy(WindowManagerService wmService, RootDisplayArea root) {65mWmService = wmService;66mRoot = root;67}6869/**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 */75public abstract void addWindow(WindowToken token); 91/** Provider for platform-default display area policy. */92static final class DefaultProvider implements DisplayAreaPolicy.Provider {93@Override94public DisplayAreaPolicy instantiate(WindowManagerService wmService,95DisplayContent content, RootDisplayArea root,96DisplayArea.Tokens imeContainer) {97final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,98"DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);99final List<TaskDisplayArea> tdaList = new ArrayList();100tdaList.add(defaultTaskDisplayArea);101102// Define the features that will be supported under the root of the whole logical103// display. The policy will build the DisplayArea hierarchy based on this.104final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);105// Set the essential containers (even if the display doesn't support IME).106rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);107if (content.isTrusted()) {108// Only trusted display can have system decorations.109configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);110}111112// Instantiate the policy with the hierarchy defined above. This will create and attach113// all the necessary DisplayAreas to the root.114return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);115}116117private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,118WindowManagerService wmService, DisplayContent content) {119// WindowedMagnification should be on the top so that there is only one surface120// to be magnified.121rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",122FEATURE_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());128if (content.isDefaultDisplay) {129// Only default display can have cutout.130// See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.131rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",132FEATURE_HIDE_DISPLAY_CUTOUT)133.all()134.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,135TYPE_NOTIFICATION_SHADE)136.build())137.addFeature(new Feature.Builder(wmService.mPolicy,138"OneHandedBackgroundPanel",139FEATURE_ONE_HANDED_BACKGROUND_PANEL)140.upTo(TYPE_WALLPAPER)141.build())142.addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",143FEATURE_ONE_HANDED)144.all()145.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)146.build());147}148rootHierarchy149.addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",150FEATURE_FULLSCREEN_MAGNIFICATION)151.all()152.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,153TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,154TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)155.build())156.addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",157FEATURE_IME_PLACEHOLDER)158.and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)159.build());160}161}162DisplayAreaOrganizerController291/**292 * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}.293 */294private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,295int taskDisplayAreaFeatureId) {291/**292 * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}.293 */294private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,295int taskDisplayAreaFeatureId) {296final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,297root.mWmService, name, taskDisplayAreaFeatureId, true /* createdByOrganizer */);298299// Find the top most DA that can contain Task (either a TDA or a DisplayAreaGroup).300final DisplayArea topTaskContainer = root.getItemFromDisplayAreas(da -> {301if (da.mType != ANY) {302return null;303}304305final RootDisplayArea rootDA = da.getRootDisplayArea();306if (rootDA == root || rootDA == da) {307// Either it is the top TDA below the root or it is a DisplayAreaGroup.308return da;309}310return null;311});312if (topTaskContainer == null) {313throw new IllegalStateException("Root must either contain TDA or DAG root=" + root);314}315316// Insert the TaskDisplayArea as the top Task container.317final WindowContainer parent = topTaskContainer.getParent();318final int index = parent.mChildren.indexOf(topTaskContainer) + 1;319parent.addChild(taskDisplayArea, index);320321return taskDisplayArea;322}
基于Android S分析:现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。TaskDisplayArea容器类的addChild()的相关代码分析TaskDisplayArea盛放的东西是:App应用类型窗口的Task是app window containers调试命令:dumpsys activity containersdumpsys activity activitiesDisplayAreaOrganizerController.javacreateTaskDisplayArea()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 */77final class TaskDisplayArea extends DisplayArea<WindowContainer> {348@Override349void addChild(WindowContainer child, int position) {350if (child.asTaskDisplayArea() != null) {351if (DEBUG_ROOT_TASK) {352Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this);353}354super.addChild(child, position);355} else if (child.asTask() != null) {356addChildTask(child.asTask(), position);357} else {358throw new IllegalArgumentException(359"TaskDisplayArea can only add Task and TaskDisplayArea, but found "360+ child);361}362}363364private void addChildTask(Task task, int position) {365if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);366367addRootTaskReferenceIfNeeded(task);368position = findPositionForRootTask(position, task, true /* adding */);369370super.addChild(task, position);371if (mPreferredTopFocusableRootTask != null372&& task.isFocusable()373&& mPreferredTopFocusableRootTask.compareTo(task) < 0) {374// Clear preferred top because the adding focusable task has a higher z-order.375mPreferredTopFocusableRootTask = null;376}377mAtmService.updateSleepIfNeededLocked();378onRootTaskOrderChanged(task);379}1067/**1068 * When two level tasks are required for given windowing mode and activity type, returns an1069 * 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 create1071 * a new root task if no candidate task.1072 *1073 * @param windowingMode The windowing mode the root task should be created in.1074 * @param activityTypeThe 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 sourceTaskThe task requesting to start activity. Used to determine which of the1079 *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 */1085Task 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.1090if (!alwaysCreateRootTask(1091windowingMode != WINDOWING_MODE_UNDEFINED " />: getWindowingMode(),1092activityType)) {1093Task rootTask = getRootTask(windowingMode, activityType);1094if (rootTask != null) {1095return rootTask;1096}1097} else if (candidateTask != null) {1098final Task rootTask = candidateTask;1099final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;1100final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options,1101sourceTask, launchFlags);11021103if (launchRootTask != null) {1104if (rootTask.getParent() == null) {1105launchRootTask.addChild(rootTask, position);1106} else if (rootTask.getParent() != launchRootTask) {1107rootTask.reparent(launchRootTask, position);1108}1109} else if (rootTask.getDisplayArea() != this || !rootTask.isRootTask()) {1110if (rootTask.getParent() == null) {1111addChild(rootTask, position);1112} else {1113rootTask.reparent(this, onTop);1114}1115}1116// Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.1117if (candidateTask.getWindowingMode() != windowingMode) {1118candidateTask.setWindowingMode(windowingMode);1119}1120return rootTask;1121}1122return 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}
254class Task extends WindowContainer<WindowContainer> {@Override1721void addChild(WindowContainer child, int index) {1722// If this task had any child before we added this one.1723boolean hadChild = hasChild();1724// getActivityType() looks at the top child, so we need to read the type before adding1725// a new child in case the new child is on top and UNDEFINED.1726final int activityType = getActivityType();17271728index = getAdjustedChildPosition(child, index);1729super.addChild(child, index);17301731ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);17321733// A rootable task that is now being added to be the child of an organized task. Making1734// sure the root task references is keep updated.1735if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {1736getDisplayArea().addRootTaskReferenceIfNeeded((Task) child);1737}17381739// Make sure the list of display UID allowlists is updated1740// now that this record is in a new task.1741mRootWindowContainer.updateUIDsPresentOnDisplay();17421743final ActivityRecord r = child.asActivityRecord();1744if (r == null) return;17451746r.inHistory = true;17471748// Only set this based on the first activity1749if (!hadChild) {1750if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {1751// Normally non-standard activity type for the activity record will be set when the1752// object is created, however we delay setting the standard application type until1753// this point so that the task can set the type for additional activities added in1754// the else condition below.1755r.setActivityType(ACTIVITY_TYPE_STANDARD);1756}1757setActivityType(r.getActivityType());1758isPersistable = r.isPersistable();1759mCallingUid = r.launchedFromUid;1760mCallingPackage = r.launchedFromPackage;1761mCallingFeatureId = r.launchedFromFeatureId;1762// Clamp to [1, max].1763maxRecents = Math.min(Math.max(r.info.maxRecents, 1),1764ActivityTaskManager.getMaxAppRecentsLimitStatic());1765} else {1766// Otherwise make all added activities match this one.1767r.setActivityType(activityType);1768}17691770updateEffectiveIntent();1771}17721773void addChild(ActivityRecord r) {1774addChild(r, Integer.MAX_VALUE /* add on top */);1775}7569void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) {7570Task task = child.asTask();7571try {7572if (task != null) {7573task.setForceShowForAllUsers(showForAllUsers);7574}7575// We only want to move the parents to the parents if we are creating this task at the7576// top of its root task.7577addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/);7578} finally {7579if (task != null) {7580task.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 (including7692 * 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 */7696private void addChild(WindowContainer child, int position, boolean moveParents) {7697// Add child task.7698addChild(child, null);76997700// Move child to a proper position, as some restriction for position might apply.7701positionChildAt(position, child, moveParents /* includingParents */);7702}Task创建Activity 生命周期状态adb shell cmd window logging enable-text WM_DEBUG_STATESadb shell cmd window logging enable-text WM_DEBUG_TASKSadb shell cmd window logging enable-text WM_DEBUG_IMEadb shell cmd window logging enable-text WM_DEBUG_ADD_REMOVEadb shell cmd window logging enable-text WM_DEBUG_WINDOW_ORGANIZERTask.javanew Task.Builder()reuseOrCreateTask()
基于Android S分析:现在分析其他从WindowContainer类派生出的类的addChild()的相关代码。ActivityRecord容器类的addChild()的相关代码分析ActivityRecord extends WindowTokenWindowToken extends WindowContainer<WindowState>ActivityRecord容器盛放的东西是:WindowState调试命令:dumpsys activity containersdumpsys activity activitiesdumpsys window364/**365 * An entry in the history task, representing an activity.366 */367public final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {3625@Override3626void addWindow(WindowState w) {3627super.addWindow(w);36283629boolean gotReplacementWindow = false;3630for (int i = mChildren.size() - 1; i >= 0; i--) {3631final WindowState candidate = mChildren.get(i);3632gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);3633}36343635// if we got a replacement window, reset the timeout to give drawing more time3636if (gotReplacementWindow) {3637mWmService.scheduleWindowReplacementTimeouts(this);3638}3639checkKeyguardFlagsChanged();3640}3642@Override3643void removeChild(WindowState child) {3644if (!mChildren.contains(child)) {3645// This can be true when testing.3646return;3647}3648super.removeChild(child);3649checkKeyguardFlagsChanged();3650updateLetterboxSurface(child);3651}