diff options
| -rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java | 221 | ||||
| -rw-r--r-- | packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java | 265 |
2 files changed, 403 insertions, 83 deletions
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 04922d6e2c99..c8992c344b2d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -64,6 +64,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; @@ -85,13 +86,13 @@ import java.util.concurrent.CountDownLatch; // FOR ACONFIGD TEST MISSION AND ROLLOUT import java.io.DataInputStream; import java.io.DataOutputStream; -import android.net.LocalSocketAddress; -import android.net.LocalSocket; import android.util.proto.ProtoInputStream; import android.aconfigd.Aconfigd.StorageRequestMessage; import android.aconfigd.Aconfigd.StorageRequestMessages; import android.aconfigd.Aconfigd.StorageReturnMessage; import android.aconfigd.Aconfigd.StorageReturnMessages; +import android.aconfigd.AconfigdClientSocket; +import android.aconfigd.AconfigdFlagInfo; import android.aconfigd.AconfigdJavaUtils; import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon; /** @@ -265,6 +266,10 @@ final class SettingsState { @NonNull private Map<String, Map<String, String>> mNamespaceDefaults; + // TOBO(b/312444587): remove the comparison logic after Test Mission 2. + @NonNull + private Map<String, AconfigdFlagInfo> mAconfigDefaultFlags; + public static final int SETTINGS_TYPE_GLOBAL = 0; public static final int SETTINGS_TYPE_SYSTEM = 1; public static final int SETTINGS_TYPE_SECURE = 2; @@ -334,8 +339,13 @@ final class SettingsState { + settingTypeToString(getTypeFromKey(key)) + "]"; } - public SettingsState(Context context, Object lock, File file, int key, - int maxBytesPerAppPackage, Looper looper) { + public SettingsState( + Context context, + Object lock, + File file, + int key, + int maxBytesPerAppPackage, + Looper looper) { // It is important that we use the same lock as the settings provider // to ensure multiple mutations on this state are atomically persisted // as the async persistence should be blocked while we make changes. @@ -353,12 +363,15 @@ final class SettingsState { mPackageToMemoryUsage = null; } - mHistoricalOperations = Build.IS_DEBUGGABLE - ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null; + mHistoricalOperations = + Build.IS_DEBUGGABLE ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null; mNamespaceDefaults = new HashMap<>(); + mAconfigDefaultFlags = new HashMap<>(); ProtoOutputStream requests = null; + Map<String, AconfigdFlagInfo> aconfigFlagMap = new HashMap<>(); + synchronized (mLock) { readStateSyncLocked(); @@ -375,39 +388,114 @@ final class SettingsState { } } + if (enableAconfigStorageDaemon()) { + if (isConfigSettingsKey(mKey)) { + aconfigFlagMap = getAllAconfigFlagsFromSettings(); + } + } + if (isConfigSettingsKey(mKey)) { - requests = handleBulkSyncToNewStorage(); + requests = handleBulkSyncToNewStorage(aconfigFlagMap); } } - if (requests != null) { - LocalSocket client = new LocalSocket(); - try{ - client.connect(new LocalSocketAddress( - "aconfigd", LocalSocketAddress.Namespace.RESERVED)); - Slog.d(LOG_TAG, "connected to aconfigd socket"); - } catch (IOException ioe) { - Slog.e(LOG_TAG, "failed to connect to aconfigd socket", ioe); - return; + if (enableAconfigStorageDaemon()) { + if (isConfigSettingsKey(mKey)){ + AconfigdClientSocket localSocket = AconfigdJavaUtils.getAconfigdClientSocket(); + if (requests != null) { + InputStream res = localSocket.send(requests.getBytes()); + if (res == null) { + Slog.w(LOG_TAG, "Bulk sync request to acongid failed."); + } + } + // TOBO(b/312444587): remove the comparison logic after Test Mission 2. + if (mSettings.get("aconfigd_marker/bulk_synced").value.equals("true") + && requests == null) { + Map<String, AconfigdFlagInfo> aconfigdFlagMap = + AconfigdJavaUtils.listFlagsValueInNewStorage(localSocket); + compareFlagValueInNewStorage( + aconfigFlagMap, + mAconfigDefaultFlags, + aconfigdFlagMap); + } } - AconfigdJavaUtils.sendAconfigdRequests(client, requests); } } - // TODO(b/341764371): migrate aconfig flag push to GMS core - public static class FlagOverrideToSync { - public String packageName; - public String flagName; - public String flagValue; - public boolean isLocal; + // TOBO(b/312444587): remove the comparison logic after Test Mission 2. + public int compareFlagValueInNewStorage( + Map<String, AconfigdFlagInfo> settingFlagMap, + Map<String, AconfigdFlagInfo> defaultFlagMap, + Map<String, AconfigdFlagInfo> aconfigdFlagMap) { + + // Get all defaults from the default map. The mSettings may not contain + // all flags, since it only contains updated flags. + int diffNum = 0; + for (Map.Entry<String, AconfigdFlagInfo> entry : defaultFlagMap.entrySet()) { + String key = entry.getKey(); + AconfigdFlagInfo flag = entry.getValue(); + if (settingFlagMap.containsKey(key)) { + flag.merge(settingFlagMap.get(key)); + } + + AconfigdFlagInfo aconfigdFlag = aconfigdFlagMap.get(key); + if (aconfigdFlag == null) { + Slog.w(LOG_TAG, String.format("Flag %s is missing from aconfigd", key)); + diffNum++; + continue; + } + String diff = flag.dumpDiff(aconfigdFlag); + if (!diff.isEmpty()) { + Slog.w( + LOG_TAG, + String.format( + "Flag %s is different in Settings and aconfig: %s", key, diff)); + diffNum++; + } + } + + for (String key : aconfigdFlagMap.keySet()) { + if (defaultFlagMap.containsKey(key)) continue; + Slog.w(LOG_TAG, String.format("Flag %s is missing from Settings", key)); + diffNum++; + } + + if (diffNum == 0) { + Slog.i(LOG_TAG, "Settings and new storage have same flags."); + } + return diffNum; + } + + @GuardedBy("mLock") + public Map<String, AconfigdFlagInfo> getAllAconfigFlagsFromSettings() { + Map<String, AconfigdFlagInfo> ret = new HashMap<>(); + int numSettings = mSettings.size(); + int num_requests = 0; + for (int i = 0; i < numSettings; i++) { + String name = mSettings.keyAt(i); + Setting setting = mSettings.valueAt(i); + AconfigdFlagInfo flag = + getFlagOverrideToSync(name, setting.getValue()); + if (flag == null) { + continue; + } + String fullFlagName = flag.getFullFlagName(); + AconfigdFlagInfo prev = ret.putIfAbsent(fullFlagName,flag); + if (prev != null) { + prev.merge(flag); + } + ++num_requests; + } + Slog.i(LOG_TAG, num_requests + " flag override requests created"); + return ret; } // TODO(b/341764371): migrate aconfig flag push to GMS core @VisibleForTesting @GuardedBy("mLock") - public FlagOverrideToSync getFlagOverrideToSync(String name, String value) { + public AconfigdFlagInfo getFlagOverrideToSync(String name, String value) { int slashIdx = name.indexOf("/"); - if (slashIdx <= 0 || slashIdx >= name.length()-1) { + if (slashIdx <= 0 || slashIdx >= name.length() - 1) { Slog.e(LOG_TAG, "invalid flag name " + name); return null; } @@ -430,8 +518,9 @@ final class SettingsState { } String aconfigName = namespace + "/" + fullFlagName; - boolean isAconfig = mNamespaceDefaults.containsKey(namespace) - && mNamespaceDefaults.get(namespace).containsKey(aconfigName); + boolean isAconfig = + mNamespaceDefaults.containsKey(namespace) + && mNamespaceDefaults.get(namespace).containsKey(aconfigName); if (!isAconfig) { return null; } @@ -443,25 +532,30 @@ final class SettingsState { return null; } - FlagOverrideToSync flag = new FlagOverrideToSync(); - flag.packageName = fullFlagName.substring(0, dotIdx); - flag.flagName = fullFlagName.substring(dotIdx + 1); - flag.isLocal = isLocal; - flag.flagValue = value; - return flag; + AconfigdFlagInfo.Builder builder = AconfigdFlagInfo.newBuilder() + .setPackageName(fullFlagName.substring(0, dotIdx)) + .setFlagName(fullFlagName.substring(dotIdx + 1)) + .setDefaultFlagValue(mNamespaceDefaults.get(namespace).get(aconfigName)); + + if (isLocal) { + builder.setHasLocalOverride(isLocal).setBootFlagValue(value).setLocalFlagValue(value); + } else { + builder.setHasServerOverride(true).setServerFlagValue(value).setBootFlagValue(value); + } + return builder.build(); } // TODO(b/341764371): migrate aconfig flag push to GMS core @VisibleForTesting @GuardedBy("mLock") - public ProtoOutputStream handleBulkSyncToNewStorage() { + public ProtoOutputStream handleBulkSyncToNewStorage( + Map<String, AconfigdFlagInfo> aconfigFlagMap) { // get marker or add marker if it does not exist final String bulkSyncMarkerName = new String("aconfigd_marker/bulk_synced"); Setting markerSetting = mSettings.get(bulkSyncMarkerName); if (markerSetting == null) { - markerSetting = new Setting( - bulkSyncMarkerName, "false", false, "aconfig", "aconfig"); + markerSetting = new Setting(bulkSyncMarkerName, "false", false, "aconfig", "aconfig"); mSettings.put(bulkSyncMarkerName, markerSetting); } @@ -479,24 +573,19 @@ final class SettingsState { AconfigdJavaUtils.writeResetStorageRequest(requests); // loop over all settings and add flag override requests - final int numSettings = mSettings.size(); - int num_requests = 0; - for (int i = 0; i < numSettings; i++) { - String name = mSettings.keyAt(i); - Setting setting = mSettings.valueAt(i); - FlagOverrideToSync flag = - getFlagOverrideToSync(name, setting.getValue()); - if (flag == null) { - continue; - } - ++num_requests; + for (AconfigdFlagInfo flag : aconfigFlagMap.values()) { + String value = + flag.getHasLocalOverride() + ? flag.getLocalFlagValue() + : flag.getServerFlagValue(); AconfigdJavaUtils.writeFlagOverrideRequest( - requests, flag.packageName, flag.flagName, flag.flagValue, - flag.isLocal); + requests, + flag.getPackageName(), + flag.getFlagName(), + value, + flag.getHasLocalOverride()); } - Slog.i(LOG_TAG, num_requests + " flag override requests created"); - // mark sync has been done markerSetting.value = "true"; scheduleWriteIfNeededLocked(); @@ -513,14 +602,14 @@ final class SettingsState { return null; } } - } @GuardedBy("mLock") private void loadAconfigDefaultValuesLocked(List<String> filePaths) { for (String fileName : filePaths) { try (FileInputStream inputStream = new FileInputStream(fileName)) { - loadAconfigDefaultValues(inputStream.readAllBytes(), mNamespaceDefaults); + loadAconfigDefaultValues( + inputStream.readAllBytes(), mNamespaceDefaults, mAconfigDefaultFlags); } catch (IOException e) { Slog.e(LOG_TAG, "failed to read protobuf", e); } @@ -566,21 +655,30 @@ final class SettingsState { @VisibleForTesting @GuardedBy("mLock") - public static void loadAconfigDefaultValues(byte[] fileContents, - @NonNull Map<String, Map<String, String>> defaultMap) { + public static void loadAconfigDefaultValues( + byte[] fileContents, + @NonNull Map<String, Map<String, String>> defaultMap, + @NonNull Map<String, AconfigdFlagInfo> flagInfoDefault) { try { - parsed_flags parsedFlags = - parsed_flags.parseFrom(fileContents); + parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents); for (parsed_flag flag : parsedFlags.getParsedFlagList()) { 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"; + String fullFlagName = flag.getPackage() + "." + flag.getName(); + String flagName = flag.getNamespace() + "/" + fullFlagName; + String flagValue = flag.getState() == flag_state.ENABLED ? "true" : "false"; defaultMap.get(flag.getNamespace()).put(flagName, flagValue); + if (!flagInfoDefault.containsKey(fullFlagName)) { + flagInfoDefault.put( + fullFlagName, + AconfigdFlagInfo.newBuilder() + .setPackageName(flag.getPackage()) + .setFlagName(flag.getName()) + .setDefaultFlagValue(flagValue) + .build()); + } } } catch (IOException e) { Slog.e(LOG_TAG, "failed to parse protobuf", e); @@ -1646,7 +1744,6 @@ final class SettingsState { } } } - mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag, fromSystem, id, isPreservedInRestore)); diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java index 244c8c4d99bc..256b999ca6c5 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java @@ -24,13 +24,13 @@ import static junit.framework.Assert.fail; import android.aconfig.Aconfig; import android.aconfig.Aconfig.parsed_flag; import android.aconfig.Aconfig.parsed_flags; +import android.aconfigd.AconfigdFlagInfo; import android.os.Looper; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Xml; import android.util.proto.ProtoOutputStream; -import com.android.providers.settings.SettingsState.FlagOverrideToSync; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -145,16 +145,32 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.ENABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + + AconfigdFlagInfo flag1 = AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setDefaultFlagValue("false") + .build(); + AconfigdFlagInfo flag2 = AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag2") + .setDefaultFlagValue("true") + .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(2, namespaceDefaults.keySet().size()); assertEquals("false", namespaceDefaults.get("test_namespace/com.android.flags.flag1")); assertEquals("true", namespaceDefaults.get("test_namespace/com.android.flags.flag2")); } + + assertEquals(flag1, flagInfoDefault.get(flag1.getFullFlagName())); + assertEquals(flag2, flagInfoDefault.get(flag2.getFullFlagName())); } @Test @@ -165,6 +181,8 @@ public class SettingsStateTest { InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); + parsed_flags flags = parsed_flags .newBuilder() .addParsedFlag(parsed_flag @@ -177,7 +195,8 @@ public class SettingsStateTest { synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(null, namespaceDefaults); @@ -204,10 +223,12 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.DISABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); settingsState.addAconfigDefaultValuesFromMap(defaults); settingsState.insertSettingLocked("test_namespace/com.android.flags.flag5", @@ -238,8 +259,10 @@ public class SettingsStateTest { @Test public void testInvalidAconfigProtoDoesNotCrash() { Map<String, Map<String, String>> defaults = new HashMap<>(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); SettingsState settingsState = getSettingStateObject(); - settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes(), defaults); + settingsState.loadAconfigDefaultValues( + "invalid protobuf".getBytes(), defaults, flagInfoDefault); } @Test @@ -759,6 +782,8 @@ public class SettingsStateTest { Map<String, String> keyValues = Map.of("test_namespace/com.android.flags.flag3", "true"); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); + parsed_flags flags = parsed_flags .newBuilder() .addParsedFlag(parsed_flag @@ -774,7 +799,8 @@ public class SettingsStateTest { synchronized (mLock) { settingsState.loadAconfigDefaultValues( - flags.toByteArray(), settingsState.getAconfigDefaultValues()); + flags.toByteArray(), + settingsState.getAconfigDefaultValues(), flagInfoDefault); List<String> updates = settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); assertEquals(1, updates.size()); @@ -840,10 +866,13 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.DISABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (mLock) { settingsState.loadAconfigDefaultValues( - flags.toByteArray(), settingsState.getAconfigDefaultValues()); + flags.toByteArray(), + settingsState.getAconfigDefaultValues(), + flagInfoDefault); List<String> updates = settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); assertEquals(3, updates.size()); @@ -973,10 +1002,12 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.DISABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(1, namespaceDefaults.keySet().size()); settingsState.addAconfigDefaultValuesFromMap(defaults); @@ -991,22 +1022,28 @@ public class SettingsStateTest { "some_namespace/some_flag", "false") == null); // server override - FlagOverrideToSync flag = settingsState.getFlagOverrideToSync( + AconfigdFlagInfo flag = settingsState.getFlagOverrideToSync( "test_namespace/com.android.flags.flag1", "false"); assertTrue(flag != null); - assertEquals(flag.packageName, "com.android.flags"); - assertEquals(flag.flagName, "flag1"); - assertEquals(flag.flagValue, "false"); - assertEquals(flag.isLocal, false); + assertEquals(flag.getPackageName(), "com.android.flags"); + assertEquals(flag.getFlagName(), "flag1"); + assertEquals("false", flag.getBootFlagValue()); + assertEquals("false", flag.getServerFlagValue()); + assertFalse(flag.getHasLocalOverride()); + assertNull(flag.getLocalFlagValue()); + assertEquals("false", flag.getDefaultFlagValue()); // local override flag = settingsState.getFlagOverrideToSync( "device_config_overrides/test_namespace:com.android.flags.flag1", "false"); assertTrue(flag != null); - assertEquals(flag.packageName, "com.android.flags"); - assertEquals(flag.flagName, "flag1"); - assertEquals(flag.flagValue, "false"); - assertEquals(flag.isLocal, true); + assertEquals(flag.getPackageName(), "com.android.flags"); + assertEquals(flag.getFlagName(), "flag1"); + assertEquals("false", flag.getLocalFlagValue()); + assertEquals("false", flag.getBootFlagValue()); + assertTrue(flag.getHasLocalOverride()); + assertNull(flag.getServerFlagValue()); + assertEquals("false", flag.getDefaultFlagValue()); } @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -1020,18 +1057,25 @@ public class SettingsStateTest { InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + Map<String, AconfigdFlagInfo> flags = new HashMap<>(); + AconfigdFlagInfo flag = AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setBootFlagValue("true").build(); + flags.put("com.android.flags/flag1", flag); + synchronized (lock) { settingsState.insertSettingLocked("aconfigd_marker/bulk_synced", "false", null, false, "aconfig"); // first bulk sync - ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(); + ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests != null); String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("true", value); // send time should no longer bulk sync - requests = settingsState.handleBulkSyncToNewStorage(); + requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests == null); value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("true", value); @@ -1047,21 +1091,200 @@ public class SettingsStateTest { InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + Map<String, AconfigdFlagInfo> flags = new HashMap<>(); synchronized (lock) { settingsState.insertSettingLocked("aconfigd_marker/bulk_synced", "true", null, false, "aconfig"); // when aconfigd is off, should change the marker to false - ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(); + ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests == null); String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("false", value); // marker started with false value, after call, it should remain false - requests = settingsState.handleBulkSyncToNewStorage(); + requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests == null); value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("false", value); } } + + @Test + public void testGetAllAconfigFlagsFromSettings() throws Exception { + final Object lock = new Object(); + final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); + os.print( + "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + + "<settings version=\"120\">" + + " <setting id=\"0\" name=\"test_namespace/com.android.flags.flag1\" " + + "value=\"false\" package=\"com.android.flags\" />" + + " <setting id=\"1\" name=\"device_config_overrides/test_namespace:com.android.flags.flag1\" " + + "value=\"true\" package=\"com.android.flags\" />" + + " <setting id=\"2\" name=\"device_config_overrides/test_namespace:com.android.flags.flag2\" " + + "value=\"true\" package=\"com.android.flags\" />" + + " <setting id=\"3\" name=\"test_namespace/com.android.flags.flag3\" " + + "value=\"true\" package=\"com.android.flags\" />" + + "</settings>"); + os.close(); + + int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); + + SettingsState settingsState = new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + + Map<String, AconfigdFlagInfo> ret; + synchronized (lock) { + ret = settingsState.getAllAconfigFlagsFromSettings(); + } + + assertTrue(ret.isEmpty()); + + parsed_flags flags = + parsed_flags + .newBuilder() + .addParsedFlag( + parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag1") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .addParsedFlag( + parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag2") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .addParsedFlag( + parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag3") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .build(); + + Map<String, Map<String, String>> defaults = new HashMap<>(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); + synchronized (lock) { + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); + settingsState.addAconfigDefaultValuesFromMap(defaults); + ret = settingsState.getAllAconfigFlagsFromSettings(); + } + + AconfigdFlagInfo expectedFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setServerFlagValue("false") + .setLocalFlagValue("true") + .setDefaultFlagValue("false") + .setBootFlagValue("true") + .setHasServerOverride(true) + .setHasLocalOverride(true) + .setIsReadWrite(false) + .build(); + + AconfigdFlagInfo expectedFlag2 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag2") + .setLocalFlagValue("true") + .setDefaultFlagValue("false") + .setBootFlagValue("true") + .setHasLocalOverride(true) + .setHasServerOverride(false) + .setIsReadWrite(false) + .build(); + + + AconfigdFlagInfo expectedFlag3 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag3") + .setServerFlagValue("true") + .setBootFlagValue("true") + .setDefaultFlagValue("false") + .setHasServerOverride(true) + .setIsReadWrite(false) + .build(); + + assertEquals(expectedFlag1, ret.get("com.android.flags.flag1")); + assertEquals(expectedFlag2, ret.get("com.android.flags.flag2")); + assertEquals(expectedFlag3, ret.get("com.android.flags.flag3")); + } + + @Test + public void testCompareFlagValueInNewStorage() { + int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); + Object lock = new Object(); + SettingsState settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), + lock, + mSettingsFile, + configKey, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, + Looper.getMainLooper()); + + AconfigdFlagInfo defaultFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setDefaultFlagValue("false") + .build(); + + AconfigdFlagInfo settingFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setServerFlagValue("true") + .setHasServerOverride(true) + .build(); + + AconfigdFlagInfo expectedFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setBootFlagValue("true") + .setServerFlagValue("true") + .setDefaultFlagValue("false") + .setHasServerOverride(true) + .build(); + + Map<String, AconfigdFlagInfo> settingMap = new HashMap<>(); + Map<String, AconfigdFlagInfo> aconfigdMap = new HashMap<>(); + Map<String, AconfigdFlagInfo> defaultMap = new HashMap<>(); + + defaultMap.put("com.android.flags.flag1", defaultFlag1); + settingMap.put("com.android.flags.flag1", settingFlag1); + aconfigdMap.put("com.android.flags.flag1", expectedFlag1); + + int ret = settingsState.compareFlagValueInNewStorage(settingMap, defaultMap, aconfigdMap); + assertEquals(0, ret); + + AconfigdFlagInfo defaultFlag2 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag2") + .setDefaultFlagValue("false") + .build(); + defaultMap.put("com.android.flags.flag2", defaultFlag2); + + ret = settingsState.compareFlagValueInNewStorage(settingMap, defaultMap, aconfigdMap); + assertEquals(1, ret); + } } |