diff options
3 files changed, 253 insertions, 268 deletions
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index cc266d60465e..f54c96b88f70 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -22,17 +22,16 @@ import java.util.Map; parcelable CompatibilityChangeConfig; parcelable CompatibilityChangeInfo; - /** * Platform private API for talking with the PlatformCompat service. * - * <p> Should be used for gating and logging from non-app processes. - * For app processes please use android.compat.Compatibility API. + * <p>Should be used for gating and logging from non-app processes. + * + * <p>Note: for app processes please use {@code android.compat.Compatibility} API. * * {@hide} */ -interface IPlatformCompat -{ +interface IPlatformCompat { /** * Reports that a compatibility change is affecting an app process now. @@ -40,8 +39,9 @@ interface IPlatformCompat * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)}, * you do not need to call this API directly. The change will be reported for you. * - * @param changeId The ID of the compatibility change taking effect. - * @param appInfo Representing the affected app. + * @param changeId the ID of the compatibility change taking effect + * @param appInfo representing the affected app + * @throws SecurityException if logging is not allowed */ void reportChange(long changeId, in ApplicationInfo appInfo); @@ -51,11 +51,12 @@ interface IPlatformCompat * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)}, * you do not need to call this API directly. The change will be reported for you. * - * @param changeId The ID of the compatibility change taking effect. - * @param userId The ID of the user that the operation is done for. - * @param packageName The package name of the app in question. + * @param changeId the ID of the compatibility change taking effect + * @param userId the ID of the user that the operation is done for + * @param packageName the package name of the app in question + * @throws SecurityException if logging is not allowed */ - void reportChangeByPackageName(long changeId, in String packageName, int userId); + void reportChangeByPackageName(long changeId, in String packageName, int userId); /** * Reports that a compatibility change is affecting an app process now. @@ -63,13 +64,14 @@ interface IPlatformCompat * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)}, * you do not need to call this API directly. The change will be reported for you. * - * @param changeId The ID of the compatibility change taking effect. - * @param uid The UID of the app in question. + * @param changeId the ID of the compatibility change taking effect + * @param uid the UID of the app in question + * @throws SecurityException if logging is not allowed */ void reportChangeByUid(long changeId, int uid); /** - * Query if a given compatibility change is enabled for an app process. This method should + * Queries if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * * <p>If this method returns {@code true}, the calling code should implement the compatibility @@ -79,14 +81,15 @@ interface IPlatformCompat * <p>It will also report the change as {@link #reportChange(long, ApplicationInfo)} would, so * there is no need to call that method directly. * - * @param changeId The ID of the compatibility change in question. - * @param appInfo Representing the app in question. - * @return {@code true} if the change is enabled for the current app. + * @param changeId the ID of the compatibility change in question + * @param appInfo representing the app in question + * @return {@code true} if the change is enabled for the current app + * @throws SecurityException if logging or reading compat confis is not allowed */ boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo); /** - * Query if a given compatibility change is enabled for an app process. This method should + * Queries if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name @@ -102,15 +105,16 @@ interface IPlatformCompat * <p>It will also report the change as {@link #reportChange(long, String)} would, so there is * no need to call that method directly. * - * @param changeId The ID of the compatibility change in question. - * @param packageName The package name of the app in question. - * @param userId The ID of the user that the operation is done for. - * @return {@code true} if the change is enabled for the current app. + * @param changeId the ID of the compatibility change in question + * @param packageName the package name of the app in question + * @param userId the ID of the user that the operation is done for + * @return {@code true} if the change is enabled for the current app + * @throws SecurityException if logging or reading compat confis is not allowed */ boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId); /** - * Query if a given compatibility change is enabled for an app process. This method should + * Queries if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a uid @@ -127,110 +131,121 @@ interface IPlatformCompat * <p>It will also report the change as {@link #reportChange(long, int)} would, so there is * no need to call that method directly. * - * @param changeId The ID of the compatibility change in question. - * @param uid The UID of the app in question. - * @return {@code true} if the change is enabled for the current app. + * @param changeId the ID of the compatibility change in question + * @param uid the UID of the app in question + * @return {@code true} if the change is enabled for the current app + * @throws SecurityException if logging or reading compat confis is not allowed */ boolean isChangeEnabledByUid(long changeId, int uid); /** - * Add overrides to compatibility changes. Kills the app to allow the changes to take effect. + * Adds overrides to compatibility changes. * - * @param overrides Parcelable containing the compat change overrides to be applied. - * @param packageName The package name of the app whose changes will be overridden. + * <p>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 + * @throws SecurityException if overriding changes is not permitted */ void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** - * Add overrides to compatibility changes. Doesn't kill the app, to be only used in tests. + * Adds overrides to compatibility changes. * - * @param overrides Parcelable containing the compat change overrides to be applied. - * @param packageName The package name of the app whose changes will be overridden. + * <p>Does not 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 + * @throws SecurityException if overriding changes is not permitted. */ 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. + * Restores the default behaviour for the given change and app. + * + * <p>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; + * @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 + * @throws SecurityException if overriding changes is not permitted */ boolean clearOverride(long changeId, String packageName); /** - * Enable all compatibility changes which have enabledSinceTargetSdk == - * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the - * changes to take effect. + * Enables all compatibility changes that have enabledSinceTargetSdk == + * {@param targetSdkVersion} for an app, subject to the policy. * - * @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. + * <p>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. + * @throws SecurityException if overriding changes is not permitted. */ 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. + * Disables all compatibility changes that have enabledAfterTargetSdk == + * {@param targetSdkVersion} for an app, subject to the policy. * - * @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. + * <p>Kills the app to allow the changes to take effect. * - * @return The number of changes that were disabled. + * @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 + * @throws SecurityException if overriding changes is not permitted. */ int disableTargetSdkChanges(in String packageName, int targetSdkVersion); /** - * Revert overrides to compatibility changes. Kills the app to allow the changes to take effect. + * Restores the default behaviour for the given app. * - * @param packageName The package name of the app whose overrides will be cleared. + * <p>Kills the app to allow the changes to take effect. * + * @param packageName the package name of the app whose overrides will be cleared + * @throws SecurityException if overriding changes is not permitted */ void clearOverrides(in String packageName); /** - * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests. + * Restores the default behaviour for the given app. * - * @param packageName The package name of the app whose overrides will be cleared. + * <p>Does not kill the app; to be only used in tests. * + * @param packageName the package name of the app whose overrides will be cleared + * @throws SecurityException if overriding changes is not permitted */ void clearOverridesForTest(in String packageName); - /** * Get configs for an application. * - * @param appInfo The application whose config will be returned. - * - * @return A {@link CompatibilityChangeConfig}, representing whether a change is enabled for - * the given app or not. + * @param appInfo the application whose config will be returned + * @return a {@link CompatibilityChangeConfig}, representing whether a change is enabled for + * the given app or not */ CompatibilityChangeConfig getAppConfig(in ApplicationInfo appInfo); /** * List all compatibility changes. * - * @return An array of {@link CompatChangeInfo} known to the service. + * @return an array of {@link CompatibilityChangeInfo} known to the service */ CompatibilityChangeInfo[] listAllChanges(); /** - * List the compatibility changes that should be present in the UI. - * Filters out certain changes like e.g. logging only. - * - * @return An array of {@link CompatChangeInfo}. - */ + * List the compatibility changes that should be present in the UI. + * Filters out certain changes like e.g. logging only. + * + * @return an array of {@link CompatibilityChangeInfo} + */ CompatibilityChangeInfo[] listUIChanges(); /** - * Get an instance that can determine whether a changeid can be overridden for a package name. + * Gets an instance that can determine whether a changeid can be overridden for a package name. */ IOverrideValidator getOverrideValidator(); } diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 9376e8dc16ea..69686a2e4678 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -21,7 +21,6 @@ import android.compat.Compatibility.ChangeConfig; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Environment; -import android.os.RemoteException; import android.text.TextUtils; import android.util.LongArray; import android.util.LongSparseArray; @@ -53,7 +52,7 @@ import java.util.Set; import javax.xml.datatype.DatatypeConfigurationException; /** - * This class maintains state relating to platform compatibility changes. + * CompatConfig maintains state related to the platform compatibility changes. * * <p>It stores the default configuration for each change, and any per-package overrides that have * been configured. @@ -65,18 +64,38 @@ final class CompatConfig { @GuardedBy("mChanges") private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); - private OverrideValidatorImpl mOverrideValidator; + private final OverrideValidatorImpl mOverrideValidator; @VisibleForTesting CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this); } + static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) { + CompatConfig config = new CompatConfig(androidBuildClassifier, context); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "etc", "compatconfig")); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "system_ext", "etc", "compatconfig")); + + List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos(); + for (ApexManager.ActiveApexInfo apex : apexes) { + config.initConfigFromLib(Environment.buildPath( + apex.apexDirectory, "etc", "compatconfig")); + } + config.invalidateCache(); + return config; + } + /** - * Add a change. This is intended to be used by code that reads change config from the - * filesystem. This should be done at system startup time. + * Adds a change. + * + * <p>This is intended to be used by code that reads change config from the filesystem. This + * should be done at system startup time. * - * @param change The change to add. Any change with the same ID will be overwritten. + * <p>Any change with the same ID will be overwritten. + * + * @param change the change to add */ void addChange(CompatChange change) { synchronized (mChanges) { @@ -86,13 +105,15 @@ final class CompatConfig { } /** - * 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. + * Retrieves the set of disabled changes for a given app. + * + * <p>Any change ID not in the returned array is by default enabled for the app. + * + * <p>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. * - * @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. + * @param app the app in question + * @return a sorted long array of change IDs */ long[] getDisabledChanges(ApplicationInfo app) { LongArray disabled = new LongArray(); @@ -110,10 +131,10 @@ final class CompatConfig { } /** - * Look up a change ID by name. + * Looks 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. + * @param name name of the change to look up + * @return the change ID, or {@code -1} if no change with that name exists */ long lookupChangeId(String name) { synchronized (mChanges) { @@ -127,10 +148,10 @@ final class CompatConfig { } /** - * Find if a given change is enabled for a given application. + * Checks 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 changeId the ID of the change in question + * @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. */ @@ -146,10 +167,10 @@ final class CompatConfig { } /** - * Find if a given change will be enabled for a given package name, prior to installation. + * Checks if a given change will be enabled for a given package name after the installation. * - * @param changeId The ID of the change in question - * @param packageName Package name to check for + * @param changeId the ID of the change in question + * @param packageName package name to check for * @return {@code true} if the change would be enabled for this package name. Also returns * {@code true} if the change ID is not known, as unknown changes are enabled by default. */ @@ -165,22 +186,22 @@ final class CompatConfig { } /** - * Overrides the enabled state for a given change and app. This method is intended to be used - * *only* for debugging purposes, ultimately invoked either by an adb command, or from some - * developer settings UI. + * Overrides the enabled state for a given change and app. + * + * <p>This method is intended to be used *only* for debugging purposes, ultimately invoked + * either by an adb command, or from some developer settings UI. * - * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. + * <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 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. + * @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 + * @throws IllegalStateException if overriding is not allowed */ - boolean addOverride(long changeId, String packageName, boolean enabled) - throws SecurityException { + boolean addOverride(long changeId, String packageName, boolean enabled) { boolean alreadyKnown = true; OverrideAllowedState allowedState = mOverrideValidator.getOverrideAllowedState(changeId, packageName); @@ -201,18 +222,14 @@ final class CompatConfig { break; default: throw new IllegalStateException("Should only be able to override changes that " - + "are allowed or can be deferred."); + + "are allowed or can be deferred."); } invalidateCache(); } return alreadyKnown; } - /** - * Check whether the change is known to the compat config. - * - * @return {@code true} if the change is known. - */ + /** Checks whether the change is known to the compat config. */ boolean isKnownChangeId(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); @@ -221,16 +238,13 @@ final class CompatConfig { } /** - * Returns the maximum sdk version for which this change can be opted in (or -1 if it is not - * target sdk gated). + * Returns the maximum SDK version for which this change can be opted in (or -1 if it is not + * target SDK gated). */ int maxTargetSdkForChangeIdOptIn(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c == null) { - return -1; - } - if (c.getEnableSinceTargetSdk() != -1) { + if (c != null && c.getEnableSinceTargetSdk() != -1) { return c.getEnableSinceTargetSdk() - 1; } return -1; @@ -243,10 +257,7 @@ final class CompatConfig { boolean isLoggingOnly(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c == null) { - return false; - } - return c.getLoggingOnly(); + return c != null && c.getLoggingOnly(); } } @@ -256,24 +267,21 @@ final class CompatConfig { boolean isDisabled(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c == null) { - return false; - } - return c.getDisabled(); + return c != null && c.getDisabled(); } } /** - * 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. + * Removes an override previously added via {@link #addOverride(long, String, boolean)}. + * + * <p>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 packageName The app package name 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; */ - boolean removeOverride(long changeId, String packageName) - throws SecurityException { + boolean removeOverride(long changeId, String packageName) { boolean overrideExists = false; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); @@ -299,13 +307,12 @@ final class CompatConfig { /** * Overrides the enabled state for a given change and app. * - * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. + * <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 packageName app for which the overrides will be applied. + * @param overrides list of overrides to default changes config + * @param packageName app for which the overrides will be applied */ - void addOverrides(CompatibilityChangeConfig overrides, String packageName) - throws RemoteException, SecurityException { + void addOverrides(CompatibilityChangeConfig overrides, String packageName) { synchronized (mChanges) { for (Long changeId : overrides.enabledChanges()) { addOverride(changeId, packageName, true); @@ -324,9 +331,9 @@ final class CompatConfig { * * <p>This restores the default behaviour for the given app. * - * @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 SecurityException { + void removePackageOverrides(String packageName) { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { CompatChange change = mChanges.valueAt(i); @@ -337,8 +344,7 @@ final class CompatConfig { } private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName, - int targetSdkVersion) - throws RemoteException { + int targetSdkVersion) { LongArray allowed = new LongArray(); synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { @@ -348,7 +354,7 @@ final class CompatConfig { } OverrideAllowedState allowedState = mOverrideValidator.getOverrideAllowedState(change.getId(), - packageName); + packageName); if (allowedState.state == OverrideAllowedState.ALLOWED) { allowed.add(change.getId()); } @@ -361,10 +367,9 @@ final class CompatConfig { * Enables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for * {@param packageName}. * - * @return The number of changes that were toggled. + * @return the number of changes that were toggled */ - int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) - throws RemoteException { + int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) { long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion); for (long changeId : changes) { addOverride(changeId, packageName, true); @@ -372,15 +377,13 @@ final class CompatConfig { return changes.length; } - /** * Disables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for * {@param packageName}. * - * @return The number of changes that were toggled. + * @return the number of changes that were toggled */ - int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) - throws RemoteException { + int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) { long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion); for (long changeId : changes) { addOverride(changeId, packageName, false); @@ -425,7 +428,7 @@ final class CompatConfig { /** * Dumps the current list of compatibility config information. * - * @param pw The {@link PrintWriter} instance to which the information will be dumped. + * @param pw {@link PrintWriter} instance to which the information will be dumped */ void dumpConfig(PrintWriter pw) { synchronized (mChanges) { @@ -441,13 +444,10 @@ final class CompatConfig { } /** - * Get the config for a given app. + * Returns config for a given app. * - * @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. + * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped */ - CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) { Set<Long> enabled = new HashSet<>(); Set<Long> disabled = new HashSet<>(); @@ -467,7 +467,7 @@ final class CompatConfig { /** * Dumps all the compatibility change information. * - * @return An array of {@link CompatibilityChangeInfo} with the current changes. + * @return an array of {@link CompatibilityChangeInfo} with the current changes */ CompatibilityChangeInfo[] dumpChanges() { synchronized (mChanges) { @@ -480,22 +480,6 @@ final class CompatConfig { } } - static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) { - CompatConfig config = new CompatConfig(androidBuildClassifier, context); - config.initConfigFromLib(Environment.buildPath( - Environment.getRootDirectory(), "etc", "compatconfig")); - config.initConfigFromLib(Environment.buildPath( - Environment.getRootDirectory(), "system_ext", "etc", "compatconfig")); - - List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos(); - for (ApexManager.ActiveApexInfo apex : apexes) { - config.initConfigFromLib(Environment.buildPath( - apex.apexDirectory, "etc", "compatconfig")); - } - config.invalidateCache(); - return config; - } - void initConfigFromLib(File libraryDir) { if (!libraryDir.exists() || !libraryDir.isDirectory()) { Slog.d(TAG, "No directory " + libraryDir + ", skipping"); @@ -526,6 +510,7 @@ final class CompatConfig { private void invalidateCache() { ChangeIdStateCache.invalidate(); } + /** * Rechecks all the existing overrides for a package. */ diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 1ea468c341d2..cf5e16e53926 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -63,45 +63,43 @@ public class PlatformCompat extends IPlatformCompat.Stub { private final ChangeReporter mChangeReporter; private final CompatConfig mCompatConfig; - private static int sMinTargetSdk = Build.VERSION_CODES.Q; - public PlatformCompat(Context context) { mContext = context; - mChangeReporter = new ChangeReporter( - ChangeReporter.SOURCE_SYSTEM_SERVER); + mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); } @VisibleForTesting PlatformCompat(Context context, CompatConfig compatConfig) { mContext = context; - mChangeReporter = new ChangeReporter( - ChangeReporter.SOURCE_SYSTEM_SERVER); + mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = compatConfig; + registerPackageReceiver(context); } @Override public void reportChange(long changeId, ApplicationInfo appInfo) { - checkCompatChangeLogPermission(); - reportChange(changeId, appInfo.uid, - ChangeReporter.STATE_LOGGED); + reportChangeByUid(changeId, appInfo.uid); } @Override - public void reportChangeByPackageName(long changeId, String packageName, int userId) { - checkCompatChangeLogPermission(); + public void reportChangeByPackageName(long changeId, String packageName, + @UserIdInt int userId) { ApplicationInfo appInfo = getApplicationInfo(packageName, userId); - if (appInfo == null) { - return; + if (appInfo != null) { + reportChangeByUid(changeId, appInfo.uid); } - reportChange(changeId, appInfo); } @Override public void reportChangeByUid(long changeId, int uid) { checkCompatChangeLogPermission(); - reportChange(changeId, uid, ChangeReporter.STATE_LOGGED); + reportChangeInternal(changeId, uid, ChangeReporter.STATE_LOGGED); + } + + private void reportChangeInternal(long changeId, int uid, int state) { + mChangeReporter.reportChange(uid, changeId, state); } @Override @@ -110,28 +108,6 @@ public class PlatformCompat extends IPlatformCompat.Stub { return isChangeEnabledInternal(changeId, appInfo); } - /** - * Internal version of the above method, without logging. Does not perform costly permission - * check. - * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property. - */ - public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) { - return mCompatConfig.isChangeEnabled(changeId, appInfo); - } - - /** - * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. Does not perform costly - * permission check. - */ - public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) { - boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo); - if (appInfo != null) { - reportChange(changeId, appInfo.uid, - enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED); - } - return enabled; - } - @Override public boolean isChangeEnabledByPackageName(long changeId, String packageName, @UserIdInt int userId) { @@ -140,7 +116,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { if (appInfo == null) { return mCompatConfig.willChangeBeEnabled(changeId, packageName); } - return isChangeEnabled(changeId, appInfo); + return isChangeEnabledInternal(changeId, appInfo); } @Override @@ -152,81 +128,82 @@ public class PlatformCompat extends IPlatformCompat.Stub { } boolean enabled = true; for (String packageName : packages) { - enabled = enabled && isChangeEnabledByPackageName(changeId, packageName, + enabled &= isChangeEnabledByPackageName(changeId, packageName, UserHandle.getUserId(uid)); } return enabled; } /** - * Register a listener for change state overrides. Only one listener per change is allowed. + * Internal version of the above method, without logging. * - * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with - * packageName before the app is killed upon an override change. The state of a change is not - * guaranteed to change when {@code listener.onCompatChange(String)} is called. + * <p>Does not perform costly permission check. + * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property. + */ + public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) { + return mCompatConfig.isChangeEnabled(changeId, appInfo); + } + + /** + * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. * - * @param changeId to get updates for - * @param listener the listener that will be called upon a potential change for package. - * @throws IllegalStateException if a listener was already registered for changeId - * @returns {@code true} if a change with changeId was already known, or (@code false} - * otherwise. + * <p>Does not perform costly permission check. */ - public boolean registerListener(long changeId, CompatChange.ChangeListener listener) { - return mCompatConfig.registerListener(changeId, listener); + public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) { + boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo); + if (appInfo != null) { + reportChangeInternal(changeId, appInfo.uid, + enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED); + } + return enabled; } @Override - public void setOverrides(CompatibilityChangeConfig overrides, String packageName) - throws RemoteException, SecurityException { + public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.addOverrides(overrides, packageName); killPackage(packageName); } @Override - public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) - throws RemoteException, SecurityException { + public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.addOverrides(overrides, packageName); } @Override - public int enableTargetSdkChanges(String packageName, int targetSdkVersion) - throws RemoteException, SecurityException { + public int enableTargetSdkChanges(String packageName, int targetSdkVersion) { checkCompatChangeOverridePermission(); - int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName, - targetSdkVersion); + int numChanges = + mCompatConfig.enableTargetSdkChangesForPackage(packageName, targetSdkVersion); killPackage(packageName); return numChanges; } @Override - public int disableTargetSdkChanges(String packageName, int targetSdkVersion) - throws RemoteException, SecurityException { + public int disableTargetSdkChanges(String packageName, int targetSdkVersion) { checkCompatChangeOverridePermission(); - int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName, - targetSdkVersion); + int numChanges = + mCompatConfig.disableTargetSdkChangesForPackage(packageName, targetSdkVersion); killPackage(packageName); return numChanges; } @Override - public void clearOverrides(String packageName) throws RemoteException, SecurityException { + public void clearOverrides(String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.removePackageOverrides(packageName); killPackage(packageName); } @Override - public void clearOverridesForTest(String packageName) - throws RemoteException, SecurityException { + public void clearOverridesForTest(String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.removePackageOverrides(packageName); } @Override - public boolean clearOverride(long changeId, String packageName) - throws RemoteException, SecurityException { + public boolean clearOverride(long changeId, String packageName) { checkCompatChangeOverridePermission(); boolean existed = mCompatConfig.removeOverride(changeId, packageName); killPackage(packageName); @@ -247,18 +224,13 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public CompatibilityChangeInfo[] listUIChanges() { - return Arrays.stream(listAllChanges()).filter( - x -> isShownInUI(x)).toArray(CompatibilityChangeInfo[]::new); + return Arrays.stream(listAllChanges()).filter(this::isShownInUI).toArray( + CompatibilityChangeInfo[]::new); } - /** - * Check whether the change is known to the compat config. - * - * @return {@code true} if the change is known. - */ + /** Checks whether the change is known to the compat config. */ public boolean isKnownChangeId(long changeId) { return mCompatConfig.isKnownChangeId(changeId); - } /** @@ -286,7 +258,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; + if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) { + return; + } checkCompatChangeReadAndLogPermission(); mCompatConfig.dumpConfig(pw); } @@ -298,7 +272,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { /** * Clears information stored about events reported on behalf of an app. - * To be called once upon app start or end. A second call would be a no-op. + * + * <p>To be called once upon app start or end. A second call would be a no-op. * * @param appInfo the app to reset */ @@ -311,13 +286,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { packageName, 0, userId, userId); } - private void reportChange(long changeId, int uid, int state) { - mChangeReporter.reportChange(uid, changeId, state); - } - private void killPackage(String packageName) { int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName, - 0, UserHandle.myUserId()); + 0, UserHandle.myUserId()); if (uid < 0) { Slog.w(TAG, "Didn't find package " + packageName + " on device."); @@ -325,21 +296,18 @@ public class PlatformCompat extends IPlatformCompat.Stub { } Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ")."); - killUid(UserHandle.getAppId(uid), - UserHandle.USER_ALL, "PlatformCompat overrides"); + killUid(UserHandle.getAppId(uid)); } - private void killUid(int appId, int userId, String reason) { + private void killUid(int appId) { 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 */ - } + am.killUid(appId, UserHandle.USER_ALL, "PlatformCompat overrides"); } + } catch (RemoteException e) { + /* ignore - same process */ } finally { Binder.restoreCallingIdentity(identity); } @@ -350,13 +318,12 @@ public class PlatformCompat extends IPlatformCompat.Stub { if (Binder.getCallingUid() == SYSTEM_UID) { return; } - if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) - != PERMISSION_GRANTED) { + if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) != PERMISSION_GRANTED) { throw new SecurityException("Cannot log compat change usage"); } } - private void checkCompatChangeReadPermission() throws SecurityException { + private void checkCompatChangeReadPermission() { // Don't check for permissions within the system process if (Binder.getCallingUid() == SYSTEM_UID) { return; @@ -367,7 +334,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } - private void checkCompatChangeOverridePermission() throws SecurityException { + private void checkCompatChangeOverridePermission() { // Don't check for permissions within the system process if (Binder.getCallingUid() == SYSTEM_UID) { return; @@ -378,7 +345,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } - private void checkCompatChangeReadAndLogPermission() throws SecurityException { + private void checkCompatChangeReadAndLogPermission() { checkCompatChangeReadPermission(); checkCompatChangeLogPermission(); } @@ -391,16 +358,34 @@ public class PlatformCompat extends IPlatformCompat.Stub { return false; } if (change.getEnableSinceTargetSdk() > 0) { - if (change.getEnableSinceTargetSdk() < sMinTargetSdk) { - return false; - } + return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q; } return true; } /** + * Registers a listener for change state overrides. + * + * <p>Only one listener per change is allowed. + * + * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with + * packageName before the app is killed upon an override change. The state of a change is not + * guaranteed to change when {@code listener.onCompatChange(String)} is called. + * + * @param changeId to get updates for + * @param listener the listener that will be called upon a potential change for package + * @return {@code true} if a change with changeId was already known, or (@code false} + * otherwise + * @throws IllegalStateException if a listener was already registered for changeId + */ + public boolean registerListener(long changeId, CompatChange.ChangeListener listener) { + return mCompatConfig.registerListener(changeId, listener); + } + + /** * Registers a broadcast receiver that listens for package install, replace or remove. - * @param context the context where the receiver should be registered. + * + * @param context the context where the receiver should be registered */ public void registerPackageReceiver(Context context) { final BroadcastReceiver receiver = new BroadcastReceiver() { @@ -429,8 +414,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } /** - * Register the observer for - * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT} + * Registers the observer for + * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}. */ public void registerContentObserver() { mCompatConfig.registerContentObserver(); |