Loading core/java/android/content/pm/ActivityInfo.java +2 −1 Original line number Diff line number Diff line Loading @@ -1348,7 +1348,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { public boolean neverSandboxDisplayApis() { return CompatChanges.isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS, applicationInfo.packageName, UserHandle.getUserHandleForUid(applicationInfo.uid)); UserHandle.getUserHandleForUid(applicationInfo.uid)) || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo); } /** Loading core/java/android/content/pm/ConstrainDisplayApisConfig.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import android.provider.DeviceConfig; import android.util.Slog; import java.util.Arrays; import java.util.List; /** * Class for processing flags in the Device Config namespace 'constrain_display_apis'. * * @hide */ public final class ConstrainDisplayApisConfig { private static final String TAG = ConstrainDisplayApisConfig.class.getSimpleName(); /** * A string flag whose value holds a comma separated list of package entries in the format * '<package-name>:<min-version-code>?:<max-version-code>?' for which Display APIs should never * be constrained. */ private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS = "never_constrain_display_apis"; /** * A boolean flag indicating whether Display APIs should never be constrained for all * packages. If true, {@link #FLAG_NEVER_CONSTRAIN_DISPLAY_APIS} is ignored. */ private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES = "never_constrain_display_apis_all_packages"; /** * Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the * flag 'never_constrain_display_apis' contains a package entry that matches the given {@code * applicationInfo}. * * @param applicationInfo Information about the application/package. */ public static boolean neverConstrainDisplayApis(ApplicationInfo applicationInfo) { if (DeviceConfig.getBoolean(NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) { return true; } String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { return false; } for (String packageEntryString : configStr.split(",")) { if (matchesApplicationInfo(packageEntryString, applicationInfo)) { return true; } } return false; } /** * Parses the given {@code packageEntryString} and returns true if {@code * applicationInfo.packageName} matches the package name in the config and {@code * applicationInfo.longVersionCode} is within the version range in the config. * * <p>Logs a warning and returns false in case the given {@code packageEntryString} is invalid. * * @param packageEntryStr A package entry expected to be in the format * '<package-name>:<min-version-code>?:<max-version-code>?'. * @param applicationInfo Information about the application/package. */ private static boolean matchesApplicationInfo(String packageEntryStr, ApplicationInfo applicationInfo) { List<String> packageAndVersions = Arrays.asList(packageEntryStr.split(":", 3)); if (packageAndVersions.size() != 3) { Slog.w(TAG, "Invalid package entry in flag 'never_constrain_display_apis': " + packageEntryStr); return false; } String packageName = packageAndVersions.get(0); String minVersionCodeStr = packageAndVersions.get(1); String maxVersionCodeStr = packageAndVersions.get(2); if (!packageName.equals(applicationInfo.packageName)) { return false; } long version = applicationInfo.longVersionCode; try { if (!minVersionCodeStr.isEmpty() && version < Long.parseLong(minVersionCodeStr)) { return false; } if (!maxVersionCodeStr.isEmpty() && version > Long.parseLong(maxVersionCodeStr)) { return false; } } catch (NumberFormatException e) { Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryStr); return false; } return true; } } core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.annotation.Nullable; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import androidx.test.filters.SmallTest; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for {@link ConstrainDisplayApisConfig}. * * Build/Install/Run: * atest FrameworksCoreTests:ConstrainDisplayApisConfigTest */ @SmallTest @Presubmit public final class ConstrainDisplayApisConfigTest { private Properties mInitialConstrainDisplayApisFlags; @Before public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); clearConstrainDisplayApisFlags(); } @After public void tearDown() throws Exception { DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags); } @Test public void neverConstrainDisplayApis_allPackagesFlagTrue_returnsTrue() { setNeverConstrainDisplayApisAllPackagesFlag("true"); // Setting 'never_constrain_display_apis' as well to make sure it is ignored. setNeverConstrainDisplayApisFlag("com.android.other:1:2,com.android.other2::"); testNeverConstrainDisplayApis("com.android.test", /* version= */ 5, /* expected= */ true); testNeverConstrainDisplayApis("com.android.other", /* version= */ 0, /* expected= */ true); testNeverConstrainDisplayApis("com.android.other", /* version= */ 3, /* expected= */ true); } @Test public void neverConstrainDisplayApis_flagsNoSet_returnsFalse() { testNeverConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ false); } @Test public void neverConstrainDisplayApis_flagsHasSingleEntry_returnsTrueForPackageWithinRange() { setNeverConstrainDisplayApisFlag("com.android.test:1:1"); testNeverConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test", /* version= */ 0, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test", /* version= */ 2, /* expected= */ false); } @Test public void neverConstrainDisplayApis_flagHasEntries_returnsTrueForPackagesWithinRange() { setNeverConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1:3," + "com.android.test3:5:,com.android.test4::8"); // Package 'com.android.other' testNeverConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ false); // Package 'com.android.test1' testNeverConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true); // Package 'com.android.test2' testNeverConstrainDisplayApis("com.android.test2", /* version= */ 0, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 1, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 3, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 4, /* expected= */ false); // Package 'com.android.test3' testNeverConstrainDisplayApis("com.android.test3", /* version= */ 4, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test3", /* version= */ 5, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test3", /* version= */ 6, /* expected= */ true); // Package 'com.android.test4' testNeverConstrainDisplayApis("com.android.test4", /* version= */ 7, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test4", /* version= */ 8, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test4", /* version= */ 9, /* expected= */ false); } @Test public void neverConstrainDisplayApis_flagHasInvalidEntries_ignoresInvalidEntries() { // We add a valid entry before and after the invalid ones to make sure they are applied. setNeverConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1," + "com.android.test3:5:ten,com.android.test4:5::,com.android.test5::"); testNeverConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test3", /* version= */ 7, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test4", /* version= */ 7, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test5", /* version= */ 5, /* expected= */ true); } private static void testNeverConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis( buildApplicationInfo(packageName, version)); if (expected) { assertTrue(result); } else { assertFalse(result); } } private static ApplicationInfo buildApplicationInfo(String packageName, long version) { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.packageName = packageName; applicationInfo.longVersionCode = version; return applicationInfo; } private static void setNeverConstrainDisplayApisFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis", value, /* makeDefault= */ false); } private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis_all_packages", value, /* makeDefault= */ false); } private static void clearConstrainDisplayApisFlags() { setNeverConstrainDisplayApisFlag(null); setNeverConstrainDisplayApisAllPackagesFlag(null); } } services/tests/wmtests/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" /> <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" /> <uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <application android:debuggable="true" Loading services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +119 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; Loading Loading @@ -54,6 +55,7 @@ import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doCallRealMethod; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.WindowConfiguration; Loading @@ -64,6 +66,8 @@ import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.res.Configuration; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.view.WindowManager; import androidx.test.filters.MediumTest; Loading @@ -71,6 +75,8 @@ import androidx.test.filters.MediumTest; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; Loading @@ -91,6 +97,19 @@ public class SizeCompatTests extends WindowTestsBase { private Task mTask; private ActivityRecord mActivity; private Properties mInitialConstrainDisplayApisFlags; @Before public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); clearConstrainDisplayApisFlags(); } @After public void tearDown() throws Exception { DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags); } private void setUpApp(DisplayContent display) { mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build(); Loading Loading @@ -790,6 +809,90 @@ public class SizeCompatTests extends WindowTestsBase { assertActivityMaxBoundsSandboxed(activity); } @Test public void testNeverConstrainDisplayApisDeviceConfig_allPackagesFlagTrue_sandboxNotApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisAllPackagesFlag("true"); // Setting 'never_constrain_display_apis' as well to make sure it is ignored. setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should not be sandboxed, even though it is letterboxed. assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) .isEqualTo(activity.getDisplayArea().getBounds()); } @Test public void testNeverConstrainDisplayApisDeviceConfig_packageInRange_sandboxingNotApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisFlag( "com.android.frameworks.wmtests:20:,com.android.other::," + "com.android.frameworks.wmtests:0:10"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should not be sandboxed, even though it is letterboxed. assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) .isEqualTo(activity.getDisplayArea().getBounds()); } @Test public void testNeverConstrainDisplayApisDeviceConfig_packageOutsideRange_sandboxingApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisFlag("com.android.other::,com.android.frameworks.wmtests:1:5"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag. assertActivityMaxBoundsSandboxed(activity); } @Test public void testNeverConstrainDisplayApisDeviceConfig_packageNotInFlag_sandboxingApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag. assertActivityMaxBoundsSandboxed(activity); } @Test @EnableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) public void testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_unresizable() { Loading Loading @@ -1927,4 +2030,20 @@ public class SizeCompatTests extends WindowTestsBase { displayContent.computeScreenConfiguration(c); displayContent.onRequestedOverrideConfigurationChanged(c); } private static void setNeverConstrainDisplayApisFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis", value, /* makeDefault= */ false); } private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis_all_packages", value, /* makeDefault= */ false); } private static void clearConstrainDisplayApisFlags() { setNeverConstrainDisplayApisFlag(null); setNeverConstrainDisplayApisAllPackagesFlag(null); } } Loading
core/java/android/content/pm/ActivityInfo.java +2 −1 Original line number Diff line number Diff line Loading @@ -1348,7 +1348,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { public boolean neverSandboxDisplayApis() { return CompatChanges.isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS, applicationInfo.packageName, UserHandle.getUserHandleForUid(applicationInfo.uid)); UserHandle.getUserHandleForUid(applicationInfo.uid)) || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo); } /** Loading
core/java/android/content/pm/ConstrainDisplayApisConfig.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import android.provider.DeviceConfig; import android.util.Slog; import java.util.Arrays; import java.util.List; /** * Class for processing flags in the Device Config namespace 'constrain_display_apis'. * * @hide */ public final class ConstrainDisplayApisConfig { private static final String TAG = ConstrainDisplayApisConfig.class.getSimpleName(); /** * A string flag whose value holds a comma separated list of package entries in the format * '<package-name>:<min-version-code>?:<max-version-code>?' for which Display APIs should never * be constrained. */ private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS = "never_constrain_display_apis"; /** * A boolean flag indicating whether Display APIs should never be constrained for all * packages. If true, {@link #FLAG_NEVER_CONSTRAIN_DISPLAY_APIS} is ignored. */ private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES = "never_constrain_display_apis_all_packages"; /** * Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the * flag 'never_constrain_display_apis' contains a package entry that matches the given {@code * applicationInfo}. * * @param applicationInfo Information about the application/package. */ public static boolean neverConstrainDisplayApis(ApplicationInfo applicationInfo) { if (DeviceConfig.getBoolean(NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) { return true; } String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { return false; } for (String packageEntryString : configStr.split(",")) { if (matchesApplicationInfo(packageEntryString, applicationInfo)) { return true; } } return false; } /** * Parses the given {@code packageEntryString} and returns true if {@code * applicationInfo.packageName} matches the package name in the config and {@code * applicationInfo.longVersionCode} is within the version range in the config. * * <p>Logs a warning and returns false in case the given {@code packageEntryString} is invalid. * * @param packageEntryStr A package entry expected to be in the format * '<package-name>:<min-version-code>?:<max-version-code>?'. * @param applicationInfo Information about the application/package. */ private static boolean matchesApplicationInfo(String packageEntryStr, ApplicationInfo applicationInfo) { List<String> packageAndVersions = Arrays.asList(packageEntryStr.split(":", 3)); if (packageAndVersions.size() != 3) { Slog.w(TAG, "Invalid package entry in flag 'never_constrain_display_apis': " + packageEntryStr); return false; } String packageName = packageAndVersions.get(0); String minVersionCodeStr = packageAndVersions.get(1); String maxVersionCodeStr = packageAndVersions.get(2); if (!packageName.equals(applicationInfo.packageName)) { return false; } long version = applicationInfo.longVersionCode; try { if (!minVersionCodeStr.isEmpty() && version < Long.parseLong(minVersionCodeStr)) { return false; } if (!maxVersionCodeStr.isEmpty() && version > Long.parseLong(maxVersionCodeStr)) { return false; } } catch (NumberFormatException e) { Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryStr); return false; } return true; } }
core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.annotation.Nullable; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import androidx.test.filters.SmallTest; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for {@link ConstrainDisplayApisConfig}. * * Build/Install/Run: * atest FrameworksCoreTests:ConstrainDisplayApisConfigTest */ @SmallTest @Presubmit public final class ConstrainDisplayApisConfigTest { private Properties mInitialConstrainDisplayApisFlags; @Before public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); clearConstrainDisplayApisFlags(); } @After public void tearDown() throws Exception { DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags); } @Test public void neverConstrainDisplayApis_allPackagesFlagTrue_returnsTrue() { setNeverConstrainDisplayApisAllPackagesFlag("true"); // Setting 'never_constrain_display_apis' as well to make sure it is ignored. setNeverConstrainDisplayApisFlag("com.android.other:1:2,com.android.other2::"); testNeverConstrainDisplayApis("com.android.test", /* version= */ 5, /* expected= */ true); testNeverConstrainDisplayApis("com.android.other", /* version= */ 0, /* expected= */ true); testNeverConstrainDisplayApis("com.android.other", /* version= */ 3, /* expected= */ true); } @Test public void neverConstrainDisplayApis_flagsNoSet_returnsFalse() { testNeverConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ false); } @Test public void neverConstrainDisplayApis_flagsHasSingleEntry_returnsTrueForPackageWithinRange() { setNeverConstrainDisplayApisFlag("com.android.test:1:1"); testNeverConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test", /* version= */ 0, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test", /* version= */ 2, /* expected= */ false); } @Test public void neverConstrainDisplayApis_flagHasEntries_returnsTrueForPackagesWithinRange() { setNeverConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1:3," + "com.android.test3:5:,com.android.test4::8"); // Package 'com.android.other' testNeverConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ false); // Package 'com.android.test1' testNeverConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true); // Package 'com.android.test2' testNeverConstrainDisplayApis("com.android.test2", /* version= */ 0, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 1, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 3, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 4, /* expected= */ false); // Package 'com.android.test3' testNeverConstrainDisplayApis("com.android.test3", /* version= */ 4, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test3", /* version= */ 5, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test3", /* version= */ 6, /* expected= */ true); // Package 'com.android.test4' testNeverConstrainDisplayApis("com.android.test4", /* version= */ 7, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test4", /* version= */ 8, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test4", /* version= */ 9, /* expected= */ false); } @Test public void neverConstrainDisplayApis_flagHasInvalidEntries_ignoresInvalidEntries() { // We add a valid entry before and after the invalid ones to make sure they are applied. setNeverConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1," + "com.android.test3:5:ten,com.android.test4:5::,com.android.test5::"); testNeverConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true); testNeverConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test3", /* version= */ 7, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test4", /* version= */ 7, /* expected= */ false); testNeverConstrainDisplayApis("com.android.test5", /* version= */ 5, /* expected= */ true); } private static void testNeverConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis( buildApplicationInfo(packageName, version)); if (expected) { assertTrue(result); } else { assertFalse(result); } } private static ApplicationInfo buildApplicationInfo(String packageName, long version) { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.packageName = packageName; applicationInfo.longVersionCode = version; return applicationInfo; } private static void setNeverConstrainDisplayApisFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis", value, /* makeDefault= */ false); } private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis_all_packages", value, /* makeDefault= */ false); } private static void clearConstrainDisplayApisFlags() { setNeverConstrainDisplayApisFlag(null); setNeverConstrainDisplayApisAllPackagesFlag(null); } }
services/tests/wmtests/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" /> <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" /> <uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"/> <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <application android:debuggable="true" Loading
services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +119 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; Loading Loading @@ -54,6 +55,7 @@ import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doCallRealMethod; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.WindowConfiguration; Loading @@ -64,6 +66,8 @@ import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.res.Configuration; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.view.WindowManager; import androidx.test.filters.MediumTest; Loading @@ -71,6 +75,8 @@ import androidx.test.filters.MediumTest; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; Loading @@ -91,6 +97,19 @@ public class SizeCompatTests extends WindowTestsBase { private Task mTask; private ActivityRecord mActivity; private Properties mInitialConstrainDisplayApisFlags; @Before public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); clearConstrainDisplayApisFlags(); } @After public void tearDown() throws Exception { DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags); } private void setUpApp(DisplayContent display) { mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build(); Loading Loading @@ -790,6 +809,90 @@ public class SizeCompatTests extends WindowTestsBase { assertActivityMaxBoundsSandboxed(activity); } @Test public void testNeverConstrainDisplayApisDeviceConfig_allPackagesFlagTrue_sandboxNotApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisAllPackagesFlag("true"); // Setting 'never_constrain_display_apis' as well to make sure it is ignored. setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should not be sandboxed, even though it is letterboxed. assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) .isEqualTo(activity.getDisplayArea().getBounds()); } @Test public void testNeverConstrainDisplayApisDeviceConfig_packageInRange_sandboxingNotApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisFlag( "com.android.frameworks.wmtests:20:,com.android.other::," + "com.android.frameworks.wmtests:0:10"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should not be sandboxed, even though it is letterboxed. assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) .isEqualTo(activity.getDisplayArea().getBounds()); } @Test public void testNeverConstrainDisplayApisDeviceConfig_packageOutsideRange_sandboxingApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisFlag("com.android.other::,com.android.frameworks.wmtests:1:5"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag. assertActivityMaxBoundsSandboxed(activity); } @Test public void testNeverConstrainDisplayApisDeviceConfig_packageNotInFlag_sandboxingApplied() { setUpDisplaySizeWithApp(1000, 1200); setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::"); // Make the task root resizable. mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; // Create an activity with a max aspect ratio on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag. assertActivityMaxBoundsSandboxed(activity); } @Test @EnableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) public void testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_unresizable() { Loading Loading @@ -1927,4 +2030,20 @@ public class SizeCompatTests extends WindowTestsBase { displayContent.computeScreenConfiguration(c); displayContent.onRequestedOverrideConfigurationChanged(c); } private static void setNeverConstrainDisplayApisFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis", value, /* makeDefault= */ false); } private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) { DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis_all_packages", value, /* makeDefault= */ false); } private static void clearConstrainDisplayApisFlags() { setNeverConstrainDisplayApisFlag(null); setNeverConstrainDisplayApisAllPackagesFlag(null); } }