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