diff options
10 files changed, 330 insertions, 18 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7e729e55071b..f7e28fc57aa3 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1124,10 +1124,11 @@ package android.app.backup { package android.app.compat { public final class CompatChanges { + method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void addPackageOverrides(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>); method public static boolean isChangeEnabled(long); method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int); - method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void setPackageOverride(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>); + method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removePackageOverrides(@NonNull String, @NonNull java.util.Set<java.lang.Long>); } public final class PackageOverride { diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java index 74e1ece3fa89..8ca43c4a8e70 100644 --- a/core/java/android/app/compat/CompatChanges.java +++ b/core/java/android/app/compat/CompatChanges.java @@ -26,9 +26,11 @@ import android.os.ServiceManager; import android.os.UserHandle; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import com.android.internal.compat.IPlatformCompat; import java.util.Map; +import java.util.Set; /** * CompatChanges APIs - to be used by platform code only (including mainline @@ -98,15 +100,19 @@ public final class CompatChanges { } /** - * Set an app compat override for a given package. This will check whether the caller is allowed + * Adds app compat overrides for a given package. This will check whether the caller is allowed * to perform this operation on the given apk and build. Only the installer package is allowed * to set overrides on a non-debuggable final build and a non-test apk. * + * <p>Note that calling this method doesn't remove previously added overrides for the given + * package if their change ID isn't in the given map, only replaces those that have the same + * change ID. + * * @param packageName The package name of the app in question. - * @param overrides A map from changeId to the override applied for this change id. + * @param overrides A map from change ID to the override applied for this change ID. */ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) - public static void setPackageOverride(@NonNull String packageName, + public static void addPackageOverrides(@NonNull String packageName, @NonNull Map<Long, PackageOverride> overrides) { IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); @@ -117,4 +123,29 @@ public final class CompatChanges { e.rethrowFromSystemServer(); } } + + /** + * Removes app compat overrides for a given package. This will check whether the caller is + * allowed to perform this operation on the given apk and build. Only the installer package is + * allowed to clear overrides on a non-debuggable final build and a non-test apk. + * + * <p>Note that calling this method with an empty set is a no-op and no overrides will be + * removed for the given package. + * + * @param packageName The package name of the app in question. + * @param overridesToRemove A set of change IDs for which to remove overrides. + */ + @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) + public static void removePackageOverrides(@NonNull String packageName, + @NonNull Set<Long> overridesToRemove) { + IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + try { + platformCompat.removeOverridesOnReleaseBuilds(config, packageName); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl new file mode 100644 index 000000000000..441e553e4d88 --- /dev/null +++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.aidl @@ -0,0 +1,19 @@ +/* + * 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 com.android.internal.compat; + +parcelable CompatibilityOverridesToRemoveConfig; diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java new file mode 100644 index 000000000000..642f79ca7afa --- /dev/null +++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java @@ -0,0 +1,72 @@ +/* + * 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 com.android.internal.compat; + + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashSet; +import java.util.Set; + +/** + * Parcelable containing compat config change IDs for which to remove overrides for a given + * application. + * @hide + */ +public final class CompatibilityOverridesToRemoveConfig implements Parcelable { + public final Set<Long> changeIds; + + public CompatibilityOverridesToRemoveConfig(Set<Long> changeIds) { + this.changeIds = changeIds; + } + + private CompatibilityOverridesToRemoveConfig(Parcel in) { + int keyCount = in.readInt(); + changeIds = new HashSet<>(); + for (int i = 0; i < keyCount; i++) { + changeIds.add(in.readLong()); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(changeIds.size()); + for (Long changeId : changeIds) { + dest.writeLong(changeId); + } + } + + public static final Creator<CompatibilityOverridesToRemoveConfig> CREATOR = + new Creator<CompatibilityOverridesToRemoveConfig>() { + + @Override + public CompatibilityOverridesToRemoveConfig createFromParcel(Parcel in) { + return new CompatibilityOverridesToRemoveConfig(in); + } + + @Override + public CompatibilityOverridesToRemoveConfig[] newArray(int size) { + return new CompatibilityOverridesToRemoveConfig[size]; + } + }; +} diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 78d1d22c401e..c9f170421e7b 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -22,6 +22,7 @@ import java.util.Map; parcelable CompatibilityChangeConfig; parcelable CompatibilityOverrideConfig; +parcelable CompatibilityOverridesToRemoveConfig; parcelable CompatibilityChangeInfo; /** * Platform private API for talking with the PlatformCompat service. @@ -204,6 +205,27 @@ interface IPlatformCompat { void clearOverrideForTest(long changeId, String packageName); /** + * Restores the default behaviour for compatibility changes on release builds. + * + * <p>The caller to this API needs to hold + * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids + * in {@code overridesToRemove} need to annotated with + * {@link android.compat.annotation.Overridable}. + * + * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to + * be {@code false}. + * + * <p>Note that this does not kill the app, and therefore overrides read from the app process + * will not be updated. Overrides read from the system process do take effect. + * + * @param overridesToRemove parcelable containing the compat change overrides to be removed + * @param packageName the package name of the app whose changes will be restored to the + * default behaviour + * @throws SecurityException if overriding changes is not permitted + */ + void removeOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveConfig overridesToRemove, in String packageName); + + /** * Enables all compatibility changes that have enabledSinceTargetSdk == * {@param targetSdkVersion} for an app, subject to the policy. * diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 55e269630093..924756889408 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -33,6 +33,7 @@ import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import com.android.internal.compat.IOverrideValidator; import com.android.internal.compat.OverrideAllowedState; import com.android.server.compat.config.Change; @@ -370,6 +371,27 @@ final class CompatConfig { } } + /** + * Removes overrides whose change ID is specified in {@code overridesToRemove} that were + * previously added via {@link #addOverride(long, String, boolean)} or + * {@link #addOverrides(CompatibilityOverrideConfig, String)} for a certain package. + * + * <p>This restores the default behaviour for the given change IDs and app. + * + * @param overridesToRemove list of change IDs for which to restore the default behaviour. + * @param packageName the package for which the overrides should be purged + */ + void removePackageOverrides(CompatibilityOverridesToRemoveConfig overridesToRemove, + String packageName) { + synchronized (mChanges) { + for (Long changeId : overridesToRemove.changeIds) { + removeOverrideUnsafe(changeId, packageName); + } + saveOverrides(); + invalidateCache(); + } + } + private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName, int targetSdkVersion) { LongArray allowed = new LongArray(); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 20469a21db0c..2591f38b2bb3 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -46,6 +46,7 @@ import com.android.internal.compat.ChangeReporter; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import com.android.internal.compat.IOverrideValidator; import com.android.internal.compat.IPlatformCompat; import com.android.internal.util.DumpUtils; @@ -54,6 +55,7 @@ import com.android.server.LocalServices; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -187,7 +189,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { String packageName) { // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods. checkCompatChangeOverrideOverridablePermission(); - checkAllCompatOverridesAreOverridable(overrides); + checkAllCompatOverridesAreOverridable(overrides.overrides.keySet()); mCompatConfig.addOverrides(overrides, packageName); } @@ -251,6 +253,16 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public void removeOverridesOnReleaseBuilds( + CompatibilityOverridesToRemoveConfig overridesToRemove, + String packageName) { + // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods. + checkCompatChangeOverrideOverridablePermission(); + checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds); + mCompatConfig.removePackageOverrides(overridesToRemove, packageName); + } + + @Override public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) { checkCompatChangeReadAndLogPermission(); return mCompatConfig.getAppConfig(appInfo); @@ -396,8 +408,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } - private void checkAllCompatOverridesAreOverridable(CompatibilityOverrideConfig overrides) { - for (Long changeId : overrides.overrides.keySet()) { + private void checkAllCompatOverridesAreOverridable(Collection<Long> changeIds) { + for (Long changeId : changeIds) { if (!mCompatConfig.isOverridable(changeId)) { throw new SecurityException("Only change ids marked as Overridable can be " + "overridden."); 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 7bdc87ef6bd7..6b9aa18b9f8f 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -115,7 +115,12 @@ class CompatConfigBuilder { return this; } - CompatConfigBuilder addOverridableChangeWithId(long id) { + CompatConfigBuilder addEnabledOverridableChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, -1, false, false, "", true)); + return this; + } + + CompatConfigBuilder addDisabledOverridableChangeWithId(long id) { mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", true)); return this; } 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 a866363f46e6..0248b9b88788 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -36,6 +36,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityOverrideConfig; +import com.android.internal.compat.CompatibilityOverridesToRemoveConfig; import org.junit.Before; import org.junit.Test; @@ -50,6 +51,10 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; @RunWith(AndroidJUnit4.class) @@ -249,7 +254,7 @@ public class CompatConfigTest { when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) .thenReturn(applicationInfo); - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(true); @@ -261,10 +266,12 @@ public class CompatConfigTest { @Test public void testInstallerCanSetOverrides() throws Exception { - final long changeId = 1234L; - final int installerUid = 23; + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + // We make disabledChangeId2 non-overridable to make sure it is ignored. CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) - .addOverridableChangeWithId(1234L) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) .build(); ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("com.some.package") @@ -274,19 +281,56 @@ public class CompatConfigTest { when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) .thenReturn(applicationInfo); - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(true); CompatibilityOverrideConfig config = new CompatibilityOverrideConfig( - Collections.singletonMap(1234L, + Collections.singletonMap(disabledChangeId1, new PackageOverride.Builder() .setMaxVersionCode(99L) .setEnabled(true) .build())); compatConfig.addOverrides(config, "com.some.package"); - assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isFalse(); + } + + @Test + public void testPreventInstallerSetNonOverridable() throws Exception { + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + final long disabledChangeId3 = 1236L; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) + .addDisabledOverridableChangeWithId(disabledChangeId3) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + // Force the validator to prevent overriding non-overridable changes by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + Map<Long, PackageOverride> overrides = new HashMap<>(); + overrides.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build()); + overrides.put(disabledChangeId2, new PackageOverride.Builder().setEnabled(true).build()); + overrides.put(disabledChangeId3, new PackageOverride.Builder().setEnabled(true).build()); + CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides); + + assertThrows(SecurityException.class, + () -> compatConfig.addOverrides(config, "com.some.package") + ); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isFalse(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isFalse(); } @Test @@ -459,7 +503,7 @@ public class CompatConfigTest { assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); // Reject all override attempts. - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(false); // Try to turn off change, but validator prevents it. @@ -481,7 +525,7 @@ public class CompatConfigTest { .thenReturn(applicationInfo); // Reject all override attempts. - // Force the validator to prevent overriding the change by using a user build. + // Force the validator to prevent overriding non-overridable changes by using a user build. when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(true); // Try to remove a non existing override, and it doesn't fail. @@ -509,6 +553,90 @@ public class CompatConfigTest { } @Test + public void testInstallerCanRemoveOverrides() throws Exception { + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + final long enabledChangeId = 1236L; + // We make disabledChangeId2 non-overridable to make sure it is ignored. + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) + .addEnabledOverridableChangeWithId(enabledChangeId) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + assertThat(compatConfig.addOverride(disabledChangeId1, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(disabledChangeId2, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(enabledChangeId, "com.some.package", false)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo)).isFalse(); + + // Force the validator to prevent overriding non-overridable changes by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + Set<Long> overridesToRemove = new HashSet<>(); + overridesToRemove.add(disabledChangeId1); + overridesToRemove.add(enabledChangeId); + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + + compatConfig.removePackageOverrides(config, "com.some.package"); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isFalse(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo)).isTrue(); + } + + @Test + public void testPreventInstallerRemoveNonOverridable() throws Exception { + final long disabledChangeId1 = 1234L; + final long disabledChangeId2 = 1235L; + final long disabledChangeId3 = 1236L; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledOverridableChangeWithId(disabledChangeId1) + .addDisabledChangeWithId(disabledChangeId2) + .addDisabledOverridableChangeWithId(disabledChangeId3) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + assertThat(compatConfig.addOverride(disabledChangeId1, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(disabledChangeId2, "com.some.package", true)).isTrue(); + assertThat(compatConfig.addOverride(disabledChangeId3, "com.some.package", true)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isTrue(); + + // Force the validator to prevent overriding non-overridable changes by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + Set<Long> overridesToRemove = new HashSet<>(); + overridesToRemove.add(disabledChangeId1); + overridesToRemove.add(disabledChangeId2); + overridesToRemove.add(disabledChangeId3); + CompatibilityOverridesToRemoveConfig config = new CompatibilityOverridesToRemoveConfig( + overridesToRemove); + + assertThrows(SecurityException.class, + () -> compatConfig.removePackageOverrides(config, "com.some.package") + ); + assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo)).isFalse(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo)).isTrue(); + assertThat(compatConfig.isChangeEnabled(disabledChangeId3, applicationInfo)).isTrue(); + } + + @Test public void testEnableTargetSdkChangesForPackage() throws Exception { CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) .addEnabledChangeWithId(1L) 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 a2664e5f3b0a..9accd49bc392 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -98,7 +98,7 @@ public class PlatformCompatTest { .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L) .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L) .addLoggingOnlyChangeWithId(7L) - .addOverridableChangeWithId(8L) + .addDisabledOverridableChangeWithId(8L) .build(); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier); assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly( |