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 android.os.Looper; 19 import android.test.AndroidTestCase; 20 import android.util.TypedXmlSerializer; 21 import android.util.Xml; 22 23 import java.io.ByteArrayOutputStream; 24 import java.io.File; 25 import java.io.FileOutputStream; 26 import java.io.PrintStream; 27 28 public class SettingsStateTest extends AndroidTestCase { 29 public static final String CRAZY_STRING = 30 "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" + 31 "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" + 32 "\u001b\u001c\u001d\u001e\u001f\u0020" + 33 "fake_setting_value_1" + 34 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 35 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 36 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 37 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 38 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 39 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 40 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 41 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 42 "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" + 43 "\ud800\udc00\udbff\udfff" + // surrogate pairs 44 "\uD800ab\uDC00 " + // broken surrogate pairs 45 "日本語"; 46 47 private static final String TEST_PACKAGE = "package"; 48 private static final String SYSTEM_PACKAGE = "android"; 49 private static final String SETTING_NAME = "test_setting"; 50 51 private final Object mLock = new Object(); 52 53 private File mSettingsFile; 54 55 @Override setUp()56 protected void setUp() { 57 mSettingsFile = new File(getContext().getCacheDir(), "setting.xml"); 58 mSettingsFile.delete(); 59 } 60 testIsBinary()61 public void testIsBinary() { 62 assertFalse(SettingsState.isBinary(" abc 日本語")); 63 64 for (char ch = 0x20; ch < 0xd800; ch++) { 65 assertFalse("ch=" + Integer.toString(ch, 16), 66 SettingsState.isBinary(String.valueOf(ch))); 67 } 68 for (char ch = 0xe000; ch < 0xfffe; ch++) { 69 assertFalse("ch=" + Integer.toString(ch, 16), 70 SettingsState.isBinary(String.valueOf(ch))); 71 } 72 73 for (char ch = 0x0000; ch < 0x20; ch++) { 74 assertTrue("ch=" + Integer.toString(ch, 16), 75 SettingsState.isBinary(String.valueOf(ch))); 76 } 77 for (char ch = 0xd800; ch < 0xe000; ch++) { 78 assertTrue("ch=" + Integer.toString(ch, 16), 79 SettingsState.isBinary(String.valueOf(ch))); 80 } 81 assertTrue(SettingsState.isBinary("\ufffe")); 82 assertTrue(SettingsState.isBinary("\uffff")); 83 try { 84 assertFalse(SettingsState.isBinary(null)); 85 fail("NullPointerException expected"); 86 } catch (NullPointerException expected) { 87 } 88 } 89 90 /** Make sure we won't pass invalid characters to XML serializer. */ testWriteReadNoCrash()91 public void testWriteReadNoCrash() throws Exception { 92 ByteArrayOutputStream os = new ByteArrayOutputStream(); 93 94 TypedXmlSerializer serializer = Xml.resolveSerializer(os); 95 serializer.startDocument(null, true); 96 97 for (int ch = 0; ch < 0x10000; ch++) { 98 checkWriteSingleSetting("char=0x" + Integer.toString(ch, 16), serializer, 99 "key", String.valueOf((char) ch)); 100 } 101 checkWriteSingleSetting(serializer, "k", ""); 102 checkWriteSingleSetting(serializer, "x", "abc"); 103 checkWriteSingleSetting(serializer, "abc", CRAZY_STRING); 104 checkWriteSingleSetting(serializer, "def", null); 105 106 // Invlid input, but shouoldn't crash. 107 checkWriteSingleSetting(serializer, null, null); 108 checkWriteSingleSetting(serializer, CRAZY_STRING, null); 109 SettingsState.writeSingleSetting( 110 SettingsState.SETTINGS_VERSION_NEW_ENCODING, 111 serializer, null, "k", "v", null, "package", null, false, false); 112 SettingsState.writeSingleSetting( 113 SettingsState.SETTINGS_VERSION_NEW_ENCODING, 114 serializer, "1", "k", "v", null, null, null, false, false); 115 } 116 checkWriteSingleSetting(TypedXmlSerializer serializer, String key, String value)117 private void checkWriteSingleSetting(TypedXmlSerializer serializer, String key, String value) 118 throws Exception { 119 checkWriteSingleSetting(key + "/" + value, serializer, key, value); 120 } 121 checkWriteSingleSetting(String msg, TypedXmlSerializer serializer, String key, String value)122 private void checkWriteSingleSetting(String msg, TypedXmlSerializer serializer, 123 String key, String value) throws Exception { 124 // Make sure the XML serializer won't crash. 125 SettingsState.writeSingleSetting( 126 SettingsState.SETTINGS_VERSION_NEW_ENCODING, 127 serializer, "1", key, value, null, "package", null, false, false); 128 } 129 130 /** 131 * Make sure settings can be written to a file and also can be read. 132 */ testReadWrite()133 public void testReadWrite() { 134 final File file = new File(getContext().getCacheDir(), "setting.xml"); 135 file.delete(); 136 final Object lock = new Object(); 137 138 final SettingsState ssWriter = new SettingsState(getContext(), lock, file, 1, 139 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 140 ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); 141 142 ssWriter.insertSettingLocked("k1", "\u0000", null, false, "package"); 143 ssWriter.insertSettingLocked("k2", "abc", null, false, "p2"); 144 ssWriter.insertSettingLocked("k3", null, null, false, "p2"); 145 ssWriter.insertSettingLocked("k4", CRAZY_STRING, null, false, "p3"); 146 synchronized (lock) { 147 ssWriter.persistSyncLocked(); 148 } 149 150 final SettingsState ssReader = new SettingsState(getContext(), lock, file, 1, 151 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 152 synchronized (lock) { 153 assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue()); 154 assertEquals("abc", ssReader.getSettingLocked("k2").getValue()); 155 assertEquals(null, ssReader.getSettingLocked("k3").getValue()); 156 assertEquals(CRAZY_STRING, ssReader.getSettingLocked("k4").getValue()); 157 } 158 } 159 160 /** 161 * In version 120, value "null" meant {code NULL}. 162 */ testUpgrade()163 public void testUpgrade() throws Exception { 164 final File file = new File(getContext().getCacheDir(), "setting.xml"); 165 file.delete(); 166 final Object lock = new Object(); 167 final PrintStream os = new PrintStream(new FileOutputStream(file)); 168 os.print( 169 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + 170 "<settings version=\"120\">" + 171 " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" + 172 " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" + 173 " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" + 174 "</settings>"); 175 os.close(); 176 177 final SettingsState ss = new SettingsState(getContext(), lock, file, 1, 178 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 179 synchronized (lock) { 180 SettingsState.Setting s; 181 s = ss.getSettingLocked("k0"); 182 assertEquals(null, s.getValue()); 183 assertEquals("null", s.getPackageName()); 184 185 s = ss.getSettingLocked("k1"); 186 assertEquals("", s.getValue()); 187 assertEquals("", s.getPackageName()); 188 189 s = ss.getSettingLocked("k2"); 190 assertEquals("v2", s.getValue()); 191 assertEquals("p2", s.getPackageName()); 192 } 193 } 194 testInitializeSetting_preserveFlagNotSet()195 public void testInitializeSetting_preserveFlagNotSet() { 196 SettingsState settingsWriter = getSettingStateObject(); 197 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 198 settingsWriter.persistSyncLocked(); 199 200 SettingsState settingsReader = getSettingStateObject(); 201 assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 202 } 203 testModifySetting_preserveFlagSet()204 public void testModifySetting_preserveFlagSet() { 205 SettingsState settingsWriter = getSettingStateObject(); 206 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 207 settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE); 208 settingsWriter.persistSyncLocked(); 209 210 SettingsState settingsReader = getSettingStateObject(); 211 assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 212 } 213 testModifySettingOverrideableByRestore_preserveFlagNotSet()214 public void testModifySettingOverrideableByRestore_preserveFlagNotSet() { 215 SettingsState settingsWriter = getSettingStateObject(); 216 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 217 settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, false, TEST_PACKAGE, 218 /* overrideableByRestore */ true); 219 settingsWriter.persistSyncLocked(); 220 221 SettingsState settingsReader = getSettingStateObject(); 222 assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 223 } 224 testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged()225 public void testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged() { 226 SettingsState settingsWriter = getSettingStateObject(); 227 // Init the setting. 228 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 229 // This modification will set isValuePreservedInRestore = true. 230 settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 231 // This modification shouldn't change the value of isValuePreservedInRestore since it's 232 // already been set to true. 233 settingsWriter.insertSettingLocked(SETTING_NAME, "2", null, false, false, TEST_PACKAGE, 234 /* overrideableByRestore */ true); 235 settingsWriter.persistSyncLocked(); 236 237 SettingsState settingsReader = getSettingStateObject(); 238 assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 239 } 240 testResetSetting_preservedFlagIsReset()241 public void testResetSetting_preservedFlagIsReset() { 242 SettingsState settingsState = getSettingStateObject(); 243 // Initialize the setting. 244 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); 245 // Update the setting so that preserved flag is set. 246 settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE); 247 248 settingsState.resetSettingLocked(SETTING_NAME); 249 assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 250 251 } 252 testModifySettingBySystemPackage_sameValue_preserveFlagNotSet()253 public void testModifySettingBySystemPackage_sameValue_preserveFlagNotSet() { 254 SettingsState settingsState = getSettingStateObject(); 255 // Initialize the setting. 256 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, SYSTEM_PACKAGE); 257 // Update the setting. 258 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, SYSTEM_PACKAGE); 259 260 assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 261 } 262 testModifySettingBySystemPackage_newValue_preserveFlagSet()263 public void testModifySettingBySystemPackage_newValue_preserveFlagSet() { 264 SettingsState settingsState = getSettingStateObject(); 265 // Initialize the setting. 266 settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, SYSTEM_PACKAGE); 267 // Update the setting. 268 settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, SYSTEM_PACKAGE); 269 270 assertTrue(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); 271 } 272 getSettingStateObject()273 private SettingsState getSettingStateObject() { 274 SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, 275 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); 276 settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); 277 return settingsState; 278 } 279 } 280