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