Merge "Refactor PlatformCompat and related files."

This commit is contained in:
satayev
2021-01-20 14:13:45 +00:00
committed by Gerrit Code Review
3 changed files with 254 additions and 269 deletions

View File

@@ -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.
*
* @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;
* <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
* @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.
* <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();
}

View File

@@ -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.
*
* @param change The change to add. Any change with the same ID will be overwritten.
* <p>This is intended to be used by code that reads change config from the filesystem. This
* should be done at system startup time.
*
* <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.
*
* @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.
* <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
*/
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>Note, package overrides are not persistent and will be lost on system or runtime restart.
* <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.
*
* @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.
* <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
* @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)}.
*
* @param changeId The ID of the change that was overridden.
* @param packageName The app package name that was overridden.
* <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
* @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.
*/

View File

@@ -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.
*
* @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.
* TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
*/
public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
return mCompatConfig.registerListener(changeId, listener);
public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
return mCompatConfig.isChangeEnabled(changeId, appInfo);
}
/**
* Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}.
*
* <p>Does not perform costly permission check.
*/
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();