Loading core/java/com/android/internal/compat/IPlatformCompat.aidl +23 −2 Original line number Diff line number Diff line Loading @@ -133,7 +133,7 @@ interface IPlatformCompat boolean isChangeEnabledByUid(long changeId, int uid); /** * Add overrides to compatibility changes. * Add overrides to compatibility changes. Kills the app to allow the changes to take effect. * * @param overrides Parcelable containing the compat change overrides to be applied. * @param packageName The package name of the app whose changes will be overridden. Loading @@ -142,7 +142,28 @@ interface IPlatformCompat void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** * Revert overrides to compatibility changes. * Add overrides to compatibility changes. Doesn't kill the app, to be only used in tests. * * @param overrides Parcelable containing the compat change overrides to be applied. * @param packageName The package name of the app whose changes will be overridden. * */ void setOverridesForTest(in CompatibilityChangeConfig overrides, in String packageName); /** * Removes an override previously added via {@link #setOverrides(CompatibilityChangeConfig, * String)}. This restores the default behaviour for the given change and app, once any app * processes have been restarted. * Kills the app to allow the changes to take effect. * * @param changeId The ID of the change that was overridden. * @param packageName The app package name that was overridden. * @return {@code true} if an override existed; */ boolean clearOverride(long changeId, String packageName); /** * Revert overrides to compatibility changes. Kills the app to allow the changes to take effect. * * @param packageName The package name of the app whose overrides will be cleared. * Loading services/core/java/com/android/server/am/ActivityManagerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -349,7 +349,6 @@ import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto; import com.android.server.appop.AppOpsService; import com.android.server.compat.CompatConfig; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.firewall.IntentFirewall; Loading Loading @@ -5049,8 +5048,9 @@ public class ActivityManagerService extends IActivityManager.Stub bindApplicationTimeMillis = SystemClock.elapsedRealtime(); mAtmInternal.preBindApplication(app.getWindowProcessController()); final ActiveInstrumentation instr2 = app.getActiveInstrumentation(); long[] disabledCompatChanges = CompatConfig.get().getDisabledChanges(app.info); long[] disabledCompatChanges = {}; if (mPlatformCompat != null) { disabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info); mPlatformCompat.resetReporting(app.info); } if (app.isolatedEntryPoint != null) { Loading services/core/java/com/android/server/am/ActivityManagerShellCommand.java +25 −29 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.app.usage.AppStandbyInfo; import android.app.usage.ConfigurationStats; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageStatsManager; import android.compat.Compatibility; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -80,15 +81,17 @@ import android.os.UserManager; import android.text.TextUtils; import android.text.format.Time; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.DisplayMetrics; import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.util.HexDump; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; import com.android.server.compat.CompatConfig; import com.android.server.compat.PlatformCompat; import java.io.BufferedReader; import java.io.File; Loading Loading @@ -2868,56 +2871,49 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } private void killPackage(String packageName, PrintWriter pw) throws RemoteException { int uid = mPm.getPackageUid(packageName, 0, mUserId); if (uid < 0) { // uid is negative if the package wasn't found. pw.println("Didn't find package " + packageName + " on device."); } else { pw.println("Killing package " + packageName + " (UID " + uid + ")."); final long origId = Binder.clearCallingIdentity(); mInterface.killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL, "killPackage"); Binder.restoreCallingIdentity(origId); } } private int runCompat(PrintWriter pw) throws RemoteException { final CompatConfig config = CompatConfig.get(); final PlatformCompat platformCompat = (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE); String toggleValue = getNextArgRequired(); long changeId; String changeIdString = getNextArgRequired(); try { changeId = Long.parseLong(changeIdString); } catch (NumberFormatException e) { changeId = config.lookupChangeId(changeIdString); changeId = platformCompat.lookupChangeId(changeIdString); } if (changeId == -1) { pw.println("Unknown or invalid change: '" + changeIdString + "'."); return -1; } String packageName = getNextArgRequired(); switch (toggleValue) { case "enable": if (!config.addOverride(changeId, packageName, true)) { pw.println("Warning! Change " + changeId + " is not known yet. Enabling it" if (!platformCompat.isKnownChangeId(changeId)) { pw.println("Warning! Change " + changeId + " is not known yet. Enabling/disabling it" + " could have no effect."); } ArraySet<Long> enabled = new ArraySet<>(); ArraySet<Long> disabled = new ArraySet<>(); switch (toggleValue) { case "enable": enabled.add(changeId); pw.println("Enabled change " + changeId + " for " + packageName + "."); killPackage(packageName, pw); CompatibilityChangeConfig overrides = new CompatibilityChangeConfig( new Compatibility.ChangeConfig(enabled, disabled)); platformCompat.setOverrides(overrides, packageName); return 0; case "disable": if (!config.addOverride(changeId, packageName, false)) { pw.println("Warning! Change " + changeId + " is not known yet. Disabling it" + " could have no effect."); } disabled.add(changeId); pw.println("Disabled change " + changeId + " for " + packageName + "."); killPackage(packageName, pw); overrides = new CompatibilityChangeConfig( new Compatibility.ChangeConfig(enabled, disabled)); platformCompat.setOverrides(overrides, packageName); return 0; case "reset": if (config.removeOverride(changeId, packageName)) { if (platformCompat.clearOverride(changeId, packageName)) { pw.println("Reset change " + changeId + " for " + packageName + " to default value."); killPackage(packageName, pw); } else { pw.println("No override exists for changeId " + changeId + "."); } Loading services/core/java/com/android/server/compat/CompatConfig.java +49 −35 Original line number Diff line number Diff line Loading @@ -43,13 +43,14 @@ import java.util.HashSet; import java.util.Set; import javax.xml.datatype.DatatypeConfigurationException; /** * This class maintains state relating to platform compatibility changes. * * <p>It stores the default configuration for each change, and any per-package overrides that have * been configured. */ public final class CompatConfig { final class CompatConfig { private static final String TAG = "CompatConfig"; Loading @@ -61,13 +62,13 @@ public final class CompatConfig { private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); @VisibleForTesting public CompatConfig() { CompatConfig() { } /** * @return The static instance of this class to be used within the system server. */ public static CompatConfig get() { static CompatConfig get() { return sInstance; } Loading @@ -77,7 +78,7 @@ public final class CompatConfig { * * @param change The change to add. Any change with the same ID will be overwritten. */ public void addChange(CompatChange change) { void addChange(CompatChange change) { synchronized (mChanges) { mChanges.put(change.getId(), change); } Loading @@ -92,7 +93,7 @@ public final class CompatConfig { * footprint: Every app process will store this array statically so we aim to reduce * overhead as much as possible. */ public long[] getDisabledChanges(ApplicationInfo app) { long[] getDisabledChanges(ApplicationInfo app) { LongArray disabled = new LongArray(); synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { Loading @@ -113,7 +114,7 @@ public final class CompatConfig { * @param name Name of the change to look up * @return The change ID, or {@code -1} if no change with that name exists. */ public long lookupChangeId(String name) { long lookupChangeId(String name) { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { if (TextUtils.equals(mChanges.valueAt(i).getName(), name)) { Loading @@ -132,7 +133,7 @@ public final class CompatConfig { * @return {@code true} if the change is enabled for this app. Also returns {@code true} if the * change ID is not known, as unknown changes are enabled by default. */ public boolean isChangeEnabled(long changeId, ApplicationInfo app) { boolean isChangeEnabled(long changeId, ApplicationInfo app) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); if (c == null) { Loading @@ -150,14 +151,15 @@ public final class CompatConfig { * * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. * * @param changeId The ID of the change to be overridden. Note, this call will succeed even if * @param changeId The ID of the change to be overridden. Note, this call will succeed even * if * this change is not known; it will only have any effect if any code in the * platform is gated on the ID given. * @param packageName The app package name to override the change for. * @param enabled If the change should be enabled or disabled. * @return {@code true} if the change existed before adding the override. */ public boolean addOverride(long changeId, String packageName, boolean enabled) { boolean addOverride(long changeId, String packageName, boolean enabled) { boolean alreadyKnown = true; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); Loading @@ -171,6 +173,18 @@ public final class CompatConfig { return alreadyKnown; } /** * Check whether the change is known to the compat config. * * @return {@code true} if the change is known. */ boolean isKnownChangeId(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); return c != null; } } /** * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This * restores the default behaviour for the given change and app, once any app processes have been Loading @@ -180,7 +194,7 @@ public final class CompatConfig { * @param packageName The app package name that was overridden. * @return {@code true} if an override existed; */ public boolean removeOverride(long changeId, String packageName) { boolean removeOverride(long changeId, String packageName) { boolean overrideExists = false; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); Loading @@ -191,6 +205,7 @@ public final class CompatConfig { } return overrideExists; } /** * Overrides the enabled state for a given change and app. This method is intended to be used * *only* for debugging purposes. Loading @@ -200,8 +215,7 @@ public final class CompatConfig { * @param overrides list of overrides to default changes config. * @param packageName app for which the overrides will be applied. */ public void addOverrides( CompatibilityChangeConfig overrides, String packageName) { void addOverrides(CompatibilityChangeConfig overrides, String packageName) { synchronized (mChanges) { for (Long changeId : overrides.enabledChanges()) { addOverride(changeId, packageName, true); Loading @@ -221,7 +235,7 @@ public final class CompatConfig { * * @param packageName The package for which the overrides should be purged. */ public void removePackageOverrides(String packageName) { void removePackageOverrides(String packageName) { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { mChanges.valueAt(i).removePackageOverride(packageName); Loading @@ -234,7 +248,7 @@ public final class CompatConfig { * * @param pw The {@link PrintWriter} instance to which the information will be dumped. */ public void dumpConfig(PrintWriter pw) { void dumpConfig(PrintWriter pw) { synchronized (mChanges) { if (mChanges.size() == 0) { pw.println("No compat overrides."); Loading @@ -255,7 +269,7 @@ public final class CompatConfig { * given app. */ public CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) { CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) { Set<Long> enabled = new HashSet<>(); Set<Long> disabled = new HashSet<>(); synchronized (mChanges) { Loading @@ -276,7 +290,7 @@ public final class CompatConfig { * * @return An array of {@link CompatibilityChangeInfo} with the current changes. */ public CompatibilityChangeInfo[] dumpChanges() { CompatibilityChangeInfo[] dumpChanges() { synchronized (mChanges) { CompatibilityChangeInfo[] changeInfos = new CompatibilityChangeInfo[mChanges.size()]; for (int i = 0; i < mChanges.size(); ++i) { Loading services/core/java/com/android/server/compat/PlatformCompat.java +81 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.server.compat; import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.util.StatsLog; Loading Loading @@ -106,12 +110,26 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { CompatConfig.get().addOverrides(overrides, packageName); killPackage(packageName); } @Override public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) { CompatConfig.get().addOverrides(overrides, packageName); } @Override public void clearOverrides(String packageName) { CompatConfig config = CompatConfig.get(); config.removePackageOverrides(packageName); killPackage(packageName); } @Override public boolean clearOverride(long changeId, String packageName) { boolean existed = CompatConfig.get().removeOverride(changeId, packageName); killPackage(packageName); return existed; } @Override Loading @@ -124,6 +142,39 @@ public class PlatformCompat extends IPlatformCompat.Stub { return CompatConfig.get().dumpChanges(); } /** * Check whether the change is known to the compat config. * @param changeId * @return {@code true} if the change is known. */ public boolean isKnownChangeId(long changeId) { return CompatConfig.get().isKnownChangeId(changeId); } /** * Retrieves the set of disabled changes for a given app. Any change ID not in the returned * array is by default enabled for the app. * * @param appInfo The app in question * @return A sorted long array of change IDs. We use a primitive array to minimize memory * footprint: Every app process will store this array statically so we aim to reduce * overhead as much as possible. */ public long[] getDisabledChanges(ApplicationInfo appInfo) { return CompatConfig.get().getDisabledChanges(appInfo); } /** * Look up a change ID by name. * * @param name Name of the change to look up * @return The change ID, or {@code -1} if no change with that name exists. */ public long lookupChangeId(String name) { return CompatConfig.get().lookupChangeId(name); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; Loading Loading @@ -151,4 +202,34 @@ public class PlatformCompat extends IPlatformCompat.Stub { private void reportChange(long changeId, int uid, int state) { mChangeReporter.reportChange(uid, changeId, state); } private void killPackage(String packageName) { int uid = -1; try { uid = mContext.getPackageManager().getPackageUid(packageName, 0); } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Didn't find package " + packageName + " on device.", e); return; } Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ")."); killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL, "PlatformCompat overrides"); } private void killUid(int appId, int userId, String reason) { final long identity = Binder.clearCallingIdentity(); try { IActivityManager am = ActivityManager.getService(); if (am != null) { try { am.killUid(appId, userId, reason); } catch (RemoteException e) { /* ignore - same process */ } } } finally { Binder.restoreCallingIdentity(identity); } } } Loading
core/java/com/android/internal/compat/IPlatformCompat.aidl +23 −2 Original line number Diff line number Diff line Loading @@ -133,7 +133,7 @@ interface IPlatformCompat boolean isChangeEnabledByUid(long changeId, int uid); /** * Add overrides to compatibility changes. * Add overrides to compatibility changes. Kills the app to allow the changes to take effect. * * @param overrides Parcelable containing the compat change overrides to be applied. * @param packageName The package name of the app whose changes will be overridden. Loading @@ -142,7 +142,28 @@ interface IPlatformCompat void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** * Revert overrides to compatibility changes. * Add overrides to compatibility changes. Doesn't kill the app, to be only used in tests. * * @param overrides Parcelable containing the compat change overrides to be applied. * @param packageName The package name of the app whose changes will be overridden. * */ void setOverridesForTest(in CompatibilityChangeConfig overrides, in String packageName); /** * Removes an override previously added via {@link #setOverrides(CompatibilityChangeConfig, * String)}. This restores the default behaviour for the given change and app, once any app * processes have been restarted. * Kills the app to allow the changes to take effect. * * @param changeId The ID of the change that was overridden. * @param packageName The app package name that was overridden. * @return {@code true} if an override existed; */ boolean clearOverride(long changeId, String packageName); /** * Revert overrides to compatibility changes. Kills the app to allow the changes to take effect. * * @param packageName The package name of the app whose overrides will be cleared. * Loading
services/core/java/com/android/server/am/ActivityManagerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -349,7 +349,6 @@ import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto; import com.android.server.appop.AppOpsService; import com.android.server.compat.CompatConfig; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.firewall.IntentFirewall; Loading Loading @@ -5049,8 +5048,9 @@ public class ActivityManagerService extends IActivityManager.Stub bindApplicationTimeMillis = SystemClock.elapsedRealtime(); mAtmInternal.preBindApplication(app.getWindowProcessController()); final ActiveInstrumentation instr2 = app.getActiveInstrumentation(); long[] disabledCompatChanges = CompatConfig.get().getDisabledChanges(app.info); long[] disabledCompatChanges = {}; if (mPlatformCompat != null) { disabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info); mPlatformCompat.resetReporting(app.info); } if (app.isolatedEntryPoint != null) { Loading
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +25 −29 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.app.usage.AppStandbyInfo; import android.app.usage.ConfigurationStats; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageStatsManager; import android.compat.Compatibility; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -80,15 +81,17 @@ import android.os.UserManager; import android.text.TextUtils; import android.text.format.Time; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.DisplayMetrics; import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.util.HexDump; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; import com.android.server.compat.CompatConfig; import com.android.server.compat.PlatformCompat; import java.io.BufferedReader; import java.io.File; Loading Loading @@ -2868,56 +2871,49 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } private void killPackage(String packageName, PrintWriter pw) throws RemoteException { int uid = mPm.getPackageUid(packageName, 0, mUserId); if (uid < 0) { // uid is negative if the package wasn't found. pw.println("Didn't find package " + packageName + " on device."); } else { pw.println("Killing package " + packageName + " (UID " + uid + ")."); final long origId = Binder.clearCallingIdentity(); mInterface.killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL, "killPackage"); Binder.restoreCallingIdentity(origId); } } private int runCompat(PrintWriter pw) throws RemoteException { final CompatConfig config = CompatConfig.get(); final PlatformCompat platformCompat = (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE); String toggleValue = getNextArgRequired(); long changeId; String changeIdString = getNextArgRequired(); try { changeId = Long.parseLong(changeIdString); } catch (NumberFormatException e) { changeId = config.lookupChangeId(changeIdString); changeId = platformCompat.lookupChangeId(changeIdString); } if (changeId == -1) { pw.println("Unknown or invalid change: '" + changeIdString + "'."); return -1; } String packageName = getNextArgRequired(); switch (toggleValue) { case "enable": if (!config.addOverride(changeId, packageName, true)) { pw.println("Warning! Change " + changeId + " is not known yet. Enabling it" if (!platformCompat.isKnownChangeId(changeId)) { pw.println("Warning! Change " + changeId + " is not known yet. Enabling/disabling it" + " could have no effect."); } ArraySet<Long> enabled = new ArraySet<>(); ArraySet<Long> disabled = new ArraySet<>(); switch (toggleValue) { case "enable": enabled.add(changeId); pw.println("Enabled change " + changeId + " for " + packageName + "."); killPackage(packageName, pw); CompatibilityChangeConfig overrides = new CompatibilityChangeConfig( new Compatibility.ChangeConfig(enabled, disabled)); platformCompat.setOverrides(overrides, packageName); return 0; case "disable": if (!config.addOverride(changeId, packageName, false)) { pw.println("Warning! Change " + changeId + " is not known yet. Disabling it" + " could have no effect."); } disabled.add(changeId); pw.println("Disabled change " + changeId + " for " + packageName + "."); killPackage(packageName, pw); overrides = new CompatibilityChangeConfig( new Compatibility.ChangeConfig(enabled, disabled)); platformCompat.setOverrides(overrides, packageName); return 0; case "reset": if (config.removeOverride(changeId, packageName)) { if (platformCompat.clearOverride(changeId, packageName)) { pw.println("Reset change " + changeId + " for " + packageName + " to default value."); killPackage(packageName, pw); } else { pw.println("No override exists for changeId " + changeId + "."); } Loading
services/core/java/com/android/server/compat/CompatConfig.java +49 −35 Original line number Diff line number Diff line Loading @@ -43,13 +43,14 @@ import java.util.HashSet; import java.util.Set; import javax.xml.datatype.DatatypeConfigurationException; /** * This class maintains state relating to platform compatibility changes. * * <p>It stores the default configuration for each change, and any per-package overrides that have * been configured. */ public final class CompatConfig { final class CompatConfig { private static final String TAG = "CompatConfig"; Loading @@ -61,13 +62,13 @@ public final class CompatConfig { private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); @VisibleForTesting public CompatConfig() { CompatConfig() { } /** * @return The static instance of this class to be used within the system server. */ public static CompatConfig get() { static CompatConfig get() { return sInstance; } Loading @@ -77,7 +78,7 @@ public final class CompatConfig { * * @param change The change to add. Any change with the same ID will be overwritten. */ public void addChange(CompatChange change) { void addChange(CompatChange change) { synchronized (mChanges) { mChanges.put(change.getId(), change); } Loading @@ -92,7 +93,7 @@ public final class CompatConfig { * footprint: Every app process will store this array statically so we aim to reduce * overhead as much as possible. */ public long[] getDisabledChanges(ApplicationInfo app) { long[] getDisabledChanges(ApplicationInfo app) { LongArray disabled = new LongArray(); synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { Loading @@ -113,7 +114,7 @@ public final class CompatConfig { * @param name Name of the change to look up * @return The change ID, or {@code -1} if no change with that name exists. */ public long lookupChangeId(String name) { long lookupChangeId(String name) { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { if (TextUtils.equals(mChanges.valueAt(i).getName(), name)) { Loading @@ -132,7 +133,7 @@ public final class CompatConfig { * @return {@code true} if the change is enabled for this app. Also returns {@code true} if the * change ID is not known, as unknown changes are enabled by default. */ public boolean isChangeEnabled(long changeId, ApplicationInfo app) { boolean isChangeEnabled(long changeId, ApplicationInfo app) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); if (c == null) { Loading @@ -150,14 +151,15 @@ public final class CompatConfig { * * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. * * @param changeId The ID of the change to be overridden. Note, this call will succeed even if * @param changeId The ID of the change to be overridden. Note, this call will succeed even * if * this change is not known; it will only have any effect if any code in the * platform is gated on the ID given. * @param packageName The app package name to override the change for. * @param enabled If the change should be enabled or disabled. * @return {@code true} if the change existed before adding the override. */ public boolean addOverride(long changeId, String packageName, boolean enabled) { boolean addOverride(long changeId, String packageName, boolean enabled) { boolean alreadyKnown = true; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); Loading @@ -171,6 +173,18 @@ public final class CompatConfig { return alreadyKnown; } /** * Check whether the change is known to the compat config. * * @return {@code true} if the change is known. */ boolean isKnownChangeId(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); return c != null; } } /** * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This * restores the default behaviour for the given change and app, once any app processes have been Loading @@ -180,7 +194,7 @@ public final class CompatConfig { * @param packageName The app package name that was overridden. * @return {@code true} if an override existed; */ public boolean removeOverride(long changeId, String packageName) { boolean removeOverride(long changeId, String packageName) { boolean overrideExists = false; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); Loading @@ -191,6 +205,7 @@ public final class CompatConfig { } return overrideExists; } /** * Overrides the enabled state for a given change and app. This method is intended to be used * *only* for debugging purposes. Loading @@ -200,8 +215,7 @@ public final class CompatConfig { * @param overrides list of overrides to default changes config. * @param packageName app for which the overrides will be applied. */ public void addOverrides( CompatibilityChangeConfig overrides, String packageName) { void addOverrides(CompatibilityChangeConfig overrides, String packageName) { synchronized (mChanges) { for (Long changeId : overrides.enabledChanges()) { addOverride(changeId, packageName, true); Loading @@ -221,7 +235,7 @@ public final class CompatConfig { * * @param packageName The package for which the overrides should be purged. */ public void removePackageOverrides(String packageName) { void removePackageOverrides(String packageName) { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { mChanges.valueAt(i).removePackageOverride(packageName); Loading @@ -234,7 +248,7 @@ public final class CompatConfig { * * @param pw The {@link PrintWriter} instance to which the information will be dumped. */ public void dumpConfig(PrintWriter pw) { void dumpConfig(PrintWriter pw) { synchronized (mChanges) { if (mChanges.size() == 0) { pw.println("No compat overrides."); Loading @@ -255,7 +269,7 @@ public final class CompatConfig { * given app. */ public CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) { CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) { Set<Long> enabled = new HashSet<>(); Set<Long> disabled = new HashSet<>(); synchronized (mChanges) { Loading @@ -276,7 +290,7 @@ public final class CompatConfig { * * @return An array of {@link CompatibilityChangeInfo} with the current changes. */ public CompatibilityChangeInfo[] dumpChanges() { CompatibilityChangeInfo[] dumpChanges() { synchronized (mChanges) { CompatibilityChangeInfo[] changeInfos = new CompatibilityChangeInfo[mChanges.size()]; for (int i = 0; i < mChanges.size(); ++i) { Loading
services/core/java/com/android/server/compat/PlatformCompat.java +81 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.server.compat; import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.util.StatsLog; Loading Loading @@ -106,12 +110,26 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { CompatConfig.get().addOverrides(overrides, packageName); killPackage(packageName); } @Override public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) { CompatConfig.get().addOverrides(overrides, packageName); } @Override public void clearOverrides(String packageName) { CompatConfig config = CompatConfig.get(); config.removePackageOverrides(packageName); killPackage(packageName); } @Override public boolean clearOverride(long changeId, String packageName) { boolean existed = CompatConfig.get().removeOverride(changeId, packageName); killPackage(packageName); return existed; } @Override Loading @@ -124,6 +142,39 @@ public class PlatformCompat extends IPlatformCompat.Stub { return CompatConfig.get().dumpChanges(); } /** * Check whether the change is known to the compat config. * @param changeId * @return {@code true} if the change is known. */ public boolean isKnownChangeId(long changeId) { return CompatConfig.get().isKnownChangeId(changeId); } /** * Retrieves the set of disabled changes for a given app. Any change ID not in the returned * array is by default enabled for the app. * * @param appInfo The app in question * @return A sorted long array of change IDs. We use a primitive array to minimize memory * footprint: Every app process will store this array statically so we aim to reduce * overhead as much as possible. */ public long[] getDisabledChanges(ApplicationInfo appInfo) { return CompatConfig.get().getDisabledChanges(appInfo); } /** * Look up a change ID by name. * * @param name Name of the change to look up * @return The change ID, or {@code -1} if no change with that name exists. */ public long lookupChangeId(String name) { return CompatConfig.get().lookupChangeId(name); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; Loading Loading @@ -151,4 +202,34 @@ public class PlatformCompat extends IPlatformCompat.Stub { private void reportChange(long changeId, int uid, int state) { mChangeReporter.reportChange(uid, changeId, state); } private void killPackage(String packageName) { int uid = -1; try { uid = mContext.getPackageManager().getPackageUid(packageName, 0); } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "Didn't find package " + packageName + " on device.", e); return; } Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ")."); killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL, "PlatformCompat overrides"); } private void killUid(int appId, int userId, String reason) { final long identity = Binder.clearCallingIdentity(); try { IActivityManager am = ActivityManager.getService(); if (am != null) { try { am.killUid(appId, userId, reason); } catch (RemoteException e) { /* ignore - same process */ } } } finally { Binder.restoreCallingIdentity(identity); } } }