Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e44bf21 authored by Chris Li's avatar Chris Li
Browse files

Add enforcement for unique displayarea id

Fix: 173513713
Test: atest WmTests:DisplayAreaPolicyBuilderTest
Change-Id: Ia11be2b4bc49c6c23d17f2501c3fda53c9540720
parent a86113f6
Loading
Loading
Loading
Loading
+89 −10
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;

import android.annotation.Nullable;
import android.os.Bundle;
@@ -166,32 +167,48 @@ class DisplayAreaPolicyBuilder {
        return this;
    }

    /** Makes sure the setting meets the requirement. */
    /**
     * Makes sure the setting meets the requirement:
     * 1. {@link mRootHierarchyBuilder} must be set.
     * 2. {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
     * 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
     * 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
     * 5. There must be exactly one {@link HierarchyBuilder} that contains the default
     *    {@link TaskDisplayArea} with id {@link FEATURE_DEFAULT_TASK_CONTAINER}.
     * 6. None of the ids is greater than {@link FEATURE_VENDOR_LAST}.
     */
    private void validate() {
        if (mRootHierarchyBuilder == null) {
            throw new IllegalStateException("Root must be set for the display area policy.");
        }

        final Set<Integer> rootIdSet = new ArraySet<>();
        rootIdSet.add(mRootHierarchyBuilder.mRoot.mFeatureId);
        final Set<Integer> uniqueIdSet = new ArraySet<>();
        final Set<Integer> allIdSet = new ArraySet<>();
        validateIds(mRootHierarchyBuilder, uniqueIdSet, allIdSet);
        boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
        boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
        for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
            HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
            if (!rootIdSet.add(hierarchyBuilder.mRoot.mFeatureId)) {
                throw new IllegalStateException("There should not be two RootDisplayAreas with id "
                        + hierarchyBuilder.mRoot.mFeatureId);
            }
            validateIds(hierarchyBuilder, uniqueIdSet, allIdSet);

            if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
                throw new IllegalStateException(
                        "DisplayAreaGroup must contain at least one TaskDisplayArea.");
            }

            containsImeContainer = containsImeContainer || hierarchyBuilder.mImeContainer != null;
            if (containsImeContainer) {
                if (hierarchyBuilder.mImeContainer != null) {
                    throw new IllegalStateException(
                            "Only one DisplayArea hierarchy can contain the IME container");
                }
            } else {
                containsImeContainer = hierarchyBuilder.mImeContainer != null;
            }

            if (containsDefaultTda) {
                if (containsDefaultTaskDisplayArea(hierarchyBuilder)) {
                    throw new IllegalStateException("Only one TaskDisplayArea can have the feature "
                            + "of FEATURE_DEFAULT_TASK_CONTAINER");
                            + "id of FEATURE_DEFAULT_TASK_CONTAINER");
                }
            } else {
                containsDefaultTda = containsDefaultTaskDisplayArea(hierarchyBuilder);
@@ -203,7 +220,8 @@ class DisplayAreaPolicyBuilder {
        }

        if (!containsDefaultTda) {
            throw new IllegalStateException("There must be a default TaskDisplayArea.");
            throw new IllegalStateException("There must be a default TaskDisplayArea with id of "
                    + "FEATURE_DEFAULT_TASK_CONTAINER.");
        }
    }

@@ -218,6 +236,67 @@ class DisplayAreaPolicyBuilder {
        return false;
    }

    /**
     * Makes sure that ids meet requirement.
     * {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
     * {@link Feature} below the same {@link RootDisplayArea} must have unique ids, but
     * {@link Feature} below different {@link RootDisplayArea} can have the same id so that we can
     * organize them together.
     * None of the ids is greater than {@link FEATURE_VENDOR_LAST}
     *
     * @param uniqueIdSet ids of {@link RootDisplayArea} and {@link TaskDisplayArea} that must be
     *                    unique,
     * @param allIdSet ids of {@link RootDisplayArea}, {@link TaskDisplayArea} and {@link Feature}.
     */
    private static void validateIds(HierarchyBuilder displayAreaHierarchy,
            Set<Integer> uniqueIdSet, Set<Integer> allIdSet) {
        // Root must have unique id.
        final int rootId = displayAreaHierarchy.mRoot.mFeatureId;
        if (!allIdSet.add(rootId) || !uniqueIdSet.add(rootId)) {
            throw new IllegalStateException(
                    "RootDisplayArea must have unique id, but id=" + rootId + " is not unique.");
        }
        if (rootId > FEATURE_VENDOR_LAST) {
            throw new IllegalStateException(
                    "RootDisplayArea should not have an id greater than FEATURE_VENDOR_LAST.");
        }

        // TDAs must have unique id.
        for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
            final int taskDisplayAreaId = displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId;
            if (!allIdSet.add(taskDisplayAreaId) || !uniqueIdSet.add(taskDisplayAreaId)) {
                throw new IllegalStateException("TaskDisplayArea must have unique id, but id="
                        + taskDisplayAreaId + " is not unique.");
            }
            if (taskDisplayAreaId > FEATURE_VENDOR_LAST) {
                throw new IllegalStateException("TaskDisplayArea declared in the policy should not"
                        + "have an id greater than FEATURE_VENDOR_LAST.");
            }
        }

        // Features below the same root must have unique ids.
        final Set<Integer> featureIdSet = new ArraySet<>();
        for (int i = 0; i < displayAreaHierarchy.mFeatures.size(); i++) {
            final int featureId = displayAreaHierarchy.mFeatures.get(i).getId();
            if (uniqueIdSet.contains(featureId)) {
                throw new IllegalStateException("Feature must not have same id with any "
                        + "RootDisplayArea or TaskDisplayArea, but id=" + featureId + " is used");
            }
            if (!featureIdSet.add(featureId)) {
                throw new IllegalStateException("Feature below the same root must have unique id, "
                        + "but id=" + featureId + " is not unique.");
            }
            if (featureId > FEATURE_VENDOR_LAST) {
                throw new IllegalStateException(
                        "Feature should not have an id greater than FEATURE_VENDOR_LAST.");
            }
        }

        // Features below different roots can have the same id so that we can organize them
        // together.
        allIdSet.addAll(featureIdSet);
    }

    Result build(WindowManagerService wmService) {
        validate();

+145 −9
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;

import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
@@ -114,11 +115,13 @@ public class DisplayAreaPolicyBuilderTest {
        final Feature bar;
        DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .addFeature(foo = new Feature.Builder(mPolicy, "Foo", 0)
                        .addFeature(foo = new Feature.Builder(mPolicy, "Foo",
                                FEATURE_VENDOR_FIRST)
                                .upTo(TYPE_STATUS_BAR)
                                .and(TYPE_NAVIGATION_BAR)
                                .build())
                        .addFeature(bar = new Feature.Builder(mPolicy, "Bar", 1)
                        .addFeature(bar = new Feature.Builder(mPolicy, "Bar",
                                FEATURE_VENDOR_FIRST + 1)
                                .all()
                                .except(TYPE_STATUS_BAR)
                                .build())
@@ -240,12 +243,14 @@ public class DisplayAreaPolicyBuilderTest {
        final Feature other;
        DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable", 0)
                        .addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable",
                                FEATURE_VENDOR_FIRST)
                                .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                                .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                                .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                                .build())
                        .addFeature(other = new Feature.Builder(mPolicy, "Other", 1)
                        .addFeature(other = new Feature.Builder(mPolicy, "Other",
                                FEATURE_VENDOR_FIRST + 1)
                                .all()
                                .build())
                        .setImeContainer(mImeContainer)
@@ -313,9 +318,7 @@ public class DisplayAreaPolicyBuilderTest {
        builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
                mGroupRoot1)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(Lists.newArrayList(
                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
                                FEATURE_VENDOR_FIRST + 1))));
                .setTaskDisplayAreas(Lists.newArrayList(mTda1)));

        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));

@@ -340,11 +343,144 @@ public class DisplayAreaPolicyBuilderTest {
                .setTaskDisplayAreas(mTaskDisplayAreaList));
        builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
                mGroupRoot2)
                .setTaskDisplayAreas(Lists.newArrayList(mTda1)));

        builder4.build(mWms);
    }

    @Test
    public void testBuilder_rootHasUniqueId() {
        // Root must have different id from all roots.
        final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
        builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(mTaskDisplayAreaList));
        final RootDisplayArea groupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1",
                mRoot.mFeatureId);
        builder1.addDisplayAreaGroupHierarchy(
                new DisplayAreaPolicyBuilder.HierarchyBuilder(groupRoot1)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1)));

        assertThrows(IllegalStateException.class, () -> builder1.build(mWms));

        // Root must have different id from all TDAs.
        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(Lists.newArrayList(
                        mDefaultTaskDisplayArea,
                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
                                FEATURE_VENDOR_FIRST + 1))));
                                mRoot.mFeatureId))));

        builder4.build(mWms);
        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));

        // Root must have different id from all features.
        final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
        builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(mTaskDisplayAreaList)
                .addFeature(new Feature.Builder(mPolicy, "testFeature", mRoot.mFeatureId)
                        .all()
                        .build()));

        assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
    }

    @Test
    public void testBuilder_taskDisplayAreaHasUniqueId() {
        // TDA must have different id from all TDAs.
        final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
        final List<TaskDisplayArea> tdaList = Lists.newArrayList(
                mDefaultTaskDisplayArea,
                mTda1,
                new TaskDisplayArea(mDisplayContent, mWms, "tda2", mTda1.mFeatureId));
        builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(tdaList));

        assertThrows(IllegalStateException.class, () -> builder.build(mWms));

        // TDA must have different id from all features.
        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(Lists.newArrayList(
                        mDefaultTaskDisplayArea,
                        mTda1))
                .addFeature(new Feature.Builder(mPolicy, "testFeature", mTda1.mFeatureId)
                        .all()
                        .build()));

        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
    }

    @Test
    public void testBuilder_featureHasUniqueId() {
        // Feature must have different id from features below the same root.
        final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
        builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(mTaskDisplayAreaList)
                .addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10)
                        .all()
                        .build())
                .addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10)
                        .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                        .build()));

        assertThrows(IllegalStateException.class, () -> builder.build(mWms));

        // Features below different root can have the same id.
        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(mTaskDisplayAreaList)
                .addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10)
                        .all()
                        .build()));
        builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
                mGroupRoot1)
                .setTaskDisplayAreas(Lists.newArrayList(mTda1))
                .addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10)
                        .all()
                        .build()));

        builder2.build(mWms);
    }

    @Test
    public void testBuilder_idsNotGreaterThanFeatureVendorLast() {
        // Root id should not be greater than FEATURE_VENDOR_LAST.
        final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
        final RootDisplayArea root = new SurfacelessDisplayAreaRoot(mWms, "testRoot",
                FEATURE_VENDOR_LAST + 1);
        builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(mTaskDisplayAreaList));

        assertThrows(IllegalStateException.class, () -> builder1.build(mWms));

        // TDA id should not be greater than FEATURE_VENDOR_LAST.
        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(Lists.newArrayList(
                        mDefaultTaskDisplayArea,
                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
                                FEATURE_VENDOR_LAST + 1))));

        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));

        // Feature id should not be greater than FEATURE_VENDOR_LAST.
        final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
        builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                .setImeContainer(mImeContainer)
                .setTaskDisplayAreas(mTaskDisplayAreaList)
                .addFeature(new Feature.Builder(mPolicy, "testFeature", FEATURE_VENDOR_LAST + 1)
                        .all()
                        .build()));

        assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
    }

    @Test