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

Commit babdebb8 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use new flag storage in AconfigFlags" into main

parents 53ae4c63 0dd2f0b3
Loading
Loading
Loading
Loading
+12 −1
Original line number Original line Diff line number Diff line
@@ -138,3 +138,14 @@ flag {
    description: "flag always meant to be false, for testing resource flagging within cts tests"
    description: "flag always meant to be false, for testing resource flagging within cts tests"
    bug: "377974898"
    bug: "377974898"
}
}

flag {
    name: "use_new_aconfig_storage"
    is_exported: true
    namespace: "resource_manager"
    description: "Retrieve flag values from new Aconfig flag storage in AconfigFlags.java"
    bug: "352348353"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+62 −15
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.internal.pm.pkg.component;
package com.android.internal.pm.pkg.component;


import static android.provider.flags.Flags.newStoragePublicApi;
import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;


import android.aconfig.DeviceProtos;
import android.aconfig.DeviceProtos;
@@ -27,6 +28,7 @@ import android.annotation.Nullable;
import android.content.res.Flags;
import android.content.res.Flags;
import android.os.Environment;
import android.os.Environment;
import android.os.Process;
import android.os.Process;
import android.os.flagging.AconfigPackage;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Slog;
import android.util.Xml;
import android.util.Xml;
@@ -43,6 +45,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Map;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
/**
 * A class that manages a cache of all device feature flags and their default + override values.
 * A class that manages a cache of all device feature flags and their default + override values.
@@ -58,7 +61,8 @@ public class AconfigFlags {
    private static final String OVERRIDE_PREFIX = "device_config_overrides/";
    private static final String OVERRIDE_PREFIX = "device_config_overrides/";
    private static final String STAGED_PREFIX = "staged/";
    private static final String STAGED_PREFIX = "staged/";


    private final ArrayMap<String, Boolean> mFlagValues = new ArrayMap<>();
    private final Map<String, Boolean> mFlagValues = new ArrayMap<>();
    private final Map<String, AconfigPackage> mAconfigPackages = new ConcurrentHashMap<>();


    public AconfigFlags() {
    public AconfigFlags() {
        if (!Flags.manifestFlagging()) {
        if (!Flags.manifestFlagging()) {
@@ -67,6 +71,11 @@ public class AconfigFlags {
            }
            }
            return;
            return;
        }
        }

        if (useNewStorage()) {
            Slog.i(LOG_TAG, "Using new flag storage");
        } else {
            Slog.i(LOG_TAG, "Using OLD proto flag storage");
            final var defaultFlagProtoFiles =
            final var defaultFlagProtoFiles =
                    (Process.myUid() == Process.SYSTEM_UID) ? DeviceProtos.parsedFlagsProtoPaths()
                    (Process.myUid() == Process.SYSTEM_UID) ? DeviceProtos.parsedFlagsProtoPaths()
                            : Arrays.asList(DeviceProtos.PATHS);
                            : Arrays.asList(DeviceProtos.PATHS);
@@ -74,15 +83,20 @@ public class AconfigFlags {
                try (var inputStream = new FileInputStream(fileName)) {
                try (var inputStream = new FileInputStream(fileName)) {
                    loadAconfigDefaultValues(inputStream.readAllBytes());
                    loadAconfigDefaultValues(inputStream.readAllBytes());
                } catch (IOException e) {
                } catch (IOException e) {
                Slog.e(LOG_TAG, "Failed to read Aconfig values from " + fileName, e);
                    Slog.w(LOG_TAG, "Failed to read Aconfig values from " + fileName, e);
                }
                }
            }
            }
            if (Process.myUid() == Process.SYSTEM_UID) {
            if (Process.myUid() == Process.SYSTEM_UID) {
            // Server overrides are only accessible to the system, no need to even try loading them
                // Server overrides are only accessible to the system, no need to even try loading
            // in user processes.
                // them in user processes.
                loadServerOverrides();
                loadServerOverrides();
            }
            }
        }
        }
    }

    private static boolean useNewStorage() {
        return newStoragePublicApi() && Flags.useNewAconfigStorage();
    }


    private void loadServerOverrides() {
    private void loadServerOverrides() {
        // Reading the proto files is enough for READ_ONLY flags but if it's a READ_WRITE flag
        // Reading the proto files is enough for READ_ONLY flags but if it's a READ_WRITE flag
@@ -200,12 +214,45 @@ public class AconfigFlags {
     */
     */
    @Nullable
    @Nullable
    public Boolean getFlagValue(@NonNull String flagPackageAndName) {
    public Boolean getFlagValue(@NonNull String flagPackageAndName) {
        if (useNewStorage()) {
            return getFlagValueFromNewStorage(flagPackageAndName);
        } else {
            Boolean value = mFlagValues.get(flagPackageAndName);
            Boolean value = mFlagValues.get(flagPackageAndName);
            if (DEBUG) {
            if (DEBUG) {
                Slog.v(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value);
                Slog.v(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value);
            }
            }
            return value;
            return value;
        }
        }
    }

    private Boolean getFlagValueFromNewStorage(String flagPackageAndName) {
        int index = flagPackageAndName.lastIndexOf('.');
        if (index < 0) {
            Slog.e(LOG_TAG, "Unable to parse package name from " + flagPackageAndName);
            return null;
        }
        String flagPackage = flagPackageAndName.substring(0, index);
        String flagName = flagPackageAndName.substring(index + 1);
        Boolean value = null;
        AconfigPackage aconfigPackage = mAconfigPackages.computeIfAbsent(flagPackage, p -> {
            try {
                return AconfigPackage.load(p);
            } catch (Exception e) {
                Slog.e(LOG_TAG, "Failed to load aconfig package " + p, e);
                return null;
            }
        });
        if (aconfigPackage != null) {
            // Default value is false for when the flag is not found.
            // Note: Unlike with the old storage, with AconfigPackage, we don't have a way to
            // know if the flag is not found or if it's found but the value is false.
            value = aconfigPackage.getBooleanFlagValue(flagName, false);
        }
        if (DEBUG) {
            Slog.v(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value);
        }
        return value;
    }


    /**
    /**
     * Check if the element in {@code parser} should be skipped because of the feature flag.
     * Check if the element in {@code parser} should be skipped because of the feature flag.