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 Diff line number Diff line
@@ -138,3 +138,14 @@ flag {
    description: "flag always meant to be false, for testing resource flagging within cts tests"
    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 Diff line number Diff line
@@ -16,6 +16,7 @@

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 android.aconfig.DeviceProtos;
@@ -27,6 +28,7 @@ import android.annotation.Nullable;
import android.content.res.Flags;
import android.os.Environment;
import android.os.Process;
import android.os.flagging.AconfigPackage;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
@@ -43,6 +45,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
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.
@@ -58,7 +61,8 @@ public class AconfigFlags {
    private static final String OVERRIDE_PREFIX = "device_config_overrides/";
    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() {
        if (!Flags.manifestFlagging()) {
@@ -67,6 +71,11 @@ public class AconfigFlags {
            }
            return;
        }

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

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

    private void loadServerOverrides() {
        // 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
    public Boolean getFlagValue(@NonNull String flagPackageAndName) {
        if (useNewStorage()) {
            return getFlagValueFromNewStorage(flagPackageAndName);
        } else {
            Boolean value = mFlagValues.get(flagPackageAndName);
            if (DEBUG) {
                Slog.v(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + 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.