Merge "Persist compat framework overrides across reboot"
This commit is contained in:
@@ -84,6 +84,7 @@ java_library_static {
|
|||||||
":storaged_aidl",
|
":storaged_aidl",
|
||||||
":vold_aidl",
|
":vold_aidl",
|
||||||
":platform-compat-config",
|
":platform-compat-config",
|
||||||
|
":platform-compat-overrides",
|
||||||
":display-device-config",
|
":display-device-config",
|
||||||
"java/com/android/server/EventLogTags.logtags",
|
"java/com/android/server/EventLogTags.logtags",
|
||||||
"java/com/android/server/am/EventLogTags.logtags",
|
"java/com/android/server/am/EventLogTags.logtags",
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ import android.content.pm.ApplicationInfo;
|
|||||||
|
|
||||||
import com.android.internal.compat.CompatibilityChangeInfo;
|
import com.android.internal.compat.CompatibilityChangeInfo;
|
||||||
import com.android.server.compat.config.Change;
|
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.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -253,6 +256,71 @@ public final class CompatChange extends CompatibilityChangeInfo {
|
|||||||
return mDeferredOverrides != null && mDeferredOverrides.containsKey(packageName);
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder("ChangeId(")
|
StringBuilder sb = new StringBuilder("ChangeId(")
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ import com.android.internal.compat.CompatibilityChangeInfo;
|
|||||||
import com.android.internal.compat.IOverrideValidator;
|
import com.android.internal.compat.IOverrideValidator;
|
||||||
import com.android.internal.compat.OverrideAllowedState;
|
import com.android.internal.compat.OverrideAllowedState;
|
||||||
import com.android.server.compat.config.Change;
|
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 com.android.server.pm.ApexManager;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
@@ -60,11 +63,14 @@ import javax.xml.datatype.DatatypeConfigurationException;
|
|||||||
final class CompatConfig {
|
final class CompatConfig {
|
||||||
|
|
||||||
private static final String TAG = "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")
|
@GuardedBy("mChanges")
|
||||||
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
|
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
|
||||||
|
|
||||||
private final OverrideValidatorImpl mOverrideValidator;
|
private final OverrideValidatorImpl mOverrideValidator;
|
||||||
|
private File mOverridesFile;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
|
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
|
||||||
@@ -83,6 +89,8 @@ final class CompatConfig {
|
|||||||
config.initConfigFromLib(Environment.buildPath(
|
config.initConfigFromLib(Environment.buildPath(
|
||||||
apex.apexDirectory, "etc", "compatconfig"));
|
apex.apexDirectory, "etc", "compatconfig"));
|
||||||
}
|
}
|
||||||
|
File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE);
|
||||||
|
config.initOverrides(overridesFile);
|
||||||
config.invalidateCache();
|
config.invalidateCache();
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -202,6 +210,17 @@ final class CompatConfig {
|
|||||||
* @throws IllegalStateException if overriding is not allowed
|
* @throws IllegalStateException if overriding is not allowed
|
||||||
*/
|
*/
|
||||||
boolean addOverride(long changeId, String packageName, boolean enabled) {
|
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;
|
boolean alreadyKnown = true;
|
||||||
OverrideAllowedState allowedState =
|
OverrideAllowedState allowedState =
|
||||||
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
|
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
|
||||||
@@ -224,7 +243,6 @@ final class CompatConfig {
|
|||||||
throw new IllegalStateException("Should only be able to override changes that "
|
throw new IllegalStateException("Should only be able to override changes that "
|
||||||
+ "are allowed or can be deferred.");
|
+ "are allowed or can be deferred.");
|
||||||
}
|
}
|
||||||
invalidateCache();
|
|
||||||
}
|
}
|
||||||
return alreadyKnown;
|
return alreadyKnown;
|
||||||
}
|
}
|
||||||
@@ -282,6 +300,17 @@ final class CompatConfig {
|
|||||||
* @return {@code true} if an override existed;
|
* @return {@code true} if an override existed;
|
||||||
*/
|
*/
|
||||||
boolean removeOverride(long changeId, String packageName) {
|
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;
|
boolean overrideExists = false;
|
||||||
synchronized (mChanges) {
|
synchronized (mChanges) {
|
||||||
CompatChange c = mChanges.get(changeId);
|
CompatChange c = mChanges.get(changeId);
|
||||||
@@ -300,7 +329,6 @@ final class CompatConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidateCache();
|
|
||||||
return overrideExists;
|
return overrideExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,12 +343,13 @@ final class CompatConfig {
|
|||||||
void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
|
void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
|
||||||
synchronized (mChanges) {
|
synchronized (mChanges) {
|
||||||
for (Long changeId : overrides.enabledChanges()) {
|
for (Long changeId : overrides.enabledChanges()) {
|
||||||
addOverride(changeId, packageName, true);
|
addOverrideUnsafe(changeId, packageName, true);
|
||||||
}
|
}
|
||||||
for (Long changeId : overrides.disabledChanges()) {
|
for (Long changeId : overrides.disabledChanges()) {
|
||||||
addOverride(changeId, packageName, false);
|
addOverrideUnsafe(changeId, packageName, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
saveOverrides();
|
||||||
invalidateCache();
|
invalidateCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,8 +366,9 @@ final class CompatConfig {
|
|||||||
synchronized (mChanges) {
|
synchronized (mChanges) {
|
||||||
for (int i = 0; i < mChanges.size(); ++i) {
|
for (int i = 0; i < mChanges.size(); ++i) {
|
||||||
CompatChange change = mChanges.valueAt(i);
|
CompatChange change = mChanges.valueAt(i);
|
||||||
removeOverride(change.getId(), packageName);
|
removeOverrideUnsafe(change.getId(), packageName);
|
||||||
}
|
}
|
||||||
|
saveOverrides();
|
||||||
invalidateCache();
|
invalidateCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,8 +402,10 @@ final class CompatConfig {
|
|||||||
int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
|
int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
|
||||||
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
|
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
|
||||||
for (long changeId : changes) {
|
for (long changeId : changes) {
|
||||||
addOverride(changeId, packageName, true);
|
addOverrideUnsafe(changeId, packageName, true);
|
||||||
}
|
}
|
||||||
|
saveOverrides();
|
||||||
|
invalidateCache();
|
||||||
return changes.length;
|
return changes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,8 +418,10 @@ final class CompatConfig {
|
|||||||
int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
|
int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
|
||||||
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
|
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
|
||||||
for (long changeId : changes) {
|
for (long changeId : changes) {
|
||||||
addOverride(changeId, packageName, false);
|
addOverrideUnsafe(changeId, packageName, false);
|
||||||
}
|
}
|
||||||
|
saveOverrides();
|
||||||
|
invalidateCache();
|
||||||
return changes.length;
|
return changes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +528,8 @@ final class CompatConfig {
|
|||||||
|
|
||||||
private void readConfig(File configFile) {
|
private void readConfig(File configFile) {
|
||||||
try (InputStream in = new BufferedInputStream(new FileInputStream(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());
|
Slog.d(TAG, "Adding: " + change.toString());
|
||||||
addChange(new CompatChange(change));
|
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() {
|
IOverrideValidator getOverrideValidator() {
|
||||||
return mOverrideValidator;
|
return mOverrideValidator;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,19 @@ xsd_config {
|
|||||||
|
|
||||||
xsd_config {
|
xsd_config {
|
||||||
name: "platform-compat-config",
|
name: "platform-compat-config",
|
||||||
srcs: ["platform-compat-config.xsd"],
|
srcs: ["platform-compat/config/platform-compat-config.xsd"],
|
||||||
api_dir: "platform-compat-schema",
|
api_dir: "platform-compat/config/schema",
|
||||||
package_name: "com.android.server.compat.config",
|
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 {
|
xsd_config {
|
||||||
name: "display-device-config",
|
name: "display-device-config",
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// Signature format: 2.0
|
||||||
@@ -44,6 +44,8 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@@ -69,6 +71,10 @@ public class CompatConfigTest {
|
|||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String readFile(File file) throws IOException {
|
||||||
|
return new String(Files.readAllBytes(Paths.get(file.toURI())));
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
@@ -499,4 +505,86 @@ public class CompatConfigTest {
|
|||||||
assertThat(compatConfig.isChangeEnabled(1236L,
|
assertThat(compatConfig.isChangeEnabled(1236L,
|
||||||
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user