Loading core/java/android/content/pm/ActivityInfo.java +4 −4 Original line number Diff line number Diff line Loading @@ -1367,18 +1367,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Returns if the activity should never be sandboxed to the activity window bounds. * @hide */ public boolean neverSandboxDisplayApis() { public boolean neverSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) { return isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS) || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo); || constrainDisplayApisConfig.getNeverConstrainDisplayApis(applicationInfo); } /** * Returns if the activity should always be sandboxed to the activity window bounds. * @hide */ public boolean alwaysSandboxDisplayApis() { public boolean alwaysSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) { return isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS) || ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo); || constrainDisplayApisConfig.getAlwaysConstrainDisplayApis(applicationInfo); } /** @hide */ Loading core/java/android/content/pm/ConstrainDisplayApisConfig.java +114 −50 Original line number Diff line number Diff line Loading @@ -19,10 +19,15 @@ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import com.android.internal.os.BackgroundThread; import java.util.Arrays; import java.util.List; import java.util.Map; /** * Class for processing flags in the Device Config namespace 'constrain_display_apis'. Loading Loading @@ -54,6 +59,33 @@ public final class ConstrainDisplayApisConfig { private static final String FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS = "always_constrain_display_apis"; /** * Indicates that display APIs should never be constrained to the activity window bounds for all * packages. */ private boolean mNeverConstrainDisplayApisAllPackages; /** * Indicates that display APIs should never be constrained to the activity window bounds for * a set of defined packages. Map keys are package names, and entries are a * 'Pair(<min-version-code>, <max-version-code>)'. */ private ArrayMap<String, Pair<Long, Long>> mNeverConstrainConfigMap; /** * Indicates that display APIs should always be constrained to the activity window bounds for * a set of defined packages. Map keys are package names, and entries are a * 'Pair(<min-version-code>, <max-version-code>)'. */ private ArrayMap<String, Pair<Long, Long>> mAlwaysConstrainConfigMap; public ConstrainDisplayApisConfig() { updateCache(); DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CONSTRAIN_DISPLAY_APIS, BackgroundThread.getExecutor(), properties -> updateCache()); } /** * 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 Loading @@ -61,13 +93,12 @@ public final class ConstrainDisplayApisConfig { * * @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)) { public boolean getNeverConstrainDisplayApis(ApplicationInfo applicationInfo) { if (mNeverConstrainDisplayApisAllPackages) { return true; } return flagHasMatchingPackageEntry(FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, applicationInfo); return flagHasMatchingPackageEntry(mNeverConstrainConfigMap, applicationInfo); } /** Loading @@ -76,73 +107,106 @@ public final class ConstrainDisplayApisConfig { * * @param applicationInfo Information about the application/package. */ public static boolean alwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { return flagHasMatchingPackageEntry(FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, applicationInfo); public boolean getAlwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { return flagHasMatchingPackageEntry(mAlwaysConstrainConfigMap, applicationInfo); } /** * Returns true if the flag with the given {@code flagName} contains a package entry that * matches the given {@code applicationInfo}. * * @param applicationInfo Information about the application/package. * Updates {@link #mNeverConstrainDisplayApisAllPackages}, {@link #mNeverConstrainConfigMap}, * and {@link #mAlwaysConstrainConfigMap} from the {@link DeviceConfig}. */ private static boolean flagHasMatchingPackageEntry(String flagName, ApplicationInfo applicationInfo) { String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, flagName, /* defaultValue= */ ""); private void updateCache() { mNeverConstrainDisplayApisAllPackages = DeviceConfig.getBoolean( NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false); final String neverConstrainConfigStr = DeviceConfig.getString( NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); mNeverConstrainConfigMap = buildConfigMap(neverConstrainConfigStr); final String alwaysConstrainConfigStr = DeviceConfig.getString( NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); mAlwaysConstrainConfigMap = buildConfigMap(alwaysConstrainConfigStr); } /** * Processes the configuration string into a map of version codes, for the given * configuration to be applied to the specified packages. If the given package * entry string is invalid, then the map will not contain an entry for the package. * * @param configStr A configuration string expected to be in the format of a list of package * entries separated by ','. A package entry expected to be in the format * '<package-name>:<min-version-code>?:<max-version-code>?'. * @return a map of configuration entries, where each key is a package name. Each value is * a pair of version codes, in the format 'Pair(<min-version-code>, <max-version-code>)'. */ private static ArrayMap<String, Pair<Long, Long>> buildConfigMap(String configStr) { ArrayMap<String, Pair<Long, Long>> configMap = new ArrayMap<>(); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { return false; return configMap; } for (String packageEntryString : configStr.split(",")) { if (matchesApplicationInfo(packageEntryString, applicationInfo)) { return true; List<String> packageAndVersions = Arrays.asList(packageEntryString.split(":", 3)); if (packageAndVersions.size() != 3) { Slog.w(TAG, "Invalid package entry in flag 'never/always_constrain_display_apis': " + packageEntryString); // Skip this entry. continue; } String packageName = packageAndVersions.get(0); String minVersionCodeStr = packageAndVersions.get(1); String maxVersionCodeStr = packageAndVersions.get(2); try { final long minVersion = minVersionCodeStr.isEmpty() ? Long.MIN_VALUE : Long.parseLong( minVersionCodeStr); final long maxVersion = maxVersionCodeStr.isEmpty() ? Long.MAX_VALUE : Long.parseLong( maxVersionCodeStr); Pair<Long, Long> minMaxVersionCodes = new Pair<>(minVersion, maxVersion); configMap.put(packageName, minMaxVersionCodes); } catch (NumberFormatException e) { Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryString); // Skip this entry. } return false; } return configMap; } /** * 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. * Returns true if the flag with the given {@code flagName} contains a package entry that * matches the given {@code applicationInfo}. * * @param packageEntryStr A package entry expected to be in the format * '<package-name>:<min-version-code>?:<max-version-code>?'. * @param configMap the map representing the current configuration value to examine * @param applicationInfo Information about the application/package. */ private static boolean matchesApplicationInfo(String packageEntryStr, private static boolean flagHasMatchingPackageEntry(Map<String, Pair<Long, Long>> configMap, 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); if (configMap.isEmpty()) { return false; } String packageName = packageAndVersions.get(0); String minVersionCodeStr = packageAndVersions.get(1); String maxVersionCodeStr = packageAndVersions.get(2); if (!packageName.equals(applicationInfo.packageName)) { if (!configMap.containsKey(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 matchesApplicationInfo(configMap.get(applicationInfo.packageName), applicationInfo); } return true; /** * Parses the given {@code minMaxVersionCodes} and returns true if {@code * applicationInfo.longVersionCode} is within the version range in the pair. * Returns false otherwise. * * @param minMaxVersionCodes A pair expected to be in the format * 'Pair(<min-version-code>, <max-version-code>)'. * @param applicationInfo Information about the application/package. */ private static boolean matchesApplicationInfo(Pair<Long, Long> minMaxVersionCodes, ApplicationInfo applicationInfo) { return applicationInfo.longVersionCode >= minMaxVersionCodes.first && applicationInfo.longVersionCode <= minMaxVersionCodes.second; } } core/proto/android/server/windowmanagerservice.proto +1 −0 Original line number Diff line number Diff line Loading @@ -366,6 +366,7 @@ message ActivityRecordProto { optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; optional float min_aspect_ratio = 33; optional bool provides_max_bounds = 34; } /* represents WindowToken */ Loading core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java +8 −16 Original line number Diff line number Diff line Loading @@ -18,8 +18,7 @@ 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 static org.junit.Assert.assertEquals; import android.annotation.Nullable; import android.platform.test.annotations.Presubmit; Loading Loading @@ -146,24 +145,17 @@ public final class ConstrainDisplayApisConfigTest { private static void testNeverConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis( buildApplicationInfo(packageName, version)); if (expected) { assertTrue(result); } else { assertFalse(result); } ConstrainDisplayApisConfig config = new ConstrainDisplayApisConfig(); assertEquals(expected, config.getNeverConstrainDisplayApis(buildApplicationInfo(packageName, version))); } private static void testAlwaysConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.alwaysConstrainDisplayApis( buildApplicationInfo(packageName, version)); if (expected) { assertTrue(result); } else { assertFalse(result); } ConstrainDisplayApisConfig config = new ConstrainDisplayApisConfig(); assertEquals(expected, config.getAlwaysConstrainDisplayApis(buildApplicationInfo(packageName, version))); } private static ApplicationInfo buildApplicationInfo(String packageName, long version) { Loading services/core/java/com/android/server/wm/ActivityRecord.java +19 −6 Original line number Diff line number Diff line Loading @@ -160,6 +160,7 @@ import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; import static com.android.server.wm.ActivityRecordProto.PIP_AUTO_ENTER_ENABLED; import static com.android.server.wm.ActivityRecordProto.PROC_ID; import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS; import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN; import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE; import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED; Loading Loading @@ -261,6 +262,7 @@ import android.content.Intent; import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConstrainDisplayApisConfig; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; Loading Loading @@ -596,6 +598,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private CompatDisplayInsets mCompatDisplayInsets; private static ConstrainDisplayApisConfig sConstrainDisplayApisConfig; boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session IVoiceInteractionSession voiceSession; // Voice interaction session for this activity Loading Loading @@ -1162,8 +1166,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (info.configChanges != 0) { pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges)); } pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis()); pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis()); pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis( sConstrainDisplayApisConfig)); pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis( sConstrainDisplayApisConfig)); } if (mLastParentBeforePip != null) { pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId); Loading Loading @@ -1769,6 +1775,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A info.windowLayout.windowLayoutAffinity = uid + ":" + info.windowLayout.windowLayoutAffinity; } // Initialize once, when we know all system services are available. if (sConstrainDisplayApisConfig == null) { sConstrainDisplayApisConfig = new ConstrainDisplayApisConfig(); } stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0; nonLocalizedLabel = aInfo.nonLocalizedLabel; labelRes = aInfo.labelRes; Loading Loading @@ -7465,8 +7475,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + "should create compatDisplayInsets = %s", getUid(), mTmpBounds, info.neverSandboxDisplayApis(), info.alwaysSandboxDisplayApis(), info.neverSandboxDisplayApis(sConstrainDisplayApisConfig), info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig), !matchParentBounds(), mCompatDisplayInsets != null, shouldCreateCompatDisplayInsets()); Loading Loading @@ -8027,11 +8037,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } // Never apply sandboxing to an app that should be explicitly excluded from the config. if (info != null && info.neverSandboxDisplayApis()) { if (info.neverSandboxDisplayApis(sConstrainDisplayApisConfig)) { return false; } // Always apply sandboxing to an app that should be explicitly included from the config. if (info != null && info.alwaysSandboxDisplayApis()) { if (info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig)) { return true; } // Max bounds should be sandboxed when an activity should have compatDisplayInsets, and it Loading Loading @@ -9047,6 +9057,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); proto.write(MIN_ASPECT_RATIO, getMinAspectRatio()); // Only record if max bounds sandboxing is applied, if the caller has the necessary // permission to access the device configs. proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds()); } @Override Loading Loading
core/java/android/content/pm/ActivityInfo.java +4 −4 Original line number Diff line number Diff line Loading @@ -1367,18 +1367,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Returns if the activity should never be sandboxed to the activity window bounds. * @hide */ public boolean neverSandboxDisplayApis() { public boolean neverSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) { return isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS) || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo); || constrainDisplayApisConfig.getNeverConstrainDisplayApis(applicationInfo); } /** * Returns if the activity should always be sandboxed to the activity window bounds. * @hide */ public boolean alwaysSandboxDisplayApis() { public boolean alwaysSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) { return isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS) || ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo); || constrainDisplayApisConfig.getAlwaysConstrainDisplayApis(applicationInfo); } /** @hide */ Loading
core/java/android/content/pm/ConstrainDisplayApisConfig.java +114 −50 Original line number Diff line number Diff line Loading @@ -19,10 +19,15 @@ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.Pair; import android.util.Slog; import com.android.internal.os.BackgroundThread; import java.util.Arrays; import java.util.List; import java.util.Map; /** * Class for processing flags in the Device Config namespace 'constrain_display_apis'. Loading Loading @@ -54,6 +59,33 @@ public final class ConstrainDisplayApisConfig { private static final String FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS = "always_constrain_display_apis"; /** * Indicates that display APIs should never be constrained to the activity window bounds for all * packages. */ private boolean mNeverConstrainDisplayApisAllPackages; /** * Indicates that display APIs should never be constrained to the activity window bounds for * a set of defined packages. Map keys are package names, and entries are a * 'Pair(<min-version-code>, <max-version-code>)'. */ private ArrayMap<String, Pair<Long, Long>> mNeverConstrainConfigMap; /** * Indicates that display APIs should always be constrained to the activity window bounds for * a set of defined packages. Map keys are package names, and entries are a * 'Pair(<min-version-code>, <max-version-code>)'. */ private ArrayMap<String, Pair<Long, Long>> mAlwaysConstrainConfigMap; public ConstrainDisplayApisConfig() { updateCache(); DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CONSTRAIN_DISPLAY_APIS, BackgroundThread.getExecutor(), properties -> updateCache()); } /** * 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 Loading @@ -61,13 +93,12 @@ public final class ConstrainDisplayApisConfig { * * @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)) { public boolean getNeverConstrainDisplayApis(ApplicationInfo applicationInfo) { if (mNeverConstrainDisplayApisAllPackages) { return true; } return flagHasMatchingPackageEntry(FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, applicationInfo); return flagHasMatchingPackageEntry(mNeverConstrainConfigMap, applicationInfo); } /** Loading @@ -76,73 +107,106 @@ public final class ConstrainDisplayApisConfig { * * @param applicationInfo Information about the application/package. */ public static boolean alwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { return flagHasMatchingPackageEntry(FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, applicationInfo); public boolean getAlwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { return flagHasMatchingPackageEntry(mAlwaysConstrainConfigMap, applicationInfo); } /** * Returns true if the flag with the given {@code flagName} contains a package entry that * matches the given {@code applicationInfo}. * * @param applicationInfo Information about the application/package. * Updates {@link #mNeverConstrainDisplayApisAllPackages}, {@link #mNeverConstrainConfigMap}, * and {@link #mAlwaysConstrainConfigMap} from the {@link DeviceConfig}. */ private static boolean flagHasMatchingPackageEntry(String flagName, ApplicationInfo applicationInfo) { String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, flagName, /* defaultValue= */ ""); private void updateCache() { mNeverConstrainDisplayApisAllPackages = DeviceConfig.getBoolean( NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false); final String neverConstrainConfigStr = DeviceConfig.getString( NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); mNeverConstrainConfigMap = buildConfigMap(neverConstrainConfigStr); final String alwaysConstrainConfigStr = DeviceConfig.getString( NAMESPACE_CONSTRAIN_DISPLAY_APIS, FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); mAlwaysConstrainConfigMap = buildConfigMap(alwaysConstrainConfigStr); } /** * Processes the configuration string into a map of version codes, for the given * configuration to be applied to the specified packages. If the given package * entry string is invalid, then the map will not contain an entry for the package. * * @param configStr A configuration string expected to be in the format of a list of package * entries separated by ','. A package entry expected to be in the format * '<package-name>:<min-version-code>?:<max-version-code>?'. * @return a map of configuration entries, where each key is a package name. Each value is * a pair of version codes, in the format 'Pair(<min-version-code>, <max-version-code>)'. */ private static ArrayMap<String, Pair<Long, Long>> buildConfigMap(String configStr) { ArrayMap<String, Pair<Long, Long>> configMap = new ArrayMap<>(); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { return false; return configMap; } for (String packageEntryString : configStr.split(",")) { if (matchesApplicationInfo(packageEntryString, applicationInfo)) { return true; List<String> packageAndVersions = Arrays.asList(packageEntryString.split(":", 3)); if (packageAndVersions.size() != 3) { Slog.w(TAG, "Invalid package entry in flag 'never/always_constrain_display_apis': " + packageEntryString); // Skip this entry. continue; } String packageName = packageAndVersions.get(0); String minVersionCodeStr = packageAndVersions.get(1); String maxVersionCodeStr = packageAndVersions.get(2); try { final long minVersion = minVersionCodeStr.isEmpty() ? Long.MIN_VALUE : Long.parseLong( minVersionCodeStr); final long maxVersion = maxVersionCodeStr.isEmpty() ? Long.MAX_VALUE : Long.parseLong( maxVersionCodeStr); Pair<Long, Long> minMaxVersionCodes = new Pair<>(minVersion, maxVersion); configMap.put(packageName, minMaxVersionCodes); } catch (NumberFormatException e) { Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryString); // Skip this entry. } return false; } return configMap; } /** * 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. * Returns true if the flag with the given {@code flagName} contains a package entry that * matches the given {@code applicationInfo}. * * @param packageEntryStr A package entry expected to be in the format * '<package-name>:<min-version-code>?:<max-version-code>?'. * @param configMap the map representing the current configuration value to examine * @param applicationInfo Information about the application/package. */ private static boolean matchesApplicationInfo(String packageEntryStr, private static boolean flagHasMatchingPackageEntry(Map<String, Pair<Long, Long>> configMap, 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); if (configMap.isEmpty()) { return false; } String packageName = packageAndVersions.get(0); String minVersionCodeStr = packageAndVersions.get(1); String maxVersionCodeStr = packageAndVersions.get(2); if (!packageName.equals(applicationInfo.packageName)) { if (!configMap.containsKey(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 matchesApplicationInfo(configMap.get(applicationInfo.packageName), applicationInfo); } return true; /** * Parses the given {@code minMaxVersionCodes} and returns true if {@code * applicationInfo.longVersionCode} is within the version range in the pair. * Returns false otherwise. * * @param minMaxVersionCodes A pair expected to be in the format * 'Pair(<min-version-code>, <max-version-code>)'. * @param applicationInfo Information about the application/package. */ private static boolean matchesApplicationInfo(Pair<Long, Long> minMaxVersionCodes, ApplicationInfo applicationInfo) { return applicationInfo.longVersionCode >= minMaxVersionCodes.first && applicationInfo.longVersionCode <= minMaxVersionCodes.second; } }
core/proto/android/server/windowmanagerservice.proto +1 −0 Original line number Diff line number Diff line Loading @@ -366,6 +366,7 @@ message ActivityRecordProto { optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; optional float min_aspect_ratio = 33; optional bool provides_max_bounds = 34; } /* represents WindowToken */ Loading
core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java +8 −16 Original line number Diff line number Diff line Loading @@ -18,8 +18,7 @@ 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 static org.junit.Assert.assertEquals; import android.annotation.Nullable; import android.platform.test.annotations.Presubmit; Loading Loading @@ -146,24 +145,17 @@ public final class ConstrainDisplayApisConfigTest { private static void testNeverConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis( buildApplicationInfo(packageName, version)); if (expected) { assertTrue(result); } else { assertFalse(result); } ConstrainDisplayApisConfig config = new ConstrainDisplayApisConfig(); assertEquals(expected, config.getNeverConstrainDisplayApis(buildApplicationInfo(packageName, version))); } private static void testAlwaysConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.alwaysConstrainDisplayApis( buildApplicationInfo(packageName, version)); if (expected) { assertTrue(result); } else { assertFalse(result); } ConstrainDisplayApisConfig config = new ConstrainDisplayApisConfig(); assertEquals(expected, config.getAlwaysConstrainDisplayApis(buildApplicationInfo(packageName, version))); } private static ApplicationInfo buildApplicationInfo(String packageName, long version) { Loading
services/core/java/com/android/server/wm/ActivityRecord.java +19 −6 Original line number Diff line number Diff line Loading @@ -160,6 +160,7 @@ import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; import static com.android.server.wm.ActivityRecordProto.PIP_AUTO_ENTER_ENABLED; import static com.android.server.wm.ActivityRecordProto.PROC_ID; import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS; import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN; import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE; import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED; Loading Loading @@ -261,6 +262,7 @@ import android.content.Intent; import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConstrainDisplayApisConfig; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; Loading Loading @@ -596,6 +598,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private CompatDisplayInsets mCompatDisplayInsets; private static ConstrainDisplayApisConfig sConstrainDisplayApisConfig; boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session IVoiceInteractionSession voiceSession; // Voice interaction session for this activity Loading Loading @@ -1162,8 +1166,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (info.configChanges != 0) { pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges)); } pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis()); pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis()); pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis( sConstrainDisplayApisConfig)); pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis( sConstrainDisplayApisConfig)); } if (mLastParentBeforePip != null) { pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId); Loading Loading @@ -1769,6 +1775,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A info.windowLayout.windowLayoutAffinity = uid + ":" + info.windowLayout.windowLayoutAffinity; } // Initialize once, when we know all system services are available. if (sConstrainDisplayApisConfig == null) { sConstrainDisplayApisConfig = new ConstrainDisplayApisConfig(); } stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0; nonLocalizedLabel = aInfo.nonLocalizedLabel; labelRes = aInfo.labelRes; Loading Loading @@ -7465,8 +7475,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + "should create compatDisplayInsets = %s", getUid(), mTmpBounds, info.neverSandboxDisplayApis(), info.alwaysSandboxDisplayApis(), info.neverSandboxDisplayApis(sConstrainDisplayApisConfig), info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig), !matchParentBounds(), mCompatDisplayInsets != null, shouldCreateCompatDisplayInsets()); Loading Loading @@ -8027,11 +8037,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } // Never apply sandboxing to an app that should be explicitly excluded from the config. if (info != null && info.neverSandboxDisplayApis()) { if (info.neverSandboxDisplayApis(sConstrainDisplayApisConfig)) { return false; } // Always apply sandboxing to an app that should be explicitly included from the config. if (info != null && info.alwaysSandboxDisplayApis()) { if (info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig)) { return true; } // Max bounds should be sandboxed when an activity should have compatDisplayInsets, and it Loading Loading @@ -9047,6 +9057,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); proto.write(MIN_ASPECT_RATIO, getMinAspectRatio()); // Only record if max bounds sandboxing is applied, if the caller has the necessary // permission to access the device configs. proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds()); } @Override Loading