SettingsProvider.java revision f41334bb155383c1a3fb7e5cf540160aa9ab883a
1/* 2 * Copyright (C) 2007 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.Manifest; 20import android.app.ActivityManager; 21import android.app.AppOpsManager; 22import android.app.backup.BackupManager; 23import android.content.BroadcastReceiver; 24import android.content.ContentProvider; 25import android.content.ContentValues; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.pm.ApplicationInfo; 30import android.content.pm.PackageInfo; 31import android.content.pm.PackageManager; 32import android.content.pm.UserInfo; 33import android.database.Cursor; 34import android.database.MatrixCursor; 35import android.database.sqlite.SQLiteDatabase; 36import android.database.sqlite.SQLiteQueryBuilder; 37import android.hardware.camera2.utils.ArrayUtils; 38import android.media.AudioManager; 39import android.net.Uri; 40import android.os.Binder; 41import android.os.Build; 42import android.os.Bundle; 43import android.os.DropBoxManager; 44import android.os.Environment; 45import android.os.ParcelFileDescriptor; 46import android.os.Process; 47import android.os.SystemProperties; 48import android.os.UserHandle; 49import android.os.UserManager; 50import android.provider.Settings; 51import android.text.TextUtils; 52import android.util.ArrayMap; 53import android.util.ArraySet; 54import android.util.Slog; 55import android.util.SparseArray; 56 57import com.android.internal.annotations.GuardedBy; 58import com.android.internal.content.PackageMonitor; 59import com.android.internal.os.BackgroundThread; 60 61import java.io.File; 62import java.io.FileDescriptor; 63import java.io.FileNotFoundException; 64import java.io.PrintWriter; 65import java.security.SecureRandom; 66import java.util.Arrays; 67import java.util.List; 68import java.util.Map; 69import java.util.Set; 70import java.util.regex.Pattern; 71 72import com.android.providers.settings.SettingsState.Setting; 73 74/** 75 * <p> 76 * This class is a content provider that publishes the system settings. 77 * It can be accessed via the content provider APIs or via custom call 78 * commands. The latter is a bit faster and is the preferred way to access 79 * the platform settings. 80 * </p> 81 * <p> 82 * There are three settings types, global (with signature level protection 83 * and shared across users), secure (with signature permission level 84 * protection and per user), and system (with dangerous permission level 85 * protection and per user). Global settings are stored under the device owner. 86 * Each of these settings is represented by a {@link 87 * com.android.providers.settings.SettingsState} object mapped to an integer 88 * key derived from the setting type in the most significant bits and user 89 * id in the least significant bits. Settings are synchronously loaded on 90 * instantiation of a SettingsState and asynchronously persisted on mutation. 91 * Settings are stored in the user specific system directory. 92 * </p> 93 * <p> 94 * Apps targeting APIs Lollipop MR1 and lower can add custom settings entries 95 * and get a warning. Targeting higher API version prohibits this as the 96 * system settings are not a place for apps to save their state. When a package 97 * is removed the settings it added are deleted. Apps cannot delete system 98 * settings added by the platform. System settings values are validated to 99 * ensure the clients do not put bad values. Global and secure settings are 100 * changed only by trusted parties, therefore no validation is performed. Also 101 * there is a limit on the amount of app specific settings that can be added 102 * to prevent unlimited growth of the system process memory footprint. 103 * </p> 104 */ 105@SuppressWarnings("deprecation") 106public class SettingsProvider extends ContentProvider { 107 private static final boolean DEBUG = false; 108 109 private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE; 110 111 private static final String LOG_TAG = "SettingsProvider"; 112 113 private static final String TABLE_SYSTEM = "system"; 114 private static final String TABLE_SECURE = "secure"; 115 private static final String TABLE_GLOBAL = "global"; 116 117 // Old tables no longer exist. 118 private static final String TABLE_FAVORITES = "favorites"; 119 private static final String TABLE_OLD_FAVORITES = "old_favorites"; 120 private static final String TABLE_BLUETOOTH_DEVICES = "bluetooth_devices"; 121 private static final String TABLE_BOOKMARKS = "bookmarks"; 122 private static final String TABLE_ANDROID_METADATA = "android_metadata"; 123 124 // The set of removed legacy tables. 125 private static final Set<String> REMOVED_LEGACY_TABLES = new ArraySet<>(); 126 static { 127 REMOVED_LEGACY_TABLES.add(TABLE_FAVORITES); 128 REMOVED_LEGACY_TABLES.add(TABLE_OLD_FAVORITES); 129 REMOVED_LEGACY_TABLES.add(TABLE_BLUETOOTH_DEVICES); 130 REMOVED_LEGACY_TABLES.add(TABLE_BOOKMARKS); 131 REMOVED_LEGACY_TABLES.add(TABLE_ANDROID_METADATA); 132 } 133 134 private static final int MUTATION_OPERATION_INSERT = 1; 135 private static final int MUTATION_OPERATION_DELETE = 2; 136 private static final int MUTATION_OPERATION_UPDATE = 3; 137 138 private static final String[] ALL_COLUMNS = new String[] { 139 Settings.NameValueTable._ID, 140 Settings.NameValueTable.NAME, 141 Settings.NameValueTable.VALUE 142 }; 143 144 private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null); 145 146 // Per user settings that cannot be modified if associated user restrictions are enabled. 147 private static final Map<String, String> sSettingToUserRestrictionMap = new ArrayMap<>(); 148 static { 149 sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_MODE, 150 UserManager.DISALLOW_SHARE_LOCATION); 151 sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED, 152 UserManager.DISALLOW_SHARE_LOCATION); 153 sSettingToUserRestrictionMap.put(Settings.Secure.INSTALL_NON_MARKET_APPS, 154 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); 155 sSettingToUserRestrictionMap.put(Settings.Global.ADB_ENABLED, 156 UserManager.DISALLOW_DEBUGGING_FEATURES); 157 sSettingToUserRestrictionMap.put(Settings.Global.PACKAGE_VERIFIER_ENABLE, 158 UserManager.ENSURE_VERIFY_APPS); 159 sSettingToUserRestrictionMap.put(Settings.Global.PREFERRED_NETWORK_MODE, 160 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); 161 } 162 163 // Per user secure settings that moved to the for all users global settings. 164 static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>(); 165 static { 166 Settings.Secure.getMovedToGlobalSettings(sSecureMovedToGlobalSettings); 167 } 168 169 // Per user system settings that moved to the for all users global settings. 170 static final Set<String> sSystemMovedToGlobalSettings = new ArraySet<>(); 171 static { 172 Settings.System.getMovedToGlobalSettings(sSystemMovedToGlobalSettings); 173 } 174 175 // Per user system settings that moved to the per user secure settings. 176 static final Set<String> sSystemMovedToSecureSettings = new ArraySet<>(); 177 static { 178 Settings.System.getMovedToSecureSettings(sSystemMovedToSecureSettings); 179 } 180 181 // Per all users global settings that moved to the per user secure settings. 182 static final Set<String> sGlobalMovedToSecureSettings = new ArraySet<>(); 183 static { 184 Settings.Global.getMovedToSecureSettings(sGlobalMovedToSecureSettings); 185 } 186 187 // Per user secure settings that are cloned for the managed profiles of the user. 188 private static final Set<String> sSecureCloneToManagedSettings = new ArraySet<>(); 189 static { 190 Settings.Secure.getCloneToManagedProfileSettings(sSecureCloneToManagedSettings); 191 } 192 193 // Per user system settings that are cloned for the managed profiles of the user. 194 private static final Set<String> sSystemCloneToManagedSettings = new ArraySet<>(); 195 static { 196 Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings); 197 } 198 199 private final Object mLock = new Object(); 200 201 @GuardedBy("mLock") 202 private SettingsRegistry mSettingsRegistry; 203 204 // We have to call in the user manager with no lock held, 205 private volatile UserManager mUserManager; 206 207 // We have to call in the app ops manager with no lock held, 208 private volatile AppOpsManager mAppOpsManager; 209 210 // We have to call in the package manager with no lock held, 211 private volatile PackageManager mPackageManager; 212 213 @Override 214 public boolean onCreate() { 215 synchronized (mLock) { 216 mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); 217 mAppOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 218 mPackageManager = getContext().getPackageManager(); 219 mSettingsRegistry = new SettingsRegistry(); 220 } 221 registerBroadcastReceivers(); 222 return true; 223 } 224 225 @Override 226 public Bundle call(String method, String name, Bundle args) { 227 final int requestingUserId = getRequestingUserId(args); 228 switch (method) { 229 case Settings.CALL_METHOD_GET_GLOBAL: { 230 Setting setting = getGlobalSetting(name); 231 return packageValueForCallResult(setting); 232 } 233 234 case Settings.CALL_METHOD_GET_SECURE: { 235 Setting setting = getSecureSetting(name, requestingUserId); 236 return packageValueForCallResult(setting); 237 } 238 239 case Settings.CALL_METHOD_GET_SYSTEM: { 240 Setting setting = getSystemSetting(name, requestingUserId); 241 return packageValueForCallResult(setting); 242 } 243 244 case Settings.CALL_METHOD_PUT_GLOBAL: { 245 String value = getSettingValue(args); 246 insertGlobalSetting(name, value, requestingUserId); 247 break; 248 } 249 250 case Settings.CALL_METHOD_PUT_SECURE: { 251 String value = getSettingValue(args); 252 insertSecureSetting(name, value, requestingUserId); 253 break; 254 } 255 256 case Settings.CALL_METHOD_PUT_SYSTEM: { 257 String value = getSettingValue(args); 258 insertSystemSetting(name, value, requestingUserId); 259 break; 260 } 261 262 default: { 263 Slog.w(LOG_TAG, "call() with invalid method: " + method); 264 } break; 265 } 266 267 return null; 268 } 269 270 @Override 271 public String getType(Uri uri) { 272 Arguments args = new Arguments(uri, null, null, true); 273 if (TextUtils.isEmpty(args.name)) { 274 return "vnd.android.cursor.dir/" + args.table; 275 } else { 276 return "vnd.android.cursor.item/" + args.table; 277 } 278 } 279 280 @Override 281 public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs, 282 String order) { 283 if (DEBUG) { 284 Slog.v(LOG_TAG, "query() for user: " + UserHandle.getCallingUserId()); 285 } 286 287 Arguments args = new Arguments(uri, where, whereArgs, true); 288 String[] normalizedProjection = normalizeProjection(projection); 289 290 // If a legacy table that is gone, done. 291 if (REMOVED_LEGACY_TABLES.contains(args.table)) { 292 return new MatrixCursor(normalizedProjection, 0); 293 } 294 295 switch (args.table) { 296 case TABLE_GLOBAL: { 297 if (args.name != null) { 298 Setting setting = getGlobalSetting(args.name); 299 return packageSettingForQuery(setting, normalizedProjection); 300 } else { 301 return getAllGlobalSettings(projection); 302 } 303 } 304 305 case TABLE_SECURE: { 306 final int userId = UserHandle.getCallingUserId(); 307 if (args.name != null) { 308 Setting setting = getSecureSetting(args.name, userId); 309 return packageSettingForQuery(setting, normalizedProjection); 310 } else { 311 return getAllSecureSettings(userId, projection); 312 } 313 } 314 315 case TABLE_SYSTEM: { 316 final int userId = UserHandle.getCallingUserId(); 317 if (args.name != null) { 318 Setting setting = getSystemSetting(args.name, userId); 319 return packageSettingForQuery(setting, normalizedProjection); 320 } else { 321 return getAllSystemSettings(userId, projection); 322 } 323 } 324 325 default: { 326 throw new IllegalArgumentException("Invalid Uri path:" + uri); 327 } 328 } 329 } 330 331 @Override 332 public Uri insert(Uri uri, ContentValues values) { 333 if (DEBUG) { 334 Slog.v(LOG_TAG, "insert() for user: " + UserHandle.getCallingUserId()); 335 } 336 337 String table = getValidTableOrThrow(uri); 338 339 // If a legacy table that is gone, done. 340 if (REMOVED_LEGACY_TABLES.contains(table)) { 341 return null; 342 } 343 344 String name = values.getAsString(Settings.Secure.NAME); 345 if (!isKeyValid(name)) { 346 return null; 347 } 348 349 String value = values.getAsString(Settings.Secure.VALUE); 350 351 switch (table) { 352 case TABLE_GLOBAL: { 353 if (insertGlobalSetting(name, value, UserHandle.getCallingUserId())) { 354 return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name); 355 } 356 } break; 357 358 case TABLE_SECURE: { 359 if (insertSecureSetting(name, value, UserHandle.getCallingUserId())) { 360 return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); 361 } 362 } break; 363 364 case TABLE_SYSTEM: { 365 if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) { 366 return Uri.withAppendedPath(Settings.System.CONTENT_URI, name); 367 } 368 } break; 369 370 default: { 371 throw new IllegalArgumentException("Bad Uri path:" + uri); 372 } 373 } 374 375 return null; 376 } 377 378 @Override 379 public int bulkInsert(Uri uri, ContentValues[] allValues) { 380 if (DEBUG) { 381 Slog.v(LOG_TAG, "bulkInsert() for user: " + UserHandle.getCallingUserId()); 382 } 383 384 int insertionCount = 0; 385 final int valuesCount = allValues.length; 386 for (int i = 0; i < valuesCount; i++) { 387 ContentValues values = allValues[i]; 388 if (insert(uri, values) != null) { 389 insertionCount++; 390 } 391 } 392 393 return insertionCount; 394 } 395 396 @Override 397 public int delete(Uri uri, String where, String[] whereArgs) { 398 if (DEBUG) { 399 Slog.v(LOG_TAG, "delete() for user: " + UserHandle.getCallingUserId()); 400 } 401 402 Arguments args = new Arguments(uri, where, whereArgs, false); 403 404 // If a legacy table that is gone, done. 405 if (REMOVED_LEGACY_TABLES.contains(args.table)) { 406 return 0; 407 } 408 409 if (!isKeyValid(args.name)) { 410 return 0; 411 } 412 413 switch (args.table) { 414 case TABLE_GLOBAL: { 415 final int userId = UserHandle.getCallingUserId(); 416 return deleteGlobalSetting(args.name, userId) ? 1 : 0; 417 } 418 419 case TABLE_SECURE: { 420 final int userId = UserHandle.getCallingUserId(); 421 return deleteSecureSetting(args.name, userId) ? 1 : 0; 422 } 423 424 case TABLE_SYSTEM: { 425 final int userId = UserHandle.getCallingUserId(); 426 return deleteSystemSetting(args.name, userId) ? 1 : 0; 427 } 428 429 default: { 430 throw new IllegalArgumentException("Bad Uri path:" + uri); 431 } 432 } 433 } 434 435 @Override 436 public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { 437 if (DEBUG) { 438 Slog.v(LOG_TAG, "update() for user: " + UserHandle.getCallingUserId()); 439 } 440 441 Arguments args = new Arguments(uri, where, whereArgs, false); 442 443 // If a legacy table that is gone, done. 444 if (REMOVED_LEGACY_TABLES.contains(args.table)) { 445 return 0; 446 } 447 448 String name = values.getAsString(Settings.Secure.NAME); 449 if (!isKeyValid(name)) { 450 return 0; 451 } 452 String value = values.getAsString(Settings.Secure.VALUE); 453 454 switch (args.table) { 455 case TABLE_GLOBAL: { 456 final int userId = UserHandle.getCallingUserId(); 457 return updateGlobalSetting(args.name, value, userId) ? 1 : 0; 458 } 459 460 case TABLE_SECURE: { 461 final int userId = UserHandle.getCallingUserId(); 462 return updateSecureSetting(args.name, value, userId) ? 1 : 0; 463 } 464 465 case TABLE_SYSTEM: { 466 final int userId = UserHandle.getCallingUserId(); 467 return updateSystemSetting(args.name, value, userId) ? 1 : 0; 468 } 469 470 default: { 471 throw new IllegalArgumentException("Invalid Uri path:" + uri); 472 } 473 } 474 } 475 476 @Override 477 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 478 throw new FileNotFoundException("Direct file access no longer supported; " 479 + "ringtone playback is available through android.media.Ringtone"); 480 } 481 482 @Override 483 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 484 synchronized (mLock) { 485 final long identity = Binder.clearCallingIdentity(); 486 try { 487 List<UserInfo> users = mUserManager.getUsers(true); 488 final int userCount = users.size(); 489 for (int i = 0; i < userCount; i++) { 490 UserInfo user = users.get(i); 491 dumpForUser(user.id, pw); 492 } 493 } finally { 494 Binder.restoreCallingIdentity(identity); 495 } 496 } 497 } 498 499 private void dumpForUser(int userId, PrintWriter pw) { 500 if (userId == UserHandle.USER_OWNER) { 501 pw.println("GLOBAL SETTINGS (user " + userId + ")"); 502 Cursor globalCursor = getAllGlobalSettings(ALL_COLUMNS); 503 dumpSettings(globalCursor, pw); 504 pw.println(); 505 } 506 507 pw.println("SECURE SETTINGS (user " + userId + ")"); 508 Cursor secureCursor = getAllSecureSettings(userId, ALL_COLUMNS); 509 dumpSettings(secureCursor, pw); 510 pw.println(); 511 512 pw.println("SYSTEM SETTINGS (user " + userId + ")"); 513 Cursor systemCursor = getAllSystemSettings(userId, ALL_COLUMNS); 514 dumpSettings(systemCursor, pw); 515 pw.println(); 516 } 517 518 private void dumpSettings(Cursor cursor, PrintWriter pw) { 519 if (cursor == null || !cursor.moveToFirst()) { 520 return; 521 } 522 523 final int idColumnIdx = cursor.getColumnIndex(Settings.NameValueTable._ID); 524 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME); 525 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE); 526 527 do { 528 pw.append("_id:").append(toDumpString(cursor.getString(idColumnIdx))); 529 pw.append(" name:").append(toDumpString(cursor.getString(nameColumnIdx))); 530 pw.append(" value:").append(toDumpString(cursor.getString(valueColumnIdx))); 531 pw.println(); 532 } while (cursor.moveToNext()); 533 } 534 535 private static final String toDumpString(String s) { 536 if (s != null) { 537 return s; 538 } 539 return "{null}"; 540 } 541 542 private void registerBroadcastReceivers() { 543 IntentFilter userFilter = new IntentFilter(); 544 userFilter.addAction(Intent.ACTION_USER_REMOVED); 545 userFilter.addAction(Intent.ACTION_USER_STOPPED); 546 547 getContext().registerReceiver(new BroadcastReceiver() { 548 @Override 549 public void onReceive(Context context, Intent intent) { 550 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 551 UserHandle.USER_OWNER); 552 553 switch (intent.getAction()) { 554 case Intent.ACTION_USER_REMOVED: { 555 mSettingsRegistry.removeUserStateLocked(userId, true); 556 } break; 557 558 case Intent.ACTION_USER_STOPPED: { 559 mSettingsRegistry.removeUserStateLocked(userId, false); 560 } break; 561 } 562 } 563 }, userFilter); 564 565 PackageMonitor monitor = new PackageMonitor() { 566 @Override 567 public void onPackageRemoved(String packageName, int uid) { 568 synchronized (mLock) { 569 mSettingsRegistry.onPackageRemovedLocked(packageName, 570 UserHandle.getUserId(uid)); 571 } 572 } 573 }; 574 575 // package changes 576 monitor.register(getContext(), BackgroundThread.getHandler().getLooper(), 577 UserHandle.ALL, true); 578 } 579 580 private Cursor getAllGlobalSettings(String[] projection) { 581 if (DEBUG) { 582 Slog.v(LOG_TAG, "getAllGlobalSettings()"); 583 } 584 585 synchronized (mLock) { 586 // Get the settings. 587 SettingsState settingsState = mSettingsRegistry.getSettingsLocked( 588 SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER); 589 590 List<String> names = settingsState.getSettingNamesLocked(); 591 592 final int nameCount = names.size(); 593 594 String[] normalizedProjection = normalizeProjection(projection); 595 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); 596 597 // Anyone can get the global settings, so no security checks. 598 for (int i = 0; i < nameCount; i++) { 599 String name = names.get(i); 600 Setting setting = settingsState.getSettingLocked(name); 601 appendSettingToCursor(result, setting); 602 } 603 604 return result; 605 } 606 } 607 608 private Setting getGlobalSetting(String name) { 609 if (DEBUG) { 610 Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")"); 611 } 612 613 // Get the value. 614 synchronized (mLock) { 615 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, 616 UserHandle.USER_OWNER, name); 617 } 618 } 619 620 private boolean updateGlobalSetting(String name, String value, int requestingUserId) { 621 if (DEBUG) { 622 Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ")"); 623 } 624 return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); 625 } 626 627 private boolean insertGlobalSetting(String name, String value, int requestingUserId) { 628 if (DEBUG) { 629 Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ")"); 630 } 631 return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT); 632 } 633 634 private boolean deleteGlobalSetting(String name, int requestingUserId) { 635 if (DEBUG) { 636 Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")"); 637 } 638 return mutateGlobalSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE); 639 } 640 641 private boolean mutateGlobalSetting(String name, String value, int requestingUserId, 642 int operation) { 643 // Make sure the caller can change the settings - treated as secure. 644 enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); 645 646 // Verify whether this operation is allowed for the calling package. 647 if (!isAppOpWriteSettingsAllowedForCallingPackage()) { 648 return false; 649 } 650 651 // Resolve the userId on whose behalf the call is made. 652 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId); 653 654 // If this is a setting that is currently restricted for this user, done. 655 if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) { 656 return false; 657 } 658 659 // Perform the mutation. 660 synchronized (mLock) { 661 switch (operation) { 662 case MUTATION_OPERATION_INSERT: { 663 return mSettingsRegistry 664 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, 665 UserHandle.USER_OWNER, name, value, getCallingPackage()); 666 } 667 668 case MUTATION_OPERATION_DELETE: { 669 return mSettingsRegistry.deleteSettingLocked( 670 SettingsRegistry.SETTINGS_TYPE_GLOBAL, 671 UserHandle.USER_OWNER, name); 672 } 673 674 case MUTATION_OPERATION_UPDATE: { 675 return mSettingsRegistry 676 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, 677 UserHandle.USER_OWNER, name, value, getCallingPackage()); 678 } 679 } 680 } 681 682 return false; 683 } 684 685 private Cursor getAllSecureSettings(int userId, String[] projection) { 686 if (DEBUG) { 687 Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")"); 688 } 689 690 // Resolve the userId on whose behalf the call is made. 691 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId); 692 693 synchronized (mLock) { 694 List<String> names = mSettingsRegistry.getSettingsNamesLocked( 695 SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId); 696 697 final int nameCount = names.size(); 698 699 String[] normalizedProjection = normalizeProjection(projection); 700 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); 701 702 for (int i = 0; i < nameCount; i++) { 703 String name = names.get(i); 704 // Determine the owning user as some profile settings are cloned from the parent. 705 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, 706 name); 707 708 // Special case for location (sigh). 709 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) { 710 return null; 711 } 712 713 Setting setting = mSettingsRegistry.getSettingLocked( 714 SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name); 715 appendSettingToCursor(result, setting); 716 } 717 718 return result; 719 } 720 } 721 722 private Setting getSecureSetting(String name, int requestingUserId) { 723 if (DEBUG) { 724 Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")"); 725 } 726 727 // Resolve the userId on whose behalf the call is made. 728 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId); 729 730 // Determine the owning user as some profile settings are cloned from the parent. 731 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name); 732 733 // Special case for location (sigh). 734 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) { 735 return null; 736 } 737 738 // Get the value. 739 synchronized (mLock) { 740 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, 741 owningUserId, name); 742 } 743 } 744 745 private boolean insertSecureSetting(String name, String value, int requestingUserId) { 746 if (DEBUG) { 747 Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", " 748 + requestingUserId + ")"); 749 } 750 751 return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT); 752 } 753 754 private boolean deleteSecureSetting(String name, int requestingUserId) { 755 if (DEBUG) { 756 Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId + ")"); 757 } 758 759 return mutateSecureSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE); 760 } 761 762 private boolean updateSecureSetting(String name, String value, int requestingUserId) { 763 if (DEBUG) { 764 Slog.v(LOG_TAG, "updateSecureSetting(" + name + ", " + value + ", " 765 + requestingUserId + ")"); 766 } 767 768 return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); 769 } 770 771 private boolean mutateSecureSetting(String name, String value, int requestingUserId, 772 int operation) { 773 // Make sure the caller can change the settings. 774 enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); 775 776 // Verify whether this operation is allowed for the calling package. 777 if (!isAppOpWriteSettingsAllowedForCallingPackage()) { 778 return false; 779 } 780 781 // Resolve the userId on whose behalf the call is made. 782 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId); 783 784 // If this is a setting that is currently restricted for this user, done. 785 if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) { 786 return false; 787 } 788 789 // Determine the owning user as some profile settings are cloned from the parent. 790 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name); 791 792 // Only the owning user can change the setting. 793 if (owningUserId != callingUserId) { 794 return false; 795 } 796 797 // Special cases for location providers (sigh). 798 if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) { 799 return updateLocationProvidersAllowedLocked(value, owningUserId); 800 } 801 802 // Mutate the value. 803 synchronized (mLock) { 804 switch (operation) { 805 case MUTATION_OPERATION_INSERT: { 806 return mSettingsRegistry 807 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, 808 owningUserId, name, value, getCallingPackage()); 809 } 810 811 case MUTATION_OPERATION_DELETE: { 812 return mSettingsRegistry.deleteSettingLocked( 813 SettingsRegistry.SETTINGS_TYPE_SECURE, 814 owningUserId, name); 815 } 816 817 case MUTATION_OPERATION_UPDATE: { 818 return mSettingsRegistry 819 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, 820 owningUserId, name, value, getCallingPackage()); 821 } 822 } 823 } 824 825 return false; 826 } 827 828 private Cursor getAllSystemSettings(int userId, String[] projection) { 829 if (DEBUG) { 830 Slog.v(LOG_TAG, "getAllSecureSystem(" + userId + ")"); 831 } 832 833 // Resolve the userId on whose behalf the call is made. 834 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId); 835 836 synchronized (mLock) { 837 List<String> names = mSettingsRegistry.getSettingsNamesLocked( 838 SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId); 839 840 final int nameCount = names.size(); 841 842 String[] normalizedProjection = normalizeProjection(projection); 843 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); 844 845 for (int i = 0; i < nameCount; i++) { 846 String name = names.get(i); 847 848 // Determine the owning user as some profile settings are cloned from the parent. 849 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, 850 name); 851 852 Setting setting = mSettingsRegistry.getSettingLocked( 853 SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name); 854 appendSettingToCursor(result, setting); 855 } 856 857 return result; 858 } 859 } 860 861 private Setting getSystemSetting(String name, int requestingUserId) { 862 if (DEBUG) { 863 Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")"); 864 } 865 866 // Resolve the userId on whose behalf the call is made. 867 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId); 868 869 // Determine the owning user as some profile settings are cloned from the parent. 870 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name); 871 872 // Get the value. 873 synchronized (mLock) { 874 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, 875 owningUserId, name); 876 } 877 } 878 879 private boolean insertSystemSetting(String name, String value, int requestingUserId) { 880 if (DEBUG) { 881 Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", " 882 + requestingUserId + ")"); 883 } 884 885 return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT); 886 } 887 888 private boolean deleteSystemSetting(String name, int requestingUserId) { 889 if (DEBUG) { 890 Slog.v(LOG_TAG, "deleteSystemSetting(" + name + ", " + requestingUserId + ")"); 891 } 892 893 return mutateSystemSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE); 894 } 895 896 private boolean updateSystemSetting(String name, String value, int requestingUserId) { 897 if (DEBUG) { 898 Slog.v(LOG_TAG, "updateSystemSetting(" + name + ", " + value + ", " 899 + requestingUserId + ")"); 900 } 901 902 return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); 903 } 904 905 private boolean mutateSystemSetting(String name, String value, int runAsUserId, 906 int operation) { 907 // Check for permissions first. 908 hasPermissionsToMutateSystemSettings(); 909 910 // Verify whether this operation is allowed for the calling package. 911 if (!isAppOpWriteSettingsAllowedForCallingPackage()) { 912 return false; 913 } 914 915 // Enforce what the calling package can mutate the system settings. 916 enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name); 917 918 // Resolve the userId on whose behalf the call is made. 919 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId); 920 921 // Determine the owning user as some profile settings are cloned from the parent. 922 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name); 923 924 // Only the owning user id can change the setting. 925 if (owningUserId != callingUserId) { 926 return false; 927 } 928 929 // Mutate the value. 930 synchronized (mLock) { 931 switch (operation) { 932 case MUTATION_OPERATION_INSERT: { 933 validateSystemSettingValue(name, value); 934 return mSettingsRegistry 935 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, 936 owningUserId, name, value, getCallingPackage()); 937 } 938 939 case MUTATION_OPERATION_DELETE: { 940 return mSettingsRegistry.deleteSettingLocked( 941 SettingsRegistry.SETTINGS_TYPE_SYSTEM, 942 owningUserId, name); 943 } 944 945 case MUTATION_OPERATION_UPDATE: { 946 validateSystemSettingValue(name, value); 947 return mSettingsRegistry 948 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, 949 owningUserId, name, value, getCallingPackage()); 950 } 951 } 952 953 return false; 954 } 955 } 956 957 private boolean hasPermissionsToMutateSystemSettings() { 958 // Write secure settings is a more protected permission. If caller has it we are good. 959 if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) 960 == PackageManager.PERMISSION_GRANTED) { 961 return true; 962 } 963 964 // The write settings permission gates mutation of system settings. 965 if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SETTINGS) 966 == PackageManager.PERMISSION_GRANTED) { 967 return true; 968 } 969 970 // Excpet we let system apps change system settings without the permission. 971 PackageInfo packageInfo = getCallingPackageInfoOrThrow(); 972 if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 973 return true; 974 } 975 976 return false; 977 } 978 979 private void validateSystemSettingValue(String name, String value) { 980 Settings.System.Validator validator = Settings.System.VALIDATORS.get(name); 981 if (validator != null && !validator.validate(value)) { 982 throw new IllegalArgumentException("Invalid value: " + value 983 + " for setting: " + name); 984 } 985 } 986 987 private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId, 988 int owningUserId) { 989 // Optimization - location providers are restricted only for managed profiles. 990 if (callingUserId == owningUserId) { 991 return false; 992 } 993 if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name) 994 && mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, 995 new UserHandle(callingUserId))) { 996 return true; 997 } 998 return false; 999 } 1000 1001 private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId) { 1002 String restriction = sSettingToUserRestrictionMap.get(setting); 1003 if (restriction == null) { 1004 return false; 1005 } 1006 return mUserManager.hasUserRestriction(restriction, new UserHandle(userId)); 1007 } 1008 1009 private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) { 1010 return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting); 1011 } 1012 1013 private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) { 1014 return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting); 1015 } 1016 1017 private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) { 1018 final int parentId = getGroupParentLocked(userId); 1019 if (parentId != userId && keys.contains(name)) { 1020 return parentId; 1021 } 1022 return userId; 1023 } 1024 1025 private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation, 1026 String name) { 1027 // System/root/shell can mutate whatever secure settings they want. 1028 final int callingUid = Binder.getCallingUid(); 1029 if (callingUid == android.os.Process.SYSTEM_UID 1030 || callingUid == Process.SHELL_UID 1031 || callingUid == Process.ROOT_UID) { 1032 return; 1033 } 1034 1035 switch (operation) { 1036 case MUTATION_OPERATION_INSERT: 1037 // Insert updates. 1038 case MUTATION_OPERATION_UPDATE: { 1039 if (Settings.System.PUBLIC_SETTINGS.contains(name)) { 1040 return; 1041 } 1042 1043 // The calling package is already verified. 1044 PackageInfo packageInfo = getCallingPackageInfoOrThrow(); 1045 1046 // Privileged apps can do whatever they want. 1047 if ((packageInfo.applicationInfo.privateFlags 1048 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { 1049 return; 1050 } 1051 1052 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( 1053 packageInfo.applicationInfo.targetSdkVersion, name); 1054 } break; 1055 1056 case MUTATION_OPERATION_DELETE: { 1057 if (Settings.System.PUBLIC_SETTINGS.contains(name) 1058 || Settings.System.PRIVATE_SETTINGS.contains(name)) { 1059 throw new IllegalArgumentException("You cannot delete system defined" 1060 + " secure settings."); 1061 } 1062 1063 // The calling package is already verified. 1064 PackageInfo packageInfo = getCallingPackageInfoOrThrow(); 1065 1066 // Privileged apps can do whatever they want. 1067 if ((packageInfo.applicationInfo.privateFlags & 1068 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { 1069 return; 1070 } 1071 1072 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( 1073 packageInfo.applicationInfo.targetSdkVersion, name); 1074 } break; 1075 } 1076 } 1077 1078 private PackageInfo getCallingPackageInfoOrThrow() { 1079 try { 1080 return mPackageManager.getPackageInfo(getCallingPackage(), 0); 1081 } catch (PackageManager.NameNotFoundException e) { 1082 throw new IllegalStateException("Calling package doesn't exist"); 1083 } 1084 } 1085 1086 private int getGroupParentLocked(int userId) { 1087 // Most frequent use case. 1088 if (userId == UserHandle.USER_OWNER) { 1089 return userId; 1090 } 1091 // We are in the same process with the user manager and the returned 1092 // user info is a cached instance, so just look up instead of cache. 1093 final long identity = Binder.clearCallingIdentity(); 1094 try { 1095 // Just a lookup and not reentrant, so holding a lock is fine. 1096 UserInfo userInfo = mUserManager.getProfileParent(userId); 1097 return (userInfo != null) ? userInfo.id : userId; 1098 } finally { 1099 Binder.restoreCallingIdentity(identity); 1100 } 1101 } 1102 1103 private boolean isAppOpWriteSettingsAllowedForCallingPackage() { 1104 final int callingUid = Binder.getCallingUid(); 1105 1106 mAppOpsManager.checkPackage(Binder.getCallingUid(), getCallingPackage()); 1107 1108 return mAppOpsManager.noteOp(AppOpsManager.OP_WRITE_SETTINGS, callingUid, 1109 getCallingPackage()) == AppOpsManager.MODE_ALLOWED; 1110 } 1111 1112 private void enforceWritePermission(String permission) { 1113 if (getContext().checkCallingOrSelfPermission(permission) 1114 != PackageManager.PERMISSION_GRANTED) { 1115 throw new SecurityException("Permission denial: writing to settings requires:" 1116 + permission); 1117 } 1118 } 1119 1120 /* 1121 * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED. 1122 * This setting contains a list of the currently enabled location providers. 1123 * But helper functions in android.providers.Settings can enable or disable 1124 * a single provider by using a "+" or "-" prefix before the provider name. 1125 * 1126 * @returns whether the enabled location providers changed. 1127 */ 1128 private boolean updateLocationProvidersAllowedLocked(String value, int owningUserId) { 1129 if (TextUtils.isEmpty(value)) { 1130 return false; 1131 } 1132 1133 final char prefix = value.charAt(0); 1134 if (prefix != '+' && prefix != '-') { 1135 return false; 1136 } 1137 1138 // skip prefix 1139 value = value.substring(1); 1140 1141 Setting settingValue = getSecureSetting( 1142 Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId); 1143 1144 String oldProviders = (settingValue != null) ? settingValue.getValue() : ""; 1145 1146 int index = oldProviders.indexOf(value); 1147 int end = index + value.length(); 1148 1149 // check for commas to avoid matching on partial string 1150 if (index > 0 && oldProviders.charAt(index - 1) != ',') { 1151 index = -1; 1152 } 1153 1154 // check for commas to avoid matching on partial string 1155 if (end < oldProviders.length() && oldProviders.charAt(end) != ',') { 1156 index = -1; 1157 } 1158 1159 String newProviders; 1160 1161 if (prefix == '+' && index < 0) { 1162 // append the provider to the list if not present 1163 if (oldProviders.length() == 0) { 1164 newProviders = value; 1165 } else { 1166 newProviders = oldProviders + ',' + value; 1167 } 1168 } else if (prefix == '-' && index >= 0) { 1169 // remove the provider from the list if present 1170 // remove leading or trailing comma 1171 if (index > 0) { 1172 index--; 1173 } else if (end < oldProviders.length()) { 1174 end++; 1175 } 1176 1177 newProviders = oldProviders.substring(0, index); 1178 if (end < oldProviders.length()) { 1179 newProviders += oldProviders.substring(end); 1180 } 1181 } else { 1182 // nothing changed, so no need to update the database 1183 return false; 1184 } 1185 1186 return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, 1187 owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders, 1188 getCallingPackage()); 1189 } 1190 1191 private void sendNotify(Uri uri, int userId) { 1192 final long identity = Binder.clearCallingIdentity(); 1193 try { 1194 getContext().getContentResolver().notifyChange(uri, null, true, userId); 1195 if (DEBUG) { 1196 Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri); 1197 } 1198 } finally { 1199 Binder.restoreCallingIdentity(identity); 1200 } 1201 } 1202 1203 private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( 1204 int targetSdkVersion, String name) { 1205 // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash. 1206 if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) { 1207 if (Settings.System.PRIVATE_SETTINGS.contains(name)) { 1208 Slog.w(LOG_TAG, "You shouldn't not change private system settings." 1209 + " This will soon become an error."); 1210 } else { 1211 Slog.w(LOG_TAG, "You shouldn't keep your settings in the secure settings." 1212 + " This will soon become an error."); 1213 } 1214 } else { 1215 if (Settings.System.PRIVATE_SETTINGS.contains(name)) { 1216 throw new IllegalArgumentException("You cannot change private secure settings."); 1217 } else { 1218 throw new IllegalArgumentException("You cannot keep your settings in" 1219 + " the secure settings."); 1220 } 1221 } 1222 } 1223 1224 private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) { 1225 if (requestingUserId == UserHandle.getCallingUserId()) { 1226 return requestingUserId; 1227 } 1228 return ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1229 Binder.getCallingUid(), requestingUserId, false, true, 1230 "get/set setting for user", null); 1231 } 1232 1233 private static Bundle packageValueForCallResult(Setting setting) { 1234 if (setting == null) { 1235 return NULL_SETTING; 1236 } 1237 return Bundle.forPair(Settings.NameValueTable.VALUE, setting.getValue()); 1238 } 1239 1240 private static int getRequestingUserId(Bundle args) { 1241 final int callingUserId = UserHandle.getCallingUserId(); 1242 return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId) 1243 : callingUserId; 1244 } 1245 1246 private static String getSettingValue(Bundle args) { 1247 return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null; 1248 } 1249 1250 private static String getValidTableOrThrow(Uri uri) { 1251 if (uri.getPathSegments().size() > 0) { 1252 String table = uri.getPathSegments().get(0); 1253 if (DatabaseHelper.isValidTable(table)) { 1254 return table; 1255 } 1256 throw new IllegalArgumentException("Bad root path: " + table); 1257 } 1258 throw new IllegalArgumentException("Invalid URI:" + uri); 1259 } 1260 1261 private static MatrixCursor packageSettingForQuery(Setting setting, String[] projection) { 1262 if (setting == null) { 1263 return new MatrixCursor(projection, 0); 1264 } 1265 MatrixCursor cursor = new MatrixCursor(projection, 1); 1266 appendSettingToCursor(cursor, setting); 1267 return cursor; 1268 } 1269 1270 private static String[] normalizeProjection(String[] projection) { 1271 if (projection == null) { 1272 return ALL_COLUMNS; 1273 } 1274 1275 final int columnCount = projection.length; 1276 for (int i = 0; i < columnCount; i++) { 1277 String column = projection[i]; 1278 if (!ArrayUtils.contains(ALL_COLUMNS, column)) { 1279 throw new IllegalArgumentException("Invalid column: " + column); 1280 } 1281 } 1282 1283 return projection; 1284 } 1285 1286 private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) { 1287 final int columnCount = cursor.getColumnCount(); 1288 1289 String[] values = new String[columnCount]; 1290 1291 for (int i = 0; i < columnCount; i++) { 1292 String column = cursor.getColumnName(i); 1293 1294 switch (column) { 1295 case Settings.NameValueTable._ID: { 1296 values[i] = setting.getId(); 1297 } break; 1298 1299 case Settings.NameValueTable.NAME: { 1300 values[i] = setting.getName(); 1301 } break; 1302 1303 case Settings.NameValueTable.VALUE: { 1304 values[i] = setting.getValue(); 1305 } break; 1306 } 1307 } 1308 1309 cursor.addRow(values); 1310 } 1311 1312 private static boolean isKeyValid(String key) { 1313 return !(TextUtils.isEmpty(key) || SettingsState.isBinary(key)); 1314 } 1315 1316 private static final class Arguments { 1317 private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS = 1318 Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*"); 1319 1320 private static final Pattern WHERE_PATTERN_WITH_PARAM_IN_BRACKETS = 1321 Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*\\?[\\s]*\\)[\\s]*"); 1322 1323 private static final Pattern WHERE_PATTERN_NO_PARAM_IN_BRACKETS = 1324 Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*\\)[\\s]*"); 1325 1326 private static final Pattern WHERE_PATTERN_NO_PARAM_NO_BRACKETS = 1327 Pattern.compile("[\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*"); 1328 1329 public final String table; 1330 public final String name; 1331 1332 public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) { 1333 final int segmentSize = uri.getPathSegments().size(); 1334 switch (segmentSize) { 1335 case 1: { 1336 if (where != null 1337 && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches() 1338 || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches()) 1339 && whereArgs.length == 1) { 1340 name = whereArgs[0]; 1341 table = computeTableForSetting(uri, name); 1342 return; 1343 } else if (where != null 1344 && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches() 1345 || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) { 1346 final int startIndex = Math.max(where.indexOf("'"), 1347 where.indexOf("\"")) + 1; 1348 final int endIndex = Math.max(where.lastIndexOf("'"), 1349 where.lastIndexOf("\"")); 1350 name = where.substring(startIndex, endIndex); 1351 table = computeTableForSetting(uri, name); 1352 return; 1353 } else if (supportAll && where == null && whereArgs == null) { 1354 name = null; 1355 table = computeTableForSetting(uri, null); 1356 return; 1357 } 1358 } break; 1359 1360 case 2: { 1361 if (where == null && whereArgs == null) { 1362 name = uri.getPathSegments().get(1); 1363 table = computeTableForSetting(uri, name); 1364 return; 1365 } 1366 } break; 1367 } 1368 1369 EventLogTags.writeUnsupportedSettingsQuery( 1370 uri.toSafeString(), where, Arrays.toString(whereArgs)); 1371 String message = String.format( "Supported SQL:\n" 1372 + " uri content://some_table/some_property with null where and where args\n" 1373 + " uri content://some_table with query name=? and single name as arg\n" 1374 + " uri content://some_table with query name=some_name and null args\n" 1375 + " but got - uri:%1s, where:%2s whereArgs:%3s", uri, where, 1376 Arrays.toString(whereArgs)); 1377 throw new IllegalArgumentException(message); 1378 } 1379 1380 private static String computeTableForSetting(Uri uri, String name) { 1381 String table = getValidTableOrThrow(uri); 1382 1383 if (name != null) { 1384 if (sSystemMovedToSecureSettings.contains(name)) { 1385 table = TABLE_SECURE; 1386 } 1387 1388 if (sSystemMovedToGlobalSettings.contains(name)) { 1389 table = TABLE_GLOBAL; 1390 } 1391 1392 if (sSecureMovedToGlobalSettings.contains(name)) { 1393 table = TABLE_GLOBAL; 1394 } 1395 1396 if (sGlobalMovedToSecureSettings.contains(name)) { 1397 table = TABLE_SECURE; 1398 } 1399 } 1400 1401 return table; 1402 } 1403 } 1404 1405 final class SettingsRegistry { 1406 private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid"; 1407 1408 private static final int SETTINGS_TYPE_GLOBAL = 0; 1409 private static final int SETTINGS_TYPE_SYSTEM = 1; 1410 private static final int SETTINGS_TYPE_SECURE = 2; 1411 1412 private static final int SETTINGS_TYPE_MASK = 0xF0000000; 1413 private static final int SETTINGS_TYPE_SHIFT = 28; 1414 1415 private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml"; 1416 private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml"; 1417 private static final String SETTINGS_FILE_SECURE = "settings_secure.xml"; 1418 1419 private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>(); 1420 1421 private final BackupManager mBackupManager; 1422 1423 public SettingsRegistry() { 1424 mBackupManager = new BackupManager(getContext()); 1425 migrateAllLegacySettingsIfNeeded(); 1426 } 1427 1428 public List<String> getSettingsNamesLocked(int type, int userId) { 1429 final int key = makeKey(type, userId); 1430 SettingsState settingsState = peekSettingsStateLocked(key); 1431 return settingsState.getSettingNamesLocked(); 1432 } 1433 1434 public SettingsState getSettingsLocked(int type, int userId) { 1435 final int key = makeKey(type, userId); 1436 return peekSettingsStateLocked(key); 1437 } 1438 1439 public void ensureSettingsForUserLocked(int userId) { 1440 // Migrate the setting for this user if needed. 1441 migrateLegacySettingsForUserIfNeededLocked(userId); 1442 1443 // Ensure global settings loaded if owner. 1444 if (userId == UserHandle.USER_OWNER) { 1445 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER); 1446 ensureSettingsStateLocked(globalKey); 1447 } 1448 1449 // Ensure secure settings loaded. 1450 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId); 1451 ensureSettingsStateLocked(secureKey); 1452 1453 // Make sure the secure settings have an Android id set. 1454 SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId); 1455 ensureSecureSettingAndroidIdSetLocked(secureSettings); 1456 1457 // Ensure system settings loaded. 1458 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId); 1459 ensureSettingsStateLocked(systemKey); 1460 1461 // Upgrade the settings to the latest version. 1462 UpgradeController upgrader = new UpgradeController(userId); 1463 upgrader.upgradeIfNeededLocked(); 1464 } 1465 1466 private void ensureSettingsStateLocked(int key) { 1467 if (mSettingsStates.get(key) == null) { 1468 final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key)); 1469 SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key, 1470 maxBytesPerPackage); 1471 mSettingsStates.put(key, settingsState); 1472 } 1473 } 1474 1475 public void removeUserStateLocked(int userId, boolean permanently) { 1476 // We always keep the global settings in memory. 1477 1478 // Nuke system settings. 1479 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId); 1480 final SettingsState systemSettingsState = mSettingsStates.get(systemKey); 1481 if (systemSettingsState != null) { 1482 if (permanently) { 1483 mSettingsStates.remove(systemKey); 1484 systemSettingsState.destroyLocked(null); 1485 } else { 1486 systemSettingsState.destroyLocked(new Runnable() { 1487 @Override 1488 public void run() { 1489 mSettingsStates.remove(systemKey); 1490 } 1491 }); 1492 } 1493 } 1494 1495 // Nuke secure settings. 1496 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId); 1497 final SettingsState secureSettingsState = mSettingsStates.get(secureKey); 1498 if (secureSettingsState != null) { 1499 if (permanently) { 1500 mSettingsStates.remove(secureKey); 1501 secureSettingsState.destroyLocked(null); 1502 } else { 1503 secureSettingsState.destroyLocked(new Runnable() { 1504 @Override 1505 public void run() { 1506 mSettingsStates.remove(secureKey); 1507 } 1508 }); 1509 } 1510 } 1511 } 1512 1513 public boolean insertSettingLocked(int type, int userId, String name, String value, 1514 String packageName) { 1515 final int key = makeKey(type, userId); 1516 1517 SettingsState settingsState = peekSettingsStateLocked(key); 1518 final boolean success = settingsState.insertSettingLocked(name, value, packageName); 1519 1520 if (success) { 1521 notifyForSettingsChange(key, name); 1522 } 1523 return success; 1524 } 1525 1526 public boolean deleteSettingLocked(int type, int userId, String name) { 1527 final int key = makeKey(type, userId); 1528 1529 SettingsState settingsState = peekSettingsStateLocked(key); 1530 final boolean success = settingsState.deleteSettingLocked(name); 1531 1532 if (success) { 1533 notifyForSettingsChange(key, name); 1534 } 1535 return success; 1536 } 1537 1538 public Setting getSettingLocked(int type, int userId, String name) { 1539 final int key = makeKey(type, userId); 1540 1541 SettingsState settingsState = peekSettingsStateLocked(key); 1542 return settingsState.getSettingLocked(name); 1543 } 1544 1545 public boolean updateSettingLocked(int type, int userId, String name, String value, 1546 String packageName) { 1547 final int key = makeKey(type, userId); 1548 1549 SettingsState settingsState = peekSettingsStateLocked(key); 1550 final boolean success = settingsState.updateSettingLocked(name, value, packageName); 1551 1552 if (success) { 1553 notifyForSettingsChange(key, name); 1554 } 1555 1556 return success; 1557 } 1558 1559 public void onPackageRemovedLocked(String packageName, int userId) { 1560 // Global and secure settings are signature protected. Apps signed 1561 // by the platform certificate are generally not uninstalled and 1562 // the main exception is tests. We trust components signed 1563 // by the platform certificate and do not do a clean up after them. 1564 1565 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId); 1566 SettingsState systemSettings = mSettingsStates.get(systemKey); 1567 if (systemSettings != null) { 1568 systemSettings.onPackageRemovedLocked(packageName); 1569 } 1570 } 1571 1572 private SettingsState peekSettingsStateLocked(int key) { 1573 SettingsState settingsState = mSettingsStates.get(key); 1574 if (settingsState != null) { 1575 return settingsState; 1576 } 1577 1578 ensureSettingsForUserLocked(getUserIdFromKey(key)); 1579 return mSettingsStates.get(key); 1580 } 1581 1582 private void migrateAllLegacySettingsIfNeeded() { 1583 synchronized (mLock) { 1584 final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER); 1585 File globalFile = getSettingsFile(key); 1586 if (globalFile.exists()) { 1587 return; 1588 } 1589 1590 final long identity = Binder.clearCallingIdentity(); 1591 try { 1592 List<UserInfo> users = mUserManager.getUsers(true); 1593 1594 final int userCount = users.size(); 1595 for (int i = 0; i < userCount; i++) { 1596 final int userId = users.get(i).id; 1597 1598 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId); 1599 SQLiteDatabase database = dbHelper.getWritableDatabase(); 1600 migrateLegacySettingsForUserLocked(dbHelper, database, userId); 1601 1602 // Upgrade to the latest version. 1603 UpgradeController upgrader = new UpgradeController(userId); 1604 upgrader.upgradeIfNeededLocked(); 1605 1606 // Drop from memory if not a running user. 1607 if (!mUserManager.isUserRunning(new UserHandle(userId))) { 1608 removeUserStateLocked(userId, false); 1609 } 1610 } 1611 } finally { 1612 Binder.restoreCallingIdentity(identity); 1613 } 1614 } 1615 } 1616 1617 private void migrateLegacySettingsForUserIfNeededLocked(int userId) { 1618 // Every user has secure settings and if no file we need to migrate. 1619 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId); 1620 File secureFile = getSettingsFile(secureKey); 1621 if (secureFile.exists()) { 1622 return; 1623 } 1624 1625 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId); 1626 SQLiteDatabase database = dbHelper.getWritableDatabase(); 1627 1628 migrateLegacySettingsForUserLocked(dbHelper, database, userId); 1629 } 1630 1631 private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper, 1632 SQLiteDatabase database, int userId) { 1633 // Move over the global settings if owner. 1634 if (userId == UserHandle.USER_OWNER) { 1635 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId); 1636 ensureSettingsStateLocked(globalKey); 1637 SettingsState globalSettings = mSettingsStates.get(globalKey); 1638 migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL); 1639 globalSettings.persistSyncLocked(); 1640 } 1641 1642 // Move over the secure settings. 1643 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId); 1644 ensureSettingsStateLocked(secureKey); 1645 SettingsState secureSettings = mSettingsStates.get(secureKey); 1646 migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE); 1647 ensureSecureSettingAndroidIdSetLocked(secureSettings); 1648 secureSettings.persistSyncLocked(); 1649 1650 // Move over the system settings. 1651 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId); 1652 ensureSettingsStateLocked(systemKey); 1653 SettingsState systemSettings = mSettingsStates.get(systemKey); 1654 migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM); 1655 systemSettings.persistSyncLocked(); 1656 1657 // Drop the database as now all is moved and persisted. 1658 if (DROP_DATABASE_ON_MIGRATION) { 1659 dbHelper.dropDatabase(); 1660 } else { 1661 dbHelper.backupDatabase(); 1662 } 1663 } 1664 1665 private void migrateLegacySettingsLocked(SettingsState settingsState, 1666 SQLiteDatabase database, String table) { 1667 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); 1668 queryBuilder.setTables(table); 1669 1670 Cursor cursor = queryBuilder.query(database, ALL_COLUMNS, 1671 null, null, null, null, null); 1672 1673 if (cursor == null) { 1674 return; 1675 } 1676 1677 try { 1678 if (!cursor.moveToFirst()) { 1679 return; 1680 } 1681 1682 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME); 1683 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE); 1684 1685 settingsState.setVersionLocked(database.getVersion()); 1686 1687 while (!cursor.isAfterLast()) { 1688 String name = cursor.getString(nameColumnIdx); 1689 String value = cursor.getString(valueColumnIdx); 1690 settingsState.insertSettingLocked(name, value, 1691 SettingsState.SYSTEM_PACKAGE_NAME); 1692 cursor.moveToNext(); 1693 } 1694 } finally { 1695 cursor.close(); 1696 } 1697 } 1698 1699 private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) { 1700 Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID); 1701 1702 if (value != null) { 1703 return; 1704 } 1705 1706 final int userId = getUserIdFromKey(secureSettings.mKey); 1707 1708 final UserInfo user; 1709 final long identity = Binder.clearCallingIdentity(); 1710 try { 1711 user = mUserManager.getUserInfo(userId); 1712 } finally { 1713 Binder.restoreCallingIdentity(identity); 1714 } 1715 if (user == null) { 1716 // Can happen due to races when deleting users - treat as benign. 1717 return; 1718 } 1719 1720 String androidId = Long.toHexString(new SecureRandom().nextLong()); 1721 secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId, 1722 SettingsState.SYSTEM_PACKAGE_NAME); 1723 1724 Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId 1725 + "] for user " + userId); 1726 1727 // Write a drop box entry if it's a restricted profile 1728 if (user.isRestricted()) { 1729 DropBoxManager dbm = (DropBoxManager) getContext().getSystemService( 1730 Context.DROPBOX_SERVICE); 1731 if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) { 1732 dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis() 1733 + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n"); 1734 } 1735 } 1736 } 1737 1738 private void notifyForSettingsChange(int key, String name) { 1739 // Update the system property *first*, so if someone is listening for 1740 // a notification and then using the contract class to get their data, 1741 // the system property will be updated and they'll get the new data. 1742 1743 boolean backedUpDataChanged = false; 1744 String property = null; 1745 if (isGlobalSettingsKey(key)) { 1746 property = Settings.Global.SYS_PROP_SETTING_VERSION; 1747 backedUpDataChanged = true; 1748 } else if (isSecureSettingsKey(key)) { 1749 property = Settings.Secure.SYS_PROP_SETTING_VERSION; 1750 backedUpDataChanged = true; 1751 } else if (isSystemSettingsKey(key)) { 1752 property = Settings.System.SYS_PROP_SETTING_VERSION; 1753 backedUpDataChanged = true; 1754 } 1755 1756 if (property != null) { 1757 final long version = SystemProperties.getLong(property, 0) + 1; 1758 SystemProperties.set(property, Long.toString(version)); 1759 if (DEBUG) { 1760 Slog.v(LOG_TAG, "System property " + property + "=" + version); 1761 } 1762 } 1763 1764 // Inform the backup manager about a data change 1765 if (backedUpDataChanged) { 1766 mBackupManager.dataChanged(); 1767 } 1768 1769 // Now send the notification through the content framework. 1770 1771 final int userId = getUserIdFromKey(key); 1772 Uri uri = getNotificationUriFor(key, name); 1773 1774 sendNotify(uri, userId); 1775 } 1776 1777 private int makeKey(int type, int userId) { 1778 return (type << SETTINGS_TYPE_SHIFT) | userId; 1779 } 1780 1781 private int getTypeFromKey(int key) { 1782 return key >> SETTINGS_TYPE_SHIFT; 1783 } 1784 1785 private int getUserIdFromKey(int key) { 1786 return key & ~SETTINGS_TYPE_MASK; 1787 } 1788 1789 private boolean isGlobalSettingsKey(int key) { 1790 return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL; 1791 } 1792 1793 private boolean isSystemSettingsKey(int key) { 1794 return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM; 1795 } 1796 1797 private boolean isSecureSettingsKey(int key) { 1798 return getTypeFromKey(key) == SETTINGS_TYPE_SECURE; 1799 } 1800 1801 private File getSettingsFile(int key) { 1802 if (isGlobalSettingsKey(key)) { 1803 final int userId = getUserIdFromKey(key); 1804 return new File(Environment.getUserSystemDirectory(userId), 1805 SETTINGS_FILE_GLOBAL); 1806 } else if (isSystemSettingsKey(key)) { 1807 final int userId = getUserIdFromKey(key); 1808 return new File(Environment.getUserSystemDirectory(userId), 1809 SETTINGS_FILE_SYSTEM); 1810 } else if (isSecureSettingsKey(key)) { 1811 final int userId = getUserIdFromKey(key); 1812 return new File(Environment.getUserSystemDirectory(userId), 1813 SETTINGS_FILE_SECURE); 1814 } else { 1815 throw new IllegalArgumentException("Invalid settings key:" + key); 1816 } 1817 } 1818 1819 private Uri getNotificationUriFor(int key, String name) { 1820 if (isGlobalSettingsKey(key)) { 1821 return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name) 1822 : Settings.Global.CONTENT_URI; 1823 } else if (isSecureSettingsKey(key)) { 1824 return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name) 1825 : Settings.Secure.CONTENT_URI; 1826 } else if (isSystemSettingsKey(key)) { 1827 return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name) 1828 : Settings.System.CONTENT_URI; 1829 } else { 1830 throw new IllegalArgumentException("Invalid settings key:" + key); 1831 } 1832 } 1833 1834 private int getMaxBytesPerPackageForType(int type) { 1835 switch (type) { 1836 case SETTINGS_TYPE_GLOBAL: 1837 case SETTINGS_TYPE_SECURE: { 1838 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED; 1839 } 1840 1841 default: { 1842 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED; 1843 } 1844 } 1845 } 1846 1847 private final class UpgradeController { 1848 private static final int SETTINGS_VERSION = 121; 1849 1850 private final int mUserId; 1851 1852 public UpgradeController(int userId) { 1853 mUserId = userId; 1854 } 1855 1856 public void upgradeIfNeededLocked() { 1857 // The version of all settings for a user is the same (all users have secure). 1858 SettingsState secureSettings = getSettingsLocked( 1859 SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId); 1860 1861 // Try an update from the current state. 1862 final int oldVersion = secureSettings.getVersionLocked(); 1863 final int newVersion = SETTINGS_VERSION; 1864 1865 // If up do date - done. 1866 if (oldVersion == newVersion) { 1867 return; 1868 } 1869 1870 // Try to upgrade. 1871 final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion); 1872 1873 // If upgrade failed start from scratch and upgrade. 1874 if (curVersion != newVersion) { 1875 // Drop state we have for this user. 1876 removeUserStateLocked(mUserId, true); 1877 1878 // Recreate the database. 1879 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId); 1880 SQLiteDatabase database = dbHelper.getWritableDatabase(); 1881 dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion); 1882 1883 // Migrate the settings for this user. 1884 migrateLegacySettingsForUserLocked(dbHelper, database, mUserId); 1885 1886 // Now upgrade should work fine. 1887 onUpgradeLocked(mUserId, oldVersion, newVersion); 1888 } 1889 1890 // Set the global settings version if owner. 1891 if (mUserId == UserHandle.USER_OWNER) { 1892 SettingsState globalSettings = getSettingsLocked( 1893 SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId); 1894 globalSettings.setVersionLocked(newVersion); 1895 } 1896 1897 // Set the secure settings version. 1898 secureSettings.setVersionLocked(newVersion); 1899 1900 // Set the system settings version. 1901 SettingsState systemSettings = getSettingsLocked( 1902 SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId); 1903 systemSettings.setVersionLocked(newVersion); 1904 } 1905 1906 private SettingsState getGlobalSettingsLocked() { 1907 return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER); 1908 } 1909 1910 private SettingsState getSecureSettingsLocked(int userId) { 1911 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId); 1912 } 1913 1914 private SettingsState getSystemSettingsLocked(int userId) { 1915 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId); 1916 } 1917 1918 /** 1919 * You must perform all necessary mutations to bring the settings 1920 * for this user from the old to the new version. When you add a new 1921 * upgrade step you *must* update SETTINGS_VERSION. 1922 * 1923 * This is an example of moving a setting from secure to global. 1924 * 1925 * // v119: Example settings changes. 1926 * if (currentVersion == 118) { 1927 * if (userId == UserHandle.USER_OWNER) { 1928 * // Remove from the secure settings. 1929 * SettingsState secureSettings = getSecureSettingsLocked(userId); 1930 * String name = "example_setting_to_move"; 1931 * String value = secureSettings.getSetting(name); 1932 * secureSettings.deleteSetting(name); 1933 * 1934 * // Add to the global settings. 1935 * SettingsState globalSettings = getGlobalSettingsLocked(); 1936 * globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME); 1937 * } 1938 * 1939 * // Update the current version. 1940 * currentVersion = 119; 1941 * } 1942 */ 1943 private int onUpgradeLocked(int userId, int oldVersion, int newVersion) { 1944 if (DEBUG) { 1945 Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: " 1946 + oldVersion + " to version: " + newVersion); 1947 } 1948 1949 int currentVersion = oldVersion; 1950 1951 // v119: Reset zen + ringer mode. 1952 if (currentVersion == 118) { 1953 if (userId == UserHandle.USER_OWNER) { 1954 final SettingsState globalSettings = getGlobalSettingsLocked(); 1955 globalSettings.updateSettingLocked(Settings.Global.ZEN_MODE, 1956 Integer.toString(Settings.Global.ZEN_MODE_OFF), 1957 SettingsState.SYSTEM_PACKAGE_NAME); 1958 globalSettings.updateSettingLocked(Settings.Global.MODE_RINGER, 1959 Integer.toString(AudioManager.RINGER_MODE_NORMAL), 1960 SettingsState.SYSTEM_PACKAGE_NAME); 1961 } 1962 currentVersion = 119; 1963 } 1964 1965 // v120: Add double tap to wake setting. 1966 if (currentVersion == 119) { 1967 SettingsState secureSettings = getSecureSettingsLocked(userId); 1968 secureSettings.insertSettingLocked(Settings.Secure.DOUBLE_TAP_TO_WAKE, 1969 getContext().getResources().getBoolean( 1970 R.bool.def_double_tap_to_wake) ? "1" : "0", 1971 SettingsState.SYSTEM_PACKAGE_NAME); 1972 1973 currentVersion = 120; 1974 } 1975 1976 // Before 121, we used a different string encoding logic. We just bump the version 1977 // here; SettingsState knows how to handle pre-version 120 files. 1978 currentVersion = 121; 1979 1980 // vXXX: Add new settings above this point. 1981 1982 // Return the current version. 1983 return currentVersion; 1984 } 1985 } 1986 } 1987} 1988