• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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