SettingsProvider.java revision 8de348095f0967ffaa09d2448dc1ccff72a4e284
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            // Global and secure settings are signature protected. Apps signed
1504            // by the platform certificate are generally not uninstalled  and
1505            // the main exception is tests. We trust components signed
1506            // by the platform certificate and do not do a clean up after them.
1507
1508            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1509            SettingsState systemSettings = mSettingsStates.get(systemKey);
1510            if (systemSettings != null) {
1511                systemSettings.onPackageRemovedLocked(packageName);
1512            }
1513        }
1514
1515        private SettingsState peekSettingsStateLocked(int key) {
1516            SettingsState settingsState = mSettingsStates.get(key);
1517            if (settingsState != null) {
1518                return settingsState;
1519            }
1520
1521            ensureSettingsForUserLocked(getUserIdFromKey(key));
1522            return mSettingsStates.get(key);
1523        }
1524
1525        private void migrateAllLegacySettingsIfNeeded() {
1526            synchronized (mLock) {
1527                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
1528                File globalFile = getSettingsFile(key);
1529                if (globalFile.exists()) {
1530                    return;
1531                }
1532
1533                final long identity = Binder.clearCallingIdentity();
1534                try {
1535                    List<UserInfo> users = mUserManager.getUsers(true);
1536
1537                    final int userCount = users.size();
1538                    for (int i = 0; i < userCount; i++) {
1539                        final int userId = users.get(i).id;
1540
1541                        DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1542                        SQLiteDatabase database = dbHelper.getWritableDatabase();
1543                        migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1544
1545                        // Upgrade to the latest version.
1546                        UpgradeController upgrader = new UpgradeController(userId);
1547                        upgrader.upgradeIfNeededLocked();
1548
1549                        // Drop from memory if not a running user.
1550                        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
1551                            removeUserStateLocked(userId, false);
1552                        }
1553                    }
1554                } finally {
1555                    Binder.restoreCallingIdentity(identity);
1556                }
1557            }
1558        }
1559
1560        private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
1561            // Every user has secure settings and if no file we need to migrate.
1562            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1563            File secureFile = getSettingsFile(secureKey);
1564            if (secureFile.exists()) {
1565                return;
1566            }
1567
1568            DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1569            SQLiteDatabase database = dbHelper.getWritableDatabase();
1570
1571            migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1572        }
1573
1574        private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
1575                SQLiteDatabase database, int userId) {
1576            // Move over the global settings if owner.
1577            if (userId == UserHandle.USER_OWNER) {
1578                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
1579                ensureSettingsStateLocked(globalKey);
1580                SettingsState globalSettings = mSettingsStates.get(globalKey);
1581                migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
1582                globalSettings.persistSyncLocked();
1583            }
1584
1585            // Move over the secure settings.
1586            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1587            ensureSettingsStateLocked(secureKey);
1588            SettingsState secureSettings = mSettingsStates.get(secureKey);
1589            migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
1590            ensureSecureSettingAndroidIdSetLocked(secureSettings);
1591            secureSettings.persistSyncLocked();
1592
1593            // Move over the system settings.
1594            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1595            ensureSettingsStateLocked(systemKey);
1596            SettingsState systemSettings = mSettingsStates.get(systemKey);
1597            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
1598            systemSettings.persistSyncLocked();
1599
1600            // Drop the database as now all is moved and persisted.
1601            if (DROP_DATABASE_ON_MIGRATION) {
1602                dbHelper.dropDatabase();
1603            } else {
1604                dbHelper.backupDatabase();
1605            }
1606        }
1607
1608        private void migrateLegacySettingsLocked(SettingsState settingsState,
1609                SQLiteDatabase database, String table) {
1610            SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
1611            queryBuilder.setTables(table);
1612
1613            Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
1614                    null, null, null, null, null);
1615
1616            if (cursor == null) {
1617                return;
1618            }
1619
1620            try {
1621                if (!cursor.moveToFirst()) {
1622                    return;
1623                }
1624
1625                final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
1626                final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
1627
1628                settingsState.setVersionLocked(database.getVersion());
1629
1630                while (!cursor.isAfterLast()) {
1631                    String name = cursor.getString(nameColumnIdx);
1632                    String value = cursor.getString(valueColumnIdx);
1633                    settingsState.insertSettingLocked(name, value,
1634                            SettingsState.SYSTEM_PACKAGE_NAME);
1635                    cursor.moveToNext();
1636                }
1637            } finally {
1638                cursor.close();
1639            }
1640        }
1641
1642        private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
1643            Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
1644
1645            if (value != null) {
1646                return;
1647            }
1648
1649            final int userId = getUserIdFromKey(secureSettings.mKey);
1650
1651            final UserInfo user;
1652            final long identity = Binder.clearCallingIdentity();
1653            try {
1654                user = mUserManager.getUserInfo(userId);
1655            } finally {
1656                Binder.restoreCallingIdentity(identity);
1657            }
1658            if (user == null) {
1659                // Can happen due to races when deleting users - treat as benign.
1660                return;
1661            }
1662
1663            String androidId = Long.toHexString(new SecureRandom().nextLong());
1664            secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
1665                    SettingsState.SYSTEM_PACKAGE_NAME);
1666
1667            Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
1668                    + "] for user " + userId);
1669
1670            // Write a drop box entry if it's a restricted profile
1671            if (user.isRestricted()) {
1672                DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
1673                        Context.DROPBOX_SERVICE);
1674                if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
1675                    dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
1676                            + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
1677                }
1678            }
1679        }
1680
1681        private void notifyForSettingsChange(int key, String name) {
1682            // Update the system property *first*, so if someone is listening for
1683            // a notification and then using the contract class to get their data,
1684            // the system property will be updated and they'll get the new data.
1685
1686            boolean backedUpDataChanged = false;
1687            String property = null;
1688            if (isGlobalSettingsKey(key)) {
1689                property = Settings.Global.SYS_PROP_SETTING_VERSION;
1690                backedUpDataChanged = true;
1691            } else if (isSecureSettingsKey(key)) {
1692                property = Settings.Secure.SYS_PROP_SETTING_VERSION;
1693                backedUpDataChanged = true;
1694            } else if (isSystemSettingsKey(key)) {
1695                property = Settings.System.SYS_PROP_SETTING_VERSION;
1696                backedUpDataChanged = true;
1697            }
1698
1699            if (property != null) {
1700                final long version = SystemProperties.getLong(property, 0) + 1;
1701                SystemProperties.set(property, Long.toString(version));
1702                if (DEBUG) {
1703                    Slog.v(LOG_TAG, "System property " + property + "=" + version);
1704                }
1705            }
1706
1707            // Inform the backup manager about a data change
1708            if (backedUpDataChanged) {
1709                mBackupManager.dataChanged();
1710            }
1711
1712            // Now send the notification through the content framework.
1713
1714            final int userId = getUserIdFromKey(key);
1715            Uri uri = getNotificationUriFor(key, name);
1716
1717            sendNotify(uri, userId);
1718        }
1719
1720        private int makeKey(int type, int userId) {
1721            return (type << SETTINGS_TYPE_SHIFT) | userId;
1722        }
1723
1724        private int getTypeFromKey(int key) {
1725            return key >> SETTINGS_TYPE_SHIFT;
1726        }
1727
1728        private int getUserIdFromKey(int key) {
1729            return key & ~SETTINGS_TYPE_MASK;
1730        }
1731
1732        private boolean isGlobalSettingsKey(int key) {
1733            return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
1734        }
1735
1736        private boolean isSystemSettingsKey(int key) {
1737            return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
1738        }
1739
1740        private boolean isSecureSettingsKey(int key) {
1741            return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
1742        }
1743
1744        private File getSettingsFile(int key) {
1745            if (isGlobalSettingsKey(key)) {
1746                final int userId = getUserIdFromKey(key);
1747                return new File(Environment.getUserSystemDirectory(userId),
1748                        SETTINGS_FILE_GLOBAL);
1749            } else if (isSystemSettingsKey(key)) {
1750                final int userId = getUserIdFromKey(key);
1751                return new File(Environment.getUserSystemDirectory(userId),
1752                        SETTINGS_FILE_SYSTEM);
1753            } else if (isSecureSettingsKey(key)) {
1754                final int userId = getUserIdFromKey(key);
1755                return new File(Environment.getUserSystemDirectory(userId),
1756                        SETTINGS_FILE_SECURE);
1757            } else {
1758                throw new IllegalArgumentException("Invalid settings key:" + key);
1759            }
1760        }
1761
1762        private Uri getNotificationUriFor(int key, String name) {
1763            if (isGlobalSettingsKey(key)) {
1764                return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
1765                        : Settings.Global.CONTENT_URI;
1766            } else if (isSecureSettingsKey(key)) {
1767                return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
1768                        : Settings.Secure.CONTENT_URI;
1769            } else if (isSystemSettingsKey(key)) {
1770                return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
1771                        : Settings.System.CONTENT_URI;
1772            } else {
1773                throw new IllegalArgumentException("Invalid settings key:" + key);
1774            }
1775        }
1776
1777        private int getMaxBytesPerPackageForType(int type) {
1778            switch (type) {
1779                case SETTINGS_TYPE_GLOBAL:
1780                case SETTINGS_TYPE_SECURE: {
1781                    return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
1782                }
1783
1784                default: {
1785                    return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
1786                }
1787            }
1788        }
1789
1790        private final class UpgradeController {
1791            private static final int SETTINGS_VERSION = 118;
1792
1793            private final int mUserId;
1794
1795            public UpgradeController(int userId) {
1796                mUserId = userId;
1797            }
1798
1799            public void upgradeIfNeededLocked() {
1800                // The version of all settings for a user is the same (all users have secure).
1801                SettingsState secureSettings = getSettingsLocked(
1802                        SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
1803
1804                // Try an update from the current state.
1805                final int oldVersion = secureSettings.getVersionLocked();
1806                final int newVersion = SETTINGS_VERSION;
1807
1808                // If up do date - done.
1809                if (oldVersion == newVersion) {
1810                    return;
1811                }
1812
1813                // Try to upgrade.
1814                final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
1815
1816                // If upgrade failed start from scratch and upgrade.
1817                if (curVersion != newVersion) {
1818                    // Drop state we have for this user.
1819                    removeUserStateLocked(mUserId, true);
1820
1821                    // Recreate the database.
1822                    DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
1823                    SQLiteDatabase database = dbHelper.getWritableDatabase();
1824                    dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
1825
1826                    // Migrate the settings for this user.
1827                    migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
1828
1829                    // Now upgrade should work fine.
1830                    onUpgradeLocked(mUserId, oldVersion, newVersion);
1831                }
1832
1833                // Set the global settings version if owner.
1834                if (mUserId == UserHandle.USER_OWNER) {
1835                    SettingsState globalSettings = getSettingsLocked(
1836                            SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
1837                    globalSettings.setVersionLocked(newVersion);
1838                }
1839
1840                // Set the secure settings version.
1841                secureSettings.setVersionLocked(newVersion);
1842
1843                // Set the system settings version.
1844                SettingsState systemSettings = getSettingsLocked(
1845                        SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
1846                systemSettings.setVersionLocked(newVersion);
1847            }
1848
1849            private SettingsState getGlobalSettingsLocked() {
1850                return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
1851            }
1852
1853            private SettingsState getSecureSettingsLocked(int userId) {
1854                return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
1855            }
1856
1857            private SettingsState getSystemSettingsLocked(int userId) {
1858                return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
1859            }
1860
1861            /**
1862             * You must perform all necessary mutations to bring the settings
1863             * for this user from the old to the new version. When you add a new
1864             * upgrade step you *must* update SETTINGS_VERSION.
1865             *
1866             * This is an example of moving a setting from secure to global.
1867             *
1868             * // v119: Example settings changes.
1869             * if (currentVersion == 118) {
1870             *     if (userId == UserHandle.USER_OWNER) {
1871             *         // Remove from the secure settings.
1872             *         SettingsState secureSettings = getSecureSettingsLocked(userId);
1873             *         String name = "example_setting_to_move";
1874             *         String value = secureSettings.getSetting(name);
1875             *         secureSettings.deleteSetting(name);
1876             *
1877             *         // Add to the global settings.
1878             *         SettingsState globalSettings = getGlobalSettingsLocked();
1879             *         globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
1880             *     }
1881             *
1882             *     // Update the current version.
1883             *     currentVersion = 119;
1884             * }
1885             */
1886            private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
1887                if (DEBUG) {
1888                    Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
1889                            + oldVersion + " to version: " + newVersion);
1890                }
1891
1892                int currentVersion = oldVersion;
1893
1894                // vXXX: Add new settings above this point.
1895
1896                // Return the current version.
1897                return currentVersion;
1898            }
1899        }
1900    }
1901}
1902