Add support for loading a static overrides file located in /product.
Note that the dynamic overrides file in the /data/misc/appcompat will be loaded after the static file is loaded and take precedence over it (overrides in the dynamic file will override corresponding ones in the static file). This static file will be used to inject hard coded per app configuration. Bug: 180396167 Test: atest FrameworksServicesTests:CompatConfigTest Merged-In: I73569744e718274255885d270ab8285956647f4c Change-Id: I73569744e718274255885d270ab8285956647f4c
This commit is contained in:
@@ -79,6 +79,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
this(changeId, null, -1, -1, false, false, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param change an object generated by services/core/xsd/platform-compat-config.xsd
|
||||
*/
|
||||
public CompatChange(Change change) {
|
||||
this(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
|
||||
change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
|
||||
change.getDescription(), change.getOverridable());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param changeId Unique ID for the change. See {@link android.compat.Compatibility}.
|
||||
* @param name Short descriptive name.
|
||||
@@ -93,15 +102,10 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
boolean overridable) {
|
||||
super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly,
|
||||
description, overridable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param change an object generated by services/core/xsd/platform-compat-config.xsd
|
||||
*/
|
||||
public CompatChange(Change change) {
|
||||
super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
|
||||
change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
|
||||
change.getDescription(), change.getOverridable());
|
||||
// Initialize override maps.
|
||||
mEvaluatedOverrides = new HashMap<>();
|
||||
mRawOverrides = new HashMap<>();
|
||||
}
|
||||
|
||||
void registerListener(ChangeListener listener) {
|
||||
@@ -127,18 +131,13 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't add overrides for a logging only change " + toString());
|
||||
}
|
||||
if (mEvaluatedOverrides == null) {
|
||||
mEvaluatedOverrides = new HashMap<>();
|
||||
}
|
||||
mEvaluatedOverrides.put(pname, enabled);
|
||||
notifyListener(pname);
|
||||
}
|
||||
|
||||
private void removePackageOverrideInternal(String pname) {
|
||||
if (mEvaluatedOverrides != null) {
|
||||
if (mEvaluatedOverrides.remove(pname) != null) {
|
||||
notifyListener(pname);
|
||||
}
|
||||
if (mEvaluatedOverrides.remove(pname) != null) {
|
||||
notifyListener(pname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,9 +156,6 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't add overrides for a logging only change " + toString());
|
||||
}
|
||||
if (mRawOverrides == null) {
|
||||
mRawOverrides = new HashMap<>();
|
||||
}
|
||||
mRawOverrides.put(packageName, override);
|
||||
recheckOverride(packageName, allowedState, context);
|
||||
}
|
||||
@@ -212,7 +208,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
}
|
||||
|
||||
boolean hasPackageOverride(String pname) {
|
||||
return mRawOverrides != null && mRawOverrides.containsKey(pname);
|
||||
return mRawOverrides.containsKey(pname);
|
||||
}
|
||||
/**
|
||||
* Remove any package override for the given package name, restoring the default behaviour.
|
||||
@@ -223,7 +219,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
*/
|
||||
boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
|
||||
Context context) {
|
||||
if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) {
|
||||
if (mRawOverrides.remove(pname) != null) {
|
||||
recheckOverride(pname, allowedState, context);
|
||||
return true;
|
||||
}
|
||||
@@ -241,7 +237,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
if (app == null) {
|
||||
return defaultValue();
|
||||
}
|
||||
if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) {
|
||||
if (mEvaluatedOverrides.containsKey(app.packageName)) {
|
||||
return mEvaluatedOverrides.get(app.packageName);
|
||||
}
|
||||
if (getDisabled()) {
|
||||
@@ -289,7 +285,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
* @return true if there is such override
|
||||
*/
|
||||
private boolean hasOverride(String packageName) {
|
||||
return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName);
|
||||
return mEvaluatedOverrides.containsKey(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,20 +294,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
* @return true if there is such a deferred override
|
||||
*/
|
||||
private boolean hasRawOverride(String packageName) {
|
||||
return mRawOverrides != null && mRawOverrides.containsKey(packageName);
|
||||
return mRawOverrides.containsKey(packageName);
|
||||
}
|
||||
|
||||
void clearOverrides() {
|
||||
mRawOverrides.clear();
|
||||
mEvaluatedOverrides.clear();
|
||||
}
|
||||
|
||||
void loadOverrides(ChangeOverrides changeOverrides) {
|
||||
if (mRawOverrides == null) {
|
||||
mRawOverrides = new HashMap<>();
|
||||
}
|
||||
mRawOverrides.clear();
|
||||
|
||||
if (mEvaluatedOverrides == null) {
|
||||
mEvaluatedOverrides = new HashMap<>();
|
||||
}
|
||||
mEvaluatedOverrides.clear();
|
||||
|
||||
// Load deferred overrides for backwards compatibility
|
||||
if (changeOverrides.getDeferred() != null) {
|
||||
for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
|
||||
@@ -345,34 +336,30 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
}
|
||||
|
||||
ChangeOverrides saveOverrides() {
|
||||
if (mRawOverrides == null || mRawOverrides.isEmpty()) {
|
||||
if (mRawOverrides.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
ChangeOverrides changeOverrides = new ChangeOverrides();
|
||||
changeOverrides.setChangeId(getId());
|
||||
ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw();
|
||||
List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue();
|
||||
if (mRawOverrides != null) {
|
||||
for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
|
||||
RawOverrideValue override = new RawOverrideValue();
|
||||
override.setPackageName(entry.getKey());
|
||||
override.setMinVersionCode(entry.getValue().getMinVersionCode());
|
||||
override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
|
||||
override.setEnabled(entry.getValue().getEnabled());
|
||||
rawList.add(override);
|
||||
}
|
||||
for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
|
||||
RawOverrideValue override = new RawOverrideValue();
|
||||
override.setPackageName(entry.getKey());
|
||||
override.setMinVersionCode(entry.getValue().getMinVersionCode());
|
||||
override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
|
||||
override.setEnabled(entry.getValue().getEnabled());
|
||||
rawList.add(override);
|
||||
}
|
||||
changeOverrides.setRaw(rawOverrides);
|
||||
|
||||
ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
|
||||
List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
|
||||
if (mEvaluatedOverrides != null) {
|
||||
for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
|
||||
OverrideValue override = new OverrideValue();
|
||||
override.setPackageName(entry.getKey());
|
||||
override.setEnabled(entry.getValue());
|
||||
validatedList.add(override);
|
||||
}
|
||||
for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
|
||||
OverrideValue override = new OverrideValue();
|
||||
override.setPackageName(entry.getKey());
|
||||
override.setEnabled(entry.getValue());
|
||||
validatedList.add(override);
|
||||
}
|
||||
changeOverrides.setValidated(validatedOverrides);
|
||||
return changeOverrides;
|
||||
@@ -394,10 +381,10 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
||||
if (getLoggingOnly()) {
|
||||
sb.append("; loggingOnly");
|
||||
}
|
||||
if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) {
|
||||
if (!mEvaluatedOverrides.isEmpty()) {
|
||||
sb.append("; packageOverrides=").append(mEvaluatedOverrides);
|
||||
}
|
||||
if (mRawOverrides != null && mRawOverrides.size() > 0) {
|
||||
if (!mRawOverrides.isEmpty()) {
|
||||
sb.append("; rawOverrides=").append(mRawOverrides);
|
||||
}
|
||||
if (getOverridable()) {
|
||||
|
||||
@@ -67,6 +67,7 @@ final class CompatConfig {
|
||||
|
||||
private static final String TAG = "CompatConfig";
|
||||
private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
|
||||
private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat";
|
||||
private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
|
||||
|
||||
@GuardedBy("mChanges")
|
||||
@@ -94,8 +95,7 @@ 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.initOverrides();
|
||||
config.invalidateCache();
|
||||
return config;
|
||||
}
|
||||
@@ -525,10 +525,34 @@ final class CompatConfig {
|
||||
}
|
||||
}
|
||||
|
||||
void initOverrides(File overridesFile) {
|
||||
private void initOverrides() {
|
||||
initOverrides(new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE),
|
||||
new File(STATIC_OVERRIDES_PRODUCT_DIR, OVERRIDES_FILE));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void initOverrides(File dynamicOverridesFile, File staticOverridesFile) {
|
||||
// Clear overrides from all changes before loading.
|
||||
synchronized (mChanges) {
|
||||
for (int i = 0; i < mChanges.size(); ++i) {
|
||||
mChanges.valueAt(i).clearOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
loadOverrides(staticOverridesFile);
|
||||
|
||||
mOverridesFile = dynamicOverridesFile;
|
||||
loadOverrides(dynamicOverridesFile);
|
||||
|
||||
if (staticOverridesFile.exists()) {
|
||||
// Only save overrides if there is a static overrides file.
|
||||
saveOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadOverrides(File overridesFile) {
|
||||
if (!overridesFile.exists()) {
|
||||
mOverridesFile = overridesFile;
|
||||
// There have not been any overrides added yet.
|
||||
// Overrides file doesn't exist.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -548,7 +572,6 @@ final class CompatConfig {
|
||||
Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString());
|
||||
return;
|
||||
}
|
||||
mOverridesFile = overridesFile;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -602,12 +602,12 @@ public class CompatConfigTest {
|
||||
.addEnableSinceSdkChangeWithId(2, 2L)
|
||||
.build();
|
||||
compatConfig.forceNonDebuggableFinalForTest(true);
|
||||
compatConfig.initOverrides(overridesFile);
|
||||
compatConfig.initOverrides(overridesFile, new File(""));
|
||||
when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
|
||||
.thenReturn(ApplicationInfoBuilder.create()
|
||||
.withPackageName("foo.bar")
|
||||
.debuggable()
|
||||
.build());
|
||||
.withPackageName("foo.bar")
|
||||
.debuggable()
|
||||
.build());
|
||||
when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
|
||||
.thenThrow(new NameNotFoundException());
|
||||
|
||||
@@ -649,7 +649,7 @@ public class CompatConfigTest {
|
||||
.addEnableSinceSdkChangeWithId(2, 2L)
|
||||
.build();
|
||||
compatConfig.forceNonDebuggableFinalForTest(true);
|
||||
compatConfig.initOverrides(overridesFile);
|
||||
compatConfig.initOverrides(overridesFile, new File(""));
|
||||
|
||||
compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L,
|
||||
new PackageOverride.Builder()
|
||||
@@ -673,11 +673,11 @@ public class CompatConfigTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadOverridesRaw() throws Exception {
|
||||
public void testInitOverridesRaw() 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)
|
||||
// Change 2 is disabled for bar.baz (raw)
|
||||
String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
+ "<overrides>\n"
|
||||
+ " <change-overrides changeId=\"1\">\n"
|
||||
@@ -709,7 +709,7 @@ public class CompatConfigTest {
|
||||
.addEnableSinceSdkChangeWithId(2, 2L)
|
||||
.build();
|
||||
compatConfig.forceNonDebuggableFinalForTest(true);
|
||||
compatConfig.initOverrides(overridesFile);
|
||||
compatConfig.initOverrides(overridesFile, new File(""));
|
||||
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
|
||||
.withPackageName("foo.bar")
|
||||
.withVersionCode(100L)
|
||||
@@ -728,7 +728,7 @@ public class CompatConfigTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadOverridesDeferred() throws Exception {
|
||||
public void testInitOverridesDeferred() throws Exception {
|
||||
File tempDir = createTempDir();
|
||||
File overridesFile = new File(tempDir, "overrides.xml");
|
||||
// Change 1 is enabled for foo.bar (validated)
|
||||
@@ -754,7 +754,7 @@ public class CompatConfigTest {
|
||||
.addEnableSinceSdkChangeWithId(2, 2L)
|
||||
.build();
|
||||
compatConfig.forceNonDebuggableFinalForTest(true);
|
||||
compatConfig.initOverrides(overridesFile);
|
||||
compatConfig.initOverrides(overridesFile, new File(""));
|
||||
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
|
||||
.withPackageName("foo.bar")
|
||||
.debuggable()
|
||||
@@ -767,4 +767,115 @@ public class CompatConfigTest {
|
||||
assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
|
||||
assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitOverridesWithStaticFile() throws Exception {
|
||||
File tempDir = createTempDir();
|
||||
File dynamicOverridesFile = new File(tempDir, "dynamic_overrides.xml");
|
||||
File staticOverridesFile = new File(tempDir, "static_overrides.xml");
|
||||
// Change 1 is enabled for foo.bar (raw)
|
||||
// Change 2 is disabled for bar.baz (raw)
|
||||
String dynamicXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
+ "<overrides>"
|
||||
+ "<change-overrides changeId=\"1\">"
|
||||
+ "<raw>"
|
||||
+ " <raw-override-value packageName=\"foo.bar\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ "</raw>"
|
||||
+ "</change-overrides>"
|
||||
+ "<change-overrides changeId=\"2\">"
|
||||
+ "<raw>"
|
||||
+ " <raw-override-value packageName=\"bar.baz\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ "</raw>"
|
||||
+ "</change-overrides>"
|
||||
+ "</overrides>";
|
||||
writeToFile(tempDir, "dynamic_overrides.xml", dynamicXmlData);
|
||||
// Change 2 is enabled for foo.bar and bar.baz (raw)
|
||||
// Change 3 is enabled for bar.baz (raw)
|
||||
String staticXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
+ "<overrides>"
|
||||
+ "<change-overrides changeId=\"2\">"
|
||||
+ "<raw>"
|
||||
+ " <raw-override-value packageName=\"foo.bar\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ " <raw-override-value packageName=\"bar.baz\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ "</raw>"
|
||||
+ "</change-overrides>"
|
||||
+ "<change-overrides changeId=\"3\">"
|
||||
+ "<raw>"
|
||||
+ " <raw-override-value packageName=\"bar.baz\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ "</raw>"
|
||||
+ "</change-overrides>"
|
||||
+ "</overrides>";
|
||||
writeToFile(tempDir, "static_overrides.xml", staticXmlData);
|
||||
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
|
||||
.addDisabledChangeWithId(1L)
|
||||
.addDisabledChangeWithId(2L)
|
||||
.addDisabledChangeWithId(3L)
|
||||
.build();
|
||||
compatConfig.forceNonDebuggableFinalForTest(true);
|
||||
// Adding an override that will be cleared after initOverrides is called.
|
||||
compatConfig.addOverride(1L, "bar.baz", true);
|
||||
compatConfig.initOverrides(dynamicOverridesFile, staticOverridesFile);
|
||||
when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
|
||||
.thenThrow(new NameNotFoundException());
|
||||
when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
|
||||
.thenThrow(new NameNotFoundException());
|
||||
|
||||
assertThat(compatConfig.willChangeBeEnabled(1L, "foo.bar")).isTrue();
|
||||
assertThat(compatConfig.willChangeBeEnabled(2L, "foo.bar")).isTrue();
|
||||
assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
|
||||
assertThat(compatConfig.willChangeBeEnabled(3L, "bar.baz")).isTrue();
|
||||
assertThat(readFile(dynamicOverridesFile))
|
||||
.isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
+ "<overrides>\n"
|
||||
+ " <change-overrides changeId=\"1\">\n"
|
||||
+ " <validated>\n"
|
||||
+ " </validated>\n"
|
||||
+ " <raw>\n"
|
||||
+ " <raw-override-value packageName=\"foo.bar\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ " </raw>\n"
|
||||
+ " </change-overrides>\n"
|
||||
+ " <change-overrides changeId=\"2\">\n"
|
||||
+ " <validated>\n"
|
||||
+ " </validated>\n"
|
||||
+ " <raw>\n"
|
||||
+ " <raw-override-value packageName=\"foo.bar\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ " <raw-override-value packageName=\"bar.baz\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ " </raw>\n"
|
||||
+ " </change-overrides>\n"
|
||||
+ " <change-overrides changeId=\"3\">\n"
|
||||
+ " <validated>\n"
|
||||
+ " </validated>\n"
|
||||
+ " <raw>\n"
|
||||
+ " <raw-override-value packageName=\"bar.baz\" "
|
||||
+ "minVersionCode=\"-9223372036854775808\" "
|
||||
+ "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
|
||||
+ " </raw-override-value>\n"
|
||||
+ " </raw>\n"
|
||||
+ " </change-overrides>\n"
|
||||
+ "</overrides>\n");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user