Merge changes from topic "fix-policy"
* changes: Refactor CompatConfigTest and PlatformCompatTest Add test for OverrideValidatorImpl Enforce overriding methods for IPlatformCompat
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.compat;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* Platform private class for determining the type of Android build installed.
|
||||
*
|
||||
*/
|
||||
public class AndroidBuildClassifier {
|
||||
|
||||
public boolean isDebuggableBuild() {
|
||||
return Build.IS_DEBUGGABLE;
|
||||
}
|
||||
|
||||
public boolean isFinalBuild() {
|
||||
return "REL".equals(Build.VERSION.CODENAME);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.compat;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import com.android.internal.compat.OverrideAllowedState;
|
||||
|
||||
/**
|
||||
* Platform private API for determining whether a changeId can be overridden.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface IOverrideValidator
|
||||
{
|
||||
/**
|
||||
* Validation function.
|
||||
* @param changeId id of the change to be toggled on or off.
|
||||
* @param packageName package of the app for which the change should be overridden.
|
||||
* @return {@link OverrideAllowedState} specifying whether the change can be overridden for
|
||||
* the given package or a reason why not.
|
||||
*/
|
||||
OverrideAllowedState getOverrideAllowedState(long changeId, String packageName);
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.internal.compat;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import com.android.internal.compat.IOverrideValidator;
|
||||
import java.util.Map;
|
||||
|
||||
parcelable CompatibilityChangeConfig;
|
||||
@@ -195,4 +196,9 @@ interface IPlatformCompat
|
||||
* @return An array of {@link CompatChangeInfo} known to the service.
|
||||
*/
|
||||
CompatibilityChangeInfo[] listAllChanges();
|
||||
|
||||
/**
|
||||
* Get an instance that can determine whether a changeid can be overridden for a package name.
|
||||
*/
|
||||
IOverrideValidator getOverrideValidator();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.compat;
|
||||
|
||||
parcelable OverrideAllowedState;
|
||||
153
core/java/com/android/internal/compat/OverrideAllowedState.java
Normal file
153
core/java/com/android/internal/compat/OverrideAllowedState.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.compat;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* This class contains all the possible override allowed states.
|
||||
*/
|
||||
public final class OverrideAllowedState implements Parcelable {
|
||||
@IntDef({
|
||||
ALLOWED,
|
||||
DISABLED_NOT_DEBUGGABLE,
|
||||
DISABLED_NON_TARGET_SDK,
|
||||
DISABLED_TARGET_SDK_TOO_HIGH,
|
||||
PACKAGE_DOES_NOT_EXIST
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface State {
|
||||
}
|
||||
|
||||
/**
|
||||
* Change can be overridden.
|
||||
*/
|
||||
public static final int ALLOWED = 0;
|
||||
/**
|
||||
* Change cannot be overridden, due to the app not being debuggable.
|
||||
*/
|
||||
public static final int DISABLED_NOT_DEBUGGABLE = 1;
|
||||
/**
|
||||
* Change cannot be overridden, due to the build being non-debuggable and the change being
|
||||
* non-targetSdk.
|
||||
*/
|
||||
public static final int DISABLED_NON_TARGET_SDK = 2;
|
||||
/**
|
||||
* Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk.
|
||||
*/
|
||||
public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3;
|
||||
/**
|
||||
* Package does not exist.
|
||||
*/
|
||||
public static final int PACKAGE_DOES_NOT_EXIST = 4;
|
||||
|
||||
@State
|
||||
public final int state;
|
||||
public final int appTargetSdk;
|
||||
public final int changeIdTargetSdk;
|
||||
|
||||
private OverrideAllowedState(Parcel parcel) {
|
||||
state = parcel.readInt();
|
||||
appTargetSdk = parcel.readInt();
|
||||
changeIdTargetSdk = parcel.readInt();
|
||||
}
|
||||
|
||||
public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) {
|
||||
this.state = state;
|
||||
this.appTargetSdk = appTargetSdk;
|
||||
this.changeIdTargetSdk = changeIdTargetSdk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(state);
|
||||
out.writeInt(appTargetSdk);
|
||||
out.writeInt(changeIdTargetSdk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces the policy for overriding compat changes.
|
||||
*
|
||||
* @param changeId the change id that was attempted to be overridden.
|
||||
* @param packageName the package for which the attempt was made.
|
||||
* @throws SecurityException if the policy forbids this operation.
|
||||
*/
|
||||
public void enforce(long changeId, String packageName)
|
||||
throws SecurityException {
|
||||
switch (state) {
|
||||
case ALLOWED:
|
||||
return;
|
||||
case DISABLED_NOT_DEBUGGABLE:
|
||||
throw new SecurityException(
|
||||
"Cannot override a change on a non-debuggable app and user build.");
|
||||
case DISABLED_NON_TARGET_SDK:
|
||||
throw new SecurityException(
|
||||
"Cannot override a default enabled/disabled change on a user build.");
|
||||
case DISABLED_TARGET_SDK_TOO_HIGH:
|
||||
throw new SecurityException(String.format(
|
||||
"Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is "
|
||||
+ "above the change's targetSdk threshold (%4$d)",
|
||||
changeId, packageName, appTargetSdk, changeIdTargetSdk));
|
||||
case PACKAGE_DOES_NOT_EXIST:
|
||||
throw new SecurityException(String.format(
|
||||
"Cannot override %1$d for %2$s because the package does not exist, and "
|
||||
+ "the change is targetSdk gated.",
|
||||
changeId, packageName));
|
||||
}
|
||||
}
|
||||
|
||||
public static final @NonNull
|
||||
Parcelable.Creator<OverrideAllowedState> CREATOR =
|
||||
new Parcelable.Creator<OverrideAllowedState>() {
|
||||
public OverrideAllowedState createFromParcel(Parcel parcel) {
|
||||
OverrideAllowedState info = new OverrideAllowedState(parcel);
|
||||
return info;
|
||||
}
|
||||
|
||||
public OverrideAllowedState[] newArray(int size) {
|
||||
return new OverrideAllowedState[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof OverrideAllowedState)) {
|
||||
return false;
|
||||
}
|
||||
OverrideAllowedState otherState = (OverrideAllowedState) obj;
|
||||
return state == otherState.state
|
||||
&& appTargetSdk == otherState.appTargetSdk
|
||||
&& changeIdTargetSdk == otherState.changeIdTargetSdk;
|
||||
}
|
||||
}
|
||||
@@ -2899,33 +2899,37 @@ final class ActivityManagerShellCommand extends ShellCommand {
|
||||
}
|
||||
ArraySet<Long> enabled = new ArraySet<>();
|
||||
ArraySet<Long> disabled = new ArraySet<>();
|
||||
switch (toggleValue) {
|
||||
case "enable":
|
||||
enabled.add(changeId);
|
||||
pw.println("Enabled change " + changeId + " for " + packageName + ".");
|
||||
CompatibilityChangeConfig overrides =
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled));
|
||||
platformCompat.setOverrides(overrides, packageName);
|
||||
return 0;
|
||||
case "disable":
|
||||
disabled.add(changeId);
|
||||
pw.println("Disabled change " + changeId + " for " + packageName + ".");
|
||||
overrides =
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled));
|
||||
platformCompat.setOverrides(overrides, packageName);
|
||||
return 0;
|
||||
case "reset":
|
||||
if (platformCompat.clearOverride(changeId, packageName)) {
|
||||
pw.println("Reset change " + changeId + " for " + packageName
|
||||
+ " to default value.");
|
||||
} else {
|
||||
pw.println("No override exists for changeId " + changeId + ".");
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
pw.println("Invalid toggle value: '" + toggleValue + "'.");
|
||||
try {
|
||||
switch (toggleValue) {
|
||||
case "enable":
|
||||
enabled.add(changeId);
|
||||
CompatibilityChangeConfig overrides =
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled));
|
||||
platformCompat.setOverrides(overrides, packageName);
|
||||
pw.println("Enabled change " + changeId + " for " + packageName + ".");
|
||||
return 0;
|
||||
case "disable":
|
||||
disabled.add(changeId);
|
||||
overrides =
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled));
|
||||
platformCompat.setOverrides(overrides, packageName);
|
||||
pw.println("Disabled change " + changeId + " for " + packageName + ".");
|
||||
return 0;
|
||||
case "reset":
|
||||
if (platformCompat.clearOverride(changeId, packageName)) {
|
||||
pw.println("Reset change " + changeId + " for " + packageName
|
||||
+ " to default value.");
|
||||
} else {
|
||||
pw.println("No override exists for changeId " + changeId + ".");
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
pw.println("Invalid toggle value: '" + toggleValue + "'.");
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
pw.println(e.getMessage());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
package com.android.server.compat;
|
||||
|
||||
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;
|
||||
@@ -26,8 +28,11 @@ import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
import com.android.internal.compat.CompatibilityChangeConfig;
|
||||
import com.android.internal.compat.CompatibilityChangeInfo;
|
||||
import com.android.internal.compat.IOverrideValidator;
|
||||
import com.android.internal.compat.OverrideAllowedState;
|
||||
import com.android.server.compat.config.Change;
|
||||
import com.android.server.compat.config.XmlParser;
|
||||
|
||||
@@ -54,22 +59,14 @@ final class CompatConfig {
|
||||
|
||||
private static final String TAG = "CompatConfig";
|
||||
|
||||
private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib(
|
||||
Environment.buildPath(
|
||||
Environment.getRootDirectory(), "etc", "compatconfig"));
|
||||
|
||||
@GuardedBy("mChanges")
|
||||
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
|
||||
|
||||
@VisibleForTesting
|
||||
CompatConfig() {
|
||||
}
|
||||
private IOverrideValidator mOverrideValidator;
|
||||
|
||||
/**
|
||||
* @return The static instance of this class to be used within the system server.
|
||||
*/
|
||||
static CompatConfig get() {
|
||||
return sInstance;
|
||||
@VisibleForTesting
|
||||
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
|
||||
mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,8 +156,12 @@ final class CompatConfig {
|
||||
* @param enabled If the change should be enabled or disabled.
|
||||
* @return {@code true} if the change existed before adding the override.
|
||||
*/
|
||||
boolean addOverride(long changeId, String packageName, boolean enabled) {
|
||||
boolean addOverride(long changeId, String packageName, boolean enabled)
|
||||
throws RemoteException, SecurityException {
|
||||
boolean alreadyKnown = true;
|
||||
OverrideAllowedState allowedState =
|
||||
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
|
||||
allowedState.enforce(changeId, packageName);
|
||||
synchronized (mChanges) {
|
||||
CompatChange c = mChanges.get(changeId);
|
||||
if (c == null) {
|
||||
@@ -185,6 +186,20 @@ final class CompatConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum sdk version for which this change should be enabled (or 0 if it is not
|
||||
* target sdk gated).
|
||||
*/
|
||||
int minTargetSdkForChangeId(long changeId) {
|
||||
synchronized (mChanges) {
|
||||
CompatChange c = mChanges.get(changeId);
|
||||
if (c == null) {
|
||||
return 0;
|
||||
}
|
||||
return c.getEnableAfterTargetSdk();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -194,34 +209,44 @@ final class CompatConfig {
|
||||
* @param packageName The app package name that was overridden.
|
||||
* @return {@code true} if an override existed;
|
||||
*/
|
||||
boolean removeOverride(long changeId, String packageName) {
|
||||
boolean removeOverride(long changeId, String packageName)
|
||||
throws RemoteException, SecurityException {
|
||||
boolean overrideExists = false;
|
||||
synchronized (mChanges) {
|
||||
CompatChange c = mChanges.get(changeId);
|
||||
if (c != null) {
|
||||
overrideExists = true;
|
||||
c.removePackageOverride(packageName);
|
||||
try {
|
||||
if (c != null) {
|
||||
OverrideAllowedState allowedState =
|
||||
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
|
||||
allowedState.enforce(changeId, packageName);
|
||||
overrideExists = true;
|
||||
c.removePackageOverride(packageName);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// Should never occur, since validator is in the same process.
|
||||
throw new RuntimeException("Unable to call override validator!", e);
|
||||
}
|
||||
}
|
||||
return overrideExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the enabled state for a given change and app. This method is intended to be used
|
||||
* *only* for debugging purposes.
|
||||
* 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.
|
||||
*
|
||||
* @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) {
|
||||
void addOverrides(CompatibilityChangeConfig overrides, String packageName)
|
||||
throws RemoteException, SecurityException {
|
||||
synchronized (mChanges) {
|
||||
for (Long changeId : overrides.enabledChanges()) {
|
||||
addOverride(changeId, packageName, true);
|
||||
}
|
||||
for (Long changeId : overrides.disabledChanges()) {
|
||||
addOverride(changeId, packageName, false);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,10 +260,22 @@ final class CompatConfig {
|
||||
*
|
||||
* @param packageName The package for which the overrides should be purged.
|
||||
*/
|
||||
void removePackageOverrides(String packageName) {
|
||||
void removePackageOverrides(String packageName) throws RemoteException, SecurityException {
|
||||
synchronized (mChanges) {
|
||||
for (int i = 0; i < mChanges.size(); ++i) {
|
||||
mChanges.valueAt(i).removePackageOverride(packageName);
|
||||
try {
|
||||
CompatChange change = mChanges.valueAt(i);
|
||||
OverrideAllowedState allowedState =
|
||||
mOverrideValidator.getOverrideAllowedState(change.getId(),
|
||||
packageName);
|
||||
allowedState.enforce(change.getId(), packageName);
|
||||
if (change != null) {
|
||||
mChanges.valueAt(i).removePackageOverride(packageName);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// Should never occur, since validator is in the same process.
|
||||
throw new RuntimeException("Unable to call override validator!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,17 +363,23 @@ final class CompatConfig {
|
||||
}
|
||||
}
|
||||
|
||||
CompatConfig initConfigFromLib(File libraryDir) {
|
||||
static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
|
||||
CompatConfig config = new CompatConfig(androidBuildClassifier, context);
|
||||
config.initConfigFromLib(Environment.buildPath(
|
||||
Environment.getRootDirectory(), "etc", "compatconfig"));
|
||||
return config;
|
||||
}
|
||||
|
||||
void initConfigFromLib(File libraryDir) {
|
||||
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
|
||||
Slog.e(TAG, "No directory " + libraryDir + ", skipping");
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
for (File f : libraryDir.listFiles()) {
|
||||
Slog.d(TAG, "Found a config file: " + f.getPath());
|
||||
//TODO(b/138222363): Handle duplicate ids across config files.
|
||||
readConfig(f);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void readConfig(File configFile) {
|
||||
@@ -350,4 +393,7 @@ final class CompatConfig {
|
||||
}
|
||||
}
|
||||
|
||||
IOverrideValidator getOverrideValidator() {
|
||||
return mOverrideValidator;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.compat;
|
||||
|
||||
import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
|
||||
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
|
||||
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
|
||||
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
|
||||
import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
import com.android.internal.compat.IOverrideValidator;
|
||||
import com.android.internal.compat.OverrideAllowedState;
|
||||
|
||||
/**
|
||||
* Implementation of the policy for allowing compat change overrides.
|
||||
*/
|
||||
public class OverrideValidatorImpl extends IOverrideValidator.Stub {
|
||||
|
||||
private AndroidBuildClassifier mAndroidBuildClassifier;
|
||||
private Context mContext;
|
||||
private CompatConfig mCompatConfig;
|
||||
|
||||
@VisibleForTesting
|
||||
OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier,
|
||||
Context context, CompatConfig config) {
|
||||
mAndroidBuildClassifier = androidBuildClassifier;
|
||||
mContext = context;
|
||||
mCompatConfig = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
|
||||
boolean debuggableBuild = false;
|
||||
boolean finalBuild = false;
|
||||
|
||||
debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
|
||||
finalBuild = mAndroidBuildClassifier.isFinalBuild();
|
||||
|
||||
// Allow any override for userdebug or eng builds.
|
||||
if (debuggableBuild) {
|
||||
return new OverrideAllowedState(ALLOWED, -1, -1);
|
||||
}
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
if (packageManager == null) {
|
||||
throw new IllegalStateException("No PackageManager!");
|
||||
}
|
||||
ApplicationInfo applicationInfo;
|
||||
try {
|
||||
applicationInfo = packageManager.getApplicationInfo(packageName, 0);
|
||||
} catch (NameNotFoundException e) {
|
||||
return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1);
|
||||
}
|
||||
int appTargetSdk = applicationInfo.targetSdkVersion;
|
||||
// Only allow overriding debuggable apps.
|
||||
if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
|
||||
return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1);
|
||||
}
|
||||
int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
|
||||
// Do not allow overriding non-target sdk gated changes on user builds
|
||||
if (minTargetSdk == -1) {
|
||||
return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
|
||||
}
|
||||
// Allow overriding any change for debuggable apps on non-final builds.
|
||||
if (!finalBuild) {
|
||||
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
|
||||
}
|
||||
// Only allow to opt-in for a targetSdk gated change.
|
||||
if (applicationInfo.targetSdkVersion < minTargetSdk) {
|
||||
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
|
||||
}
|
||||
return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,12 @@ import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
import android.util.StatsLog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
import com.android.internal.compat.ChangeReporter;
|
||||
import com.android.internal.compat.CompatibilityChangeConfig;
|
||||
import com.android.internal.compat.CompatibilityChangeInfo;
|
||||
import com.android.internal.compat.IOverrideValidator;
|
||||
import com.android.internal.compat.IPlatformCompat;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
|
||||
@@ -45,11 +48,21 @@ public class PlatformCompat extends IPlatformCompat.Stub {
|
||||
|
||||
private final Context mContext;
|
||||
private final ChangeReporter mChangeReporter;
|
||||
private final CompatConfig mCompatConfig;
|
||||
|
||||
public PlatformCompat(Context context) {
|
||||
mContext = context;
|
||||
mChangeReporter = new ChangeReporter(
|
||||
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
|
||||
mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
PlatformCompat(Context context, CompatConfig compatConfig) {
|
||||
mContext = context;
|
||||
mChangeReporter = new ChangeReporter(
|
||||
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
|
||||
mCompatConfig = compatConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,7 +87,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
|
||||
|
||||
@Override
|
||||
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
|
||||
if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
|
||||
if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
|
||||
reportChange(changeId, appInfo.uid,
|
||||
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
|
||||
return true;
|
||||
@@ -121,57 +134,59 @@ public class PlatformCompat extends IPlatformCompat.Stub {
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
|
||||
return CompatConfig.get().registerListener(changeId, listener);
|
||||
return mCompatConfig.registerListener(changeId, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
|
||||
CompatConfig.get().addOverrides(overrides, packageName);
|
||||
public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
|
||||
throws RemoteException, SecurityException {
|
||||
mCompatConfig.addOverrides(overrides, packageName);
|
||||
killPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
|
||||
CompatConfig.get().addOverrides(overrides, packageName);
|
||||
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
|
||||
throws RemoteException, SecurityException {
|
||||
mCompatConfig.addOverrides(overrides, packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearOverrides(String packageName) {
|
||||
CompatConfig config = CompatConfig.get();
|
||||
config.removePackageOverrides(packageName);
|
||||
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
|
||||
mCompatConfig.removePackageOverrides(packageName);
|
||||
killPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearOverridesForTest(String packageName) {
|
||||
CompatConfig config = CompatConfig.get();
|
||||
config.removePackageOverrides(packageName);
|
||||
public void clearOverridesForTest(String packageName)
|
||||
throws RemoteException, SecurityException {
|
||||
mCompatConfig.removePackageOverrides(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearOverride(long changeId, String packageName) {
|
||||
boolean existed = CompatConfig.get().removeOverride(changeId, packageName);
|
||||
public boolean clearOverride(long changeId, String packageName)
|
||||
throws RemoteException, SecurityException {
|
||||
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
|
||||
killPackage(packageName);
|
||||
return existed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
|
||||
return CompatConfig.get().getAppConfig(appInfo);
|
||||
return mCompatConfig.getAppConfig(appInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompatibilityChangeInfo[] listAllChanges() {
|
||||
return CompatConfig.get().dumpChanges();
|
||||
return mCompatConfig.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);
|
||||
return mCompatConfig.isKnownChangeId(changeId);
|
||||
|
||||
}
|
||||
|
||||
@@ -181,11 +196,11 @@ public class PlatformCompat extends IPlatformCompat.Stub {
|
||||
*
|
||||
* @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.
|
||||
* 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);
|
||||
return mCompatConfig.getDisabledChanges(appInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,18 +210,24 @@ public class PlatformCompat extends IPlatformCompat.Stub {
|
||||
* @return The change ID, or {@code -1} if no change with that name exists.
|
||||
*/
|
||||
public long lookupChangeId(String name) {
|
||||
return CompatConfig.get().lookupChangeId(name);
|
||||
return mCompatConfig.lookupChangeId(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
|
||||
CompatConfig.get().dumpConfig(pw);
|
||||
mCompatConfig.dumpConfig(pw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOverrideValidator getOverrideValidator() {
|
||||
return mCompatConfig.getOverrideValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param appInfo the app to reset
|
||||
*/
|
||||
public void resetReporting(ApplicationInfo appInfo) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.compat;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
class ApplicationInfoBuilder {
|
||||
private boolean mIsDebuggable;
|
||||
private int mTargetSdk;
|
||||
private String mPackageName;
|
||||
|
||||
private ApplicationInfoBuilder() {
|
||||
mTargetSdk = -1;
|
||||
}
|
||||
|
||||
static ApplicationInfoBuilder create() {
|
||||
return new ApplicationInfoBuilder();
|
||||
}
|
||||
|
||||
ApplicationInfoBuilder withTargetSdk(int targetSdk) {
|
||||
mTargetSdk = targetSdk;
|
||||
return this;
|
||||
}
|
||||
|
||||
ApplicationInfoBuilder debuggable() {
|
||||
mIsDebuggable = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
ApplicationInfoBuilder withPackageName(String packageName) {
|
||||
mPackageName = packageName;
|
||||
return this;
|
||||
}
|
||||
|
||||
ApplicationInfo build() {
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
if (mIsDebuggable) {
|
||||
applicationInfo.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
|
||||
}
|
||||
applicationInfo.packageName = mPackageName;
|
||||
applicationInfo.targetSdkVersion = mTargetSdk;
|
||||
return applicationInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.compat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Helper class for creating a CompatConfig.
|
||||
*/
|
||||
class CompatConfigBuilder {
|
||||
private ArrayList<CompatChange> mChanges;
|
||||
private AndroidBuildClassifier mBuildClassifier;
|
||||
private Context mContext;
|
||||
|
||||
private CompatConfigBuilder(AndroidBuildClassifier buildClassifier, Context context) {
|
||||
mChanges = new ArrayList<>();
|
||||
mBuildClassifier = buildClassifier;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
static CompatConfigBuilder create(AndroidBuildClassifier buildClassifier, Context context) {
|
||||
return new CompatConfigBuilder(buildClassifier, context);
|
||||
}
|
||||
|
||||
CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
|
||||
mChanges.add(new CompatChange(id, "", sdk, false, ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
|
||||
mChanges.add(new CompatChange(id, "", sdk, true, ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
|
||||
mChanges.add(new CompatChange(id, name, sdk, false, ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
|
||||
String description) {
|
||||
mChanges.add(new CompatChange(id, "", sdk, false, description));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addEnabledChangeWithId(long id) {
|
||||
mChanges.add(new CompatChange(id, "", -1, false, ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
|
||||
mChanges.add(new CompatChange(id, name, -1, false, ""));
|
||||
return this;
|
||||
}
|
||||
CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
|
||||
mChanges.add(new CompatChange(id, "", -1, false, description));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addDisabledChangeWithId(long id) {
|
||||
mChanges.add(new CompatChange(id, "", -1, true, ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
|
||||
mChanges.add(new CompatChange(id, name, -1, true, ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
|
||||
mChanges.add(new CompatChange(id, "", -1, true, description));
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatConfig build() {
|
||||
CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
|
||||
for (CompatChange change : mChanges) {
|
||||
config.addChange(change);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,25 @@ package com.android.server.compat;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -34,12 +47,12 @@ import java.util.UUID;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class CompatConfigTest {
|
||||
|
||||
private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) {
|
||||
ApplicationInfo ai = new ApplicationInfo();
|
||||
ai.packageName = pName;
|
||||
ai.targetSdkVersion = targetSdkVersion;
|
||||
return ai;
|
||||
}
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
PackageManager mPackageManager;
|
||||
@Mock
|
||||
private AndroidBuildClassifier mBuildClassifier;
|
||||
|
||||
private File createTempDir() {
|
||||
String base = System.getProperty("java.io.tmpdir");
|
||||
@@ -54,112 +67,206 @@ public class CompatConfigTest {
|
||||
os.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownChangeEnabled() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
// Assume userdebug/eng non-final build
|
||||
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
|
||||
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledChangeDisabled() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, ""));
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
|
||||
public void testUnknownChangeEnabled() throws Exception {
|
||||
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargetSdkChangeDisabled() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null));
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
|
||||
public void testDisabledChangeDisabled() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1234L)
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build()))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargetSdkChangeEnabled() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, ""));
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
|
||||
public void testTargetSdkChangeDisabled() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addTargetSdkChangeWithId(2, 1234L)
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(2).build()))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabledOverrideTargetSdkChange() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
|
||||
public void testTargetSdkChangeEnabled() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addTargetSdkChangeWithId(2, 1234L)
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDisabledChanges() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null));
|
||||
pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null));
|
||||
assertThat(pc.getDisabledChanges(
|
||||
makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
|
||||
public void testDisabledOverrideTargetSdkChange() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addTargetSdkDisabledChangeWithId(2, 1234L)
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(3).build())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDisabledChangesSorted() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
|
||||
pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null));
|
||||
pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null));
|
||||
assertThat(pc.getDisabledChanges(
|
||||
makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
|
||||
public void testGetDisabledChanges() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1234L)
|
||||
.addEnabledChangeWithId(2345L)
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.getDisabledChanges(
|
||||
ApplicationInfoBuilder.create().build())).asList().containsExactly(1234L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageOverrideEnabled() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled
|
||||
pc.addOverride(1234L, "com.some.package", true);
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
|
||||
public void testGetDisabledChangesSorted() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1234L)
|
||||
.addDisabledChangeWithId(123L)
|
||||
.addDisabledChangeWithId(12L)
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.getDisabledChanges(ApplicationInfoBuilder.create().build()))
|
||||
.asList().containsExactly(12L, 123L, 1234L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageOverrideDisabled() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
|
||||
pc.addOverride(1234L, "com.some.package", false);
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
|
||||
public void testPackageOverrideEnabled() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1234L)
|
||||
.build();
|
||||
|
||||
compatConfig.addOverride(1234L, "com.some.package", true);
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.some.package").build())).isTrue();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.other.package").build())).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageOverrideUnknownPackage() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addOverride(1234L, "com.some.package", false);
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
|
||||
public void testPackageOverrideDisabled() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addEnabledChangeWithId(1234L)
|
||||
.build();
|
||||
|
||||
compatConfig.addOverride(1234L, "com.some.package", false);
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.some.package").build())).isFalse();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.other.package").build())).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageOverrideUnknownChange() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
|
||||
public void testPackageOverrideUnknownPackage() throws Exception {
|
||||
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
|
||||
|
||||
compatConfig.addOverride(1234L, "com.some.package", false);
|
||||
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.some.package").build())).isFalse();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.other.package").build())).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovePackageOverride() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
|
||||
pc.addOverride(1234L, "com.some.package", false);
|
||||
pc.removeOverride(1234L, "com.some.package");
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
|
||||
public void testPreventAddOverride() throws Exception {
|
||||
final long changeId = 1234L;
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1234L)
|
||||
.build();
|
||||
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.some.package")
|
||||
.build();
|
||||
PackageManager packageManager = mock(PackageManager.class);
|
||||
when(mContext.getPackageManager()).thenReturn(packageManager);
|
||||
when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
|
||||
.thenReturn(applicationInfo);
|
||||
|
||||
// Force the validator to prevent overriding the change by using a user build.
|
||||
when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
|
||||
when(mBuildClassifier.isFinalBuild()).thenReturn(true);
|
||||
|
||||
assertThrows(SecurityException.class,
|
||||
() -> compatConfig.addOverride(1234L, "com.some.package", true)
|
||||
);
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupChangeId() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
|
||||
pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null));
|
||||
assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
|
||||
public void testPreventRemoveOverride() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1234L)
|
||||
.build();
|
||||
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.some.package")
|
||||
.build();
|
||||
when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
|
||||
.thenReturn(applicationInfo);
|
||||
// Assume the override was allowed to be added.
|
||||
compatConfig.addOverride(1234L, "com.some.package", true);
|
||||
|
||||
// Validator allows turning on the change.
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
|
||||
|
||||
// Reject all override attempts.
|
||||
// Force the validator to prevent overriding the change by using a user build.
|
||||
when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
|
||||
when(mBuildClassifier.isFinalBuild()).thenReturn(true);
|
||||
// Try to turn off change, but validator prevents it.
|
||||
assertThrows(SecurityException.class,
|
||||
() -> compatConfig.removeOverride(1234L, "com.some.package"));
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupChangeIdNotPresent() {
|
||||
CompatConfig pc = new CompatConfig();
|
||||
assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
|
||||
public void testRemovePackageOverride() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addEnabledChangeWithId(1234L)
|
||||
.build();
|
||||
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
|
||||
.withPackageName("com.some.package")
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
|
||||
|
||||
compatConfig.removeOverride(1234L, "com.some.package");
|
||||
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupChangeId() throws Exception {
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addEnabledChangeWithIdAndName(1234L, "MY_CHANGE")
|
||||
.addEnabledChangeWithIdAndName(2345L, "MY_OTHER_CHANGE")
|
||||
.build();
|
||||
|
||||
assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupChangeIdNotPresent() throws Exception {
|
||||
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
|
||||
assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -172,14 +279,17 @@ public class CompatConfigTest {
|
||||
|
||||
File dir = createTempDir();
|
||||
writeToFile(dir, "platform_compat_config.xml", configXml);
|
||||
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
|
||||
compatConfig.initConfigFromLib(dir);
|
||||
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.initConfigFromLib(dir);
|
||||
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
|
||||
assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
|
||||
assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
|
||||
assertThat(compatConfig.isChangeEnabled(1235L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
|
||||
assertThat(compatConfig.isChangeEnabled(1236L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -195,15 +305,16 @@ public class CompatConfigTest {
|
||||
File dir = createTempDir();
|
||||
writeToFile(dir, "libcore_platform_compat_config.xml", configXml1);
|
||||
writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2);
|
||||
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
|
||||
compatConfig.initConfigFromLib(dir);
|
||||
|
||||
CompatConfig pc = new CompatConfig();
|
||||
pc.initConfigFromLib(dir);
|
||||
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
|
||||
assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
|
||||
assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse();
|
||||
assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
|
||||
assertThat(compatConfig.isChangeEnabled(1234L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
|
||||
assertThat(compatConfig.isChangeEnabled(1235L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
|
||||
assertThat(compatConfig.isChangeEnabled(1236L,
|
||||
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.compat;
|
||||
|
||||
import android.compat.Compatibility;
|
||||
|
||||
import com.android.internal.compat.CompatibilityChangeConfig;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
class CompatibilityChangeConfigBuilder {
|
||||
private Set<Long> mEnabled;
|
||||
private Set<Long> mDisabled;
|
||||
|
||||
private CompatibilityChangeConfigBuilder() {
|
||||
mEnabled = new HashSet<>();
|
||||
mDisabled = new HashSet<>();
|
||||
}
|
||||
|
||||
static CompatibilityChangeConfigBuilder create() {
|
||||
return new CompatibilityChangeConfigBuilder();
|
||||
}
|
||||
|
||||
CompatibilityChangeConfigBuilder enable(Long id) {
|
||||
mEnabled.add(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatibilityChangeConfigBuilder disable(Long id) {
|
||||
mDisabled.add(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
CompatibilityChangeConfig build() {
|
||||
return new CompatibilityChangeConfig(new Compatibility.ChangeConfig(mEnabled, mDisabled));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.compat;
|
||||
|
||||
import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
|
||||
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
|
||||
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
|
||||
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
import com.android.internal.compat.IOverrideValidator;
|
||||
import com.android.internal.compat.OverrideAllowedState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class OverrideValidatorImplTest {
|
||||
private static final String PACKAGE_NAME = "my.package";
|
||||
private static final int TARGET_SDK = 10;
|
||||
private static final int TARGET_SDK_BEFORE = 9;
|
||||
private static final int TARGET_SDK_AFTER = 11;
|
||||
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
Context mContext;
|
||||
|
||||
private AndroidBuildClassifier debuggableBuild() {
|
||||
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
|
||||
when(buildClassifier.isDebuggableBuild()).thenReturn(true);
|
||||
return buildClassifier;
|
||||
}
|
||||
|
||||
private AndroidBuildClassifier betaBuild() {
|
||||
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
|
||||
when(buildClassifier.isDebuggableBuild()).thenReturn(false);
|
||||
when(buildClassifier.isFinalBuild()).thenReturn(false);
|
||||
return buildClassifier;
|
||||
}
|
||||
|
||||
private AndroidBuildClassifier finalBuild() {
|
||||
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
|
||||
when(buildClassifier.isDebuggableBuild()).thenReturn(false);
|
||||
when(buildClassifier.isFinalBuild()).thenReturn(true);
|
||||
return buildClassifier;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_debugBuildAnyChangeDebugApp_allowOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK, 2)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
|
||||
.addEnabledChangeWithId(4)
|
||||
.addDisabledChangeWithId(5).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.debuggable()
|
||||
.withTargetSdk(TARGET_SDK)
|
||||
.withPackageName(PACKAGE_NAME).build());
|
||||
|
||||
OverrideAllowedState stateTargetSdkLessChange =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkEqualChange =
|
||||
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkAfterChange =
|
||||
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
|
||||
OverrideAllowedState stateEnabledChange =
|
||||
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
|
||||
OverrideAllowedState stateDisabledChange =
|
||||
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
|
||||
|
||||
assertThat(stateTargetSdkLessChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateTargetSdkEqualChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateTargetSdkAfterChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateEnabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateDisabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_debugBuildAnyChangeReleaseApp_allowOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK, 2)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
|
||||
.addEnabledChangeWithId(4)
|
||||
.addDisabledChangeWithId(5).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.withTargetSdk(TARGET_SDK).build());
|
||||
|
||||
OverrideAllowedState stateTargetSdkLessChange =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkEqualChange =
|
||||
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkAfterChange =
|
||||
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
|
||||
OverrideAllowedState stateEnabledChange =
|
||||
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
|
||||
OverrideAllowedState stateDisabledChange =
|
||||
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
|
||||
|
||||
assertThat(stateTargetSdkLessChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateTargetSdkEqualChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateTargetSdkAfterChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateEnabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
assertThat(stateDisabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_betaBuildTargetSdkChangeDebugApp_allowOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK, 2)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.debuggable()
|
||||
.withTargetSdk(TARGET_SDK)
|
||||
.withPackageName(PACKAGE_NAME).build());
|
||||
|
||||
OverrideAllowedState stateTargetSdkLessChange =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkEqualChange =
|
||||
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkAfterChange =
|
||||
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
|
||||
|
||||
assertThat(stateTargetSdkLessChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE));
|
||||
assertThat(stateTargetSdkEqualChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
|
||||
assertThat(stateTargetSdkAfterChange)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
|
||||
.addEnabledChangeWithId(1).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.debuggable()
|
||||
.build());
|
||||
|
||||
OverrideAllowedState allowedState =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
|
||||
assertThat(allowedState)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
|
||||
.addDisabledChangeWithId(1).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.debuggable()
|
||||
.withPackageName(PACKAGE_NAME).build());
|
||||
|
||||
OverrideAllowedState allowedState =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
|
||||
assertThat(allowedState)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_betaBuildAnyChangeReleaseApp_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK, 2)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
|
||||
.addEnabledChangeWithId(4)
|
||||
.addDisabledChangeWithId(5).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.withTargetSdk(TARGET_SDK).build());
|
||||
|
||||
OverrideAllowedState stateTargetSdkLessChange =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkEqualChange =
|
||||
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkAfterChange =
|
||||
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
|
||||
OverrideAllowedState stateEnabledChange =
|
||||
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
|
||||
OverrideAllowedState stateDisabledChange =
|
||||
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
|
||||
|
||||
assertThat(stateTargetSdkLessChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateTargetSdkEqualChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateTargetSdkAfterChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateEnabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateDisabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.debuggable()
|
||||
.withTargetSdk(TARGET_SDK)
|
||||
.withPackageName(PACKAGE_NAME).build());
|
||||
|
||||
OverrideAllowedState allowedState =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
|
||||
assertThat(allowedState)
|
||||
.isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK, 2).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.withTargetSdk(TARGET_SDK)
|
||||
.debuggable()
|
||||
.build());
|
||||
|
||||
OverrideAllowedState stateTargetSdkLessChange =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkEqualChange =
|
||||
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
|
||||
|
||||
assertThat(stateTargetSdkLessChange).isEqualTo(
|
||||
new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK,
|
||||
TARGET_SDK_BEFORE));
|
||||
assertThat(stateTargetSdkEqualChange).isEqualTo(
|
||||
new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
|
||||
.addEnabledChangeWithId(1).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.debuggable().build());
|
||||
|
||||
OverrideAllowedState allowedState =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
|
||||
assertThat(allowedState)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
|
||||
.addDisabledChangeWithId(1).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.debuggable().build());
|
||||
|
||||
OverrideAllowedState allowedState =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
|
||||
assertThat(allowedState)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getOverrideAllowedState_finalBuildAnyChangeReleaseApp_rejectOverride()
|
||||
throws Exception {
|
||||
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK, 2)
|
||||
.addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
|
||||
.addEnabledChangeWithId(4)
|
||||
.addDisabledChangeWithId(5).build();
|
||||
IOverrideValidator overrideValidator = config.getOverrideValidator();
|
||||
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName(PACKAGE_NAME)
|
||||
.withTargetSdk(TARGET_SDK).build());
|
||||
|
||||
OverrideAllowedState stateTargetSdkLessChange =
|
||||
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkEqualChange =
|
||||
overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
|
||||
OverrideAllowedState stateTargetSdkAfterChange =
|
||||
overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
|
||||
OverrideAllowedState stateEnabledChange =
|
||||
overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
|
||||
OverrideAllowedState stateDisabledChange =
|
||||
overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
|
||||
|
||||
assertThat(stateTargetSdkLessChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateTargetSdkEqualChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateTargetSdkAfterChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateEnabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
assertThat(stateDisabledChange)
|
||||
.isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
|
||||
}
|
||||
}
|
||||
@@ -26,21 +26,20 @@ import static org.mockito.Mockito.when;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.compat.Compatibility;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.android.internal.compat.CompatibilityChangeConfig;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.android.internal.compat.AndroidBuildClassifier;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PlatformCompatTest {
|
||||
private static final String PACKAGE_NAME = "my.package";
|
||||
|
||||
@@ -50,84 +49,77 @@ public class PlatformCompatTest {
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
CompatChange.ChangeListener mListener1, mListener2;
|
||||
|
||||
PlatformCompat mPlatformCompat;
|
||||
CompatConfig mCompatConfig;
|
||||
@Mock
|
||||
private AndroidBuildClassifier mBuildClassifier;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
|
||||
new PackageManager.NameNotFoundException());
|
||||
CompatConfig.get().clearChanges();
|
||||
mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
|
||||
mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
|
||||
// Assume userdebug/eng non-final build
|
||||
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
|
||||
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterListenerToSameIdThrows() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
|
||||
public void testRegisterListenerToSameIdThrows() throws Exception {
|
||||
// Registering a listener to change 1 is successful.
|
||||
pc.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
// Registering a listener to change 2 is successful.
|
||||
pc.registerListener(2, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener1);
|
||||
// Trying to register another listener to change id 1 fails.
|
||||
assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> mPlatformCompat.registerListener(1, mListener1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterListenerReturn() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
|
||||
public void testRegisterListenerReturn() throws Exception {
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
// Change id 1 is known (added in setOverrides).
|
||||
assertThat(pc.registerListener(1, mListener1)).isTrue();
|
||||
assertThat(mPlatformCompat.registerListener(1, mListener1)).isTrue();
|
||||
// Change 2 is unknown.
|
||||
assertThat(pc.registerListener(2, mListener1)).isFalse();
|
||||
assertThat(mPlatformCompat.registerListener(2, mListener1)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnSetOverrides() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerCalledOnSetOverrides() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener1);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
pc.registerListener(2, mListener1);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerNotCalledOnWrongPackage() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerNotCalledOnWrongPackage() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener1);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
pc.registerListener(2, mListener1);
|
||||
|
||||
pc.setOverridesForTest(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, never()).onCompatChange("other.package");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnSetOverridesTwoListeners() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
pc.registerListener(1, mListener1);
|
||||
public void testListenerCalledOnSetOverridesTwoListeners() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
|
||||
final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
|
||||
final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
@@ -136,11 +128,10 @@ public class PlatformCompatTest {
|
||||
reset(mListener1);
|
||||
reset(mListener2);
|
||||
|
||||
pc.registerListener(2, mListener2);
|
||||
mPlatformCompat.registerListener(2, mListener2);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
@@ -148,31 +139,23 @@ public class PlatformCompatTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnSetOverridesForTest() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerCalledOnSetOverridesForTest() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener1);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
pc.registerListener(2, mListener1);
|
||||
|
||||
pc.setOverridesForTest(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnSetOverridesTwoListenersForTest() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
pc.registerListener(1, mListener1);
|
||||
public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
|
||||
final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
|
||||
final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
|
||||
|
||||
pc.setOverridesForTest(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
@@ -181,10 +164,10 @@ public class PlatformCompatTest {
|
||||
reset(mListener1);
|
||||
reset(mListener2);
|
||||
|
||||
pc.registerListener(2, mListener2);
|
||||
pc.setOverridesForTest(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(enabled, disabled)),
|
||||
mPlatformCompat.registerListener(2, mListener2);
|
||||
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
@@ -192,15 +175,12 @@ public class PlatformCompatTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnClearOverrides() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerCalledOnClearOverrides() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener2);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
pc.registerListener(2, mListener2);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).build(),
|
||||
PACKAGE_NAME);
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||
@@ -208,21 +188,18 @@ public class PlatformCompatTest {
|
||||
reset(mListener1);
|
||||
reset(mListener2);
|
||||
|
||||
pc.clearOverrides(PACKAGE_NAME);
|
||||
mPlatformCompat.clearOverrides(PACKAGE_NAME);
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnClearOverridesMultipleOverrides() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerCalledOnClearOverridesMultipleOverrides() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener2);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
pc.registerListener(2, mListener2);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
|
||||
PACKAGE_NAME);
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
@@ -230,21 +207,18 @@ public class PlatformCompatTest {
|
||||
reset(mListener1);
|
||||
reset(mListener2);
|
||||
|
||||
pc.clearOverrides(PACKAGE_NAME);
|
||||
mPlatformCompat.clearOverrides(PACKAGE_NAME);
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnClearOverrideExists() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerCalledOnClearOverrideExists() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
mPlatformCompat.registerListener(2, mListener2);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
pc.registerListener(2, mListener2);
|
||||
|
||||
pc.setOverrides(
|
||||
new CompatibilityChangeConfig(
|
||||
new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
|
||||
mPlatformCompat.setOverrides(
|
||||
CompatibilityChangeConfigBuilder.create().enable(1L).build(),
|
||||
PACKAGE_NAME);
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||
@@ -252,21 +226,17 @@ public class PlatformCompatTest {
|
||||
reset(mListener1);
|
||||
reset(mListener2);
|
||||
|
||||
pc.clearOverride(1, PACKAGE_NAME);
|
||||
mPlatformCompat.clearOverride(1, PACKAGE_NAME);
|
||||
verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
|
||||
verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenerCalledOnClearOverrideDoesntExist() {
|
||||
PlatformCompat pc = new PlatformCompat(mContext);
|
||||
public void testListenerCalledOnClearOverrideDoesntExist() throws Exception {
|
||||
mPlatformCompat.registerListener(1, mListener1);
|
||||
|
||||
pc.registerListener(1, mListener1);
|
||||
|
||||
pc.clearOverride(1, PACKAGE_NAME);
|
||||
mPlatformCompat.clearOverride(1, PACKAGE_NAME);
|
||||
// Listener not called when a non existing override is removed.
|
||||
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user