1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.providers.settings; 17 18 import static junit.framework.Assert.assertEquals; 19 import static junit.framework.Assert.assertFalse; 20 import static junit.framework.Assert.assertNull; 21 import static junit.framework.Assert.assertTrue; 22 import static junit.framework.Assert.fail; 23 24 import android.aconfig.Aconfig; 25 import android.aconfig.Aconfig.parsed_flag; 26 import android.aconfig.Aconfig.parsed_flags; 27 import android.aconfigd.AconfigdFlagInfo; 28 import android.os.Looper; 29 import android.platform.test.annotations.RequiresFlagsEnabled; 30 import android.platform.test.flag.junit.CheckFlagsRule; 31 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 32 import android.util.Xml; 33 import android.util.proto.ProtoOutputStream; 34 35 import androidx.test.InstrumentationRegistry; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import com.android.modules.utils.TypedXmlSerializer; 39 40 import android.platform.test.annotations.EnableFlags; 41 import android.platform.test.annotations.DisableFlags; 42 import android.platform.test.flag.junit.SetFlagsRule; 43 44 import com.google.common.base.Strings; 45 46 import java.io.ByteArrayOutputStream; 47 import java.io.File; 48 import java.io.FileOutputStream; 49 import java.io.PrintStream; 50 import java.util.HashMap; 51 import java.util.List; 52 import java.util.Map; 53 54 import org.junit.After; 55 import org.junit.Before; 56 import org.junit.Rule; 57 import org.junit.Test; 58 import org.junit.runner.RunWith; 59 60 @RunWith(AndroidJUnit4.class) 61 public class SettingsStateTest { 62 @Rule 63 public final CheckFlagsRule mCheckFlagsRule = 64 DeviceFlagsValueProvider.createCheckFlagsRule(); 65 66 public static final String CRAZY_STRING = 67 "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" + 68 "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" + 69 "\u001b\u001c\u001d\u001e\u001f\u0020" + 70 "fake_setting_value_1" + 71 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 72 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 73 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 74 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 75 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 76 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 77 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 78 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 79 "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" + 80 "\ud800\udc00\udbff\udfff" + // surrogate pairs 81 "\uD800ab\uDC00 " + // broken surrogate pairs 82 "日本語"; 83 84 private static final String TEST_PACKAGE = "package"; 85 private static final String SYSTEM_PACKAGE = "android"; 86 private static final String SETTING_NAME = "test_setting"; 87 88 private static final String FLAG_NAME_1 = "namespace123/flag456"; 89 private static final String FLAG_NAME_1_STAGED = "staged/namespace123*flag456"; 90 private static final String FLAG_NAME_2 = "not_staged/flag101"; 91 92 private static final String INVALID_STAGED_FLAG_1 = "stagednamespace*flagName"; 93 private static final String INVALID_STAGED_FLAG_2 = "staged/"; 94 private static final String INVALID_STAGED_FLAG_3 = "staged/namespace*"; 95 private static final String INVALID_STAGED_FLAG_4 = "staged/*flagName"; 96 97 private static final String VALID_STAGED_FLAG_1 = "staged/namespace*flagName"; 98 private static final String VALID_STAGED_FLAG_1_TRANSFORMED = "namespace/flagName"; 99 100 private static final String VALUE1 = "5"; 101 private static final String VALUE2 = "6"; 102 103 private final Object mLock = new Object(); 104 105 private File mSettingsFile; 106 107 @Before setUp()108 public void setUp() { 109 mSettingsFile = new File(InstrumentationRegistry.getContext().getCacheDir(), "setting.xml"); 110 mSettingsFile.delete(); 111 } 112 113 @After tearDown()114 public void tearDown() throws Exception { 115 if (mSettingsFile != null) { 116 mSettingsFile.delete(); 117 } 118 } 119 120 @Test testLoadValidAconfigProto()121 public void testLoadValidAconfigProto() { 122 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 123 Object lock = new Object(); 124 SettingsState settingsState = new SettingsState( 125 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 126 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 127 parsed_flags flags = parsed_flags 128 .newBuilder() 129 .addParsedFlag(parsed_flag 130 .newBuilder() 131 .setPackage("com.android.flags") 132 .setName("flag1") 133 .setNamespace("test_namespace") 134 .setDescription("test flag") 135 .addBug("12345678") 136 .setState(Aconfig.flag_state.DISABLED) 137 .setPermission(Aconfig.flag_permission.READ_WRITE)) 138 .addParsedFlag(parsed_flag 139 .newBuilder() 140 .setPackage("com.android.flags") 141 .setName("flag2") 142 .setNamespace("test_namespace") 143 .setDescription("another test flag") 144 .addBug("12345678") 145 .setState(Aconfig.flag_state.ENABLED) 146 .setPermission(Aconfig.flag_permission.READ_ONLY)) 147 .build(); 148 149 AconfigdFlagInfo flag1 = AconfigdFlagInfo.newBuilder() 150 .setPackageName("com.android.flags") 151 .setFlagName("flag1") 152 .setDefaultFlagValue("false") 153 .setIsReadWrite(true) 154 .build(); 155 AconfigdFlagInfo flag2 = AconfigdFlagInfo.newBuilder() 156 .setPackageName("com.android.flags") 157 .setFlagName("flag2") 158 .setDefaultFlagValue("true") 159 .setIsReadWrite(false) 160 .build(); 161 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 162 163 synchronized (lock) { 164 Map<String, Map<String, String>> defaults = new HashMap<>(); 165 settingsState.loadAconfigDefaultValues( 166 flags.toByteArray(), defaults, flagInfoDefault); 167 Map<String, String> namespaceDefaults = defaults.get("test_namespace"); 168 assertEquals(2, namespaceDefaults.keySet().size()); 169 170 assertEquals("false", namespaceDefaults.get("test_namespace/com.android.flags.flag1")); 171 assertEquals("true", namespaceDefaults.get("test_namespace/com.android.flags.flag2")); 172 } 173 174 assertEquals(flag1, flagInfoDefault.get(flag1.getFullFlagName())); 175 assertEquals(flag2, flagInfoDefault.get(flag2.getFullFlagName())); 176 } 177 178 @Test testSkipLoadingAconfigFlagWithMissingFields()179 public void testSkipLoadingAconfigFlagWithMissingFields() { 180 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 181 Object lock = new Object(); 182 SettingsState settingsState = new SettingsState( 183 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 184 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 185 186 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 187 188 parsed_flags flags = parsed_flags 189 .newBuilder() 190 .addParsedFlag(parsed_flag 191 .newBuilder() 192 .setDescription("test flag") 193 .addBug("12345678") 194 .setState(Aconfig.flag_state.DISABLED) 195 .setPermission(Aconfig.flag_permission.READ_WRITE)) 196 .build(); 197 198 synchronized (lock) { 199 Map<String, Map<String, String>> defaults = new HashMap<>(); 200 settingsState.loadAconfigDefaultValues( 201 flags.toByteArray(), defaults, flagInfoDefault); 202 203 Map<String, String> namespaceDefaults = defaults.get("test_namespace"); 204 assertEquals(null, namespaceDefaults); 205 } 206 } 207 208 @Test 209 @RequiresFlagsEnabled(Flags.FLAG_STAGE_ALL_ACONFIG_FLAGS) testWritingAconfigFlagStages()210 public void testWritingAconfigFlagStages() { 211 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 212 Object lock = new Object(); 213 SettingsState settingsState = new SettingsState( 214 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 215 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 216 parsed_flags flags = parsed_flags 217 .newBuilder() 218 .addParsedFlag(parsed_flag 219 .newBuilder() 220 .setPackage("com.android.flags") 221 .setName("flag5") 222 .setNamespace("test_namespace") 223 .setDescription("test flag") 224 .addBug("12345678") 225 .setState(Aconfig.flag_state.DISABLED) 226 .setPermission(Aconfig.flag_permission.READ_WRITE)) 227 .build(); 228 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 229 230 synchronized (lock) { 231 Map<String, Map<String, String>> defaults = new HashMap<>(); 232 settingsState.loadAconfigDefaultValues( 233 flags.toByteArray(), defaults, flagInfoDefault); 234 settingsState.addAconfigDefaultValuesFromMap(defaults); 235 236 settingsState.insertSettingLocked("test_namespace/com.android.flags.flag5", 237 "true", null, false, "com.android.flags"); 238 settingsState.insertSettingLocked("test_namespace/com.android.flags.flag6", 239 "true", null, false, "com.android.flags"); 240 241 assertEquals("true", 242 settingsState 243 .getSettingLocked("staged/test_namespace*com.android.flags.flag5") 244 .getValue()); 245 assertEquals(null, 246 settingsState 247 .getSettingLocked("test_namespace/com.android.flags.flag5") 248 .getValue()); 249 250 assertEquals(null, 251 settingsState 252 .getSettingLocked("staged/test_namespace*com.android.flags.flag6") 253 .getValue()); 254 assertEquals("true", 255 settingsState 256 .getSettingLocked("test_namespace/com.android.flags.flag6") 257 .getValue()); 258 } 259 } 260 261 @Test testInvalidAconfigProtoDoesNotCrash()262 public void testInvalidAconfigProtoDoesNotCrash() { 263 Map<String, Map<String, String>> defaults = new HashMap<>(); 264 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 265 SettingsState settingsState = getSettingStateObject(); 266 settingsState.loadAconfigDefaultValues( 267 "invalid protobuf".getBytes(), defaults, flagInfoDefault); 268 } 269 270 @Test testIsBinary()271 public void testIsBinary() { 272 assertFalse(SettingsState.isBinary(" abc 日本語")); 273 274 for (char ch = 0x20; ch < 0xd800; ch++) { 275 assertFalse("ch=" + Integer.toString(ch, 16), 276 SettingsState.isBinary(String.valueOf(ch))); 277 } 278 for (char ch = 0xe000; ch < 0xfffe; ch++) { 279 assertFalse("ch=" + Integer.toString(ch, 16), 280 SettingsState.isBinary(String.valueOf(ch))); 281 } 282 283 for (char ch = 0x0000; ch < 0x20; ch++) { 284 assertTrue("ch=" + Integer.toString(ch, 16), 285 SettingsState.isBinary(String.valueOf(ch))); 286 } 287 for (char ch = 0xd800; ch < 0xe000; ch++) { 288 assertTrue("ch=" + Integer.toString(ch, 16), 289 SettingsState.isBinary(String.valueOf(ch))); 290 } 291 assertTrue(SettingsState.isBinary("\ufffe")); 292 assertTrue(SettingsState.isBinary("\uffff")); 293 try { 294 assertFalse(SettingsState.isBinary(null)); 295 fail("NullPointerException expected"); 296 } catch (NullPointerException expected) { 297 } 298 } 299 300 /** Make sure we won't pass invalid characters to XML serializer. */ 301 @Test testWriteReadNoCrash()302 public void testWriteReadNoCrash() throws Exception { 303 ByteArrayOutputStream os = new ByteArrayOutputStream(); 304 305 TypedXmlSerializer serializer = Xml.resolveSerializer(os); 306 serializer.startDocument(null, true); 307 308 for (int ch = 0; ch < 0x10000; ch++) { 309 checkWriteSingleSetting("char=0x" + Integer.toString(ch, 16), serializer, 310 "key", String.valueOf((char) ch)); 311 } 312 checkWriteSingleSetting(serializer, "k", ""); 313 checkWriteSingleSetting(serializer, "x", "abc"); 314 checkWriteSingleSetting(serializer, "abc", CRAZY_STRING); 315 checkWriteSingleSetting(serializer, "def", null); 316 317 // Invlid input, but shouoldn't crash. 318 checkWriteSingleSetting(serializer, null, null); 319 checkWriteSingleSetting(serializer, CRAZY_STRING, null); 320 SettingsState.writeSingleSetting( 321 SettingsState.SETTINGS_VERSION_NEW_ENCODING, 322 serializer, null, "k", "v", null, "package", null, false, false); 323 SettingsState.writeSingleSetting( 324 SettingsState.SETTINGS_VERSION_NEW_ENCODING, 325 serializer, "1", "k", "v", null, null, null, false, false); 326 } 327 checkWriteSingleSetting(TypedXmlSerializer serializer, String key, String value)328 private void checkWriteSingleSetting(TypedXmlSerializer serializer, String key, String value) 329 throws Exception { 330 checkWriteSingleSetting(key + "/" + value, serializer, key, value); 331 } 332 checkWriteSingleSetting(String msg, TypedXmlSerializer serializer, String key, String value)333 private void checkWriteSingleSetting(String msg, TypedXmlSerializer serializer, 334 String key, String value) throws Exception { 335 // Make sure the XML serializer won't crash. 336 SettingsState.writeSingleSetting( 337 SettingsState.SETTINGS_VERSION_NEW_ENCODING, 338 serializer, "1", key, value, null, "package", null, false, false); 339 } 340 341 /** 342 * Make sure settings can be written to a file and also can be read. 343 */ 344 @Test testReadWrite()345 public void testReadWrite() { 346 final Object lock = new Object(); 347 348 assertFalse(mSettingsFile.exists()); 349 final SettingsState ssWriter = 350 new SettingsState( 351 InstrumentationRegistry.getContext(), lock, mSettingsFile, 1, 352 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 353 ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); 354 355 ssWriter.insertSettingLocked("k1", "\u0000", null, false, "package"); 356 ssWriter.insertSettingLocked("k2", "abc", null, false, "p2"); 357 ssWriter.insertSettingLocked("k3", null, null, false, "p2"); 358 ssWriter.insertSettingLocked("k4", CRAZY_STRING, null, false, "p3"); 359 synchronized (lock) { 360 ssWriter.persistSettingsLocked(); 361 } 362 ssWriter.waitForHandler(); 363 assertTrue(mSettingsFile.exists()); 364 final SettingsState ssReader = 365 new SettingsState( 366 InstrumentationRegistry.getContext(), lock, mSettingsFile, 1, 367 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 368 369 synchronized (lock) { 370 assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue()); 371 assertEquals("abc", ssReader.getSettingLocked("k2").getValue()); 372 assertEquals(null, ssReader.getSettingLocked("k3").getValue()); 373 assertEquals(CRAZY_STRING, ssReader.getSettingLocked("k4").getValue()); 374 } 375 } 376 377 /** 378 * In version 120, value "null" meant {code NULL}. 379 */ 380 @Test testUpgrade()381 public void testUpgrade() throws Exception { 382 final Object lock = new Object(); 383 final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); 384 os.print( 385 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + 386 "<settings version=\"120\">" + 387 " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" + 388 " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" + 389 " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" + 390 "</settings>"); 391 os.close(); 392 393 final SettingsState ss = 394 new SettingsState( 395 InstrumentationRegistry.getContext(), lock, mSettingsFile, 1, 396 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 397 synchronized (lock) { 398 SettingsState.Setting s; 399 s = ss.getSettingLocked("k0"); 400 assertEquals(null, s.getValue()); 401 assertEquals("null", s.getPackageName()); 402 403 s = ss.getSettingLocked("k1"); 404 assertEquals("", s.getValue()); 405 assertEquals("", s.getPackageName()); 406 407 s = ss.getSettingLocked("k2"); 408 assertEquals("v2", s.getValue()); 409 assertEquals("p2", s.getPackageName()); 410 } 411 } 412 413 @Test testInitializeSetting_preserveFlagNotSet()414 public void testInitializeSetting_preserveFlagNotSet() { 415 SettingsState settingsWriter = getSettingStateObject(); 416 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 417 settingsWriter.persistSettingsLocked(); 418 settingsWriter.waitForHandler(); 419 420 SettingsState settingsReader = getSettingStateObject(); 421 assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 422 } 423 424 @Test testModifySetting_preserveFlagSet()425 public void testModifySetting_preserveFlagSet() { 426 SettingsState settingsWriter = getSettingStateObject(); 427 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 428 settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE); 429 settingsWriter.persistSettingsLocked(); 430 settingsWriter.waitForHandler(); 431 432 SettingsState settingsReader = getSettingStateObject(); 433 assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 434 } 435 436 @Test testModifySettingOverrideableByRestore_preserveFlagNotSet()437 public void testModifySettingOverrideableByRestore_preserveFlagNotSet() { 438 SettingsState settingsWriter = getSettingStateObject(); 439 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 440 settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, false, TEST_PACKAGE, 441 /* overrideableByRestore */ true); 442 settingsWriter.persistSettingsLocked(); 443 settingsWriter.waitForHandler(); 444 445 SettingsState settingsReader = getSettingStateObject(); 446 assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 447 } 448 449 @Test testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged()450 public void testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged() { 451 SettingsState settingsWriter = getSettingStateObject(); 452 // Init the setting. 453 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 454 // This modification will set isValuePreservedInRestore = true. 455 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 456 // This modification shouldn't change the value of isValuePreservedInRestore since it's 457 // already been set to true. 458 settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, false, TEST_PACKAGE, 459 /* overrideableByRestore */ true); 460 settingsWriter.persistSettingsLocked(); 461 settingsWriter.waitForHandler(); 462 463 SettingsState settingsReader = getSettingStateObject(); 464 assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 465 } 466 467 @Test testResetSetting_preservedFlagIsReset()468 public void testResetSetting_preservedFlagIsReset() { 469 SettingsState settingsState = getSettingStateObject(); 470 // Initialize the setting. 471 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 472 // Update the setting so that preserved flag is set. 473 settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE); 474 475 settingsState.resetSettingLocked(SETTING_NAME); 476 assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 477 478 } 479 480 @Test testModifySettingBySystemPackage_sameValue_preserveFlagNotSet()481 public void testModifySettingBySystemPackage_sameValue_preserveFlagNotSet() { 482 SettingsState settingsState = getSettingStateObject(); 483 // Initialize the setting. 484 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, SYSTEM_PACKAGE); 485 // Update the setting. 486 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, SYSTEM_PACKAGE); 487 488 assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 489 } 490 491 @Test testModifySettingBySystemPackage_newValue_preserveFlagSet()492 public void testModifySettingBySystemPackage_newValue_preserveFlagSet() { 493 SettingsState settingsState = getSettingStateObject(); 494 // Initialize the setting. 495 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, SYSTEM_PACKAGE); 496 // Update the setting. 497 settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, SYSTEM_PACKAGE); 498 499 assertTrue(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 500 } 501 getSettingStateObject()502 private SettingsState getSettingStateObject() { 503 SettingsState settingsState = 504 new SettingsState( 505 InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, 506 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 507 settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); 508 return settingsState; 509 } 510 511 @Test testInsertSetting_memoryUsage()512 public void testInsertSetting_memoryUsage() { 513 SettingsState settingsState = getSettingStateObject(); 514 // No exception should be thrown when there is no cap 515 settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), 516 null, false, "p1"); 517 settingsState.deleteSettingLocked(SETTING_NAME); 518 519 settingsState = 520 new SettingsState( 521 InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, 522 SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); 523 // System package doesn't have memory usage limit 524 settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), 525 null, false, SYSTEM_PACKAGE); 526 settingsState.deleteSettingLocked(SETTING_NAME); 527 528 // Should not throw if usage is under the cap 529 settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 19975), 530 null, false, "p1"); 531 settingsState.deleteSettingLocked(SETTING_NAME); 532 try { 533 settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), 534 null, false, "p1"); 535 fail("Should throw because it exceeded per package memory usage"); 536 } catch (IllegalStateException ex) { 537 assertTrue(ex.getMessage().contains("p1")); 538 } 539 try { 540 settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), 541 null, false, "p1"); 542 fail("Should throw because it exceeded per package memory usage"); 543 } catch (IllegalStateException ex) { 544 assertTrue(ex.getMessage().contains("p1")); 545 } 546 assertTrue(settingsState.getSettingLocked(SETTING_NAME).isNull()); 547 try { 548 settingsState.insertSettingLocked(Strings.repeat("A", 20001), "", 549 null, false, "p1"); 550 fail("Should throw because it exceeded per package memory usage"); 551 } catch (IllegalStateException ex) { 552 assertTrue(ex.getMessage().contains("You are adding too many system settings")); 553 } 554 } 555 556 @Test testMemoryUsagePerPackage()557 public void testMemoryUsagePerPackage() { 558 SettingsState settingsState = 559 new SettingsState( 560 InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, 561 SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); 562 563 // Test inserting one key with default 564 final String testKey1 = SETTING_NAME; 565 final String testValue1 = Strings.repeat("A", 100); 566 settingsState.insertSettingLocked(testKey1, testValue1, null, true, TEST_PACKAGE); 567 int expectedMemUsage = (testKey1.length() + testValue1.length() 568 + testValue1.length() /* size for default */) * Character.BYTES; 569 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 570 571 // Test inserting another key 572 final String testKey2 = SETTING_NAME + "2"; 573 settingsState.insertSettingLocked(testKey2, testValue1, null, false, TEST_PACKAGE); 574 expectedMemUsage += (testKey2.length() + testValue1.length()) * Character.BYTES; 575 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 576 577 // Test updating first key with new default 578 final String testValue2 = Strings.repeat("A", 300); 579 settingsState.insertSettingLocked(testKey1, testValue2, null, true, TEST_PACKAGE); 580 expectedMemUsage += (testValue2.length() - testValue1.length()) * 2 * Character.BYTES; 581 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 582 583 // Test updating first key without new default 584 final String testValue3 = Strings.repeat("A", 50); 585 settingsState.insertSettingLocked(testKey1, testValue3, null, false, TEST_PACKAGE); 586 expectedMemUsage -= (testValue2.length() - testValue3.length()) * Character.BYTES; 587 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 588 589 // Test updating second key 590 settingsState.insertSettingLocked(testKey2, testValue2, null, false, TEST_PACKAGE); 591 expectedMemUsage -= (testValue1.length() - testValue2.length()) * Character.BYTES; 592 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 593 594 // Test resetting key 595 settingsState.resetSettingLocked(testKey1); 596 expectedMemUsage += (testValue2.length() - testValue3.length()) * Character.BYTES; 597 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 598 599 // Test resetting default value 600 settingsState.resetSettingDefaultValueLocked(testKey1); 601 expectedMemUsage -= testValue2.length() * Character.BYTES; 602 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 603 604 // Test deletion 605 settingsState.deleteSettingLocked(testKey2); 606 expectedMemUsage -= (testValue2.length() + testKey2.length() /* key is deleted too */) 607 * Character.BYTES; 608 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 609 610 // Test another package with a different key 611 final String testPackage2 = TEST_PACKAGE + "2"; 612 final String testKey3 = SETTING_NAME + "3"; 613 settingsState.insertSettingLocked(testKey3, testValue1, null, true, testPackage2); 614 assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); 615 final int expectedMemUsage2 = (testKey3.length() + testValue1.length() * 2) 616 * Character.BYTES; 617 assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2)); 618 619 // Let system package take over testKey1 which is no longer subject to memory usage counting 620 settingsState.insertSettingLocked(testKey1, testValue1, null, true, SYSTEM_PACKAGE); 621 assertEquals(0, settingsState.getMemoryUsage(TEST_PACKAGE)); 622 assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2)); 623 assertEquals(0, settingsState.getMemoryUsage(SYSTEM_PACKAGE)); 624 625 // Test invalid value 626 try { 627 settingsState.insertSettingLocked(testKey1, Strings.repeat("A", 20001), null, false, 628 TEST_PACKAGE); 629 fail("Should throw because it exceeded per package memory usage"); 630 } catch (IllegalStateException ex) { 631 assertTrue(ex.getMessage().contains("You are adding too many system settings")); 632 } 633 assertEquals(0, settingsState.getMemoryUsage(TEST_PACKAGE)); 634 635 // Test invalid key 636 try { 637 settingsState.insertSettingLocked(Strings.repeat("A", 20001), "", null, false, 638 TEST_PACKAGE); 639 fail("Should throw because it exceeded per package memory usage"); 640 } catch (IllegalStateException ex) { 641 assertTrue(ex.getMessage().contains("You are adding too many system settings")); 642 } 643 assertEquals(0, settingsState.getMemoryUsage(TEST_PACKAGE)); 644 } 645 646 @Test testLargeSettingKey()647 public void testLargeSettingKey() { 648 SettingsState settingsState = 649 new SettingsState( 650 InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, 651 SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); 652 final String largeKey = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1); 653 final String testValue = "testValue"; 654 synchronized (mLock) { 655 // Test system package 656 try { 657 settingsState.insertSettingLocked(largeKey, testValue, null, true, SYSTEM_PACKAGE); 658 fail("Should throw because it exceeded max string length"); 659 } catch (IllegalArgumentException ex) { 660 assertTrue(ex.getMessage().contains("The max length allowed for the string is ")); 661 } 662 // Test non system package 663 try { 664 settingsState.insertSettingLocked(largeKey, testValue, null, true, TEST_PACKAGE); 665 fail("Should throw because it exceeded max string length"); 666 } catch (IllegalArgumentException ex) { 667 assertTrue(ex.getMessage().contains("The max length allowed for the string is ")); 668 } 669 } 670 } 671 672 @Test testLargeSettingValue()673 public void testLargeSettingValue() { 674 SettingsState settingsState = 675 new SettingsState( 676 InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, 677 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 678 final String testKey = "testKey"; 679 final String largeValue = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1); 680 synchronized (mLock) { 681 // Test system package 682 try { 683 settingsState.insertSettingLocked(testKey, largeValue, null, true, SYSTEM_PACKAGE); 684 fail("Should throw because it exceeded max string length"); 685 } catch (IllegalArgumentException ex) { 686 assertTrue(ex.getMessage().contains("The max length allowed for the string is ")); 687 } 688 // Test non system package 689 try { 690 settingsState.insertSettingLocked(testKey, largeValue, null, true, TEST_PACKAGE); 691 fail("Should throw because it exceeded max string length"); 692 } catch (IllegalArgumentException ex) { 693 assertTrue(ex.getMessage().contains("The max length allowed for the string is ")); 694 } 695 } 696 } 697 698 @Test testApplyStagedConfigValues()699 public void testApplyStagedConfigValues() { 700 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 701 Object lock = new Object(); 702 SettingsState settingsState = new SettingsState( 703 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 704 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 705 706 synchronized (lock) { 707 settingsState.insertSettingLocked( 708 FLAG_NAME_1_STAGED, VALUE1, null, false, TEST_PACKAGE); 709 settingsState.insertSettingLocked(FLAG_NAME_2, VALUE2, null, false, TEST_PACKAGE); 710 settingsState.persistSettingsLocked(); 711 } 712 settingsState.waitForHandler(); 713 714 synchronized (lock) { 715 assertEquals(VALUE1, settingsState.getSettingLocked(FLAG_NAME_1_STAGED).getValue()); 716 assertEquals(VALUE2, settingsState.getSettingLocked(FLAG_NAME_2).getValue()); 717 } 718 719 settingsState = new SettingsState( 720 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 721 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 722 723 synchronized (lock) { 724 assertEquals(VALUE1, settingsState.getSettingLocked(FLAG_NAME_1).getValue()); 725 assertEquals(VALUE2, settingsState.getSettingLocked(FLAG_NAME_2).getValue()); 726 727 assertEquals(null, settingsState.getSettingLocked(FLAG_NAME_1_STAGED).getValue()); 728 } 729 } 730 731 @Test testStagingTransformation()732 public void testStagingTransformation() { 733 assertEquals(INVALID_STAGED_FLAG_1, 734 SettingsState.createRealFlagName(INVALID_STAGED_FLAG_1)); 735 assertEquals(INVALID_STAGED_FLAG_2, 736 SettingsState.createRealFlagName(INVALID_STAGED_FLAG_2)); 737 assertEquals(INVALID_STAGED_FLAG_3, 738 SettingsState.createRealFlagName(INVALID_STAGED_FLAG_3)); 739 assertEquals(INVALID_STAGED_FLAG_4, 740 SettingsState.createRealFlagName(INVALID_STAGED_FLAG_4)); 741 742 assertEquals(VALID_STAGED_FLAG_1_TRANSFORMED, 743 SettingsState.createRealFlagName(VALID_STAGED_FLAG_1)); 744 } 745 746 @Test testInvalidStagedFlagsUnaffectedByReboot()747 public void testInvalidStagedFlagsUnaffectedByReboot() { 748 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 749 Object lock = new Object(); 750 SettingsState settingsState = new SettingsState( 751 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 752 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 753 754 synchronized (lock) { 755 settingsState.insertSettingLocked(INVALID_STAGED_FLAG_1, 756 VALUE2, null, false, TEST_PACKAGE); 757 settingsState.persistSettingsLocked(); 758 } 759 settingsState.waitForHandler(); 760 synchronized (lock) { 761 assertEquals(VALUE2, settingsState.getSettingLocked(INVALID_STAGED_FLAG_1).getValue()); 762 } 763 764 settingsState = new SettingsState( 765 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 766 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 767 768 synchronized (lock) { 769 assertEquals(VALUE2, settingsState.getSettingLocked(INVALID_STAGED_FLAG_1).getValue()); 770 } 771 } 772 773 @Test 774 @RequiresFlagsEnabled(Flags.FLAG_STAGE_ALL_ACONFIG_FLAGS) testSetSettingsLockedStagesAconfigFlags()775 public void testSetSettingsLockedStagesAconfigFlags() throws Exception { 776 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 777 778 SettingsState settingsState = new SettingsState( 779 InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey, 780 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 781 782 String prefix = "test_namespace"; 783 String packageName = "com.android.flags"; 784 Map<String, String> keyValues = 785 Map.of("test_namespace/com.android.flags.flag3", "true"); 786 787 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 788 789 parsed_flags flags = parsed_flags 790 .newBuilder() 791 .addParsedFlag(parsed_flag 792 .newBuilder() 793 .setPackage(packageName) 794 .setName("flag3") 795 .setNamespace(prefix) 796 .setDescription("test flag") 797 .addBug("12345678") 798 .setState(Aconfig.flag_state.DISABLED) 799 .setPermission(Aconfig.flag_permission.READ_WRITE)) 800 .build(); 801 802 synchronized (mLock) { 803 settingsState.loadAconfigDefaultValues( 804 flags.toByteArray(), 805 settingsState.getAconfigDefaultValues(), flagInfoDefault); 806 List<String> updates = 807 settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); 808 assertEquals(1, updates.size()); 809 assertEquals(updates.get(0), "staged/test_namespace*com.android.flags.flag3"); 810 811 SettingsState.Setting s; 812 813 s = settingsState.getSettingLocked("test_namespace/com.android.flags.flag3"); 814 assertNull(s.getValue()); 815 816 s = settingsState.getSettingLocked("staged/test_namespace*com.android.flags.flag3"); 817 assertEquals("true", s.getValue()); 818 } 819 } 820 821 @Test testsetSettingsLockedKeepTrunkDefault()822 public void testsetSettingsLockedKeepTrunkDefault() throws Exception { 823 final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); 824 os.print( 825 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" 826 + "<settings version=\"120\">" 827 + " <setting id=\"0\" name=\"test_namespace/flag0\" " 828 + "value=\"false\" package=\"com.android.flags\" />" 829 + " <setting id=\"1\" name=\"test_namespace/flag1\" " 830 + "value=\"false\" package=\"com.android.flags\" />" 831 + " <setting id=\"2\" name=\"test_namespace/com.android.flags.flag3\" " 832 + "value=\"false\" package=\"com.android.flags\" />" 833 + " <setting id=\"3\" " 834 + "name=\"test_another_namespace/com.android.another.flags.flag0\" " 835 + "value=\"false\" package=\"com.android.another.flags\" />" 836 + "</settings>"); 837 os.close(); 838 839 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 840 841 SettingsState settingsState = new SettingsState( 842 InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey, 843 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 844 845 String prefix = "test_namespace"; 846 Map<String, String> keyValues = 847 Map.of("test_namespace/flag0", "true", "test_namespace/flag2", "false"); 848 String packageName = "com.android.flags"; 849 850 parsed_flags flags = parsed_flags 851 .newBuilder() 852 .addParsedFlag(parsed_flag 853 .newBuilder() 854 .setPackage(packageName) 855 .setName("flag3") 856 .setNamespace(prefix) 857 .setDescription("test flag") 858 .addBug("12345678") 859 .setState(Aconfig.flag_state.DISABLED) 860 .setPermission(Aconfig.flag_permission.READ_WRITE)) 861 .addParsedFlag(parsed_flag 862 .newBuilder() 863 .setPackage("com.android.another.flags") 864 .setName("flag0") 865 .setNamespace("test_another_namespace") 866 .setDescription("test flag") 867 .addBug("12345678") 868 .setState(Aconfig.flag_state.DISABLED) 869 .setPermission(Aconfig.flag_permission.READ_WRITE)) 870 .build(); 871 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 872 873 synchronized (mLock) { 874 settingsState.loadAconfigDefaultValues( 875 flags.toByteArray(), 876 settingsState.getAconfigDefaultValues(), 877 flagInfoDefault); 878 List<String> updates = 879 settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); 880 assertEquals(3, updates.size()); 881 882 SettingsState.Setting s; 883 884 s = settingsState.getSettingLocked("test_namespace/flag0"); 885 assertEquals("true", s.getValue()); 886 887 s = settingsState.getSettingLocked("test_namespace/flag1"); 888 assertNull(s.getValue()); 889 890 s = settingsState.getSettingLocked("test_namespace/flag2"); 891 assertEquals("false", s.getValue()); 892 893 s = settingsState.getSettingLocked("test_namespace/com.android.flags.flag3"); 894 assertEquals("false", s.getValue()); 895 896 s = settingsState.getSettingLocked( 897 "test_another_namespace/com.android.another.flags.flag0"); 898 assertEquals("false", s.getValue()); 899 } 900 } 901 902 @Test testsetSettingsLockedNoTrunkDefault()903 public void testsetSettingsLockedNoTrunkDefault() throws Exception { 904 final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); 905 os.print( 906 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" 907 + "<settings version=\"120\">" 908 + " <setting id=\"0\" name=\"test_namespace/flag0\" " 909 + "value=\"false\" package=\"com.android.flags\" />" 910 + " <setting id=\"1\" name=\"test_namespace/flag1\" " 911 + "value=\"false\" package=\"com.android.flags\" />" 912 + "</settings>"); 913 os.close(); 914 915 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 916 917 SettingsState settingsState = new SettingsState( 918 InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey, 919 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 920 921 Map<String, String> keyValues = 922 Map.of("test_namespace/flag0", "true", "test_namespace/flag2", "false"); 923 String packageName = "com.android.flags"; 924 925 synchronized (mLock) { 926 List<String> updates = 927 settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); 928 assertEquals(3, updates.size()); 929 930 SettingsState.Setting s; 931 932 s = settingsState.getSettingLocked("test_namespace/flag0"); 933 assertEquals("true", s.getValue()); 934 935 s = settingsState.getSettingLocked("test_namespace/flag1"); 936 assertNull(s.getValue()); 937 938 s = settingsState.getSettingLocked("test_namespace/flag2"); 939 assertEquals("false", s.getValue()); 940 } 941 } 942 943 @Test testMemoryUsagePerPackage_SameSettingUsedByDifferentPackages()944 public void testMemoryUsagePerPackage_SameSettingUsedByDifferentPackages() { 945 SettingsState settingsState = 946 new SettingsState( 947 InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, 948 SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); 949 final String testKey1 = SETTING_NAME; 950 final String testKey2 = SETTING_NAME + "_2"; 951 final String testValue1 = Strings.repeat("A", 100); 952 final String testValue2 = Strings.repeat("A", 50); 953 final String package1 = "p1"; 954 final String package2 = "p2"; 955 956 settingsState.insertSettingLocked(testKey1, testValue1, null, false, package1); 957 settingsState.insertSettingLocked(testKey2, testValue1, null, true, package2); 958 // Package1's usage should be remain the same Package2 owns a different setting 959 int expectedMemUsageForPackage1 = (testKey1.length() + testValue1.length()) 960 * Character.BYTES; 961 int expectedMemUsageForPackage2 = (testKey2.length() + testValue1.length() 962 + testValue1.length() /* size for default */) * Character.BYTES; 963 assertEquals(expectedMemUsageForPackage1, settingsState.getMemoryUsage(package1)); 964 assertEquals(expectedMemUsageForPackage2, settingsState.getMemoryUsage(package2)); 965 966 settingsState.insertSettingLocked(testKey1, testValue2, null, false, package2); 967 // Package1's usage should be cleared because the setting is taken over by another package 968 expectedMemUsageForPackage1 = 0; 969 assertEquals(expectedMemUsageForPackage1, settingsState.getMemoryUsage(package1)); 970 // Package2 now owns two settings 971 expectedMemUsageForPackage2 = (testKey1.length() + testValue2.length() 972 + testKey2.length() + testValue1.length() 973 + testValue1.length() /* size for default */) 974 * Character.BYTES; 975 assertEquals(expectedMemUsageForPackage2, settingsState.getMemoryUsage(package2)); 976 977 settingsState.insertSettingLocked(testKey1, testValue1, null, true, package1); 978 // Package1 now owns setting1 979 expectedMemUsageForPackage1 = (testKey1.length() + testValue1.length() 980 + testValue1.length() /* size for default */) * Character.BYTES; 981 assertEquals(expectedMemUsageForPackage1, settingsState.getMemoryUsage(package1)); 982 // Package2 now only own setting2 983 expectedMemUsageForPackage2 = (testKey2.length() + testValue1.length() 984 + testValue1.length() /* size for default */) * Character.BYTES; 985 assertEquals(expectedMemUsageForPackage2, settingsState.getMemoryUsage(package2)); 986 } 987 988 @Test testGetFlagOverrideToSync()989 public void testGetFlagOverrideToSync() { 990 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 991 Object lock = new Object(); 992 SettingsState settingsState = 993 new SettingsState( 994 InstrumentationRegistry.getContext(), 995 lock, 996 mSettingsFile, 997 configKey, 998 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, 999 Looper.getMainLooper()); 1000 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 1001 1002 // invalid flag name 1003 assertNull(settingsState.getFlagOverrideToSync("invalid_flag", "false", flagInfoDefault)); 1004 1005 // invalid local override flag name 1006 assertNull( 1007 settingsState.getFlagOverrideToSync( 1008 "some_namespace/some_flag", "false", flagInfoDefault)); 1009 1010 // not a aconfig flag 1011 assertNull( 1012 settingsState.getFlagOverrideToSync( 1013 "some_namespace/some_flag.com", "false", flagInfoDefault)); 1014 1015 AconfigdFlagInfo flag1 = 1016 AconfigdFlagInfo.newBuilder() 1017 .setPackageName("com.android.flags") 1018 .setFlagName("flag1") 1019 .setDefaultFlagValue("false") 1020 .setIsReadWrite(true) 1021 .build(); 1022 1023 flagInfoDefault.put(flag1.getFullFlagName(), flag1); 1024 1025 // server override 1026 1027 settingsState.getFlagOverrideToSync( 1028 "test_namespace/com.android.flags.flag1", "true", flagInfoDefault); 1029 assertEquals("com.android.flags", flag1.getPackageName()); 1030 assertEquals("flag1", flag1.getFlagName()); 1031 assertEquals("true", flag1.getBootFlagValue()); 1032 assertEquals("true", flag1.getServerFlagValue()); 1033 assertEquals("false", flag1.getDefaultFlagValue()); 1034 assertTrue(flag1.getHasServerOverride()); 1035 assertNull(flag1.getLocalFlagValue()); 1036 1037 // local override 1038 settingsState.getFlagOverrideToSync( 1039 "device_config_overrides/test_namespace:com.android.flags.flag1", 1040 "false", 1041 flagInfoDefault); 1042 assertEquals("false", flag1.getBootFlagValue()); 1043 assertEquals("false", flag1.getLocalFlagValue()); 1044 assertTrue(flag1.getHasLocalOverride()); 1045 } 1046 1047 @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 1048 1049 @Test 1050 @EnableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON) testHandleBulkSyncWithAconfigdEnabled()1051 public void testHandleBulkSyncWithAconfigdEnabled() { 1052 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 1053 Object lock = new Object(); 1054 SettingsState settingsState = 1055 new SettingsState( 1056 InstrumentationRegistry.getContext(), 1057 lock, 1058 mSettingsFile, 1059 configKey, 1060 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, 1061 Looper.getMainLooper()); 1062 1063 Map<String, AconfigdFlagInfo> flags = new HashMap<>(); 1064 flags.put( 1065 "com.android.flags/flag1", 1066 AconfigdFlagInfo.newBuilder() 1067 .setPackageName("com.android.flags") 1068 .setFlagName("flag1") 1069 .setBootFlagValue("true") 1070 .setIsReadWrite(true) 1071 .build()); 1072 1073 flags.put( 1074 "com.android.flags/flag2", 1075 AconfigdFlagInfo.newBuilder() 1076 .setPackageName("com.android.flags") 1077 .setFlagName("flag2") 1078 .setBootFlagValue("true") 1079 .setIsReadWrite(false) 1080 .build()); 1081 1082 synchronized (lock) { 1083 settingsState.insertSettingLocked( 1084 "aconfigd_marker/bulk_synced", "false", null, false, "aconfig"); 1085 1086 // first bulk sync 1087 ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); 1088 assertTrue(requests != null); 1089 String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); 1090 assertEquals("true", value); 1091 1092 // send time should no longer bulk sync 1093 requests = settingsState.handleBulkSyncToNewStorage(flags); 1094 assertTrue(requests == null); 1095 value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); 1096 assertEquals("true", value); 1097 } 1098 } 1099 1100 @Test 1101 @DisableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON) testHandleBulkSyncWithAconfigdDisabled()1102 public void testHandleBulkSyncWithAconfigdDisabled() { 1103 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 1104 Object lock = new Object(); 1105 SettingsState settingsState = new SettingsState( 1106 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 1107 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 1108 1109 Map<String, AconfigdFlagInfo> flags = new HashMap<>(); 1110 synchronized (lock) { 1111 settingsState.insertSettingLocked("aconfigd_marker/bulk_synced", 1112 "true", null, false, "aconfig"); 1113 1114 // when aconfigd is off, should change the marker to false 1115 ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); 1116 assertTrue(requests == null); 1117 String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); 1118 assertEquals("false", value); 1119 1120 // marker started with false value, after call, it should remain false 1121 requests = settingsState.handleBulkSyncToNewStorage(flags); 1122 assertTrue(requests == null); 1123 value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); 1124 assertEquals("false", value); 1125 } 1126 } 1127 1128 @Test testGetAllAconfigFlagsFromSettings()1129 public void testGetAllAconfigFlagsFromSettings() throws Exception { 1130 final Object lock = new Object(); 1131 final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); 1132 os.print( 1133 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" 1134 + "<settings version=\"120\">" 1135 + " <setting id=\"0\" name=\"test_namespace/com.android.flags.flag1\" " 1136 + "value=\"false\" package=\"com.android.flags\" />" 1137 + " <setting id=\"1\" name=\"device_config_overrides/test_namespace:com.android.flags.flag1\" " 1138 + "value=\"true\" package=\"com.android.flags\" />" 1139 + " <setting id=\"2\" name=\"device_config_overrides/test_namespace:com.android.flags.flag2\" " 1140 + "value=\"true\" package=\"com.android.flags\" />" 1141 + " <setting id=\"3\" name=\"test_namespace/com.android.flags.flag3\" " 1142 + "value=\"true\" package=\"com.android.flags\" />" 1143 + " <setting id=\"3\" name=\"device_config_overrides/test_namespace:com.android.flags.flag3\" " 1144 + "value=\"true\" package=\"com.android.flags\" />" 1145 + "</settings>"); 1146 os.close(); 1147 1148 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 1149 1150 SettingsState settingsState = new SettingsState( 1151 InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, 1152 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 1153 1154 int ret; 1155 Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); 1156 synchronized (lock) { 1157 ret = settingsState.getAllAconfigFlagsFromSettings(flagInfoDefault); 1158 } 1159 assertEquals(0, ret); 1160 1161 AconfigdFlagInfo flag1 = 1162 AconfigdFlagInfo.newBuilder() 1163 .setPackageName("com.android.flags") 1164 .setFlagName("flag1") 1165 .setDefaultFlagValue("false") 1166 .setIsReadWrite(true) 1167 .build(); 1168 flagInfoDefault.put(flag1.getFullFlagName(), flag1); 1169 1170 synchronized (lock) { 1171 ret = settingsState.getAllAconfigFlagsFromSettings(flagInfoDefault); 1172 } 1173 assertEquals(2, ret); 1174 assertEquals("com.android.flags", flag1.getPackageName()); 1175 assertEquals("flag1", flag1.getFlagName()); 1176 assertEquals("true", flag1.getBootFlagValue()); 1177 assertEquals("true", flag1.getLocalFlagValue()); 1178 assertEquals("false", flag1.getServerFlagValue()); 1179 assertEquals("false", flag1.getDefaultFlagValue()); 1180 assertTrue(flag1.getHasServerOverride()); 1181 assertTrue(flag1.getHasLocalOverride()); 1182 1183 AconfigdFlagInfo flag2 = 1184 AconfigdFlagInfo.newBuilder() 1185 .setPackageName("com.android.flags") 1186 .setFlagName("flag2") 1187 .setDefaultFlagValue("false") 1188 .setIsReadWrite(true) 1189 .build(); 1190 flagInfoDefault.put(flag2.getFullFlagName(), flag2); 1191 synchronized (lock) { 1192 ret = settingsState.getAllAconfigFlagsFromSettings(flagInfoDefault); 1193 } 1194 assertEquals(3, ret); 1195 assertEquals("com.android.flags", flag2.getPackageName()); 1196 assertEquals("flag2", flag2.getFlagName()); 1197 assertEquals("true", flag2.getBootFlagValue()); 1198 assertEquals("true", flag2.getLocalFlagValue()); 1199 assertEquals("false", flag2.getDefaultFlagValue()); 1200 assertNull(flag2.getServerFlagValue()); 1201 assertFalse(flag2.getHasServerOverride()); 1202 assertTrue(flag2.getHasLocalOverride()); 1203 1204 AconfigdFlagInfo flag3 = 1205 AconfigdFlagInfo.newBuilder() 1206 .setPackageName("com.android.flags") 1207 .setFlagName("flag3") 1208 .setDefaultFlagValue("false") 1209 .setIsReadWrite(false) 1210 .build(); 1211 flagInfoDefault.put(flag3.getFullFlagName(), flag3); 1212 synchronized (lock) { 1213 ret = settingsState.getAllAconfigFlagsFromSettings(flagInfoDefault); 1214 } 1215 assertEquals(3, ret); 1216 assertEquals("com.android.flags", flag3.getPackageName()); 1217 assertEquals("flag3", flag3.getFlagName()); 1218 assertEquals("false", flag3.getBootFlagValue()); 1219 assertEquals("false", flag3.getDefaultFlagValue()); 1220 assertNull(flag3.getLocalFlagValue()); 1221 assertNull(flag3.getServerFlagValue()); 1222 assertFalse(flag3.getHasServerOverride()); 1223 assertFalse(flag3.getHasLocalOverride()); 1224 } 1225 1226 @Test testCompareFlagValueInNewStorage()1227 public void testCompareFlagValueInNewStorage() { 1228 int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); 1229 Object lock = new Object(); 1230 SettingsState settingsState = 1231 new SettingsState( 1232 InstrumentationRegistry.getContext(), 1233 lock, 1234 mSettingsFile, 1235 configKey, 1236 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, 1237 Looper.getMainLooper()); 1238 1239 AconfigdFlagInfo defaultFlag1 = 1240 AconfigdFlagInfo.newBuilder() 1241 .setPackageName("com.android.flags") 1242 .setFlagName("flag1") 1243 .setDefaultFlagValue("false") 1244 .setServerFlagValue("true") 1245 .setHasServerOverride(true) 1246 .setIsReadWrite(true) 1247 .build(); 1248 1249 AconfigdFlagInfo expectedFlag1 = 1250 AconfigdFlagInfo.newBuilder() 1251 .setPackageName("com.android.flags") 1252 .setFlagName("flag1") 1253 .setServerFlagValue("true") 1254 .setDefaultFlagValue("false") 1255 .setHasServerOverride(true) 1256 .setIsReadWrite(true) 1257 .build(); 1258 1259 Map<String, AconfigdFlagInfo> aconfigdMap = new HashMap<>(); 1260 Map<String, AconfigdFlagInfo> defaultMap = new HashMap<>(); 1261 1262 defaultMap.put("com.android.flags.flag1", defaultFlag1); 1263 aconfigdMap.put("com.android.flags.flag1", expectedFlag1); 1264 1265 int ret = settingsState.compareFlagValueInNewStorage(defaultMap, aconfigdMap); 1266 assertEquals(0, ret); 1267 1268 String value = 1269 settingsState.getSettingLocked("aconfigd_marker/compare_diff_num").getValue(); 1270 assertEquals("0", value); 1271 1272 AconfigdFlagInfo defaultFlag2 = 1273 AconfigdFlagInfo.newBuilder() 1274 .setPackageName("com.android.flags") 1275 .setFlagName("flag2") 1276 .setDefaultFlagValue("false") 1277 .build(); 1278 defaultMap.put("com.android.flags.flag2", defaultFlag2); 1279 1280 ret = settingsState.compareFlagValueInNewStorage(defaultMap, aconfigdMap); 1281 // missing from new storage 1282 assertEquals(1, ret); 1283 value = 1284 settingsState.getSettingLocked("aconfigd_marker/compare_diff_num").getValue(); 1285 assertEquals("1", value); 1286 1287 AconfigdFlagInfo expectedFlag2 = 1288 AconfigdFlagInfo.newBuilder() 1289 .setPackageName("com.android.flags") 1290 .setFlagName("flag2") 1291 .setServerFlagValue("true") 1292 .setLocalFlagValue("true") 1293 .setDefaultFlagValue("false") 1294 .setHasServerOverride(true) 1295 .setHasLocalOverride(true) 1296 .build(); 1297 aconfigdMap.put("com.android.flags.flag2", expectedFlag2); 1298 ret = settingsState.compareFlagValueInNewStorage(defaultMap, aconfigdMap); 1299 // skip the server and local value comparison when the flag is read_only 1300 assertEquals(0, ret); 1301 value = 1302 settingsState.getSettingLocked("aconfigd_marker/compare_diff_num").getValue(); 1303 assertEquals("0", value); 1304 } 1305 } 1306