Loading packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +20 −0 Original line number Diff line number Diff line Loading @@ -1349,6 +1349,26 @@ public class SettingsProvider extends ContentProvider { final int nameCount = names.size(); HashMap<String, String> flagsToValues = new HashMap<>(names.size()); if (Flags.loadAconfigDefaults()) { Map<String, Map<String, String>> allDefaults = settingsState.getAconfigDefaultValues(); if (allDefaults != null) { if (prefix != null) { String namespace = prefix.substring(0, prefix.length() - 1); Map<String, String> namespaceDefaults = allDefaults.get(namespace); if (namespaceDefaults != null) { flagsToValues.putAll(namespaceDefaults); } } else { for (Map<String, String> namespaceDefaults : allDefaults.values()) { flagsToValues.putAll(namespaceDefaults); } } } } for (int i = 0; i < nameCount; i++) { String name = names.get(i); Setting setting = settingsState.getSettingLocked(name); Loading packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +29 −27 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; Loading Loading @@ -236,6 +237,10 @@ final class SettingsState { @GuardedBy("mLock") private int mNextHistoricalOpIdx; @GuardedBy("mLock") @Nullable private Map<String, Map<String, String>> mNamespaceDefaults; public static final int SETTINGS_TYPE_GLOBAL = 0; public static final int SETTINGS_TYPE_SYSTEM = 1; public static final int SETTINGS_TYPE_SECURE = 2; Loading Loading @@ -331,25 +336,21 @@ final class SettingsState { readStateSyncLocked(); if (Flags.loadAconfigDefaults()) { // Only load aconfig defaults if this is the first boot, the XML // file doesn't exist yet, or this device is on its first boot after // an OTA. boolean shouldLoadAconfigValues = isConfigSettingsKey(mKey) && (!file.exists() || mContext.getPackageManager().isDeviceUpgrading()); if (shouldLoadAconfigValues) { if (isConfigSettingsKey(mKey)) { loadAconfigDefaultValuesLocked(); } } } } @GuardedBy("mLock") private void loadAconfigDefaultValuesLocked() { mNamespaceDefaults = new HashMap<>(); for (String fileName : sAconfigTextProtoFilesOnDevice) { try (FileInputStream inputStream = new FileInputStream(fileName)) { byte[] contents = inputStream.readAllBytes(); loadAconfigDefaultValues(contents); loadAconfigDefaultValues(inputStream.readAllBytes(), mNamespaceDefaults); } catch (IOException e) { Slog.e(LOG_TAG, "failed to read protobuf", e); } Loading @@ -358,27 +359,21 @@ final class SettingsState { @VisibleForTesting @GuardedBy("mLock") public void loadAconfigDefaultValues(byte[] fileContents) { public static void loadAconfigDefaultValues(byte[] fileContents, @NonNull Map<String, Map<String, String>> defaultMap) { try { parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents); if (parsedFlags == null) { Slog.e(LOG_TAG, "failed to parse aconfig protobuf"); return; } parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents); for (parsed_flag flag : parsedFlags.getParsedFlagList()) { String flagName = flag.getNamespace() + "/" + flag.getPackage() + "." + flag.getName(); String value = flag.getState() == flag_state.ENABLED ? "true" : "false"; Setting existingSetting = getSettingLocked(flagName); boolean isDefaultLoaded = existingSetting.getTag() != null && existingSetting.getTag().equals(BOOT_LOADED_DEFAULT_TAG); if (existingSetting.getValue() == null || isDefaultLoaded) { insertSettingLocked(flagName, value, BOOT_LOADED_DEFAULT_TAG, false, flag.getPackage()); if (!defaultMap.containsKey(flag.getNamespace())) { Map<String, String> defaults = new HashMap<>(); defaultMap.put(flag.getNamespace(), defaults); } String flagName = flag.getNamespace() + "/" + flag.getPackage() + "." + flag.getName(); String flagValue = flag.getState() == flag_state.ENABLED ? "true" : "false"; defaultMap.get(flag.getNamespace()).put(flagName, flagValue); } } catch (IOException e) { Slog.e(LOG_TAG, "failed to parse protobuf", e); Loading Loading @@ -443,6 +438,13 @@ final class SettingsState { return names; } @Nullable public Map<String, Map<String, String>> getAconfigDefaultValues() { synchronized (mLock) { return mNamespaceDefaults; } } // The settings provider must hold its lock when calling here. public Setting getSettingLocked(String name) { if (TextUtils.isEmpty(name)) { Loading packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +14 −21 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; public class SettingsStateTest extends AndroidTestCase { public static final String CRAZY_STRING = Loading Loading @@ -93,7 +95,6 @@ public class SettingsStateTest extends AndroidTestCase { SettingsState settingsState = new SettingsState( getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); parsed_flags flags = parsed_flags .newBuilder() .addParsedFlag(parsed_flag Loading @@ -117,18 +118,13 @@ public class SettingsStateTest extends AndroidTestCase { .build(); synchronized (lock) { settingsState.loadAconfigDefaultValues(flags.toByteArray()); settingsState.persistSettingsLocked(); } settingsState.waitForHandler(); Map<String, Map<String, String>> defaults = new HashMap<>(); settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(2, namespaceDefaults.keySet().size()); synchronized (lock) { assertEquals("false", settingsState.getSettingLocked( "test_namespace/com.android.flags.flag1").getValue()); assertEquals("true", settingsState.getSettingLocked( "test_namespace/com.android.flags.flag2").getValue()); assertEquals("false", namespaceDefaults.get("test_namespace/com.android.flags.flag1")); assertEquals("true", namespaceDefaults.get("test_namespace/com.android.flags.flag2")); } } Loading @@ -150,21 +146,18 @@ public class SettingsStateTest extends AndroidTestCase { .build(); synchronized (lock) { settingsState.loadAconfigDefaultValues(flags.toByteArray()); settingsState.persistSettingsLocked(); } settingsState.waitForHandler(); Map<String, Map<String, String>> defaults = new HashMap<>(); settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); synchronized (lock) { assertEquals(null, settingsState.getSettingLocked( "test_namespace/com.android.flags.flag1").getValue()); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(null, namespaceDefaults); } } public void testInvalidAconfigProtoDoesNotCrash() { Map<String, Map<String, String>> defaults = new HashMap<>(); SettingsState settingsState = getSettingStateObject(); settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes()); settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes(), defaults); } public void testIsBinary() { Loading Loading
packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +20 −0 Original line number Diff line number Diff line Loading @@ -1349,6 +1349,26 @@ public class SettingsProvider extends ContentProvider { final int nameCount = names.size(); HashMap<String, String> flagsToValues = new HashMap<>(names.size()); if (Flags.loadAconfigDefaults()) { Map<String, Map<String, String>> allDefaults = settingsState.getAconfigDefaultValues(); if (allDefaults != null) { if (prefix != null) { String namespace = prefix.substring(0, prefix.length() - 1); Map<String, String> namespaceDefaults = allDefaults.get(namespace); if (namespaceDefaults != null) { flagsToValues.putAll(namespaceDefaults); } } else { for (Map<String, String> namespaceDefaults : allDefaults.values()) { flagsToValues.putAll(namespaceDefaults); } } } } for (int i = 0; i < nameCount; i++) { String name = names.get(i); Setting setting = settingsState.getSettingLocked(name); Loading
packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +29 −27 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; Loading Loading @@ -236,6 +237,10 @@ final class SettingsState { @GuardedBy("mLock") private int mNextHistoricalOpIdx; @GuardedBy("mLock") @Nullable private Map<String, Map<String, String>> mNamespaceDefaults; public static final int SETTINGS_TYPE_GLOBAL = 0; public static final int SETTINGS_TYPE_SYSTEM = 1; public static final int SETTINGS_TYPE_SECURE = 2; Loading Loading @@ -331,25 +336,21 @@ final class SettingsState { readStateSyncLocked(); if (Flags.loadAconfigDefaults()) { // Only load aconfig defaults if this is the first boot, the XML // file doesn't exist yet, or this device is on its first boot after // an OTA. boolean shouldLoadAconfigValues = isConfigSettingsKey(mKey) && (!file.exists() || mContext.getPackageManager().isDeviceUpgrading()); if (shouldLoadAconfigValues) { if (isConfigSettingsKey(mKey)) { loadAconfigDefaultValuesLocked(); } } } } @GuardedBy("mLock") private void loadAconfigDefaultValuesLocked() { mNamespaceDefaults = new HashMap<>(); for (String fileName : sAconfigTextProtoFilesOnDevice) { try (FileInputStream inputStream = new FileInputStream(fileName)) { byte[] contents = inputStream.readAllBytes(); loadAconfigDefaultValues(contents); loadAconfigDefaultValues(inputStream.readAllBytes(), mNamespaceDefaults); } catch (IOException e) { Slog.e(LOG_TAG, "failed to read protobuf", e); } Loading @@ -358,27 +359,21 @@ final class SettingsState { @VisibleForTesting @GuardedBy("mLock") public void loadAconfigDefaultValues(byte[] fileContents) { public static void loadAconfigDefaultValues(byte[] fileContents, @NonNull Map<String, Map<String, String>> defaultMap) { try { parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents); if (parsedFlags == null) { Slog.e(LOG_TAG, "failed to parse aconfig protobuf"); return; } parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents); for (parsed_flag flag : parsedFlags.getParsedFlagList()) { String flagName = flag.getNamespace() + "/" + flag.getPackage() + "." + flag.getName(); String value = flag.getState() == flag_state.ENABLED ? "true" : "false"; Setting existingSetting = getSettingLocked(flagName); boolean isDefaultLoaded = existingSetting.getTag() != null && existingSetting.getTag().equals(BOOT_LOADED_DEFAULT_TAG); if (existingSetting.getValue() == null || isDefaultLoaded) { insertSettingLocked(flagName, value, BOOT_LOADED_DEFAULT_TAG, false, flag.getPackage()); if (!defaultMap.containsKey(flag.getNamespace())) { Map<String, String> defaults = new HashMap<>(); defaultMap.put(flag.getNamespace(), defaults); } String flagName = flag.getNamespace() + "/" + flag.getPackage() + "." + flag.getName(); String flagValue = flag.getState() == flag_state.ENABLED ? "true" : "false"; defaultMap.get(flag.getNamespace()).put(flagName, flagValue); } } catch (IOException e) { Slog.e(LOG_TAG, "failed to parse protobuf", e); Loading Loading @@ -443,6 +438,13 @@ final class SettingsState { return names; } @Nullable public Map<String, Map<String, String>> getAconfigDefaultValues() { synchronized (mLock) { return mNamespaceDefaults; } } // The settings provider must hold its lock when calling here. public Setting getSettingLocked(String name) { if (TextUtils.isEmpty(name)) { Loading
packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +14 −21 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; public class SettingsStateTest extends AndroidTestCase { public static final String CRAZY_STRING = Loading Loading @@ -93,7 +95,6 @@ public class SettingsStateTest extends AndroidTestCase { SettingsState settingsState = new SettingsState( getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); parsed_flags flags = parsed_flags .newBuilder() .addParsedFlag(parsed_flag Loading @@ -117,18 +118,13 @@ public class SettingsStateTest extends AndroidTestCase { .build(); synchronized (lock) { settingsState.loadAconfigDefaultValues(flags.toByteArray()); settingsState.persistSettingsLocked(); } settingsState.waitForHandler(); Map<String, Map<String, String>> defaults = new HashMap<>(); settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(2, namespaceDefaults.keySet().size()); synchronized (lock) { assertEquals("false", settingsState.getSettingLocked( "test_namespace/com.android.flags.flag1").getValue()); assertEquals("true", settingsState.getSettingLocked( "test_namespace/com.android.flags.flag2").getValue()); assertEquals("false", namespaceDefaults.get("test_namespace/com.android.flags.flag1")); assertEquals("true", namespaceDefaults.get("test_namespace/com.android.flags.flag2")); } } Loading @@ -150,21 +146,18 @@ public class SettingsStateTest extends AndroidTestCase { .build(); synchronized (lock) { settingsState.loadAconfigDefaultValues(flags.toByteArray()); settingsState.persistSettingsLocked(); } settingsState.waitForHandler(); Map<String, Map<String, String>> defaults = new HashMap<>(); settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); synchronized (lock) { assertEquals(null, settingsState.getSettingLocked( "test_namespace/com.android.flags.flag1").getValue()); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(null, namespaceDefaults); } } public void testInvalidAconfigProtoDoesNotCrash() { Map<String, Map<String, String>> defaults = new HashMap<>(); SettingsState settingsState = getSettingStateObject(); settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes()); settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes(), defaults); } public void testIsBinary() { Loading