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