summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java68
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java112
-rw-r--r--services/core/xsd/Android.bp12
-rw-r--r--services/core/xsd/platform-compat/OWNERS (renamed from services/core/xsd/platform-compat-schema/OWNERS)0
-rw-r--r--services/core/xsd/platform-compat/config/platform-compat-config.xsd (renamed from services/core/xsd/platform-compat-config.xsd)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/current.txt (renamed from services/core/xsd/platform-compat-schema/current.txt)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/last_current.txt (renamed from services/core/xsd/platform-compat-schema/last_current.txt)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/last_removed.txt (renamed from services/core/xsd/platform-compat-schema/last_removed.txt)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/removed.txt (renamed from services/core/xsd/platform-compat-schema/removed.txt)0
-rw-r--r--services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd55
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/current.txt51
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/last_current.txt0
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/last_removed.txt0
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/removed.txt1
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java88
16 files changed, 377 insertions, 11 deletions
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 5e7752af55b5..63d0ff5d48f1 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -91,6 +91,7 @@ java_library_static {
":storaged_aidl",
":vold_aidl",
":platform-compat-config",
+ ":platform-compat-overrides",
":display-device-config",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 9ba957ef27ae..e3757dfc6a59 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -23,8 +23,11 @@ import android.content.pm.ApplicationInfo;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.server.compat.config.Change;
+import com.android.server.compat.overrides.ChangeOverrides;
+import com.android.server.compat.overrides.OverrideValue;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -253,6 +256,71 @@ public final class CompatChange extends CompatibilityChangeInfo {
return mDeferredOverrides != null && mDeferredOverrides.containsKey(packageName);
}
+ /**
+ * Checks whether a change has any package overrides.
+ * @return true if the change has at least one deferred override
+ */
+ boolean hasAnyPackageOverride() {
+ return mDeferredOverrides != null && !mDeferredOverrides.isEmpty();
+ }
+
+ /**
+ * Checks whether a change has any deferred overrides.
+ * @return true if the change has at least one deferred override
+ */
+ boolean hasAnyDeferredOverride() {
+ return mPackageOverrides != null && !mPackageOverrides.isEmpty();
+ }
+
+ void loadOverrides(ChangeOverrides changeOverrides) {
+ if (mDeferredOverrides == null) {
+ mDeferredOverrides = new HashMap<>();
+ }
+ mDeferredOverrides.clear();
+ for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
+ mDeferredOverrides.put(override.getPackageName(), override.getEnabled());
+ }
+
+ if (mPackageOverrides == null) {
+ mPackageOverrides = new HashMap<>();
+ }
+ mPackageOverrides.clear();
+ for (OverrideValue override : changeOverrides.getValidated().getOverrideValue()) {
+ mPackageOverrides.put(override.getPackageName(), override.getEnabled());
+ }
+ }
+
+ ChangeOverrides saveOverrides() {
+ if (!hasAnyDeferredOverride() && !hasAnyPackageOverride()) {
+ return null;
+ }
+ ChangeOverrides changeOverrides = new ChangeOverrides();
+ changeOverrides.setChangeId(getId());
+ ChangeOverrides.Deferred deferredOverrides = new ChangeOverrides.Deferred();
+ List<OverrideValue> deferredList = deferredOverrides.getOverrideValue();
+ if (mDeferredOverrides != null) {
+ for (Map.Entry<String, Boolean> entry : mDeferredOverrides.entrySet()) {
+ OverrideValue override = new OverrideValue();
+ override.setPackageName(entry.getKey());
+ override.setEnabled(entry.getValue());
+ deferredList.add(override);
+ }
+ }
+ changeOverrides.setDeferred(deferredOverrides);
+ ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
+ List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
+ if (mPackageOverrides != null) {
+ for (Map.Entry<String, Boolean> entry : mPackageOverrides.entrySet()) {
+ OverrideValue override = new OverrideValue();
+ override.setPackageName(entry.getKey());
+ override.setEnabled(entry.getValue());
+ validatedList.add(override);
+ }
+ }
+ changeOverrides.setValidated(validatedOverrides);
+ return changeOverrides;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ChangeId(")
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 69686a2e4678..6b77b9d4ce39 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -34,7 +34,10 @@ 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;
+import com.android.server.compat.config.Config;
+import com.android.server.compat.overrides.ChangeOverrides;
+import com.android.server.compat.overrides.Overrides;
+import com.android.server.compat.overrides.XmlWriter;
import com.android.server.pm.ApexManager;
import org.xmlpull.v1.XmlPullParserException;
@@ -60,11 +63,14 @@ import javax.xml.datatype.DatatypeConfigurationException;
final class CompatConfig {
private static final String TAG = "CompatConfig";
+ private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
+ private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
private final OverrideValidatorImpl mOverrideValidator;
+ private File mOverridesFile;
@VisibleForTesting
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
@@ -83,6 +89,8 @@ final class CompatConfig {
config.initConfigFromLib(Environment.buildPath(
apex.apexDirectory, "etc", "compatconfig"));
}
+ File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE);
+ config.initOverrides(overridesFile);
config.invalidateCache();
return config;
}
@@ -202,6 +210,17 @@ final class CompatConfig {
* @throws IllegalStateException if overriding is not allowed
*/
boolean addOverride(long changeId, String packageName, boolean enabled) {
+ boolean alreadyKnown = addOverrideUnsafe(changeId, packageName, enabled);
+ saveOverrides();
+ invalidateCache();
+ return alreadyKnown;
+ }
+
+ /**
+ * Unsafe version of {@link #addOverride(long, String, boolean)}.
+ * It does not invalidate the cache nor save the overrides.
+ */
+ private boolean addOverrideUnsafe(long changeId, String packageName, boolean enabled) {
boolean alreadyKnown = true;
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
@@ -224,7 +243,6 @@ final class CompatConfig {
throw new IllegalStateException("Should only be able to override changes that "
+ "are allowed or can be deferred.");
}
- invalidateCache();
}
return alreadyKnown;
}
@@ -282,6 +300,17 @@ final class CompatConfig {
* @return {@code true} if an override existed;
*/
boolean removeOverride(long changeId, String packageName) {
+ boolean overrideExists = removeOverrideUnsafe(changeId, packageName);
+ saveOverrides();
+ invalidateCache();
+ return overrideExists;
+ }
+
+ /**
+ * Unsafe version of {@link #removeOverride(long, String)}.
+ * It does not invalidate the cache nor save the overrides.
+ */
+ private boolean removeOverrideUnsafe(long changeId, String packageName) {
boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
@@ -300,7 +329,6 @@ final class CompatConfig {
}
}
}
- invalidateCache();
return overrideExists;
}
@@ -315,12 +343,13 @@ final class CompatConfig {
void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
synchronized (mChanges) {
for (Long changeId : overrides.enabledChanges()) {
- addOverride(changeId, packageName, true);
+ addOverrideUnsafe(changeId, packageName, true);
}
for (Long changeId : overrides.disabledChanges()) {
- addOverride(changeId, packageName, false);
+ addOverrideUnsafe(changeId, packageName, false);
}
+ saveOverrides();
invalidateCache();
}
}
@@ -337,8 +366,9 @@ final class CompatConfig {
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
CompatChange change = mChanges.valueAt(i);
- removeOverride(change.getId(), packageName);
+ removeOverrideUnsafe(change.getId(), packageName);
}
+ saveOverrides();
invalidateCache();
}
}
@@ -372,8 +402,10 @@ final class CompatConfig {
int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
- addOverride(changeId, packageName, true);
+ addOverrideUnsafe(changeId, packageName, true);
}
+ saveOverrides();
+ invalidateCache();
return changes.length;
}
@@ -386,8 +418,10 @@ final class CompatConfig {
int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
- addOverride(changeId, packageName, false);
+ addOverrideUnsafe(changeId, packageName, false);
}
+ saveOverrides();
+ invalidateCache();
return changes.length;
}
@@ -494,7 +528,8 @@ final class CompatConfig {
private void readConfig(File configFile) {
try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
- for (Change change : XmlParser.read(in).getCompatChange()) {
+ Config config = com.android.server.compat.config.XmlParser.read(in);
+ for (Change change : config.getCompatChange()) {
Slog.d(TAG, "Adding: " + change.toString());
addChange(new CompatChange(change));
}
@@ -503,6 +538,65 @@ final class CompatConfig {
}
}
+ void initOverrides(File overridesFile) {
+ if (!overridesFile.exists()) {
+ mOverridesFile = overridesFile;
+ // There have not been any overrides added yet.
+ return;
+ }
+
+ try (InputStream in = new BufferedInputStream(new FileInputStream(overridesFile))) {
+ Overrides overrides = com.android.server.compat.overrides.XmlParser.read(in);
+ for (ChangeOverrides changeOverrides : overrides.getChangeOverrides()) {
+ long changeId = changeOverrides.getChangeId();
+ CompatChange compatChange = mChanges.get(changeId);
+ if (compatChange == null) {
+ Slog.w(TAG, "Change ID " + changeId + " not found. "
+ + "Skipping overrides for it.");
+ continue;
+ }
+ compatChange.loadOverrides(changeOverrides);
+ }
+ } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+ Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString());
+ return;
+ }
+ mOverridesFile = overridesFile;
+ }
+
+ /**
+ * Persist compat framework overrides to /data/misc/appcompat/compat_framework_overrides.xml
+ */
+ void saveOverrides() {
+ if (mOverridesFile == null) {
+ return;
+ }
+ synchronized (mChanges) {
+ // Create the file if it doesn't already exist
+ try {
+ mOverridesFile.createNewFile();
+ } catch (IOException e) {
+ Slog.e(TAG, "Could not create override config file: " + e.toString());
+ return;
+ }
+ try (PrintWriter out = new PrintWriter(mOverridesFile)) {
+ XmlWriter writer = new XmlWriter(out);
+ Overrides overrides = new Overrides();
+ List<ChangeOverrides> changeOverridesList = overrides.getChangeOverrides();
+ for (int idx = 0; idx < mChanges.size(); ++idx) {
+ CompatChange c = mChanges.valueAt(idx);
+ ChangeOverrides changeOverrides = c.saveOverrides();
+ if (changeOverrides != null) {
+ changeOverridesList.add(changeOverrides);
+ }
+ }
+ XmlWriter.write(writer, overrides);
+ } catch (IOException e) {
+ Slog.e(TAG, e.toString());
+ }
+ }
+ }
+
IOverrideValidator getOverrideValidator() {
return mOverrideValidator;
}
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index b7d6424450f3..3690afc1bc41 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -8,11 +8,19 @@ xsd_config {
xsd_config {
name: "platform-compat-config",
- srcs: ["platform-compat-config.xsd"],
- api_dir: "platform-compat-schema",
+ srcs: ["platform-compat/config/platform-compat-config.xsd"],
+ api_dir: "platform-compat/config/schema",
package_name: "com.android.server.compat.config",
}
+xsd_config {
+ name: "platform-compat-overrides",
+ srcs: ["platform-compat/overrides/platform-compat-overrides.xsd"],
+ api_dir: "platform-compat/overrides/schema",
+ package_name: "com.android.server.compat.overrides",
+ gen_writer: true,
+}
+
xsd_config {
name: "display-device-config",
diff --git a/services/core/xsd/platform-compat-schema/OWNERS b/services/core/xsd/platform-compat/OWNERS
index f8c3520e9fa8..f8c3520e9fa8 100644
--- a/services/core/xsd/platform-compat-schema/OWNERS
+++ b/services/core/xsd/platform-compat/OWNERS
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat/config/platform-compat-config.xsd
index a62e2c385766..a62e2c385766 100644
--- a/services/core/xsd/platform-compat-config.xsd
+++ b/services/core/xsd/platform-compat/config/platform-compat-config.xsd
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat/config/schema/current.txt
index fb8bbefd8374..fb8bbefd8374 100644
--- a/services/core/xsd/platform-compat-schema/current.txt
+++ b/services/core/xsd/platform-compat/config/schema/current.txt
diff --git a/services/core/xsd/platform-compat-schema/last_current.txt b/services/core/xsd/platform-compat/config/schema/last_current.txt
index e69de29bb2d1..e69de29bb2d1 100644
--- a/services/core/xsd/platform-compat-schema/last_current.txt
+++ b/services/core/xsd/platform-compat/config/schema/last_current.txt
diff --git a/services/core/xsd/platform-compat-schema/last_removed.txt b/services/core/xsd/platform-compat/config/schema/last_removed.txt
index e69de29bb2d1..e69de29bb2d1 100644
--- a/services/core/xsd/platform-compat-schema/last_removed.txt
+++ b/services/core/xsd/platform-compat/config/schema/last_removed.txt
diff --git a/services/core/xsd/platform-compat-schema/removed.txt b/services/core/xsd/platform-compat/config/schema/removed.txt
index d802177e249b..d802177e249b 100644
--- a/services/core/xsd/platform-compat-schema/removed.txt
+++ b/services/core/xsd/platform-compat/config/schema/removed.txt
diff --git a/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
new file mode 100644
index 000000000000..e27e1b8ca89d
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<!-- This defines the format of the XML file used to store compat config overrides in
+ ~ /data/misc/appcompat/compat_framework_overrides.xml
+-->
+<xs:schema version="2.0" elementFormDefault="qualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+
+ <xs:complexType name="override-value">
+ <xs:attribute type="xs:string" name="packageName" use="required" />
+ <xs:attribute type="xs:boolean" name="enabled" use="required" />
+ </xs:complexType>
+
+ <xs:complexType name="change-overrides">
+ <xs:attribute type="xs:long" name="changeId" use="required"/>
+ <xs:element name="validated">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="override-value" type="override-value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="deferred">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="override-value" type="override-value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:complexType>
+
+ <xs:element name="overrides">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="change-overrides" type="change-overrides" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
diff --git a/services/core/xsd/platform-compat/overrides/schema/current.txt b/services/core/xsd/platform-compat/overrides/schema/current.txt
new file mode 100644
index 000000000000..08b82072747b
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/current.txt
@@ -0,0 +1,51 @@
+// Signature format: 2.0
+package com.android.server.compat.overrides {
+
+ public class ChangeOverrides {
+ ctor public ChangeOverrides();
+ method public long getChangeId();
+ method public com.android.server.compat.overrides.ChangeOverrides.Deferred getDeferred();
+ method public com.android.server.compat.overrides.ChangeOverrides.Validated getValidated();
+ method public void setChangeId(long);
+ method public void setDeferred(com.android.server.compat.overrides.ChangeOverrides.Deferred);
+ method public void setValidated(com.android.server.compat.overrides.ChangeOverrides.Validated);
+ }
+
+ public static class ChangeOverrides.Deferred {
+ ctor public ChangeOverrides.Deferred();
+ method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
+ }
+
+ public static class ChangeOverrides.Validated {
+ ctor public ChangeOverrides.Validated();
+ method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
+ }
+
+ public class OverrideValue {
+ ctor public OverrideValue();
+ method public boolean getEnabled();
+ method public String getPackageName();
+ method public void setEnabled(boolean);
+ method public void setPackageName(String);
+ }
+
+ public class Overrides {
+ ctor public Overrides();
+ method public java.util.List<com.android.server.compat.overrides.ChangeOverrides> getChangeOverrides();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static com.android.server.compat.overrides.Overrides read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+ public class XmlWriter implements java.io.Closeable {
+ ctor public XmlWriter(java.io.PrintWriter);
+ method public void close();
+ method public static void write(com.android.server.compat.overrides.XmlWriter, com.android.server.compat.overrides.Overrides) throws java.io.IOException;
+ }
+
+}
+
diff --git a/services/core/xsd/platform-compat/overrides/schema/last_current.txt b/services/core/xsd/platform-compat/overrides/schema/last_current.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/last_current.txt
diff --git a/services/core/xsd/platform-compat/overrides/schema/last_removed.txt b/services/core/xsd/platform-compat/overrides/schema/last_removed.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/last_removed.txt
diff --git a/services/core/xsd/platform-compat/overrides/schema/removed.txt b/services/core/xsd/platform-compat/overrides/schema/removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index ac8dc341999a..a53ff9bc7fdc 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -44,6 +44,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.UUID;
@RunWith(AndroidJUnit4.class)
@@ -69,6 +71,10 @@ public class CompatConfigTest {
os.close();
}
+ private String readFile(File file) throws IOException {
+ return new String(Files.readAllBytes(Paths.get(file.toURI())));
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -499,4 +505,86 @@ public class CompatConfigTest {
assertThat(compatConfig.isChangeEnabled(1236L,
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
+
+ @Test
+ public void testSaveOverrides() throws Exception {
+ File overridesFile = new File(createTempDir(), "overrides.xml");
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addEnableSinceSdkChangeWithId(2, 2L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ compatConfig.initOverrides(overridesFile);
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .debuggable()
+ .build());
+ when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ compatConfig.addOverride(1L, "foo.bar", true);
+ compatConfig.addOverride(2L, "bar.baz", false);
+
+ assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<overrides>\n"
+ + " <change-overrides changeId=\"1\">\n"
+ + " <validated>\n"
+ + " <override-value packageName=\"foo.bar\" enabled=\"true\">\n"
+ + " </override-value>\n"
+ + " </validated>\n"
+ + " <deferred>\n"
+ + " </deferred>\n"
+ + " </change-overrides>\n"
+ + " <change-overrides changeId=\"2\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <deferred>\n"
+ + " <override-value packageName=\"bar.baz\" enabled=\"false\">\n"
+ + " </override-value>\n"
+ + " </deferred>\n"
+ + " </change-overrides>\n"
+ + "</overrides>\n");
+ }
+
+ @Test
+ public void testLoadOverrides() throws Exception {
+ File tempDir = createTempDir();
+ File overridesFile = new File(tempDir, "overrides.xml");
+ // Change 1 is enabled for foo.bar (validated)
+ // Change 2 is disabled for bar.baz (deferred)
+ String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<overrides>"
+ + "<change-overrides changeId=\"1\">"
+ + "<deferred/>"
+ + "<validated>"
+ + "<override-value packageName=\"foo.bar\" enabled=\"true\"/>"
+ + "</validated>"
+ + "</change-overrides>"
+ + "<change-overrides changeId=\"2\">"
+ + "<deferred>"
+ + "<override-value packageName=\"bar.baz\" enabled=\"false\"/>"
+ + "</deferred>"
+ + "<validated/>"
+ + "</change-overrides>"
+ + "</overrides>";
+ writeToFile(tempDir, "overrides.xml", xmlData);
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addEnableSinceSdkChangeWithId(2, 2L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ compatConfig.initOverrides(overridesFile);
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .debuggable()
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(applicationInfo);
+ when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
+ assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+ }
}