From 5a38625968b58ceb9a29afecdee0d233f8cec68e Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Fri, 8 Jan 2021 01:04:34 +0000 Subject: [PATCH] Check deferred overrides when querying compat fw When checking the state of a change id for a package name, also consider deferred overrides. Test: atest PlatformCompatTest Bug: 158696818 Bug: 176432102 Change-Id: I0effd7860cab946876be07be722f88fe0b358994 --- .../android/server/compat/CompatChange.java | 13 +++++++ .../android/server/compat/CompatConfig.java | 19 +++++++++ .../android/server/compat/PlatformCompat.java | 3 ++ .../server/compat/PlatformCompatTest.java | 39 +++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index c4ff99bae6947..18907a19f96dd 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -212,6 +212,19 @@ public final class CompatChange extends CompatibilityChangeInfo { return true; } + /** + * Find if this change will be enabled for the given package after installation. + * + * @param packageName The package name in question + * @return {@code true} if the change should be enabled for the package. + */ + boolean willBeEnabled(String packageName) { + if (hasDeferredOverride(packageName)) { + return mDeferredOverrides.get(packageName); + } + return defaultValue(); + } + /** * Returns the default value for the change id, assuming there are no overrides. * diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index f03a608232a23..9376e8dc16eae 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -145,6 +145,25 @@ final class CompatConfig { } } + /** + * Find if a given change will be enabled for a given package name, prior to installation. + * + * @param changeId The ID of the change in question + * @param packageName Package name to check for + * @return {@code true} if the change would be enabled for this package name. Also returns + * {@code true} if the change ID is not known, as unknown changes are enabled by default. + */ + boolean willChangeBeEnabled(long changeId, String packageName) { + synchronized (mChanges) { + CompatChange c = mChanges.get(changeId); + if (c == null) { + // we know nothing about this change: default behaviour is enabled. + return true; + } + return c.willBeEnabled(packageName); + } + } + /** * Overrides the enabled state for a given change and app. This method is intended to be used * *only* for debugging purposes, ultimately invoked either by an adb command, or from some diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 283dba7aff8ad..1ea468c341d28 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -137,6 +137,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { @UserIdInt int userId) { checkCompatChangeReadAndLogPermission(); ApplicationInfo appInfo = getApplicationInfo(packageName, userId); + if (appInfo == null) { + return mCompatConfig.willChangeBeEnabled(changeId, packageName); + } return isChangeEnabled(changeId, appInfo); } 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 3f65a4621778e..a70c51045340c 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.testng.Assert.assertThrows; +import android.compat.Compatibility.ChangeConfig; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -35,6 +36,7 @@ import android.os.Build; import androidx.test.runner.AndroidJUnit4; import com.android.internal.compat.AndroidBuildClassifier; +import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.server.LocalServices; @@ -44,6 +46,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.HashSet; +import java.util.Set; + @RunWith(AndroidJUnit4.class) public class PlatformCompatTest { private static final String PACKAGE_NAME = "my.package"; @@ -70,6 +75,8 @@ public class PlatformCompatTest { new PackageManager.NameNotFoundException()); when(mPackageManagerInternal.getPackageUid(eq(PACKAGE_NAME), eq(0), anyInt())) .thenReturn(-1); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenThrow(new PackageManager.NameNotFoundException()); mCompatConfig = new CompatConfig(mBuildClassifier, mContext); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); // Assume userdebug/eng non-final build @@ -124,6 +131,38 @@ public class PlatformCompatTest { /*enableSince*/ Build.VERSION_CODES.R, false, false, "")); } + @Test + public void testOverrideAtInstallTime() throws Exception { + mCompatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithId(1L) + .addDisabledChangeWithId(2L) + .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L) + .build(); + mCompatConfig.forceNonDebuggableFinalForTest(true); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + + // Before adding overrides. + assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue(); + assertThat(mPlatformCompat.isChangeEnabledByPackageName(2, PACKAGE_NAME, 0)).isFalse(); + assertThat(mPlatformCompat.isChangeEnabledByPackageName(3, PACKAGE_NAME, 0)).isTrue(); + + // Add overrides. + Set enabled = new HashSet<>(); + enabled.add(2L); + Set disabled = new HashSet<>(); + disabled.add(1L); + disabled.add(3L); + ChangeConfig changeConfig = new ChangeConfig(enabled, disabled); + CompatibilityChangeConfig compatibilityChangeConfig = + new CompatibilityChangeConfig(changeConfig); + mPlatformCompat.setOverridesForTest(compatibilityChangeConfig, PACKAGE_NAME); + + // After adding overrides. + assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isFalse(); + assertThat(mPlatformCompat.isChangeEnabledByPackageName(2, PACKAGE_NAME, 0)).isTrue(); + assertThat(mPlatformCompat.isChangeEnabledByPackageName(3, PACKAGE_NAME, 0)).isFalse(); + } + @Test public void testRegisterListenerToSameIdThrows() throws Exception { // Registering a listener to change 1 is successful.