Merge "Make CompatConfig be package private."
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 5857642..045a680 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -133,7 +133,7 @@
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.
@@ -142,7 +142,28 @@
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.
*
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e5c8ba5..5af1480 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -349,7 +349,6 @@
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;
@@ -5049,8 +5048,9 @@
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) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 6e92e80..d9e4844 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -41,6 +41,7 @@
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;
@@ -80,15 +81,17 @@
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;
@@ -2868,56 +2871,49 @@
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();
+ 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":
- if (!config.addOverride(changeId, packageName, true)) {
- pw.println("Warning! Change " + changeId + " is not known yet. Enabling it"
- + " could have no effect.");
- }
+ 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 + ".");
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index d6ec22b..490cce3 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -43,13 +43,14 @@
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";
@@ -61,13 +62,13 @@
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;
}
@@ -77,7 +78,7 @@
*
* @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);
}
@@ -89,10 +90,10 @@
*
* @param app 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.
+ * 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) {
@@ -113,7 +114,7 @@
* @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)) {
@@ -128,11 +129,11 @@
* Find if a given change is enabled for a given application.
*
* @param changeId The ID of the change in question
- * @param app App to check for
+ * @param app App to check for
* @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.
+ * 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) {
@@ -150,14 +151,15 @@
*
* <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
- * this change is not known; it will only have any effect if any code in the
- * platform is gated on the ID given.
+ * @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.
+ * @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);
@@ -172,15 +174,27 @@
}
/**
+ * 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
* restarted.
*
- * @param changeId The ID of the change that was overridden.
+ * @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;
*/
- public boolean removeOverride(long changeId, String packageName) {
+ boolean removeOverride(long changeId, String packageName) {
boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
@@ -191,22 +205,22 @@
}
return overrideExists;
}
+
/**
* Overrides the enabled state for a given change and app. This method is intended to be used
* *only* for debugging purposes.
*
* <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
*
- * @param overrides list of overrides to default changes config.
+ * @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()) {
+ for (Long changeId : overrides.enabledChanges()) {
addOverride(changeId, packageName, true);
}
- for (Long changeId: overrides.disabledChanges()) {
+ for (Long changeId : overrides.disabledChanges()) {
addOverride(changeId, packageName, false);
}
}
@@ -221,7 +235,7 @@
*
* @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);
@@ -230,11 +244,11 @@
}
/**
- * Dumps the current list of compatibility config information.
- *
- * @param pw The {@link PrintWriter} instance to which the information will be dumped.
- */
- public void dumpConfig(PrintWriter pw) {
+ * Dumps the current list of compatibility config information.
+ *
+ * @param pw The {@link PrintWriter} instance to which the information will be dumped.
+ */
+ void dumpConfig(PrintWriter pw) {
synchronized (mChanges) {
if (mChanges.size() == 0) {
pw.println("No compat overrides.");
@@ -252,10 +266,10 @@
*
* @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped.
* @return A {@link CompatibilityChangeConfig} which contains the compat config info for the
- * given app.
+ * given app.
*/
- public CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) {
+ CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) {
Set<Long> enabled = new HashSet<>();
Set<Long> disabled = new HashSet<>();
synchronized (mChanges) {
@@ -276,15 +290,15 @@
*
* @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) {
CompatChange change = mChanges.valueAt(i);
changeInfos[i] = new CompatibilityChangeInfo(change.getId(),
- change.getName(),
- change.getEnableAfterTargetSdk(),
- change.getDisabled());
+ change.getName(),
+ change.getEnableAfterTargetSdk(),
+ change.getDisabled());
}
return changeInfos;
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 75e2d22..709f3f8 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -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;
@@ -106,12 +110,26 @@
@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
@@ -124,6 +142,39 @@
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;
@@ -151,4 +202,34 @@
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);
+ }
+ }
}