Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51164692 authored by Andrei-Valentin Onea's avatar Andrei-Valentin Onea Committed by Gerrit Code Review
Browse files

Merge "Persist compat framework overrides across reboot"

parents 2cfb250d 38df6113
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -84,6 +84,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",
+68 −0
Original line number Diff line number Diff line
@@ -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(")
+103 −9
Original line number Diff line number Diff line
@@ -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;
    }
+10 −2
Original line number Diff line number Diff line
@@ -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",
Loading