Loading core/java/com/android/internal/compat/IPlatformCompat.aidl +24 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading services/core/java/com/android/server/am/ActivityManagerShellCommand.java +68 −29 Original line number Diff line number Diff line Loading @@ -2933,13 +2933,22 @@ 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; 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; } long changeId; } } else { String changeIdString = getNextArgRequired(); try { changeId = Long.parseLong(changeIdString); Loading @@ -2950,8 +2959,9 @@ final class ActivityManagerShellCommand extends ShellCommand { 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."); } Loading @@ -2960,22 +2970,49 @@ final class ActivityManagerShellCommand extends ShellCommand { try { switch (toggleValue) { case "enable": 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": 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); overrides = 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."); Loading Loading @@ -3305,6 +3342,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)."); Loading services/core/java/com/android/server/compat/CompatConfig.java +57 −0 Original line number Diff line number Diff line Loading @@ -293,6 +293,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) { Loading services/core/java/com/android/server/compat/PlatformCompat.java +20 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,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(); Loading services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +43 −0 Original line number Diff line number Diff line Loading @@ -264,6 +264,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) Loading Loading
core/java/com/android/internal/compat/IPlatformCompat.aidl +24 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +68 −29 Original line number Diff line number Diff line Loading @@ -2933,13 +2933,22 @@ 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; 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; } long changeId; } } else { String changeIdString = getNextArgRequired(); try { changeId = Long.parseLong(changeIdString); Loading @@ -2950,8 +2959,9 @@ final class ActivityManagerShellCommand extends ShellCommand { 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."); } Loading @@ -2960,22 +2970,49 @@ final class ActivityManagerShellCommand extends ShellCommand { try { switch (toggleValue) { case "enable": 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": 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); overrides = 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."); Loading Loading @@ -3305,6 +3342,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)."); Loading
services/core/java/com/android/server/compat/CompatConfig.java +57 −0 Original line number Diff line number Diff line Loading @@ -293,6 +293,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) { Loading
services/core/java/com/android/server/compat/PlatformCompat.java +20 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,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(); Loading
services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +43 −0 Original line number Diff line number Diff line Loading @@ -264,6 +264,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) Loading