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 17package com.android.providers.settings; 18 19import android.content.ContentResolver; 20import android.content.ContentValues; 21import android.database.ContentObserver; 22import android.database.Cursor; 23import android.net.Uri; 24import android.os.Handler; 25import android.os.Looper; 26import android.os.SystemClock; 27import android.os.UserHandle; 28import android.provider.Settings; 29import android.util.Log; 30 31import java.util.concurrent.atomic.AtomicBoolean; 32 33/** 34 * Tests for the SettingContentProvider. 35 * 36 * Before you run this test you must add a secondary user. 37 */ 38public class SettingsProviderTest extends BaseSettingsProviderTest { 39 private static final String LOG_TAG = "SettingsProviderTest"; 40 41 private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec 42 43 private static final String[] NAME_VALUE_COLUMNS = new String[]{ 44 Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE 45 }; 46 47 private final Object mLock = new Object(); 48 49 public void testSetAndGetGlobalViaFrontEndApiForOwnerUser() throws Exception { 50 performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_OWNER); 51 } 52 53 public void testSetAndGetGlobalViaFrontEndApiForNonOwnerUser() throws Exception { 54 if (mSecondaryUserId == UserHandle.USER_OWNER) { 55 Log.w(LOG_TAG, "No secondary user. Skipping " 56 + "testSetAndGetGlobalViaFrontEndApiForNonOwnerUser"); 57 return; 58 } 59 performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId); 60 } 61 62 public void testSetAndGetSecureViaFrontEndApiForOwnerUser() throws Exception { 63 performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_OWNER); 64 } 65 66 public void testSetAndGetSecureViaFrontEndApiForNonOwnerUser() throws Exception { 67 if (mSecondaryUserId == UserHandle.USER_OWNER) { 68 Log.w(LOG_TAG, "No secondary user. Skipping " 69 + "testSetAndGetSecureViaFrontEndApiForNonOwnerUser"); 70 return; 71 } 72 performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId); 73 } 74 75 public void testSetAndGetSystemViaFrontEndApiForOwnerUser() throws Exception { 76 performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_OWNER); 77 } 78 79 public void testSetAndGetSystemViaFrontEndApiForNonOwnerUser() throws Exception { 80 if (mSecondaryUserId == UserHandle.USER_OWNER) { 81 Log.w(LOG_TAG, "No secondary user. Skipping " 82 + "testSetAndGetSystemViaFrontEndApiForNonOwnerUser"); 83 return; 84 } 85 performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId); 86 } 87 88 public void testSetAndGetGlobalViaProviderApi() throws Exception { 89 performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL); 90 } 91 92 public void testSetAndGetSecureViaProviderApi() throws Exception { 93 performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE); 94 } 95 96 public void testSetAndGetSystemViaProviderApi() throws Exception { 97 performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM); 98 } 99 100 public void testSelectAllGlobalViaProviderApi() throws Exception { 101 setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL, 102 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false); 103 try { 104 queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL, 105 FAKE_SETTING_NAME); 106 } finally { 107 deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME); 108 } 109 } 110 111 public void testSelectAllSecureViaProviderApi() throws Exception { 112 setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE, 113 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false); 114 try { 115 queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE, 116 FAKE_SETTING_NAME); 117 } finally { 118 deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME); 119 } 120 } 121 122 public void testSelectAllSystemViaProviderApi() throws Exception { 123 setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM, 124 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true); 125 try { 126 queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM, 127 FAKE_SETTING_NAME); 128 } finally { 129 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME); 130 } 131 } 132 133 public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception { 134 doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL); 135 } 136 137 public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception { 138 doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE); 139 } 140 141 public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception { 142 doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM); 143 } 144 145 public void testBulkInsertGlobalViaProviderApi() throws Exception { 146 toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL); 147 } 148 149 public void testBulkInsertSystemViaProviderApi() throws Exception { 150 toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM); 151 } 152 153 public void testBulkInsertSecureViaProviderApi() throws Exception { 154 toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE); 155 } 156 157 public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception { 158 int insertedCount = 0; 159 try { 160 for (; insertedCount < 1200; insertedCount++) { 161 Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount); 162 insertStringViaProviderApi(SETTING_TYPE_SYSTEM, 163 String.valueOf(insertedCount), FAKE_SETTING_VALUE, false); 164 } 165 fail("Adding app specific settings must be bound."); 166 } catch (Exception e) { 167 for (; insertedCount >= 0; insertedCount--) { 168 Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount); 169 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, 170 String.valueOf(insertedCount)); 171 } 172 } 173 } 174 175 public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception { 176 doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL); 177 } 178 179 public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception { 180 doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE); 181 } 182 183 public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception { 184 doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM); 185 } 186 187 public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception { 188 // Make sure we have a clean slate. 189 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME); 190 191 try { 192 // Insert the setting. 193 final Uri uri = insertStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME, 194 FAKE_SETTING_VALUE, false); 195 Uri expectUri = Uri.withAppendedPath(getBaseUriForType(SETTING_TYPE_SYSTEM), 196 FAKE_SETTING_NAME); 197 assertEquals("Did not get expected Uri.", expectUri, uri); 198 199 // Make sure the first setting is there. 200 String firstValue = queryStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME, 201 false, true); 202 assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue); 203 } finally { 204 // Clean up. 205 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME); 206 } 207 } 208 209 private void doTestQueryStringInBracketsViaProviderApiForType(int type) { 210 // Make sure we have a clean slate. 211 deleteStringViaProviderApi(type, FAKE_SETTING_NAME); 212 213 try { 214 // Insert the setting. 215 final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME, 216 FAKE_SETTING_VALUE, false); 217 Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME); 218 assertEquals("Did not get expected Uri.", expectUri, uri); 219 220 // Make sure the first setting is there. 221 String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true, false); 222 assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue); 223 } finally { 224 // Clean up. 225 deleteStringViaProviderApi(type, FAKE_SETTING_NAME); 226 } 227 } 228 229 private void toTestBulkInsertViaProviderApiForType(int type) { 230 // Make sure we have a clean slate. 231 deleteStringViaProviderApi(type, FAKE_SETTING_NAME); 232 deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1); 233 deleteStringViaProviderApi(type, FAKE_SETTING_NAME_2); 234 235 try { 236 Uri uri = getBaseUriForType(type); 237 ContentValues[] allValues = new ContentValues[3]; 238 239 // Insert the first setting. 240 ContentValues firstValues = new ContentValues(); 241 firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME); 242 firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE); 243 allValues[0] = firstValues; 244 245 // Insert the second setting. 246 ContentValues secondValues = new ContentValues(); 247 secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1); 248 secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1); 249 allValues[1] = secondValues; 250 251 // Insert the third setting. (null) 252 ContentValues thirdValues = new ContentValues(); 253 thirdValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_2); 254 thirdValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_2); 255 allValues[2] = thirdValues; 256 257 // Verify insertion count. 258 final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues); 259 assertSame("Couldn't insert both values", 3, insertCount); 260 261 // Make sure the first setting is there. 262 String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME); 263 assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue); 264 265 // Make sure the second setting is there. 266 String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1); 267 assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue); 268 269 // Make sure the third setting is there. 270 String thirdValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_2); 271 assertEquals("Third setting must be present", FAKE_SETTING_VALUE_2, thirdValue); 272 } finally { 273 // Clean up. 274 deleteStringViaProviderApi(type, FAKE_SETTING_NAME); 275 deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1); 276 deleteStringViaProviderApi(type, FAKE_SETTING_NAME_2); 277 } 278 } 279 280 private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception { 281 // Make sure it is not there. 282 deleteStringViaProviderApi(type, FAKE_SETTING_NAME); 283 284 // Now selection should return nothing. 285 String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME); 286 assertNull("Setting should not be present.", value); 287 288 // Insert the setting. 289 Uri uri = insertStringViaProviderApi(type, 290 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false); 291 Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME); 292 assertEquals("Did not get expected Uri.", expectUri, uri); 293 294 // Now selection should return the setting. 295 value = queryStringViaProviderApi(type, FAKE_SETTING_NAME); 296 assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value); 297 298 // Update the setting. 299 final int changeCount = updateStringViaProviderApiSetting(type, 300 FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1); 301 assertEquals("Did not get expected change count.", 1, changeCount); 302 303 // Now selection should return the new setting. 304 value = queryStringViaProviderApi(type, FAKE_SETTING_NAME); 305 assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value); 306 307 // Delete the setting. 308 final int deletedCount = deleteStringViaProviderApi(type, 309 FAKE_SETTING_NAME); 310 assertEquals("Did not get expected deleted count", 1, deletedCount); 311 312 // Now selection should return nothing. 313 value = queryStringViaProviderApi(type, FAKE_SETTING_NAME); 314 assertNull("Setting should not be present.", value); 315 } 316 317 private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId) 318 throws Exception { 319 try { 320 // Change the setting and assert a successful change. 321 setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, 322 FAKE_SETTING_VALUE, userId); 323 } finally { 324 // Remove the setting. 325 setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId); 326 } 327 } 328 329 private void performSetAndGetSettingTestViaProviderApi(int type) 330 throws Exception { 331 try { 332 // Change the setting and assert a successful change. 333 setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, 334 FAKE_SETTING_VALUE, true); 335 } finally { 336 // Remove the setting. 337 setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null, 338 true); 339 } 340 } 341 342 private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type, 343 final String name, final String value, final int userId) throws Exception { 344 setSettingAndAssertSuccessfulChange(new Runnable() { 345 @Override 346 public void run() { 347 setStringViaFrontEndApiSetting(type, name, value, userId); 348 } 349 }, type, name, value, userId); 350 } 351 352 private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type, 353 final String name, final String value, final boolean withTableRowUri) 354 throws Exception { 355 setSettingAndAssertSuccessfulChange(new Runnable() { 356 @Override 357 public void run() { 358 insertStringViaProviderApi(type, name, value, withTableRowUri); 359 } 360 }, type, name, value, UserHandle.USER_OWNER); 361 } 362 363 private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type, 364 final String name, final String value, final int userId) throws Exception { 365 ContentResolver contentResolver = getContext().getContentResolver(); 366 367 final Uri settingUri = getBaseUriForType(type); 368 369 final AtomicBoolean success = new AtomicBoolean(); 370 371 ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { 372 public void onChange(boolean selfChange, Uri changeUri, int changeId) { 373 Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")"); 374 assertEquals("Wrong change Uri", changeUri, settingUri); 375 assertEquals("Wrong user id", userId, changeId); 376 String changeValue = getStringViaFrontEndApiSetting(type, name, userId); 377 assertEquals("Wrong setting value", value, changeValue); 378 379 success.set(true); 380 381 synchronized (mLock) { 382 mLock.notifyAll(); 383 } 384 } 385 }; 386 387 contentResolver.registerContentObserver(settingUri, false, contentObserver, userId); 388 389 try { 390 setCommand.run(); 391 392 final long startTimeMillis = SystemClock.uptimeMillis(); 393 synchronized (mLock) { 394 if (success.get()) { 395 return; 396 } 397 final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 398 if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) { 399 fail("Could not change setting for " 400 + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms"); 401 } 402 final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS 403 - elapsedTimeMillis; 404 try { 405 mLock.wait(remainingTimeMillis); 406 } catch (InterruptedException ie) { 407 /* ignore */ 408 } 409 } 410 } finally { 411 contentResolver.unregisterContentObserver(contentObserver); 412 } 413 } 414 415 private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type, 416 String name) { 417 Uri uri = getBaseUriForType(type); 418 419 Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS, 420 null, null, null); 421 422 if (cursor == null || !cursor.moveToFirst()) { 423 fail("Nothing selected"); 424 } 425 426 try { 427 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME); 428 429 while (cursor.moveToNext()) { 430 String currentName = cursor.getString(nameColumnIdx); 431 if (name.equals(currentName)) { 432 return; 433 } 434 } 435 436 fail("Not found setting: " + name); 437 } finally { 438 cursor.close(); 439 } 440 } 441} 442