diff options
author | Andrei-Valentin Onea <andreionea@google.com> | 2021-03-12 13:28:50 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-03-12 13:28:50 +0000 |
commit | 420476e0cd622dffb64e68bd8daa65e0fb7e2037 (patch) | |
tree | 121f4fbe780a7f7ae8bb225da814474fecbc2049 | |
parent | af174a57088e7ee516ae78da30064aeb341f082b (diff) | |
parent | 7bf80c14accbfacfdb340eb86b741d25710a2133 (diff) |
Merge changes Idd7d86f9,I73569744
* changes:
Do not enable changes newer than the current sdk
Add support for loading a static overrides file located in /product.
10 files changed, 302 insertions, 80 deletions
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java index 0b937fad7df1..364db06976a0 100644 --- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java +++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java @@ -31,4 +31,14 @@ public class AndroidBuildClassifier { public boolean isFinalBuild() { return "REL".equals(Build.VERSION.CODENAME); } + + /** + * The current platform SDK version. + */ + public int platformTargetSdk() { + if (isFinalBuild()) { + return Build.VERSION.SDK_INT; + } + return Build.VERSION_CODES.CUR_DEVELOPMENT; + } } diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java index c0bbe5082131..e408be2ab471 100644 --- a/core/java/com/android/internal/compat/OverrideAllowedState.java +++ b/core/java/com/android/internal/compat/OverrideAllowedState.java @@ -34,7 +34,8 @@ public final class OverrideAllowedState implements Parcelable { DISABLED_NON_TARGET_SDK, DISABLED_TARGET_SDK_TOO_HIGH, DEFERRED_VERIFICATION, - LOGGING_ONLY_CHANGE + LOGGING_ONLY_CHANGE, + PLATFORM_TOO_OLD }) @Retention(RetentionPolicy.SOURCE) public @interface State { @@ -65,6 +66,10 @@ public final class OverrideAllowedState implements Parcelable { * Change is marked as logging only, and cannot be toggled. */ public static final int LOGGING_ONLY_CHANGE = 5; + /** + * Change is gated by a target sdk version newer than the current platform sdk version. + */ + public static final int PLATFORM_TOO_OLD = 6; @State public final int state; @@ -123,6 +128,11 @@ public final class OverrideAllowedState implements Parcelable { throw new SecurityException(String.format( "Cannot override %1$d because it is marked as a logging-only change.", changeId)); + case PLATFORM_TOO_OLD: + throw new SecurityException(String.format( + "Cannot override %1$d for %2$s because the change's targetSdk threshold " + + "(%3$d) is above the platform sdk.", + changeId, packageName, changeIdTargetSdk)); } } @@ -170,6 +180,8 @@ public final class OverrideAllowedState implements Parcelable { return "DEFERRED_VERIFICATION"; case LOGGING_ONLY_CHANGE: return "LOGGING_ONLY_CHANGE"; + case PLATFORM_TOO_OLD: + return "PLATFORM_TOO_OLD"; } return "UNKNOWN"; } diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index df83df9a73fb..ae9b0015de43 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.OverrideAllowedState; import com.android.server.compat.config.Change; @@ -55,7 +56,7 @@ public final class CompatChange extends CompatibilityChangeInfo { * A change ID to be used only in the CTS test for this SystemApi */ @ChangeId - @EnabledSince(targetSdkVersion = 1235) // Needs to be > test APK targetSdkVersion. + @EnabledSince(targetSdkVersion = 31) // Needs to be > test APK targetSdkVersion. static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id. /** @@ -80,6 +81,15 @@ public final class CompatChange extends CompatibilityChangeInfo { } /** + * @param change an object generated by services/core/xsd/platform-compat-config.xsd + */ + public CompatChange(Change change) { + this(change.getId(), change.getName(), change.getEnableAfterTargetSdk(), + change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(), + change.getDescription(), change.getOverridable()); + } + + /** * @param changeId Unique ID for the change. See {@link android.compat.Compatibility}. * @param name Short descriptive name. * @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter}; @@ -93,15 +103,10 @@ public final class CompatChange extends CompatibilityChangeInfo { boolean overridable) { super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly, description, overridable); - } - /** - * @param change an object generated by services/core/xsd/platform-compat-config.xsd - */ - public CompatChange(Change change) { - super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(), - change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(), - change.getDescription(), change.getOverridable()); + // Initialize override maps. + mEvaluatedOverrides = new HashMap<>(); + mRawOverrides = new HashMap<>(); } void registerListener(ChangeListener listener) { @@ -127,18 +132,13 @@ public final class CompatChange extends CompatibilityChangeInfo { throw new IllegalArgumentException( "Can't add overrides for a logging only change " + toString()); } - if (mEvaluatedOverrides == null) { - mEvaluatedOverrides = new HashMap<>(); - } mEvaluatedOverrides.put(pname, enabled); notifyListener(pname); } private void removePackageOverrideInternal(String pname) { - if (mEvaluatedOverrides != null) { - if (mEvaluatedOverrides.remove(pname) != null) { - notifyListener(pname); - } + if (mEvaluatedOverrides.remove(pname) != null) { + notifyListener(pname); } } @@ -157,9 +157,6 @@ public final class CompatChange extends CompatibilityChangeInfo { throw new IllegalArgumentException( "Can't add overrides for a logging only change " + toString()); } - if (mRawOverrides == null) { - mRawOverrides = new HashMap<>(); - } mRawOverrides.put(packageName, override); recheckOverride(packageName, allowedState, context); } @@ -212,7 +209,7 @@ public final class CompatChange extends CompatibilityChangeInfo { } boolean hasPackageOverride(String pname) { - return mRawOverrides != null && mRawOverrides.containsKey(pname); + return mRawOverrides.containsKey(pname); } /** * Remove any package override for the given package name, restoring the default behaviour. @@ -223,7 +220,7 @@ public final class CompatChange extends CompatibilityChangeInfo { */ boolean removePackageOverride(String pname, OverrideAllowedState allowedState, Context context) { - if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) { + if (mRawOverrides.remove(pname) != null) { recheckOverride(pname, allowedState, context); return true; } @@ -237,18 +234,24 @@ public final class CompatChange extends CompatibilityChangeInfo { * @param app Info about the app in question * @return {@code true} if the change should be enabled for the package. */ - boolean isEnabled(ApplicationInfo app) { + boolean isEnabled(ApplicationInfo app, AndroidBuildClassifier buildClassifier) { if (app == null) { return defaultValue(); } - if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) { + if (mEvaluatedOverrides.containsKey(app.packageName)) { return mEvaluatedOverrides.get(app.packageName); } if (getDisabled()) { return false; } if (getEnableSinceTargetSdk() != -1) { - return app.targetSdkVersion >= getEnableSinceTargetSdk(); + // If the change is gated by a platform version newer than the one currently installed + // on the device, disregard the app's target sdk version. + int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk()); + if (compareSdk != app.targetSdkVersion) { + compareSdk = app.targetSdkVersion; + } + return compareSdk >= getEnableSinceTargetSdk(); } return true; } @@ -289,7 +292,7 @@ public final class CompatChange extends CompatibilityChangeInfo { * @return true if there is such override */ private boolean hasOverride(String packageName) { - return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName); + return mEvaluatedOverrides.containsKey(packageName); } /** @@ -298,20 +301,15 @@ public final class CompatChange extends CompatibilityChangeInfo { * @return true if there is such a deferred override */ private boolean hasRawOverride(String packageName) { - return mRawOverrides != null && mRawOverrides.containsKey(packageName); + return mRawOverrides.containsKey(packageName); } - void loadOverrides(ChangeOverrides changeOverrides) { - if (mRawOverrides == null) { - mRawOverrides = new HashMap<>(); - } + void clearOverrides() { mRawOverrides.clear(); - - if (mEvaluatedOverrides == null) { - mEvaluatedOverrides = new HashMap<>(); - } mEvaluatedOverrides.clear(); + } + void loadOverrides(ChangeOverrides changeOverrides) { // Load deferred overrides for backwards compatibility if (changeOverrides.getDeferred() != null) { for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) { @@ -345,34 +343,30 @@ public final class CompatChange extends CompatibilityChangeInfo { } ChangeOverrides saveOverrides() { - if (mRawOverrides == null || mRawOverrides.isEmpty()) { + if (mRawOverrides.isEmpty()) { return null; } ChangeOverrides changeOverrides = new ChangeOverrides(); changeOverrides.setChangeId(getId()); ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw(); List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue(); - if (mRawOverrides != null) { - for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) { - RawOverrideValue override = new RawOverrideValue(); - override.setPackageName(entry.getKey()); - override.setMinVersionCode(entry.getValue().getMinVersionCode()); - override.setMaxVersionCode(entry.getValue().getMaxVersionCode()); - override.setEnabled(entry.getValue().getEnabled()); - rawList.add(override); - } + for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) { + RawOverrideValue override = new RawOverrideValue(); + override.setPackageName(entry.getKey()); + override.setMinVersionCode(entry.getValue().getMinVersionCode()); + override.setMaxVersionCode(entry.getValue().getMaxVersionCode()); + override.setEnabled(entry.getValue().getEnabled()); + rawList.add(override); } changeOverrides.setRaw(rawOverrides); ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated(); List<OverrideValue> validatedList = validatedOverrides.getOverrideValue(); - if (mEvaluatedOverrides != null) { - for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) { - OverrideValue override = new OverrideValue(); - override.setPackageName(entry.getKey()); - override.setEnabled(entry.getValue()); - validatedList.add(override); - } + for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) { + OverrideValue override = new OverrideValue(); + override.setPackageName(entry.getKey()); + override.setEnabled(entry.getValue()); + validatedList.add(override); } changeOverrides.setValidated(validatedOverrides); return changeOverrides; @@ -394,10 +388,10 @@ public final class CompatChange extends CompatibilityChangeInfo { if (getLoggingOnly()) { sb.append("; loggingOnly"); } - if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) { + if (!mEvaluatedOverrides.isEmpty()) { sb.append("; packageOverrides=").append(mEvaluatedOverrides); } - if (mRawOverrides != null && mRawOverrides.size() > 0) { + if (!mRawOverrides.isEmpty()) { sb.append("; rawOverrides=").append(mRawOverrides); } if (getOverridable()) { diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 66a652053857..ef86f42d6c3c 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -67,18 +67,21 @@ final class CompatConfig { private static final String TAG = "CompatConfig"; private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat"; + private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat"; private static final String OVERRIDES_FILE = "compat_framework_overrides.xml"; @GuardedBy("mChanges") private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); private final OverrideValidatorImpl mOverrideValidator; + private final AndroidBuildClassifier mAndroidBuildClassifier; private Context mContext; private File mOverridesFile; @VisibleForTesting CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this); + mAndroidBuildClassifier = androidBuildClassifier; mContext = context; } @@ -94,8 +97,7 @@ final class CompatConfig { config.initConfigFromLib(Environment.buildPath( apex.apexDirectory, "etc", "compatconfig")); } - File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE); - config.initOverrides(overridesFile); + config.initOverrides(); config.invalidateCache(); return config; } @@ -133,7 +135,7 @@ final class CompatConfig { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { CompatChange c = mChanges.valueAt(i); - if (!c.isEnabled(app)) { + if (!c.isEnabled(app, mAndroidBuildClassifier)) { disabled.add(c.getId()); } } @@ -175,7 +177,7 @@ final class CompatConfig { // we know nothing about this change: default behaviour is enabled. return true; } - return c.isEnabled(app); + return c.isEnabled(app, mAndroidBuildClassifier); } } @@ -475,7 +477,7 @@ final class CompatConfig { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { CompatChange c = mChanges.valueAt(i); - if (c.isEnabled(applicationInfo)) { + if (c.isEnabled(applicationInfo, mAndroidBuildClassifier)) { enabled.add(c.getId()); } else { disabled.add(c.getId()); @@ -525,10 +527,34 @@ final class CompatConfig { } } - void initOverrides(File overridesFile) { + private void initOverrides() { + initOverrides(new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE), + new File(STATIC_OVERRIDES_PRODUCT_DIR, OVERRIDES_FILE)); + } + + @VisibleForTesting + void initOverrides(File dynamicOverridesFile, File staticOverridesFile) { + // Clear overrides from all changes before loading. + synchronized (mChanges) { + for (int i = 0; i < mChanges.size(); ++i) { + mChanges.valueAt(i).clearOverrides(); + } + } + + loadOverrides(staticOverridesFile); + + mOverridesFile = dynamicOverridesFile; + loadOverrides(dynamicOverridesFile); + + if (staticOverridesFile.exists()) { + // Only save overrides if there is a static overrides file. + saveOverrides(); + } + } + + private void loadOverrides(File overridesFile) { if (!overridesFile.exists()) { - mOverridesFile = overridesFile; - // There have not been any overrides added yet. + // Overrides file doesn't exist. return; } @@ -548,7 +574,6 @@ final class CompatConfig { Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString()); return; } - mOverridesFile = overridesFile; } /** diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java index fe5b4a98797d..aa66a1a8b01f 100644 --- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java +++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java @@ -22,6 +22,7 @@ import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARG import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; +import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -85,6 +86,9 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { if (debuggableBuild) { return new OverrideAllowedState(ALLOWED, -1, -1); } + if (maxTargetSdk >= mAndroidBuildClassifier.platformTargetSdk()) { + return new OverrideAllowedState(PLATFORM_TOO_OLD, -1, maxTargetSdk); + } PackageManager packageManager = mContext.getPackageManager(); if (packageManager == null) { throw new IllegalStateException("No PackageManager!"); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index edfc8b8f31b0..40e386359a40 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -66,18 +66,22 @@ public class PlatformCompat extends IPlatformCompat.Stub { private final Context mContext; private final ChangeReporter mChangeReporter; private final CompatConfig mCompatConfig; + private final AndroidBuildClassifier mBuildClassifier; public PlatformCompat(Context context) { mContext = context; mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); - mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); + mBuildClassifier = new AndroidBuildClassifier(); + mCompatConfig = CompatConfig.create(mBuildClassifier, mContext); } @VisibleForTesting - PlatformCompat(Context context, CompatConfig compatConfig) { + PlatformCompat(Context context, CompatConfig compatConfig, + AndroidBuildClassifier buildClassifier) { mContext = context; mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = compatConfig; + mBuildClassifier = buildClassifier; registerPackageReceiver(context); } @@ -392,7 +396,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { return false; } if (change.getEnableSinceTargetSdk() > 0) { - return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q; + return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q + && change.getEnableSinceTargetSdk() <= mBuildClassifier.platformTargetSdk(); } return true; } diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java index f00edcc85404..fcd6b842426a 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -120,6 +120,11 @@ class CompatConfigBuilder { return this; } + CompatConfigBuilder addEnabledSinceApexChangeWithId(int sdk, long id) { + mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false)); + return this; + } + CompatConfig build() { CompatConfig config = new CompatConfig(mBuildClassifier, mContext); config.forceNonDebuggableFinalForTest(false); diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index 8b0e948579fb..bd774056aef8 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -86,6 +86,7 @@ public class CompatConfigTest { // Assume userdebug/eng non-final build when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); when(mBuildClassifier.isFinalBuild()).thenReturn(false); + when(mBuildClassifier.platformTargetSdk()).thenReturn(30); ChangeIdStateCache.disable(); when(mPackageManager.getApplicationInfo(anyString(), anyInt())) .thenThrow(new NameNotFoundException()); @@ -567,6 +568,34 @@ public class CompatConfigTest { } @Test + public void testReadApexConfig() throws IOException { + String configXml = "<config>" + + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />" + + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />" + + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />" + + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />" + + "</config>"; + + File dir = createTempDir(); + writeToFile(dir, "platform_compat_config.xml", configXml); + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + compatConfig.forceNonDebuggableFinalForTest(false); + + compatConfig.initConfigFromLib(dir); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1235L, + ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1236L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1237L, + ApplicationInfoBuilder.create().withTargetSdk(31).build())).isTrue(); + } + + @Test public void testReadConfigMultipleFiles() throws IOException { String configXml1 = "<config>" + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />" @@ -602,12 +631,12 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt())) .thenReturn(ApplicationInfoBuilder.create() - .withPackageName("foo.bar") - .debuggable() - .build()); + .withPackageName("foo.bar") + .debuggable() + .build()); when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt())) .thenThrow(new NameNotFoundException()); @@ -649,7 +678,7 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L, new PackageOverride.Builder() @@ -673,11 +702,11 @@ public class CompatConfigTest { } @Test - public void testLoadOverridesRaw() throws Exception { + public void testInitOverridesRaw() throws Exception { File tempDir = createTempDir(); File overridesFile = new File(tempDir, "overrides.xml"); // Change 1 is enabled for foo.bar (validated) - // Change 2 is disabled for bar.baz (deferred) + // Change 2 is disabled for bar.baz (raw) String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<overrides>\n" + " <change-overrides changeId=\"1\">\n" @@ -709,7 +738,7 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("foo.bar") .withVersionCode(100L) @@ -728,7 +757,7 @@ public class CompatConfigTest { } @Test - public void testLoadOverridesDeferred() throws Exception { + public void testInitOverridesDeferred() throws Exception { File tempDir = createTempDir(); File overridesFile = new File(tempDir, "overrides.xml"); // Change 1 is enabled for foo.bar (validated) @@ -754,7 +783,7 @@ public class CompatConfigTest { .addEnableSinceSdkChangeWithId(2, 2L) .build(); compatConfig.forceNonDebuggableFinalForTest(true); - compatConfig.initOverrides(overridesFile); + compatConfig.initOverrides(overridesFile, new File("")); ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("foo.bar") .debuggable() @@ -767,4 +796,115 @@ public class CompatConfigTest { assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue(); assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse(); } + + @Test + public void testInitOverridesWithStaticFile() throws Exception { + File tempDir = createTempDir(); + File dynamicOverridesFile = new File(tempDir, "dynamic_overrides.xml"); + File staticOverridesFile = new File(tempDir, "static_overrides.xml"); + // Change 1 is enabled for foo.bar (raw) + // Change 2 is disabled for bar.baz (raw) + String dynamicXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + + "<overrides>" + + "<change-overrides changeId=\"1\">" + + "<raw>" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "<change-overrides changeId=\"2\">" + + "<raw>" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "</overrides>"; + writeToFile(tempDir, "dynamic_overrides.xml", dynamicXmlData); + // Change 2 is enabled for foo.bar and bar.baz (raw) + // Change 3 is enabled for bar.baz (raw) + String staticXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + + "<overrides>" + + "<change-overrides changeId=\"2\">" + + "<raw>" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "<change-overrides changeId=\"3\">" + + "<raw>" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + "</raw>" + + "</change-overrides>" + + "</overrides>"; + writeToFile(tempDir, "static_overrides.xml", staticXmlData); + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1L) + .addDisabledChangeWithId(2L) + .addDisabledChangeWithId(3L) + .build(); + compatConfig.forceNonDebuggableFinalForTest(true); + // Adding an override that will be cleared after initOverrides is called. + compatConfig.addOverride(1L, "bar.baz", true); + compatConfig.initOverrides(dynamicOverridesFile, staticOverridesFile); + when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt())) + .thenThrow(new NameNotFoundException()); + when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt())) + .thenThrow(new NameNotFoundException()); + + assertThat(compatConfig.willChangeBeEnabled(1L, "foo.bar")).isTrue(); + assertThat(compatConfig.willChangeBeEnabled(2L, "foo.bar")).isTrue(); + assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse(); + assertThat(compatConfig.willChangeBeEnabled(3L, "bar.baz")).isTrue(); + assertThat(readFile(dynamicOverridesFile)) + .isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<overrides>\n" + + " <change-overrides changeId=\"1\">\n" + + " <validated>\n" + + " </validated>\n" + + " <raw>\n" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " </raw>\n" + + " </change-overrides>\n" + + " <change-overrides changeId=\"2\">\n" + + " <validated>\n" + + " </validated>\n" + + " <raw>\n" + + " <raw-override-value packageName=\"foo.bar\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n" + + " </raw-override-value>\n" + + " </raw>\n" + + " </change-overrides>\n" + + " <change-overrides changeId=\"3\">\n" + + " <validated>\n" + + " </validated>\n" + + " <raw>\n" + + " <raw-override-value packageName=\"bar.baz\" " + + "minVersionCode=\"-9223372036854775808\" " + + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n" + + " </raw-override-value>\n" + + " </raw>\n" + + " </change-overrides>\n" + + "</overrides>\n"); + } } diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java index 0fd6445fbeeb..57fdcd340a02 100644 --- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java @@ -22,6 +22,7 @@ import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARG import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; +import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD; import static com.google.common.truth.Truth.assertThat; @@ -52,6 +53,7 @@ public class OverrideValidatorImplTest { private static final int TARGET_SDK = 10; private static final int TARGET_SDK_BEFORE = 9; private static final int TARGET_SDK_AFTER = 11; + private static final int PLATFORM_SDK_VERSION = 30; @Mock private PackageManager mPackageManager; @@ -61,6 +63,7 @@ public class OverrideValidatorImplTest { private AndroidBuildClassifier debuggableBuild() { AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); when(buildClassifier.isDebuggableBuild()).thenReturn(true); + when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION); return buildClassifier; } @@ -68,6 +71,7 @@ public class OverrideValidatorImplTest { AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); when(buildClassifier.isDebuggableBuild()).thenReturn(false); when(buildClassifier.isFinalBuild()).thenReturn(false); + when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION); return buildClassifier; } @@ -75,6 +79,7 @@ public class OverrideValidatorImplTest { AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); when(buildClassifier.isDebuggableBuild()).thenReturn(false); when(buildClassifier.isFinalBuild()).thenReturn(true); + when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION); return buildClassifier; } @@ -333,6 +338,26 @@ public class OverrideValidatorImplTest { } @Test + public void getOverrideAllowedState_targetSdkChangeGreaterThanOsVersion_rejectOverride() + throws Exception { + final AndroidBuildClassifier buildClassifier = finalBuild(); + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addEnabledSinceApexChangeWithId(PLATFORM_SDK_VERSION + 1, 1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable() + .build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + assertThat(stateTargetSdkLessChange).isEqualTo( + new OverrideAllowedState(PLATFORM_TOO_OLD, -1, + PLATFORM_SDK_VERSION)); + } + + @Test public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride() throws Exception { CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index 799b06734b54..3fc6e9918382 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -78,11 +78,12 @@ public class PlatformCompatTest { when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) .thenThrow(new PackageManager.NameNotFoundException()); mCompatConfig = new CompatConfig(mBuildClassifier, mContext); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); // Assume userdebug/eng non-final build mCompatConfig.forceNonDebuggableFinalForTest(false); when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); when(mBuildClassifier.isFinalBuild()).thenReturn(false); + when(mBuildClassifier.platformTargetSdk()).thenReturn(30); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); } @@ -99,7 +100,7 @@ public class PlatformCompatTest { .addLoggingOnlyChangeWithId(7L) .addOverridableChangeWithId(8L) .build(); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly( new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), @@ -125,8 +126,9 @@ public class PlatformCompatTest { .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L) .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L) .addLoggingOnlyChangeWithId(7L) + .addEnableSinceSdkChangeWithId(31, 8L) .build(); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly( new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), @@ -144,7 +146,7 @@ public class PlatformCompatTest { .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L) .build(); mCompatConfig.forceNonDebuggableFinalForTest(true); - mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); // Before adding overrides. assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue(); |