Merge "Introduce WindowManagerState field for sandboxing" into sc-v2-dev am: f5284f89be
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16340536 Change-Id: I4b2fd3e47e9cbb2e873fa0db37eed74f6badb734
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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'.
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates {@link #mNeverConstrainDisplayApisAllPackages}, {@link #mNeverConstrainConfigMap},
|
||||
* and {@link #mAlwaysConstrainConfigMap} from the {@link DeviceConfig}.
|
||||
*/
|
||||
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 configMap;
|
||||
}
|
||||
for (String packageEntryString : configStr.split(",")) {
|
||||
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 configMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the flag with the given {@code flagName} contains a package entry that
|
||||
* matches the given {@code applicationInfo}.
|
||||
*
|
||||
* @param configMap the map representing the current configuration value to examine
|
||||
* @param applicationInfo Information about the application/package.
|
||||
*/
|
||||
private static boolean flagHasMatchingPackageEntry(String flagName,
|
||||
private static boolean flagHasMatchingPackageEntry(Map<String, Pair<Long, Long>> configMap,
|
||||
ApplicationInfo applicationInfo) {
|
||||
String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
|
||||
flagName, /* defaultValue= */ "");
|
||||
|
||||
// String#split returns a non-empty array given an empty string.
|
||||
if (configStr.isEmpty()) {
|
||||
if (configMap.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String packageEntryString : configStr.split(",")) {
|
||||
if (matchesApplicationInfo(packageEntryString, applicationInfo)) {
|
||||
return true;
|
||||
}
|
||||
if (!configMap.containsKey(applicationInfo.packageName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return matchesApplicationInfo(configMap.get(applicationInfo.packageName), applicationInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Parses the given {@code minMaxVersionCodes} and returns true if {@code
|
||||
* applicationInfo.longVersionCode} is within the version range in the pair.
|
||||
* Returns false otherwise.
|
||||
*
|
||||
* <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 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(String packageEntryStr,
|
||||
private static boolean matchesApplicationInfo(Pair<Long, Long> minMaxVersionCodes,
|
||||
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;
|
||||
return applicationInfo.longVersionCode >= minMaxVersionCodes.first
|
||||
&& applicationInfo.longVersionCode <= minMaxVersionCodes.second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -1777,6 +1783,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;
|
||||
@@ -7473,8 +7483,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());
|
||||
@@ -8035,11 +8045,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
|
||||
@@ -9055,6 +9065,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
|
||||
|
||||
Reference in New Issue
Block a user