Add option to toggle all changes

This change adds the ability of enabling and disabling all allowed
changes for a given package and target sdk through adb.

Bug: 149980515
Test: adb shell am enable-all 28 foo.bar && \
	adb shell dumpsys platform_compat
Test: adb shell am disable-all 28 foo.bar && \
	adb shell dumpsys platform_compat
Test: atest CompatConfigTest
Merged-In: Ia84d8e1162ea0b3f4c6afe87e63db56256236940
Change-Id: I4696e13882b1b2c930731e6e7787924e20da1a46
This commit is contained in:
Andrei Onea
2020-02-27 15:35:38 +00:00
parent 88ad796fa9
commit 5b1e2eb495
5 changed files with 212 additions and 29 deletions

View File

@@ -163,6 +163,30 @@ interface IPlatformCompat
*/
boolean clearOverride(long changeId, String packageName);
/**
* Enable all compatibility changes which have enabledAfterTargetSdk ==
* {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
* changes to take effect.
*
* @param packageName The package name of the app whose compatibility changes will be enabled.
* @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled.
*
* @return The number of changes that were enabled.
*/
int enableTargetSdkChanges(in String packageName, int targetSdkVersion);
/**
* Disable all compatibility changes which have enabledAfterTargetSdk ==
* {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
* changes to take effect.
*
* @param packageName The package name of the app whose compatibility changes will be disabled.
* @param targetSdkVersion The targetSdkVersion for filtering the changes to be disabled.
*
* @return The number of changes that were disabled.
*/
int disableTargetSdkChanges(in String packageName, int targetSdkVersion);
/**
* Revert overrides to compatibility changes. Kills the app to allow the changes to take effect.
*

View File

@@ -2931,25 +2931,35 @@ final class ActivityManagerShellCommand extends ShellCommand {
final PlatformCompat platformCompat = (PlatformCompat)
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
String toggleValue = getNextArgRequired();
if (toggleValue.equals("reset-all")) {
final String packageName = getNextArgRequired();
pw.println("Reset all changes for " + packageName + " to default value.");
platformCompat.clearOverrides(packageName);
return 0;
}
long changeId;
String changeIdString = getNextArgRequired();
try {
changeId = Long.parseLong(changeIdString);
} catch (NumberFormatException e) {
changeId = platformCompat.lookupChangeId(changeIdString);
}
if (changeId == -1) {
pw.println("Unknown or invalid change: '" + changeIdString + "'.");
return -1;
boolean toggleAll = false;
int targetSdkVersion = -1;
long changeId = -1;
if (toggleValue.endsWith("-all")) {
toggleValue = toggleValue.substring(0, toggleValue.lastIndexOf("-all"));
toggleAll = true;
if (!toggleValue.equals("reset")) {
try {
targetSdkVersion = Integer.parseInt(getNextArgRequired());
} catch (NumberFormatException e) {
pw.println("Invalid targetSdkVersion!");
return -1;
}
}
} else {
String changeIdString = getNextArgRequired();
try {
changeId = Long.parseLong(changeIdString);
} catch (NumberFormatException e) {
changeId = platformCompat.lookupChangeId(changeIdString);
}
if (changeId == -1) {
pw.println("Unknown or invalid change: '" + changeIdString + "'.");
return -1;
}
}
String packageName = getNextArgRequired();
if (!platformCompat.isKnownChangeId(changeId)) {
if (!toggleAll && !platformCompat.isKnownChangeId(changeId)) {
pw.println("Warning! Change " + changeId + " is not known yet. Enabling/disabling it"
+ " could have no effect.");
}
@@ -2958,22 +2968,49 @@ final class ActivityManagerShellCommand extends ShellCommand {
try {
switch (toggleValue) {
case "enable":
enabled.add(changeId);
CompatibilityChangeConfig overrides =
new CompatibilityChangeConfig(
new Compatibility.ChangeConfig(enabled, disabled));
platformCompat.setOverrides(overrides, packageName);
pw.println("Enabled change " + changeId + " for " + packageName + ".");
if (toggleAll) {
int numChanges = platformCompat.enableTargetSdkChanges(packageName,
targetSdkVersion);
if (numChanges == 0) {
pw.println("No changes were enabled.");
return -1;
}
pw.println("Enabled " + numChanges + " changes gated by targetSdkVersion "
+ targetSdkVersion + " for " + packageName + ".");
} else {
enabled.add(changeId);
CompatibilityChangeConfig overrides =
new CompatibilityChangeConfig(
new Compatibility.ChangeConfig(enabled, disabled));
platformCompat.setOverrides(overrides, packageName);
pw.println("Enabled change " + changeId + " for " + packageName + ".");
}
return 0;
case "disable":
disabled.add(changeId);
overrides =
new CompatibilityChangeConfig(
new Compatibility.ChangeConfig(enabled, disabled));
platformCompat.setOverrides(overrides, packageName);
pw.println("Disabled change " + changeId + " for " + packageName + ".");
if (toggleAll) {
int numChanges = platformCompat.disableTargetSdkChanges(packageName,
targetSdkVersion);
if (numChanges == 0) {
pw.println("No changes were disabled.");
return -1;
}
pw.println("Disabled " + numChanges + " changes gated by targetSdkVersion "
+ targetSdkVersion + " for " + packageName + ".");
} else {
disabled.add(changeId);
CompatibilityChangeConfig overrides =
new CompatibilityChangeConfig(
new Compatibility.ChangeConfig(enabled, disabled));
platformCompat.setOverrides(overrides, packageName);
pw.println("Disabled change " + changeId + " for " + packageName + ".");
}
return 0;
case "reset":
if (toggleAll) {
platformCompat.clearOverrides(packageName);
pw.println("Reset all changes for " + packageName + " to default value.");
return 0;
}
if (platformCompat.clearOverride(changeId, packageName)) {
pw.println("Reset change " + changeId + " for " + packageName
+ " to default value.");
@@ -3304,6 +3341,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
pw.println(" enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME");
pw.println(" Toggles all changes that are gated by <targetSdkVersion>.");
pw.println(" reset-all <PACKAGE_NAME>");
pw.println(" Removes all existing overrides for all changes for ");
pw.println(" <PACKAGE_NAME> (back to default behaviour).");

View File

@@ -288,6 +288,63 @@ final class CompatConfig {
}
}
private long[] getAllowedChangesAfterTargetSdkForPackage(String packageName,
int targetSdkVersion)
throws RemoteException {
LongArray allowed = new LongArray();
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
try {
CompatChange change = mChanges.valueAt(i);
if (change.getEnableAfterTargetSdk() != targetSdkVersion) {
continue;
}
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(change.getId(),
packageName);
if (allowedState.state == OverrideAllowedState.ALLOWED) {
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);
}
}
}
return allowed.toArray();
}
/**
* Enables all changes with enabledAfterTargetSdk == {@param targetSdkVersion} for
* {@param packageName}.
*
* @return The number of changes that were toggled.
*/
int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
throws RemoteException {
long[] changes = getAllowedChangesAfterTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
addOverride(changeId, packageName, true);
}
return changes.length;
}
/**
* Disables all changes with enabledAfterTargetSdk == {@param targetSdkVersion} for
* {@param packageName}.
*
* @return The number of changes that were toggled.
*/
int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
throws RemoteException {
long[] changes = getAllowedChangesAfterTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
addOverride(changeId, packageName, false);
}
return changes.length;
}
boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
boolean alreadyKnown = true;
synchronized (mChanges) {

View File

@@ -165,6 +165,26 @@ public class PlatformCompat extends IPlatformCompat.Stub {
mCompatConfig.addOverrides(overrides, packageName);
}
@Override
public int enableTargetSdkChanges(String packageName, int targetSdkVersion)
throws RemoteException, SecurityException {
checkCompatChangeOverridePermission();
int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName,
targetSdkVersion);
killPackage(packageName);
return numChanges;
}
@Override
public int disableTargetSdkChanges(String packageName, int targetSdkVersion)
throws RemoteException, SecurityException {
checkCompatChangeOverridePermission();
int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName,
targetSdkVersion);
killPackage(packageName);
return numChanges;
}
@Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
checkCompatChangeOverridePermission();

View File

@@ -255,6 +255,49 @@ public class CompatConfigTest {
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
}
@Test
public void testEnableTargetSdkChangesForPackage() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithId(1L)
.addDisabledChangeWithId(2L)
.addTargetSdkChangeWithId(3, 3L)
.addTargetSdkChangeWithId(4, 4L)
.build();
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("foo.bar")
.withTargetSdk(2)
.build();
assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
}
@Test
public void testDisableTargetSdkChangesForPackage() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithId(1L)
.addDisabledChangeWithId(2L)
.addTargetSdkChangeWithId(3, 3L)
.addTargetSdkChangeWithId(4, 4L)
.build();
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("foo.bar")
.withTargetSdk(2)
.build();
assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
assertThat(compatConfig.disableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
}
@Test
public void testLookupChangeId() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)