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

Commit ed60ceba authored by tomnatan's avatar tomnatan Committed by Andrei Onea
Browse files

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
parent 36f5f53a
Loading
Loading
Loading
Loading
+37 −50
Original line number Diff line number Diff line
@@ -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,20 +131,15 @@ 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);
        }
    }
    }

    /**
     * Tentatively set the state of this change for a given package name.
@@ -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 loadOverrides(ChangeOverrides changeOverrides) {
        if (mRawOverrides == null) {
            mRawOverrides = new HashMap<>();
        }
    void clearOverrides() {
        mRawOverrides.clear();

        if (mEvaluatedOverrides == null) {
            mEvaluatedOverrides = new HashMap<>();
        }
        mEvaluatedOverrides.clear();
    }

    void loadOverrides(ChangeOverrides changeOverrides) {
        // Load deferred overrides for backwards compatibility
        if (changeOverrides.getDeferred() != null) {
            for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
@@ -345,14 +336,13 @@ 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());
@@ -361,19 +351,16 @@ public final class CompatChange extends CompatibilityChangeInfo {
            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);
        }
        }
        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()) {
+29 −6
Original line number Diff line number Diff line
@@ -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;
    }

    /**
+121 −10
Original line number Diff line number Diff line
@@ -602,7 +602,7 @@ 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")
@@ -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");
    }
}