Merge changes from topic "preinstall-overrides" am: 29ed176b46

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1520701

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I916e47454ada9ffe6b0eba017807baa8d904ea44
This commit is contained in:
Andrei-Valentin Onea
2021-01-07 17:15:02 +00:00
committed by Automerger Merge Worker
13 changed files with 540 additions and 65 deletions

View File

@@ -13283,6 +13283,16 @@ public final class Settings {
@TestApi @TestApi
public static final String HIDDEN_API_POLICY = "hidden_api_policy"; public static final String HIDDEN_API_POLICY = "hidden_api_policy";
/**
* Flag for forcing {@link com.android.server.compat.OverrideValidatorImpl}
* to consider this a non-debuggable build.
*
* @hide
*/
public static final String FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT =
"force_non_debuggable_final_build_for_compat";
/** /**
* Current version of signed configuration applied. * Current version of signed configuration applied.
* *

View File

@@ -33,7 +33,7 @@ public final class OverrideAllowedState implements Parcelable {
DISABLED_NOT_DEBUGGABLE, DISABLED_NOT_DEBUGGABLE,
DISABLED_NON_TARGET_SDK, DISABLED_NON_TARGET_SDK,
DISABLED_TARGET_SDK_TOO_HIGH, DISABLED_TARGET_SDK_TOO_HIGH,
PACKAGE_DOES_NOT_EXIST, DEFERRED_VERIFICATION,
LOGGING_ONLY_CHANGE LOGGING_ONLY_CHANGE
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@@ -57,10 +57,10 @@ public final class OverrideAllowedState implements Parcelable {
* Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk. * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk.
*/ */
public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3; public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3;
/** /**
* Package does not exist. * Change override decision is currently being deferred, due to the app not being installed yet.
*/ */
public static final int PACKAGE_DOES_NOT_EXIST = 4; public static final int DEFERRED_VERIFICATION = 4;
/** /**
* Change is marked as logging only, and cannot be toggled. * Change is marked as logging only, and cannot be toggled.
*/ */
@@ -106,6 +106,7 @@ public final class OverrideAllowedState implements Parcelable {
throws SecurityException { throws SecurityException {
switch (state) { switch (state) {
case ALLOWED: case ALLOWED:
case DEFERRED_VERIFICATION:
return; return;
case DISABLED_NOT_DEBUGGABLE: case DISABLED_NOT_DEBUGGABLE:
throw new SecurityException( throw new SecurityException(
@@ -118,11 +119,6 @@ public final class OverrideAllowedState implements Parcelable {
"Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is " "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is "
+ "above the change's targetSdk threshold (%4$d)", + "above the change's targetSdk threshold (%4$d)",
changeId, packageName, appTargetSdk, changeIdTargetSdk)); changeId, packageName, appTargetSdk, changeIdTargetSdk));
case PACKAGE_DOES_NOT_EXIST:
throw new SecurityException(String.format(
"Cannot override %1$d for %2$s because the package does not exist, and "
+ "the change is targetSdk gated.",
changeId, packageName));
case LOGGING_ONLY_CHANGE: case LOGGING_ONLY_CHANGE:
throw new SecurityException(String.format( throw new SecurityException(String.format(
"Cannot override %1$d because it is marked as a logging-only change.", "Cannot override %1$d because it is marked as a logging-only change.",
@@ -170,8 +166,8 @@ public final class OverrideAllowedState implements Parcelable {
return "DISABLED_NON_TARGET_SDK"; return "DISABLED_NON_TARGET_SDK";
case DISABLED_TARGET_SDK_TOO_HIGH: case DISABLED_TARGET_SDK_TOO_HIGH:
return "DISABLED_TARGET_SDK_TOO_HIGH"; return "DISABLED_TARGET_SDK_TOO_HIGH";
case PACKAGE_DOES_NOT_EXIST: case DEFERRED_VERIFICATION:
return "PACKAGE_DOES_NOT_EXIST"; return "DEFERRED_VERIFICATION";
case LOGGING_ONLY_CHANGE: case LOGGING_ONLY_CHANGE:
return "LOGGING_ONLY_CHANGE"; return "LOGGING_ONLY_CHANGE";
} }

View File

@@ -300,6 +300,7 @@ public class SettingsBackupTest {
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HIDDEN_API_POLICY, Settings.Global.HIDDEN_API_POLICY,
Settings.Global.FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT,
Settings.Global.HIDE_ERROR_DIALOGS, Settings.Global.HIDE_ERROR_DIALOGS,
Settings.Global.HTTP_PROXY, Settings.Global.HTTP_PROXY,
HYBRID_SYSUI_BATTERY_WARNING_FLAGS, HYBRID_SYSUI_BATTERY_WARNING_FLAGS,

View File

@@ -9481,6 +9481,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final long waitForNetworkTimeoutMs = Settings.Global.getLong(resolver, final long waitForNetworkTimeoutMs = Settings.Global.getLong(resolver,
NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS); NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
mHiddenApiBlacklist.registerObserver(); mHiddenApiBlacklist.registerObserver();
mPlatformCompat.registerContentObserver();
final long pssDeferralMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, final long pssDeferralMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ACTIVITY_START_PSS_DEFER_CONFIG, 0L); ACTIVITY_START_PSS_DEFER_CONFIG, 0L);

View File

@@ -61,6 +61,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
ChangeListener mListener = null; ChangeListener mListener = null;
private Map<String, Boolean> mPackageOverrides; private Map<String, Boolean> mPackageOverrides;
private Map<String, Boolean> mDeferredOverrides;
public CompatChange(long changeId) { public CompatChange(long changeId) {
this(changeId, null, -1, -1, false, false, null); this(changeId, null, -1, -1, false, false, null);
@@ -120,6 +121,56 @@ public final class CompatChange extends CompatibilityChangeInfo {
notifyListener(pname); notifyListener(pname);
} }
/**
* Tentatively set the state of this change for a given package name.
* The override will only take effect after that package is installed, if applicable.
*
* <p>Note, this method is not thread safe so callers must ensure thread safety.
*
* @param packageName Package name to tentatively enable the change for.
* @param enabled Whether or not to enable the change.
*/
void addPackageDeferredOverride(String packageName, boolean enabled) {
if (getLoggingOnly()) {
throw new IllegalArgumentException(
"Can't add overrides for a logging only change " + toString());
}
if (mDeferredOverrides == null) {
mDeferredOverrides = new HashMap<>();
}
mDeferredOverrides.put(packageName, enabled);
}
/**
* Rechecks an existing (and possibly deferred) override.
*
* <p>For deferred overrides, check if they can be promoted to a regular override. For regular
* overrides, check if they need to be demoted to deferred.</p>
*
* @param packageName Package name to apply deferred overrides for.
* @param allowed Whether the override is allowed.
*
* @return {@code true} if the recheck yielded a result that requires invalidating caches
* (a deferred override was consolidated or a regular override was removed).
*/
boolean recheckOverride(String packageName, boolean allowed) {
// A deferred override now is allowed by the policy, so promote it to a regular override.
if (hasDeferredOverride(packageName) && allowed) {
boolean overrideValue = mDeferredOverrides.remove(packageName);
addPackageOverride(packageName, overrideValue);
return true;
}
// A previously set override is no longer allowed by the policy, so make it deferred.
if (hasOverride(packageName) && !allowed) {
boolean overrideValue = mPackageOverrides.remove(packageName);
addPackageDeferredOverride(packageName, overrideValue);
// Notify because the override was removed.
notifyListener(packageName);
return true;
}
return false;
}
/** /**
* Remove any package override for the given package name, restoring the default behaviour. * Remove any package override for the given package name, restoring the default behaviour.
* *
@@ -133,6 +184,9 @@ public final class CompatChange extends CompatibilityChangeInfo {
notifyListener(pname); notifyListener(pname);
} }
} }
if (mDeferredOverrides != null) {
mDeferredOverrides.remove(pname);
}
} }
/** /**
@@ -176,6 +230,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
return mPackageOverrides != null && mPackageOverrides.containsKey(packageName); return mPackageOverrides != null && mPackageOverrides.containsKey(packageName);
} }
/**
* Checks whether a change has a deferred override for a package.
* @param packageName name of the package
* @return true if there is such a deferred override
*/
boolean hasDeferredOverride(String packageName) {
return mDeferredOverrides != null && mDeferredOverrides.containsKey(packageName);
}
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder("ChangeId(") StringBuilder sb = new StringBuilder("ChangeId(")
@@ -195,6 +258,9 @@ public final class CompatChange extends CompatibilityChangeInfo {
if (mPackageOverrides != null && mPackageOverrides.size() > 0) { if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
sb.append("; packageOverrides=").append(mPackageOverrides); sb.append("; packageOverrides=").append(mPackageOverrides);
} }
if (mDeferredOverrides != null && mDeferredOverrides.size() > 0) {
sb.append("; deferredOverrides=").append(mDeferredOverrides);
}
return sb.append(")").toString(); return sb.append(")").toString();
} }

View File

@@ -65,7 +65,7 @@ final class CompatConfig {
@GuardedBy("mChanges") @GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
private IOverrideValidator mOverrideValidator; private OverrideValidatorImpl mOverrideValidator;
@VisibleForTesting @VisibleForTesting
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
@@ -161,7 +161,7 @@ final class CompatConfig {
* @return {@code true} if the change existed before adding the override. * @return {@code true} if the change existed before adding the override.
*/ */
boolean addOverride(long changeId, String packageName, boolean enabled) boolean addOverride(long changeId, String packageName, boolean enabled)
throws RemoteException, SecurityException { throws SecurityException {
boolean alreadyKnown = true; boolean alreadyKnown = true;
OverrideAllowedState allowedState = OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(changeId, packageName); mOverrideValidator.getOverrideAllowedState(changeId, packageName);
@@ -173,7 +173,17 @@ final class CompatConfig {
c = new CompatChange(changeId); c = new CompatChange(changeId);
addChange(c); addChange(c);
} }
c.addPackageOverride(packageName, enabled); switch (allowedState.state) {
case OverrideAllowedState.ALLOWED:
c.addPackageOverride(packageName, enabled);
break;
case OverrideAllowedState.DEFERRED_VERIFICATION:
c.addPackageDeferredOverride(packageName, enabled);
break;
default:
throw new IllegalStateException("Should only be able to override changes that "
+ "are allowed or can be deferred.");
}
invalidateCache(); invalidateCache();
} }
return alreadyKnown; return alreadyKnown;
@@ -244,26 +254,26 @@ final class CompatConfig {
* @return {@code true} if an override existed; * @return {@code true} if an override existed;
*/ */
boolean removeOverride(long changeId, String packageName) boolean removeOverride(long changeId, String packageName)
throws RemoteException, SecurityException { throws SecurityException {
boolean overrideExists = false; boolean overrideExists = false;
synchronized (mChanges) { synchronized (mChanges) {
CompatChange c = mChanges.get(changeId); CompatChange c = mChanges.get(changeId);
try { if (c != null) {
if (c != null) { // Always allow removing a deferred override.
overrideExists = c.hasOverride(packageName); if (c.hasDeferredOverride(packageName)) {
if (overrideExists) { c.removePackageOverride(packageName);
OverrideAllowedState allowedState = overrideExists = true;
mOverrideValidator.getOverrideAllowedState(changeId, packageName); } else if (c.hasOverride(packageName)) {
allowedState.enforce(changeId, packageName); // Regular overrides need to pass the policy.
c.removePackageOverride(packageName); overrideExists = true;
} OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
allowedState.enforce(changeId, packageName);
c.removePackageOverride(packageName);
} }
} catch (RemoteException e) {
// Should never occur, since validator is in the same process.
throw new RuntimeException("Unable to call override validator!", e);
} }
invalidateCache();
} }
invalidateCache();
return overrideExists; return overrideExists;
} }
@@ -293,29 +303,15 @@ final class CompatConfig {
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or * Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
* {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package. * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
* *
* <p>This restores the default behaviour for the given change and app, once any app * <p>This restores the default behaviour for the given app.
* processes have been restarted.
* *
* @param packageName The package for which the overrides should be purged. * @param packageName The package for which the overrides should be purged.
*/ */
void removePackageOverrides(String packageName) throws RemoteException, SecurityException { void removePackageOverrides(String packageName) throws SecurityException {
synchronized (mChanges) { synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) { for (int i = 0; i < mChanges.size(); ++i) {
try { CompatChange change = mChanges.valueAt(i);
CompatChange change = mChanges.valueAt(i); removeOverride(change.getId(), packageName);
if (change.hasOverride(packageName)) {
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(change.getId(),
packageName);
allowedState.enforce(change.getId(), packageName);
if (change != null) {
mChanges.valueAt(i).removePackageOverride(packageName);
}
}
} catch (RemoteException e) {
// Should never occur, since validator is in the same process.
throw new RuntimeException("Unable to call override validator!", e);
}
} }
invalidateCache(); invalidateCache();
} }
@@ -327,20 +323,15 @@ final class CompatConfig {
LongArray allowed = new LongArray(); LongArray allowed = new LongArray();
synchronized (mChanges) { synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) { for (int i = 0; i < mChanges.size(); ++i) {
try { CompatChange change = mChanges.valueAt(i);
CompatChange change = mChanges.valueAt(i); if (change.getEnableSinceTargetSdk() != targetSdkVersion) {
if (change.getEnableSinceTargetSdk() != targetSdkVersion) { continue;
continue; }
} OverrideAllowedState allowedState =
OverrideAllowedState allowedState = mOverrideValidator.getOverrideAllowedState(change.getId(),
mOverrideValidator.getOverrideAllowedState(change.getId(), packageName);
packageName); if (allowedState.state == OverrideAllowedState.ALLOWED) {
if (allowedState.state == OverrideAllowedState.ALLOWED) { allowed.add(change.getId());
allowed.add(change.getId());
}
} catch (RemoteException e) {
// Should never occur, since validator is in the same process.
throw new RuntimeException("Unable to call override validator!", e);
} }
} }
} }
@@ -400,6 +391,11 @@ final class CompatConfig {
return c.defaultValue(); return c.defaultValue();
} }
@VisibleForTesting
void forceNonDebuggableFinalForTest(boolean value) {
mOverrideValidator.forceNonDebuggableFinalForTest(value);
}
@VisibleForTesting @VisibleForTesting
void clearChanges() { void clearChanges() {
synchronized (mChanges) { synchronized (mChanges) {
@@ -511,4 +507,26 @@ final class CompatConfig {
private void invalidateCache() { private void invalidateCache() {
ChangeIdStateCache.invalidate(); ChangeIdStateCache.invalidate();
} }
/**
* Rechecks all the existing overrides for a package.
*/
void recheckOverrides(String packageName) {
synchronized (mChanges) {
boolean shouldInvalidateCache = false;
for (int idx = 0; idx < mChanges.size(); ++idx) {
CompatChange c = mChanges.valueAt(idx);
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
boolean allowedOverride = (allowedState.state == OverrideAllowedState.ALLOWED);
shouldInvalidateCache |= c.recheckOverride(packageName, allowedOverride);
}
if (shouldInvalidateCache) {
invalidateCache();
}
}
}
void registerContentObserver() {
mOverrideValidator.registerContentObserver();
}
} }

View File

@@ -17,16 +17,19 @@
package com.android.server.compat; package com.android.server.compat;
import static com.android.internal.compat.OverrideAllowedState.ALLOWED; import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
import static com.android.internal.compat.OverrideAllowedState.DEFERRED_VERIFICATION;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; 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.DISABLED_TARGET_SDK_TOO_HIGH;
import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.os.Handler;
import android.provider.Settings;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.AndroidBuildClassifier;
@@ -41,6 +44,20 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
private AndroidBuildClassifier mAndroidBuildClassifier; private AndroidBuildClassifier mAndroidBuildClassifier;
private Context mContext; private Context mContext;
private CompatConfig mCompatConfig; private CompatConfig mCompatConfig;
private boolean mForceNonDebuggableFinalBuild;
private class SettingsObserver extends ContentObserver {
SettingsObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange) {
mForceNonDebuggableFinalBuild = Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT,
0) == 1;
}
}
@VisibleForTesting @VisibleForTesting
OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier, OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier,
@@ -48,6 +65,7 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
mAndroidBuildClassifier = androidBuildClassifier; mAndroidBuildClassifier = androidBuildClassifier;
mContext = context; mContext = context;
mCompatConfig = config; mCompatConfig = config;
mForceNonDebuggableFinalBuild = false;
} }
@Override @Override
@@ -56,8 +74,10 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1); return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1);
} }
boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild(); boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild()
boolean finalBuild = mAndroidBuildClassifier.isFinalBuild(); && !mForceNonDebuggableFinalBuild;
boolean finalBuild = mAndroidBuildClassifier.isFinalBuild()
|| mForceNonDebuggableFinalBuild;
int maxTargetSdk = mCompatConfig.maxTargetSdkForChangeIdOptIn(changeId); int maxTargetSdk = mCompatConfig.maxTargetSdkForChangeIdOptIn(changeId);
boolean disabled = mCompatConfig.isDisabled(changeId); boolean disabled = mCompatConfig.isDisabled(changeId);
@@ -73,7 +93,7 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
try { try {
applicationInfo = packageManager.getApplicationInfo(packageName, 0); applicationInfo = packageManager.getApplicationInfo(packageName, 0);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1); return new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1);
} }
int appTargetSdk = applicationInfo.targetSdkVersion; int appTargetSdk = applicationInfo.targetSdkVersion;
// Only allow overriding debuggable apps. // Only allow overriding debuggable apps.
@@ -94,4 +114,17 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
} }
return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, maxTargetSdk); return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, maxTargetSdk);
} }
void registerContentObserver() {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(
Settings.Global.FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT),
false,
new SettingsObserver());
}
void forceNonDebuggableFinalForTest(boolean value) {
mForceNonDebuggableFinalBuild = value;
}
} }

View File

@@ -25,9 +25,13 @@ import static android.os.Process.SYSTEM_UID;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.IActivityManager; import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal;
import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.RemoteException; import android.os.RemoteException;
@@ -74,6 +78,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
mChangeReporter = new ChangeReporter( mChangeReporter = new ChangeReporter(
ChangeReporter.SOURCE_SYSTEM_SERVER); ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = compatConfig; mCompatConfig = compatConfig;
registerPackageReceiver(context);
} }
@Override @Override
@@ -389,4 +394,42 @@ public class PlatformCompat extends IPlatformCompat.Stub {
} }
return true; return true;
} }
/**
* Registers a broadcast receiver that listens for package install, replace or remove.
* @param context the context where the receiver should be registered.
*/
public void registerPackageReceiver(Context context) {
final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
final Uri packageData = intent.getData();
if (packageData == null) {
return;
}
final String packageName = packageData.getSchemeSpecificPart();
if (packageName == null) {
return;
}
mCompatConfig.recheckOverrides(packageName);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
context.registerReceiver(receiver, filter);
}
/**
* Register the observer for
* {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}
*/
public void registerContentObserver() {
mCompatConfig.registerContentObserver();
}
} }

View File

@@ -912,6 +912,9 @@ public final class SystemServer {
mActivityManagerService.setSystemProcess(); mActivityManagerService.setSystemProcess();
t.traceEnd(); t.traceEnd();
// The package receiver depends on the activity service in order to get registered.
platformCompat.registerPackageReceiver(mSystemContext);
// Complete the watchdog setup with an ActivityManager instance and listen for reboots // Complete the watchdog setup with an ActivityManager instance and listen for reboots
// Do this only after the ActivityManagerService is properly started as a system process // Do this only after the ActivityManagerService is properly started as a system process
t.traceBegin("InitWatchdog"); t.traceBegin("InitWatchdog");

View File

@@ -117,6 +117,7 @@ class CompatConfigBuilder {
CompatConfig build() { CompatConfig build() {
CompatConfig config = new CompatConfig(mBuildClassifier, mContext); CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
config.forceNonDebuggableFinalForTest(false);
for (CompatChange change : mChanges) { for (CompatChange change : mChanges) {
config.addChange(change); config.addChange(change);
} }

View File

@@ -28,6 +28,7 @@ import android.app.compat.ChangeIdStateCache;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -81,6 +82,8 @@ public class CompatConfigTest {
@Test @Test
public void testUnknownChangeEnabled() throws Exception { public void testUnknownChangeEnabled() throws Exception {
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
compatConfig.forceNonDebuggableFinalForTest(false);
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build())) assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
.isTrue(); .isTrue();
} }
@@ -180,6 +183,8 @@ public class CompatConfigTest {
@Test @Test
public void testPackageOverrideUnknownPackage() throws Exception { public void testPackageOverrideUnknownPackage() throws Exception {
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
compatConfig.forceNonDebuggableFinalForTest(false);
compatConfig.addOverride(1234L, "com.some.package", false); compatConfig.addOverride(1234L, "com.some.package", false);
@@ -229,6 +234,83 @@ public class CompatConfigTest {
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse(); assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
} }
@Test
public void testApplyDeferredOverridesAfterInstallingApp() throws Exception {
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("com.notinstalled.foo")
.debuggable().build();
when(mPackageManager.getApplicationInfo(eq("com.notinstalled.foo"), anyInt()))
.thenThrow(new NameNotFoundException());
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addDisabledChangeWithId(1234L).build();
when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
when(mBuildClassifier.isFinalBuild()).thenReturn(true);
// Add override before the app is available.
compatConfig.addOverride(1234L, "com.notinstalled.foo", true);
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
// Pretend the app is now installed.
when(mPackageManager.getApplicationInfo(eq("com.notinstalled.foo"), anyInt()))
.thenReturn(applicationInfo);
compatConfig.recheckOverrides("com.notinstalled.foo");
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
public void testApplyDeferredOverrideClearsOverrideAfterUninstall() throws Exception {
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("com.installedapp.foo")
.debuggable().build();
when(mPackageManager.getApplicationInfo(eq("com.installedapp.foo"), anyInt()))
.thenReturn(applicationInfo);
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addDisabledChangeWithId(1234L).build();
when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
when(mBuildClassifier.isFinalBuild()).thenReturn(true);
// Add override when app is installed.
compatConfig.addOverride(1234L, "com.installedapp.foo", true);
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
// Pretend the app is now uninstalled.
when(mPackageManager.getApplicationInfo(eq("com.installedapp.foo"), anyInt()))
.thenThrow(new NameNotFoundException());
compatConfig.recheckOverrides("com.installedapp.foo");
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
}
@Test
public void testApplyDeferredOverrideClearsOverrideAfterChange() throws Exception {
ApplicationInfo debuggableApp = ApplicationInfoBuilder.create()
.withPackageName("com.installedapp.foo")
.debuggable().build();
ApplicationInfo releaseApp = ApplicationInfoBuilder.create()
.withPackageName("com.installedapp.foo")
.build();
when(mPackageManager.getApplicationInfo(eq("com.installedapp.foo"), anyInt()))
.thenReturn(debuggableApp);
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addDisabledChangeWithId(1234L).build();
when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
when(mBuildClassifier.isFinalBuild()).thenReturn(true);
// Add override for debuggable app.
compatConfig.addOverride(1234L, "com.installedapp.foo", true);
assertThat(compatConfig.isChangeEnabled(1234L, debuggableApp)).isTrue();
// Pretend the app now is no longer debuggable, but has the same package.
when(mPackageManager.getApplicationInfo(eq("com.installedapp.foo"), anyInt()))
.thenReturn(releaseApp);
compatConfig.recheckOverrides("com.installedapp.foo");
assertThat(compatConfig.isChangeEnabled(1234L, releaseApp)).isFalse();
}
@Test @Test
public void testLoggingOnlyChangePreventAddOverride() throws Exception { public void testLoggingOnlyChangePreventAddOverride() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
@@ -259,7 +341,7 @@ public class CompatConfigTest {
// Reject all override attempts. // Reject all override attempts.
// Force the validator to prevent overriding the change by using a user build. // Force the validator to prevent overriding the change by using a user build.
when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
when(mBuildClassifier.isFinalBuild()).thenReturn(true); when(mBuildClassifier.isFinalBuild()).thenReturn(false);
// Try to turn off change, but validator prevents it. // Try to turn off change, but validator prevents it.
assertThrows(SecurityException.class, assertThrows(SecurityException.class,
() -> compatConfig.removeOverride(1234L, "com.some.package")); () -> compatConfig.removeOverride(1234L, "com.some.package"));
@@ -360,6 +442,8 @@ public class CompatConfigTest {
@Test @Test
public void testLookupChangeIdNotPresent() throws Exception { public void testLookupChangeIdNotPresent() throws Exception {
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
compatConfig.forceNonDebuggableFinalForTest(false);
assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L); assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
} }
@@ -374,6 +458,8 @@ public class CompatConfigTest {
File dir = createTempDir(); File dir = createTempDir();
writeToFile(dir, "platform_compat_config.xml", configXml); writeToFile(dir, "platform_compat_config.xml", configXml);
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
compatConfig.forceNonDebuggableFinalForTest(false);
compatConfig.initConfigFromLib(dir); compatConfig.initConfigFromLib(dir);
assertThat(compatConfig.isChangeEnabled(1234L, assertThat(compatConfig.isChangeEnabled(1234L,
@@ -400,6 +486,8 @@ public class CompatConfigTest {
writeToFile(dir, "libcore_platform_compat_config.xml", configXml1); writeToFile(dir, "libcore_platform_compat_config.xml", configXml1);
writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2); writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2);
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
compatConfig.forceNonDebuggableFinalForTest(false);
compatConfig.initConfigFromLib(dir); compatConfig.initConfigFromLib(dir);
assertThat(compatConfig.isChangeEnabled(1234L, assertThat(compatConfig.isChangeEnabled(1234L,

View File

@@ -17,6 +17,7 @@
package com.android.server.compat; package com.android.server.compat;
import static com.android.internal.compat.OverrideAllowedState.ALLOWED; import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
import static com.android.internal.compat.OverrideAllowedState.DEFERRED_VERIFICATION;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; 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.DISABLED_TARGET_SDK_TOO_HIGH;
@@ -31,6 +32,7 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -409,4 +411,216 @@ public class OverrideValidatorImplTest {
assertThat(stateDLoggingOnlyChange) assertThat(stateDLoggingOnlyChange)
.isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1)); .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
} }
@Test
public void getOverrideAllowedState_finalBuildAnyChangeNotInstalledApp_deferOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
.addEnableAfterSdkChangeWithId(TARGET_SDK_BEFORE, 1)
.addEnableAfterSdkChangeWithId(TARGET_SDK, 2)
.addEnableAfterSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
.addDisabledChangeWithId(5)
.addLoggingOnlyChangeWithId(6).build();
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new NameNotFoundException());
OverrideAllowedState stateTargetSdkLessChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkEqualChange =
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkAfterChange =
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
OverrideAllowedState stateEnabledChange =
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
OverrideAllowedState stateDLoggingOnlyChange =
overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateTargetSdkEqualChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateTargetSdkAfterChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateEnabledChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateDLoggingOnlyChange)
.isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
@Test
public void getOverrideAllowedState_forceFinalBuildTargetSdkChangeDebugAppOptin_allowOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
.addEnableAfterSdkChangeWithId(TARGET_SDK_AFTER, 1)
.addEnableAfterSdkChangeWithId(TARGET_SDK, 2).build();
config.forceNonDebuggableFinalForTest(true);
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
.debuggable()
.withTargetSdk(TARGET_SDK)
.withPackageName(PACKAGE_NAME).build());
OverrideAllowedState stateTargetSdkGreaterChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkEqualChange =
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
assertThat(stateTargetSdkGreaterChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
assertThat(stateTargetSdkEqualChange)
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
}
@Test
public void getOverrideAllowedState_forceFinalBldTargetSdkChangeDebugAppOptout_rejectOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
.addEnableAfterSdkChangeWithId(TARGET_SDK_BEFORE, 1).build();
config.forceNonDebuggableFinalForTest(true);
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
.withPackageName(PACKAGE_NAME)
.withTargetSdk(TARGET_SDK)
.debuggable()
.build());
OverrideAllowedState stateTargetSdkLessChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange).isEqualTo(
new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK,
TARGET_SDK_BEFORE));
}
@Test
public void getOverrideAllowedState_forceFinalBuildEnabledChangeDebugApp_rejectOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
.addEnabledChangeWithId(1).build();
config.forceNonDebuggableFinalForTest(true);
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
.withPackageName(PACKAGE_NAME)
.debuggable().build());
OverrideAllowedState allowedState =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
assertThat(allowedState)
.isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
}
@Test
public void getOverrideAllowedState_forceFinalBuildDisabledChangeDebugApp_allowOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
.addDisabledChangeWithId(1).build();
config.forceNonDebuggableFinalForTest(true);
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
.withPackageName(PACKAGE_NAME)
.withTargetSdk(TARGET_SDK)
.debuggable().build());
OverrideAllowedState allowedState =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
assertThat(allowedState)
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, -1));
}
@Test
public void getOverrideAllowedState_forceFinalBuildAnyChangeReleaseApp_rejectOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
.addEnableAfterSdkChangeWithId(TARGET_SDK_BEFORE, 1)
.addEnableAfterSdkChangeWithId(TARGET_SDK, 2)
.addEnableAfterSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
.addDisabledChangeWithId(5)
.addLoggingOnlyChangeWithId(6).build();
config.forceNonDebuggableFinalForTest(true);
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenReturn(ApplicationInfoBuilder.create()
.withPackageName(PACKAGE_NAME)
.withTargetSdk(TARGET_SDK).build());
OverrideAllowedState stateTargetSdkLessChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkEqualChange =
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkAfterChange =
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
OverrideAllowedState stateEnabledChange =
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
OverrideAllowedState stateDLoggingOnlyChange =
overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateTargetSdkEqualChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateTargetSdkAfterChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateEnabledChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
assertThat(stateDLoggingOnlyChange)
.isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
@Test
public void getOverrideAllowedState_forceFinalBuildAnyChangeNotInstalledApp_deferOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
.addEnableAfterSdkChangeWithId(TARGET_SDK_BEFORE, 1)
.addEnableAfterSdkChangeWithId(TARGET_SDK, 2)
.addEnableAfterSdkChangeWithId(TARGET_SDK_AFTER, 3)
.addEnabledChangeWithId(4)
.addDisabledChangeWithId(5)
.addLoggingOnlyChangeWithId(6).build();
config.forceNonDebuggableFinalForTest(true);
IOverrideValidator overrideValidator = config.getOverrideValidator();
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new NameNotFoundException());
OverrideAllowedState stateTargetSdkLessChange =
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkEqualChange =
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
OverrideAllowedState stateTargetSdkAfterChange =
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
OverrideAllowedState stateEnabledChange =
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
OverrideAllowedState stateDisabledChange =
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
OverrideAllowedState stateDLoggingOnlyChange =
overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
assertThat(stateTargetSdkLessChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateTargetSdkEqualChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateTargetSdkAfterChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateEnabledChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateDisabledChange)
.isEqualTo(new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1));
assertThat(stateDLoggingOnlyChange)
.isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
}
} }

View File

@@ -73,6 +73,7 @@ public class PlatformCompatTest {
mCompatConfig = new CompatConfig(mBuildClassifier, mContext); mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
// Assume userdebug/eng non-final build // Assume userdebug/eng non-final build
mCompatConfig.forceNonDebuggableFinalForTest(false);
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
when(mBuildClassifier.isFinalBuild()).thenReturn(false); when(mBuildClassifier.isFinalBuild()).thenReturn(false);
LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.removeServiceForTest(PackageManagerInternal.class);