blob: fbf8a2bd952d666d3496b00ae1d51e6d14bebbe0 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
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
Svetoslav683914b2015-01-15 14:22:26 -080019import android.Manifest;
Christopher Tated5fe1472012-09-10 15:48:38 -070020import android.app.ActivityManager;
Xiaohui Chen43765b72015-08-31 10:57:33 -070021import android.app.AppGlobals;
Christopher Tate45281862010-03-05 15:46:30 -080022import android.app.backup.BackupManager;
Christopher Tate06efb532012-08-24 15:29:27 -070023import android.content.BroadcastReceiver;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.content.ContentProvider;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070025import android.content.ContentValues;
26import android.content.Context;
Christopher Tate06efb532012-08-24 15:29:27 -070027import android.content.Intent;
28import android.content.IntentFilter;
Svetoslav683914b2015-01-15 14:22:26 -080029import android.content.pm.ApplicationInfo;
Xiaohui Chen43765b72015-08-31 10:57:33 -070030import android.content.pm.IPackageManager;
Svetoslav683914b2015-01-15 14:22:26 -080031import android.content.pm.PackageInfo;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070032import android.content.pm.PackageManager;
Christopher Tate38e7a602013-09-03 16:57:34 -070033import android.content.pm.UserInfo;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070034import android.database.Cursor;
Svetoslav683914b2015-01-15 14:22:26 -080035import android.database.MatrixCursor;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036import android.database.sqlite.SQLiteDatabase;
37import android.database.sqlite.SQLiteQueryBuilder;
Svetoslav683914b2015-01-15 14:22:26 -080038import android.hardware.camera2.utils.ArrayUtils;
John Spurlocke11ae112015-05-11 16:09:03 -040039import android.media.AudioManager;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040import android.net.Uri;
Christopher Tate06efb532012-08-24 15:29:27 -070041import android.os.Binder;
Svetoslav683914b2015-01-15 14:22:26 -080042import android.os.Build;
Brad Fitzpatrick1877d012010-03-04 17:48:13 -080043import android.os.Bundle;
Amith Yamasani5cdf7f52013-06-27 15:12:01 -070044import android.os.DropBoxManager;
Svetoslav683914b2015-01-15 14:22:26 -080045import android.os.Environment;
Svetoslav7e0683b2015-08-03 16:02:52 -070046import android.os.Handler;
47import android.os.Looper;
48import android.os.Message;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070049import android.os.ParcelFileDescriptor;
Christopher Tate0da13572013-10-13 17:34:49 -070050import android.os.Process;
Xiaohui Chen43765b72015-08-31 10:57:33 -070051import android.os.RemoteException;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070052import android.os.SystemProperties;
Christopher Tate06efb532012-08-24 15:29:27 -070053import android.os.UserHandle;
54import android.os.UserManager;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070055import android.provider.Settings;
56import android.text.TextUtils;
Svetoslav683914b2015-01-15 14:22:26 -080057import android.util.ArraySet;
Christopher Tate06efb532012-08-24 15:29:27 -070058import android.util.Slog;
59import android.util.SparseArray;
John Spurlocke11ae112015-05-11 16:09:03 -040060
Svetoslav683914b2015-01-15 14:22:26 -080061import com.android.internal.annotations.GuardedBy;
62import com.android.internal.content.PackageMonitor;
63import com.android.internal.os.BackgroundThread;
John Spurlocke11ae112015-05-11 16:09:03 -040064
Svetoslav683914b2015-01-15 14:22:26 -080065import java.io.File;
Svetoslavb505ccc2015-02-17 12:41:04 -080066import java.io.FileDescriptor;
Svetoslav683914b2015-01-15 14:22:26 -080067import java.io.FileNotFoundException;
Svetoslavb505ccc2015-02-17 12:41:04 -080068import java.io.PrintWriter;
Svetoslav683914b2015-01-15 14:22:26 -080069import java.security.SecureRandom;
70import java.util.Arrays;
71import java.util.List;
Svetoslav683914b2015-01-15 14:22:26 -080072import java.util.Set;
73import java.util.regex.Pattern;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070074
Svetoslav683914b2015-01-15 14:22:26 -080075import com.android.providers.settings.SettingsState.Setting;
76
77/**
78 * <p>
79 * This class is a content provider that publishes the system settings.
80 * It can be accessed via the content provider APIs or via custom call
81 * commands. The latter is a bit faster and is the preferred way to access
82 * the platform settings.
83 * </p>
84 * <p>
85 * There are three settings types, global (with signature level protection
86 * and shared across users), secure (with signature permission level
87 * protection and per user), and system (with dangerous permission level
88 * protection and per user). Global settings are stored under the device owner.
89 * Each of these settings is represented by a {@link
90 * com.android.providers.settings.SettingsState} object mapped to an integer
91 * key derived from the setting type in the most significant bits and user
92 * id in the least significant bits. Settings are synchronously loaded on
93 * instantiation of a SettingsState and asynchronously persisted on mutation.
94 * Settings are stored in the user specific system directory.
95 * </p>
96 * <p>
97 * Apps targeting APIs Lollipop MR1 and lower can add custom settings entries
98 * and get a warning. Targeting higher API version prohibits this as the
99 * system settings are not a place for apps to save their state. When a package
100 * is removed the settings it added are deleted. Apps cannot delete system
101 * settings added by the platform. System settings values are validated to
102 * ensure the clients do not put bad values. Global and secure settings are
103 * changed only by trusted parties, therefore no validation is performed. Also
104 * there is a limit on the amount of app specific settings that can be added
105 * to prevent unlimited growth of the system process memory footprint.
106 * </p>
107 */
108@SuppressWarnings("deprecation")
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700109public class SettingsProvider extends ContentProvider {
Svetoslav683914b2015-01-15 14:22:26 -0800110 private static final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700111
Svetoslav683914b2015-01-15 14:22:26 -0800112 private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
113
114 private static final String LOG_TAG = "SettingsProvider";
Christopher Tate0da13572013-10-13 17:34:49 -0700115
Christopher Tate06efb532012-08-24 15:29:27 -0700116 private static final String TABLE_SYSTEM = "system";
117 private static final String TABLE_SECURE = "secure";
118 private static final String TABLE_GLOBAL = "global";
Svetoslav683914b2015-01-15 14:22:26 -0800119
120 // Old tables no longer exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private static final String TABLE_FAVORITES = "favorites";
122 private static final String TABLE_OLD_FAVORITES = "old_favorites";
Svetoslav683914b2015-01-15 14:22:26 -0800123 private static final String TABLE_BLUETOOTH_DEVICES = "bluetooth_devices";
124 private static final String TABLE_BOOKMARKS = "bookmarks";
125 private static final String TABLE_ANDROID_METADATA = "android_metadata";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
Svetoslav683914b2015-01-15 14:22:26 -0800127 // The set of removed legacy tables.
128 private static final Set<String> REMOVED_LEGACY_TABLES = new ArraySet<>();
Christopher Tate06efb532012-08-24 15:29:27 -0700129 static {
Svetoslav683914b2015-01-15 14:22:26 -0800130 REMOVED_LEGACY_TABLES.add(TABLE_FAVORITES);
131 REMOVED_LEGACY_TABLES.add(TABLE_OLD_FAVORITES);
132 REMOVED_LEGACY_TABLES.add(TABLE_BLUETOOTH_DEVICES);
133 REMOVED_LEGACY_TABLES.add(TABLE_BOOKMARKS);
134 REMOVED_LEGACY_TABLES.add(TABLE_ANDROID_METADATA);
135 }
Christopher Tate06efb532012-08-24 15:29:27 -0700136
Svetoslav683914b2015-01-15 14:22:26 -0800137 private static final int MUTATION_OPERATION_INSERT = 1;
138 private static final int MUTATION_OPERATION_DELETE = 2;
139 private static final int MUTATION_OPERATION_UPDATE = 3;
Julia Reynolds5e458dd2014-07-07 16:07:01 -0400140
Svetoslav683914b2015-01-15 14:22:26 -0800141 private static final String[] ALL_COLUMNS = new String[] {
142 Settings.NameValueTable._ID,
143 Settings.NameValueTable.NAME,
144 Settings.NameValueTable.VALUE
145 };
146
147 private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null);
148
Christopher Tate06efb532012-08-24 15:29:27 -0700149
Svetoslav683914b2015-01-15 14:22:26 -0800150 // Per user secure settings that moved to the for all users global settings.
151 static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
152 static {
153 Settings.Secure.getMovedToGlobalSettings(sSecureMovedToGlobalSettings);
Christopher Tate06efb532012-08-24 15:29:27 -0700154 }
155
Svetoslav683914b2015-01-15 14:22:26 -0800156 // Per user system settings that moved to the for all users global settings.
157 static final Set<String> sSystemMovedToGlobalSettings = new ArraySet<>();
158 static {
159 Settings.System.getMovedToGlobalSettings(sSystemMovedToGlobalSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 }
161
Svetoslav683914b2015-01-15 14:22:26 -0800162 // Per user system settings that moved to the per user secure settings.
163 static final Set<String> sSystemMovedToSecureSettings = new ArraySet<>();
164 static {
165 Settings.System.getMovedToSecureSettings(sSystemMovedToSecureSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700166 }
167
Svetoslav683914b2015-01-15 14:22:26 -0800168 // Per all users global settings that moved to the per user secure settings.
169 static final Set<String> sGlobalMovedToSecureSettings = new ArraySet<>();
170 static {
171 Settings.Global.getMovedToSecureSettings(sGlobalMovedToSecureSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700172 }
173
Svetoslav683914b2015-01-15 14:22:26 -0800174 // Per user secure settings that are cloned for the managed profiles of the user.
175 private static final Set<String> sSecureCloneToManagedSettings = new ArraySet<>();
176 static {
177 Settings.Secure.getCloneToManagedProfileSettings(sSecureCloneToManagedSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178 }
179
Svetoslav683914b2015-01-15 14:22:26 -0800180 // Per user system settings that are cloned for the managed profiles of the user.
181 private static final Set<String> sSystemCloneToManagedSettings = new ArraySet<>();
182 static {
183 Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings);
Julia Reynolds5e458dd2014-07-07 16:07:01 -0400184 }
185
Svetoslav683914b2015-01-15 14:22:26 -0800186 private final Object mLock = new Object();
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -0700187
Svetoslav683914b2015-01-15 14:22:26 -0800188 @GuardedBy("mLock")
189 private SettingsRegistry mSettingsRegistry;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -0700190
Svetoslav7ec28e82015-05-20 17:01:10 -0700191 // We have to call in the user manager with no lock held,
192 private volatile UserManager mUserManager;
Svetoslav683914b2015-01-15 14:22:26 -0800193
Svetoslav7ec28e82015-05-20 17:01:10 -0700194 // We have to call in the package manager with no lock held,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700195 private volatile IPackageManager mPackageManager;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -0700196
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700197 @Override
198 public boolean onCreate() {
Svetoslav683914b2015-01-15 14:22:26 -0800199 synchronized (mLock) {
Xiaohui Chen43765b72015-08-31 10:57:33 -0700200 mUserManager = UserManager.get(getContext());
201 mPackageManager = AppGlobals.getPackageManager();
Svetoslav683914b2015-01-15 14:22:26 -0800202 mSettingsRegistry = new SettingsRegistry();
203 }
204 registerBroadcastReceivers();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700205 return true;
206 }
207
Svetoslav683914b2015-01-15 14:22:26 -0800208 @Override
209 public Bundle call(String method, String name, Bundle args) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700210 final int requestingUserId = getRequestingUserId(args);
211 switch (method) {
212 case Settings.CALL_METHOD_GET_GLOBAL: {
213 Setting setting = getGlobalSetting(name);
214 return packageValueForCallResult(setting);
Svetoslav683914b2015-01-15 14:22:26 -0800215 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700216
217 case Settings.CALL_METHOD_GET_SECURE: {
218 Setting setting = getSecureSetting(name, requestingUserId);
219 return packageValueForCallResult(setting);
220 }
221
222 case Settings.CALL_METHOD_GET_SYSTEM: {
223 Setting setting = getSystemSetting(name, requestingUserId);
224 return packageValueForCallResult(setting);
225 }
226
227 case Settings.CALL_METHOD_PUT_GLOBAL: {
228 String value = getSettingValue(args);
229 insertGlobalSetting(name, value, requestingUserId);
230 break;
231 }
232
233 case Settings.CALL_METHOD_PUT_SECURE: {
234 String value = getSettingValue(args);
235 insertSecureSetting(name, value, requestingUserId);
236 break;
237 }
238
239 case Settings.CALL_METHOD_PUT_SYSTEM: {
240 String value = getSettingValue(args);
241 insertSystemSetting(name, value, requestingUserId);
242 break;
243 }
244
245 default: {
246 Slog.w(LOG_TAG, "call() with invalid method: " + method);
247 } break;
Christopher Tate06efb532012-08-24 15:29:27 -0700248 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700249
Christopher Tate06efb532012-08-24 15:29:27 -0700250 return null;
251 }
252
Brad Fitzpatrick1877d012010-03-04 17:48:13 -0800253 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800254 public String getType(Uri uri) {
255 Arguments args = new Arguments(uri, null, null, true);
256 if (TextUtils.isEmpty(args.name)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700257 return "vnd.android.cursor.dir/" + args.table;
258 } else {
Svetoslav7ec28e82015-05-20 17:01:10 -0700259 return "vnd.android.cursor.item/" + args.table;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700260 }
261 }
262
263 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800264 public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs,
265 String order) {
266 if (DEBUG) {
267 Slog.v(LOG_TAG, "query() for user: " + UserHandle.getCallingUserId());
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700268 }
269
Svetoslav683914b2015-01-15 14:22:26 -0800270 Arguments args = new Arguments(uri, where, whereArgs, true);
271 String[] normalizedProjection = normalizeProjection(projection);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700272
Svetoslav683914b2015-01-15 14:22:26 -0800273 // If a legacy table that is gone, done.
274 if (REMOVED_LEGACY_TABLES.contains(args.table)) {
275 return new MatrixCursor(normalizedProjection, 0);
276 }
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700277
Svetoslav7ec28e82015-05-20 17:01:10 -0700278 switch (args.table) {
279 case TABLE_GLOBAL: {
280 if (args.name != null) {
281 Setting setting = getGlobalSetting(args.name);
282 return packageSettingForQuery(setting, normalizedProjection);
283 } else {
284 return getAllGlobalSettings(projection);
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700285 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700286 }
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700287
Svetoslav7ec28e82015-05-20 17:01:10 -0700288 case TABLE_SECURE: {
289 final int userId = UserHandle.getCallingUserId();
290 if (args.name != null) {
291 Setting setting = getSecureSetting(args.name, userId);
292 return packageSettingForQuery(setting, normalizedProjection);
293 } else {
294 return getAllSecureSettings(userId, projection);
Svetoslav683914b2015-01-15 14:22:26 -0800295 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700296 }
Svetoslav683914b2015-01-15 14:22:26 -0800297
Svetoslav7ec28e82015-05-20 17:01:10 -0700298 case TABLE_SYSTEM: {
299 final int userId = UserHandle.getCallingUserId();
300 if (args.name != null) {
301 Setting setting = getSystemSetting(args.name, userId);
302 return packageSettingForQuery(setting, normalizedProjection);
303 } else {
304 return getAllSystemSettings(userId, projection);
Svetoslav683914b2015-01-15 14:22:26 -0800305 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700306 }
Svetoslav683914b2015-01-15 14:22:26 -0800307
Svetoslav7ec28e82015-05-20 17:01:10 -0700308 default: {
309 throw new IllegalArgumentException("Invalid Uri path:" + uri);
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700310 }
311 }
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700312 }
313
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700314 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800315 public Uri insert(Uri uri, ContentValues values) {
316 if (DEBUG) {
317 Slog.v(LOG_TAG, "insert() for user: " + UserHandle.getCallingUserId());
Christopher Tate06efb532012-08-24 15:29:27 -0700318 }
319
Svetoslav683914b2015-01-15 14:22:26 -0800320 String table = getValidTableOrThrow(uri);
Christopher Tate06efb532012-08-24 15:29:27 -0700321
Svetoslav683914b2015-01-15 14:22:26 -0800322 // If a legacy table that is gone, done.
323 if (REMOVED_LEGACY_TABLES.contains(table)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 return null;
325 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700326
Svetoslav683914b2015-01-15 14:22:26 -0800327 String name = values.getAsString(Settings.Secure.NAME);
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700328 if (!isKeyValid(name)) {
Svetoslav683914b2015-01-15 14:22:26 -0800329 return null;
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700330 }
331
Svetoslav683914b2015-01-15 14:22:26 -0800332 String value = values.getAsString(Settings.Secure.VALUE);
333
Svetoslav7ec28e82015-05-20 17:01:10 -0700334 switch (table) {
335 case TABLE_GLOBAL: {
336 if (insertGlobalSetting(name, value, UserHandle.getCallingUserId())) {
337 return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
Christopher Tatec221d2b2012-10-03 18:33:52 -0700338 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700339 } break;
340
341 case TABLE_SECURE: {
342 if (insertSecureSetting(name, value, UserHandle.getCallingUserId())) {
343 return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
344 }
345 } break;
346
347 case TABLE_SYSTEM: {
348 if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) {
349 return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
350 }
351 } break;
352
353 default: {
354 throw new IllegalArgumentException("Bad Uri path:" + uri);
Christopher Tatec221d2b2012-10-03 18:33:52 -0700355 }
356 }
357
Svetoslav683914b2015-01-15 14:22:26 -0800358 return null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700359 }
360
361 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800362 public int bulkInsert(Uri uri, ContentValues[] allValues) {
363 if (DEBUG) {
364 Slog.v(LOG_TAG, "bulkInsert() for user: " + UserHandle.getCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700366
Svetoslav683914b2015-01-15 14:22:26 -0800367 int insertionCount = 0;
368 final int valuesCount = allValues.length;
369 for (int i = 0; i < valuesCount; i++) {
370 ContentValues values = allValues[i];
371 if (insert(uri, values) != null) {
372 insertionCount++;
373 }
Dianne Hackborn8d051722014-10-01 14:59:58 -0700374 }
Svetoslav683914b2015-01-15 14:22:26 -0800375
376 return insertionCount;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700377 }
378
379 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800380 public int delete(Uri uri, String where, String[] whereArgs) {
381 if (DEBUG) {
382 Slog.v(LOG_TAG, "delete() for user: " + UserHandle.getCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700384
Svetoslav683914b2015-01-15 14:22:26 -0800385 Arguments args = new Arguments(uri, where, whereArgs, false);
386
387 // If a legacy table that is gone, done.
388 if (REMOVED_LEGACY_TABLES.contains(args.table)) {
389 return 0;
Dianne Hackborn8d051722014-10-01 14:59:58 -0700390 }
Svetoslav683914b2015-01-15 14:22:26 -0800391
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700392 if (!isKeyValid(args.name)) {
Svetoslav683914b2015-01-15 14:22:26 -0800393 return 0;
Dianne Hackborn8d051722014-10-01 14:59:58 -0700394 }
Svetoslav683914b2015-01-15 14:22:26 -0800395
Svetoslav7ec28e82015-05-20 17:01:10 -0700396 switch (args.table) {
397 case TABLE_GLOBAL: {
398 final int userId = UserHandle.getCallingUserId();
399 return deleteGlobalSetting(args.name, userId) ? 1 : 0;
400 }
Svetoslav683914b2015-01-15 14:22:26 -0800401
Svetoslav7ec28e82015-05-20 17:01:10 -0700402 case TABLE_SECURE: {
403 final int userId = UserHandle.getCallingUserId();
404 return deleteSecureSetting(args.name, userId) ? 1 : 0;
405 }
Svetoslav683914b2015-01-15 14:22:26 -0800406
Svetoslav7ec28e82015-05-20 17:01:10 -0700407 case TABLE_SYSTEM: {
408 final int userId = UserHandle.getCallingUserId();
409 return deleteSystemSetting(args.name, userId) ? 1 : 0;
410 }
411
412 default: {
413 throw new IllegalArgumentException("Bad Uri path:" + uri);
Svetoslav683914b2015-01-15 14:22:26 -0800414 }
Dianne Hackborn8d051722014-10-01 14:59:58 -0700415 }
Svetoslav683914b2015-01-15 14:22:26 -0800416 }
417
418 @Override
419 public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
420 if (DEBUG) {
421 Slog.v(LOG_TAG, "update() for user: " + UserHandle.getCallingUserId());
Christopher Tate06efb532012-08-24 15:29:27 -0700422 }
Svetoslav683914b2015-01-15 14:22:26 -0800423
424 Arguments args = new Arguments(uri, where, whereArgs, false);
425
426 // If a legacy table that is gone, done.
427 if (REMOVED_LEGACY_TABLES.contains(args.table)) {
428 return 0;
429 }
430
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700431 String name = values.getAsString(Settings.Secure.NAME);
432 if (!isKeyValid(name)) {
Svetoslav683914b2015-01-15 14:22:26 -0800433 return 0;
434 }
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700435 String value = values.getAsString(Settings.Secure.VALUE);
Svetoslav683914b2015-01-15 14:22:26 -0800436
Svetoslav7ec28e82015-05-20 17:01:10 -0700437 switch (args.table) {
438 case TABLE_GLOBAL: {
439 final int userId = UserHandle.getCallingUserId();
440 return updateGlobalSetting(args.name, value, userId) ? 1 : 0;
441 }
Svetoslav683914b2015-01-15 14:22:26 -0800442
Svetoslav7ec28e82015-05-20 17:01:10 -0700443 case TABLE_SECURE: {
444 final int userId = UserHandle.getCallingUserId();
445 return updateSecureSetting(args.name, value, userId) ? 1 : 0;
446 }
Svetoslav683914b2015-01-15 14:22:26 -0800447
Svetoslav7ec28e82015-05-20 17:01:10 -0700448 case TABLE_SYSTEM: {
449 final int userId = UserHandle.getCallingUserId();
450 return updateSystemSetting(args.name, value, userId) ? 1 : 0;
451 }
Svetoslav683914b2015-01-15 14:22:26 -0800452
Svetoslav7ec28e82015-05-20 17:01:10 -0700453 default: {
454 throw new IllegalArgumentException("Invalid Uri path:" + uri);
Svetoslav683914b2015-01-15 14:22:26 -0800455 }
456 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700457 }
458
459 @Override
460 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
Jeff Sharkey3b566b82014-11-12 10:39:56 -0800461 throw new FileNotFoundException("Direct file access no longer supported; "
462 + "ringtone playback is available through android.media.Ringtone");
Marco Nelissen69f593c2009-07-28 09:55:04 -0700463 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -0800464
Svetoslavb505ccc2015-02-17 12:41:04 -0800465 @Override
466 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
467 synchronized (mLock) {
468 final long identity = Binder.clearCallingIdentity();
469 try {
470 List<UserInfo> users = mUserManager.getUsers(true);
471 final int userCount = users.size();
472 for (int i = 0; i < userCount; i++) {
473 UserInfo user = users.get(i);
474 dumpForUser(user.id, pw);
475 }
476 } finally {
477 Binder.restoreCallingIdentity(identity);
478 }
479 }
480 }
481
482 private void dumpForUser(int userId, PrintWriter pw) {
Xiaohui Chen43765b72015-08-31 10:57:33 -0700483 if (userId == UserHandle.USER_SYSTEM) {
Svetoslavb505ccc2015-02-17 12:41:04 -0800484 pw.println("GLOBAL SETTINGS (user " + userId + ")");
Svetoslav7ec28e82015-05-20 17:01:10 -0700485 Cursor globalCursor = getAllGlobalSettings(ALL_COLUMNS);
Svetoslavb505ccc2015-02-17 12:41:04 -0800486 dumpSettings(globalCursor, pw);
487 pw.println();
488 }
489
490 pw.println("SECURE SETTINGS (user " + userId + ")");
Svetoslav7ec28e82015-05-20 17:01:10 -0700491 Cursor secureCursor = getAllSecureSettings(userId, ALL_COLUMNS);
Svetoslavb505ccc2015-02-17 12:41:04 -0800492 dumpSettings(secureCursor, pw);
493 pw.println();
494
495 pw.println("SYSTEM SETTINGS (user " + userId + ")");
Svetoslav7ec28e82015-05-20 17:01:10 -0700496 Cursor systemCursor = getAllSystemSettings(userId, ALL_COLUMNS);
Svetoslavb505ccc2015-02-17 12:41:04 -0800497 dumpSettings(systemCursor, pw);
498 pw.println();
499 }
500
501 private void dumpSettings(Cursor cursor, PrintWriter pw) {
Fyodor Kupolov1f450db2015-06-11 15:25:59 -0700502 if (cursor == null || !cursor.moveToFirst()) {
Svetoslavb505ccc2015-02-17 12:41:04 -0800503 return;
504 }
505
506 final int idColumnIdx = cursor.getColumnIndex(Settings.NameValueTable._ID);
507 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
508 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
509
510 do {
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700511 pw.append("_id:").append(toDumpString(cursor.getString(idColumnIdx)));
512 pw.append(" name:").append(toDumpString(cursor.getString(nameColumnIdx)));
513 pw.append(" value:").append(toDumpString(cursor.getString(valueColumnIdx)));
Svetoslavb505ccc2015-02-17 12:41:04 -0800514 pw.println();
515 } while (cursor.moveToNext());
516 }
517
Svetoslav7e0683b2015-08-03 16:02:52 -0700518 private static String toDumpString(String s) {
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700519 if (s != null) {
520 return s;
521 }
522 return "{null}";
523 }
524
Svetoslav683914b2015-01-15 14:22:26 -0800525 private void registerBroadcastReceivers() {
526 IntentFilter userFilter = new IntentFilter();
527 userFilter.addAction(Intent.ACTION_USER_REMOVED);
528 userFilter.addAction(Intent.ACTION_USER_STOPPED);
529
530 getContext().registerReceiver(new BroadcastReceiver() {
531 @Override
532 public void onReceive(Context context, Intent intent) {
533 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700534 UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -0800535
536 switch (intent.getAction()) {
537 case Intent.ACTION_USER_REMOVED: {
538 mSettingsRegistry.removeUserStateLocked(userId, true);
539 } break;
540
541 case Intent.ACTION_USER_STOPPED: {
542 mSettingsRegistry.removeUserStateLocked(userId, false);
543 } break;
544 }
545 }
546 }, userFilter);
547
548 PackageMonitor monitor = new PackageMonitor() {
549 @Override
550 public void onPackageRemoved(String packageName, int uid) {
551 synchronized (mLock) {
552 mSettingsRegistry.onPackageRemovedLocked(packageName,
553 UserHandle.getUserId(uid));
554 }
555 }
556 };
557
558 // package changes
559 monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
560 UserHandle.ALL, true);
561 }
562
Svetoslav7ec28e82015-05-20 17:01:10 -0700563 private Cursor getAllGlobalSettings(String[] projection) {
Svetoslav683914b2015-01-15 14:22:26 -0800564 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700565 Slog.v(LOG_TAG, "getAllGlobalSettings()");
Svetoslav683914b2015-01-15 14:22:26 -0800566 }
567
Svetoslav7ec28e82015-05-20 17:01:10 -0700568 synchronized (mLock) {
569 // Get the settings.
570 SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
Xiaohui Chen43765b72015-08-31 10:57:33 -0700571 SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -0800572
Svetoslav7ec28e82015-05-20 17:01:10 -0700573 List<String> names = settingsState.getSettingNamesLocked();
Svetoslav683914b2015-01-15 14:22:26 -0800574
Svetoslav7ec28e82015-05-20 17:01:10 -0700575 final int nameCount = names.size();
Svetoslav683914b2015-01-15 14:22:26 -0800576
Svetoslav7ec28e82015-05-20 17:01:10 -0700577 String[] normalizedProjection = normalizeProjection(projection);
578 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
Svetoslav683914b2015-01-15 14:22:26 -0800579
Svetoslav7ec28e82015-05-20 17:01:10 -0700580 // Anyone can get the global settings, so no security checks.
581 for (int i = 0; i < nameCount; i++) {
582 String name = names.get(i);
583 Setting setting = settingsState.getSettingLocked(name);
584 appendSettingToCursor(result, setting);
585 }
586
587 return result;
Svetoslav683914b2015-01-15 14:22:26 -0800588 }
Svetoslav683914b2015-01-15 14:22:26 -0800589 }
590
Svetoslav7ec28e82015-05-20 17:01:10 -0700591 private Setting getGlobalSetting(String name) {
Svetoslav683914b2015-01-15 14:22:26 -0800592 if (DEBUG) {
593 Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
594 }
595
596 // Get the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700597 synchronized (mLock) {
598 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700599 UserHandle.USER_SYSTEM, name);
Svetoslav683914b2015-01-15 14:22:26 -0800600 }
Svetoslav683914b2015-01-15 14:22:26 -0800601 }
602
Svetoslav7ec28e82015-05-20 17:01:10 -0700603 private boolean updateGlobalSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800604 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700605 Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800606 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700607 return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
Svetoslav683914b2015-01-15 14:22:26 -0800608 }
609
Svetoslav7ec28e82015-05-20 17:01:10 -0700610 private boolean insertGlobalSetting(String name, String value, int requestingUserId) {
611 if (DEBUG) {
612 Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ")");
613 }
614 return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
615 }
616
617 private boolean deleteGlobalSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800618 if (DEBUG) {
619 Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
620 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700621 return mutateGlobalSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
Svetoslav683914b2015-01-15 14:22:26 -0800622 }
623
Svetoslav7ec28e82015-05-20 17:01:10 -0700624 private boolean mutateGlobalSetting(String name, String value, int requestingUserId,
Svetoslav683914b2015-01-15 14:22:26 -0800625 int operation) {
626 // Make sure the caller can change the settings - treated as secure.
627 enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
628
Svetoslav683914b2015-01-15 14:22:26 -0800629 // Resolve the userId on whose behalf the call is made.
630 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
631
Makoto Onuki28da2e32015-11-20 11:30:44 -0800632 // If this is a setting that is currently restricted for this user, do not allow
633 // unrestricting changes.
634 if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
Svetoslav683914b2015-01-15 14:22:26 -0800635 return false;
636 }
637
638 // Perform the mutation.
Svetoslav7ec28e82015-05-20 17:01:10 -0700639 synchronized (mLock) {
640 switch (operation) {
641 case MUTATION_OPERATION_INSERT: {
642 return mSettingsRegistry
643 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700644 UserHandle.USER_SYSTEM, name, value, getCallingPackage());
Svetoslav7ec28e82015-05-20 17:01:10 -0700645 }
Svetoslav683914b2015-01-15 14:22:26 -0800646
Svetoslav7ec28e82015-05-20 17:01:10 -0700647 case MUTATION_OPERATION_DELETE: {
648 return mSettingsRegistry.deleteSettingLocked(
649 SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700650 UserHandle.USER_SYSTEM, name);
Svetoslav7ec28e82015-05-20 17:01:10 -0700651 }
Svetoslav683914b2015-01-15 14:22:26 -0800652
Svetoslav7ec28e82015-05-20 17:01:10 -0700653 case MUTATION_OPERATION_UPDATE: {
654 return mSettingsRegistry
655 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700656 UserHandle.USER_SYSTEM, name, value, getCallingPackage());
Svetoslav7ec28e82015-05-20 17:01:10 -0700657 }
Svetoslav683914b2015-01-15 14:22:26 -0800658 }
659 }
660
661 return false;
662 }
663
Svetoslav7ec28e82015-05-20 17:01:10 -0700664 private Cursor getAllSecureSettings(int userId, String[] projection) {
Svetoslav683914b2015-01-15 14:22:26 -0800665 if (DEBUG) {
666 Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
667 }
668
669 // Resolve the userId on whose behalf the call is made.
670 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
671
Svetoslav7ec28e82015-05-20 17:01:10 -0700672 synchronized (mLock) {
673 List<String> names = mSettingsRegistry.getSettingsNamesLocked(
674 SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
Svetoslav683914b2015-01-15 14:22:26 -0800675
Svetoslav7ec28e82015-05-20 17:01:10 -0700676 final int nameCount = names.size();
Svetoslav683914b2015-01-15 14:22:26 -0800677
Svetoslav7ec28e82015-05-20 17:01:10 -0700678 String[] normalizedProjection = normalizeProjection(projection);
679 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
Svetoslav683914b2015-01-15 14:22:26 -0800680
Svetoslav7ec28e82015-05-20 17:01:10 -0700681 for (int i = 0; i < nameCount; i++) {
682 String name = names.get(i);
683 // Determine the owning user as some profile settings are cloned from the parent.
684 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
685 name);
Svetoslav683914b2015-01-15 14:22:26 -0800686
Svetoslav7ec28e82015-05-20 17:01:10 -0700687 // Special case for location (sigh).
688 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
689 return null;
690 }
Svetoslav683914b2015-01-15 14:22:26 -0800691
Svetoslav7ec28e82015-05-20 17:01:10 -0700692 Setting setting = mSettingsRegistry.getSettingLocked(
693 SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
694 appendSettingToCursor(result, setting);
Svetoslav683914b2015-01-15 14:22:26 -0800695 }
696
Svetoslav7ec28e82015-05-20 17:01:10 -0700697 return result;
Svetoslav683914b2015-01-15 14:22:26 -0800698 }
Svetoslav683914b2015-01-15 14:22:26 -0800699 }
700
Svetoslav7ec28e82015-05-20 17:01:10 -0700701 private Setting getSecureSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800702 if (DEBUG) {
703 Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
704 }
705
706 // Resolve the userId on whose behalf the call is made.
707 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
708
709 // Determine the owning user as some profile settings are cloned from the parent.
710 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
711
712 // Special case for location (sigh).
713 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
714 return null;
715 }
716
717 // Get the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700718 synchronized (mLock) {
719 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
720 owningUserId, name);
721 }
Svetoslav683914b2015-01-15 14:22:26 -0800722 }
723
Svetoslav7ec28e82015-05-20 17:01:10 -0700724 private boolean insertSecureSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800725 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700726 Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800727 + requestingUserId + ")");
728 }
729
Svetoslav7ec28e82015-05-20 17:01:10 -0700730 return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
Svetoslav683914b2015-01-15 14:22:26 -0800731 }
732
Svetoslav7ec28e82015-05-20 17:01:10 -0700733 private boolean deleteSecureSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800734 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700735 Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800736 }
737
Svetoslav7ec28e82015-05-20 17:01:10 -0700738 return mutateSecureSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
Svetoslav683914b2015-01-15 14:22:26 -0800739 }
740
Svetoslav7ec28e82015-05-20 17:01:10 -0700741 private boolean updateSecureSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800742 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700743 Slog.v(LOG_TAG, "updateSecureSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800744 + requestingUserId + ")");
745 }
746
Svetoslav7ec28e82015-05-20 17:01:10 -0700747 return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
Svetoslav683914b2015-01-15 14:22:26 -0800748 }
749
Svetoslav7ec28e82015-05-20 17:01:10 -0700750 private boolean mutateSecureSetting(String name, String value, int requestingUserId,
Svetoslav683914b2015-01-15 14:22:26 -0800751 int operation) {
752 // Make sure the caller can change the settings.
753 enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
754
Svetoslav683914b2015-01-15 14:22:26 -0800755 // Resolve the userId on whose behalf the call is made.
756 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
757
Makoto Onuki28da2e32015-11-20 11:30:44 -0800758 // If this is a setting that is currently restricted for this user, do not allow
759 // unrestricting changes.
760 if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
Svetoslav683914b2015-01-15 14:22:26 -0800761 return false;
762 }
763
764 // Determine the owning user as some profile settings are cloned from the parent.
765 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
766
767 // Only the owning user can change the setting.
768 if (owningUserId != callingUserId) {
769 return false;
770 }
771
772 // Special cases for location providers (sigh).
773 if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
Svetoslavb596a2c2015-02-17 21:37:09 -0800774 return updateLocationProvidersAllowedLocked(value, owningUserId);
Svetoslav683914b2015-01-15 14:22:26 -0800775 }
776
777 // Mutate the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700778 synchronized (mLock) {
779 switch (operation) {
780 case MUTATION_OPERATION_INSERT: {
781 return mSettingsRegistry
782 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
783 owningUserId, name, value, getCallingPackage());
784 }
Svetoslav683914b2015-01-15 14:22:26 -0800785
Svetoslav7ec28e82015-05-20 17:01:10 -0700786 case MUTATION_OPERATION_DELETE: {
787 return mSettingsRegistry.deleteSettingLocked(
788 SettingsRegistry.SETTINGS_TYPE_SECURE,
789 owningUserId, name);
790 }
Svetoslav683914b2015-01-15 14:22:26 -0800791
Svetoslav7ec28e82015-05-20 17:01:10 -0700792 case MUTATION_OPERATION_UPDATE: {
793 return mSettingsRegistry
794 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
795 owningUserId, name, value, getCallingPackage());
796 }
Svetoslav683914b2015-01-15 14:22:26 -0800797 }
798 }
799
800 return false;
801 }
802
Svetoslav7ec28e82015-05-20 17:01:10 -0700803 private Cursor getAllSystemSettings(int userId, String[] projection) {
Svetoslav683914b2015-01-15 14:22:26 -0800804 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700805 Slog.v(LOG_TAG, "getAllSecureSystem(" + userId + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800806 }
807
808 // Resolve the userId on whose behalf the call is made.
809 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
810
Svetoslav7ec28e82015-05-20 17:01:10 -0700811 synchronized (mLock) {
812 List<String> names = mSettingsRegistry.getSettingsNamesLocked(
813 SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
Svetoslav683914b2015-01-15 14:22:26 -0800814
Svetoslav7ec28e82015-05-20 17:01:10 -0700815 final int nameCount = names.size();
Svetoslav683914b2015-01-15 14:22:26 -0800816
Svetoslav7ec28e82015-05-20 17:01:10 -0700817 String[] normalizedProjection = normalizeProjection(projection);
818 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
Svetoslav683914b2015-01-15 14:22:26 -0800819
Svetoslav7ec28e82015-05-20 17:01:10 -0700820 for (int i = 0; i < nameCount; i++) {
821 String name = names.get(i);
Svetoslav683914b2015-01-15 14:22:26 -0800822
Svetoslav7ec28e82015-05-20 17:01:10 -0700823 // Determine the owning user as some profile settings are cloned from the parent.
824 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId,
825 name);
Svetoslav683914b2015-01-15 14:22:26 -0800826
Svetoslav7ec28e82015-05-20 17:01:10 -0700827 Setting setting = mSettingsRegistry.getSettingLocked(
828 SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
829 appendSettingToCursor(result, setting);
830 }
831
832 return result;
Svetoslav683914b2015-01-15 14:22:26 -0800833 }
Svetoslav683914b2015-01-15 14:22:26 -0800834 }
835
Svetoslav7ec28e82015-05-20 17:01:10 -0700836 private Setting getSystemSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800837 if (DEBUG) {
838 Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")");
839 }
840
841 // Resolve the userId on whose behalf the call is made.
842 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
843
844 // Determine the owning user as some profile settings are cloned from the parent.
845 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
846
847 // Get the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700848 synchronized (mLock) {
849 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
850 owningUserId, name);
851 }
Svetoslav683914b2015-01-15 14:22:26 -0800852 }
853
Svetoslav7ec28e82015-05-20 17:01:10 -0700854 private boolean insertSystemSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800855 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700856 Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800857 + requestingUserId + ")");
858 }
859
Svetoslav7ec28e82015-05-20 17:01:10 -0700860 return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
Svetoslav683914b2015-01-15 14:22:26 -0800861 }
862
Svetoslav7ec28e82015-05-20 17:01:10 -0700863 private boolean deleteSystemSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800864 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700865 Slog.v(LOG_TAG, "deleteSystemSetting(" + name + ", " + requestingUserId + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800866 }
867
Svetoslav7ec28e82015-05-20 17:01:10 -0700868 return mutateSystemSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
Svetoslav683914b2015-01-15 14:22:26 -0800869 }
870
Svetoslav7ec28e82015-05-20 17:01:10 -0700871 private boolean updateSystemSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800872 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700873 Slog.v(LOG_TAG, "updateSystemSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800874 + requestingUserId + ")");
875 }
876
Svetoslav7ec28e82015-05-20 17:01:10 -0700877 return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
Svetoslav683914b2015-01-15 14:22:26 -0800878 }
879
Svetoslav7ec28e82015-05-20 17:01:10 -0700880 private boolean mutateSystemSetting(String name, String value, int runAsUserId,
Svetoslav683914b2015-01-15 14:22:26 -0800881 int operation) {
Billy Lau6ad2d662015-07-18 00:26:58 +0100882 if (!hasWriteSecureSettingsPermission()) {
883 // If the caller doesn't hold WRITE_SECURE_SETTINGS, we verify whether this
884 // operation is allowed for the calling package through appops.
885 if (!Settings.checkAndNoteWriteSettingsOperation(getContext(),
886 Binder.getCallingUid(), getCallingPackage(), true)) {
887 return false;
888 }
Svetoslav683914b2015-01-15 14:22:26 -0800889 }
890
Svetoslav683914b2015-01-15 14:22:26 -0800891 // Resolve the userId on whose behalf the call is made.
892 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
893
Svetoslavd8d25e02015-11-20 13:09:26 -0800894 // Enforce what the calling package can mutate the system settings.
895 enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name, callingUserId);
896
Svetoslav683914b2015-01-15 14:22:26 -0800897 // Determine the owning user as some profile settings are cloned from the parent.
898 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
899
900 // Only the owning user id can change the setting.
901 if (owningUserId != callingUserId) {
902 return false;
903 }
904
905 // Mutate the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700906 synchronized (mLock) {
907 switch (operation) {
908 case MUTATION_OPERATION_INSERT: {
909 validateSystemSettingValue(name, value);
910 return mSettingsRegistry
911 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
912 owningUserId, name, value, getCallingPackage());
913 }
914
915 case MUTATION_OPERATION_DELETE: {
916 return mSettingsRegistry.deleteSettingLocked(
917 SettingsRegistry.SETTINGS_TYPE_SYSTEM,
918 owningUserId, name);
919 }
920
921 case MUTATION_OPERATION_UPDATE: {
922 validateSystemSettingValue(name, value);
923 return mSettingsRegistry
924 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
925 owningUserId, name, value, getCallingPackage());
926 }
Svetoslav683914b2015-01-15 14:22:26 -0800927 }
928
Svetoslav7ec28e82015-05-20 17:01:10 -0700929 return false;
Svetoslav683914b2015-01-15 14:22:26 -0800930 }
Svetoslav683914b2015-01-15 14:22:26 -0800931 }
932
Billy Lau6ad2d662015-07-18 00:26:58 +0100933 private boolean hasWriteSecureSettingsPermission() {
Svetoslavf41334b2015-06-23 12:06:03 -0700934 // Write secure settings is a more protected permission. If caller has it we are good.
935 if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
936 == PackageManager.PERMISSION_GRANTED) {
937 return true;
938 }
939
Svetoslavf41334b2015-06-23 12:06:03 -0700940 return false;
941 }
942
Svetoslav683914b2015-01-15 14:22:26 -0800943 private void validateSystemSettingValue(String name, String value) {
944 Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
945 if (validator != null && !validator.validate(value)) {
946 throw new IllegalArgumentException("Invalid value: " + value
947 + " for setting: " + name);
948 }
949 }
950
951 private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId,
952 int owningUserId) {
953 // Optimization - location providers are restricted only for managed profiles.
954 if (callingUserId == owningUserId) {
955 return false;
956 }
957 if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)
958 && mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
959 new UserHandle(callingUserId))) {
960 return true;
961 }
962 return false;
963 }
964
Makoto Onuki28da2e32015-11-20 11:30:44 -0800965 /**
966 * Checks whether changing a setting to a value is prohibited by the corresponding user
967 * restriction.
968 *
969 * <p>See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestrictionLR},
970 * which should be in sync with this method.
971 *
972 * @return true if the change is prohibited, false if the change is allowed.
973 */
974 private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
975 String value) {
976 String restriction;
977 switch (setting) {
978 case Settings.Secure.LOCATION_MODE:
979 // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
980 // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come
981 // here normally, but we still protect it here from a direct provider write.
982 if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) return false;
983 restriction = UserManager.DISALLOW_SHARE_LOCATION;
984 break;
985
986 case Settings.Secure.LOCATION_PROVIDERS_ALLOWED:
987 // See SettingsProvider.updateLocationProvidersAllowedLocked. "-" is to disable
988 // a provider, which should be allowed even if the user restriction is set.
989 if (value != null && value.startsWith("-")) return false;
990 restriction = UserManager.DISALLOW_SHARE_LOCATION;
991 break;
992
993 case Settings.Secure.INSTALL_NON_MARKET_APPS:
994 if ("0".equals(value)) return false;
995 restriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
996 break;
997
998 case Settings.Global.ADB_ENABLED:
999 if ("0".equals(value)) return false;
1000 restriction = UserManager.DISALLOW_DEBUGGING_FEATURES;
1001 break;
1002
1003 case Settings.Global.PACKAGE_VERIFIER_ENABLE:
1004 case Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB:
1005 if ("1".equals(value)) return false;
1006 restriction = UserManager.ENSURE_VERIFY_APPS;
1007 break;
1008
1009 case Settings.Global.PREFERRED_NETWORK_MODE:
1010 restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
1011 break;
1012
1013 default:
1014 return false;
Svetoslav683914b2015-01-15 14:22:26 -08001015 }
Makoto Onuki28da2e32015-11-20 11:30:44 -08001016
1017 return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
Svetoslav683914b2015-01-15 14:22:26 -08001018 }
1019
1020 private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
1021 return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting);
1022 }
1023
1024 private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
1025 return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
1026 }
1027
1028 private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) {
1029 final int parentId = getGroupParentLocked(userId);
1030 if (parentId != userId && keys.contains(name)) {
1031 return parentId;
1032 }
1033 return userId;
1034 }
1035
Svetoslavf41334b2015-06-23 12:06:03 -07001036 private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
Xiaohui Chen43765b72015-08-31 10:57:33 -07001037 String name, int userId) {
Svetoslav683914b2015-01-15 14:22:26 -08001038 // System/root/shell can mutate whatever secure settings they want.
1039 final int callingUid = Binder.getCallingUid();
1040 if (callingUid == android.os.Process.SYSTEM_UID
1041 || callingUid == Process.SHELL_UID
1042 || callingUid == Process.ROOT_UID) {
1043 return;
1044 }
1045
1046 switch (operation) {
1047 case MUTATION_OPERATION_INSERT:
1048 // Insert updates.
1049 case MUTATION_OPERATION_UPDATE: {
1050 if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
1051 return;
1052 }
1053
1054 // The calling package is already verified.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001055 PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
Svetoslav683914b2015-01-15 14:22:26 -08001056
1057 // Privileged apps can do whatever they want.
1058 if ((packageInfo.applicationInfo.privateFlags
1059 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1060 return;
1061 }
1062
1063 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1064 packageInfo.applicationInfo.targetSdkVersion, name);
1065 } break;
1066
1067 case MUTATION_OPERATION_DELETE: {
1068 if (Settings.System.PUBLIC_SETTINGS.contains(name)
1069 || Settings.System.PRIVATE_SETTINGS.contains(name)) {
1070 throw new IllegalArgumentException("You cannot delete system defined"
1071 + " secure settings.");
1072 }
1073
1074 // The calling package is already verified.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001075 PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
Svetoslav683914b2015-01-15 14:22:26 -08001076
1077 // Privileged apps can do whatever they want.
1078 if ((packageInfo.applicationInfo.privateFlags &
1079 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1080 return;
1081 }
1082
1083 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1084 packageInfo.applicationInfo.targetSdkVersion, name);
1085 } break;
1086 }
1087 }
1088
Xiaohui Chen43765b72015-08-31 10:57:33 -07001089 private PackageInfo getCallingPackageInfoOrThrow(int userId) {
Svetoslav683914b2015-01-15 14:22:26 -08001090 try {
Xiaohui Chen43765b72015-08-31 10:57:33 -07001091 return mPackageManager.getPackageInfo(getCallingPackage(), 0, userId);
1092 } catch (RemoteException e) {
Svetoslav683914b2015-01-15 14:22:26 -08001093 throw new IllegalStateException("Calling package doesn't exist");
1094 }
1095 }
1096
1097 private int getGroupParentLocked(int userId) {
1098 // Most frequent use case.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001099 if (userId == UserHandle.USER_SYSTEM) {
Svetoslav683914b2015-01-15 14:22:26 -08001100 return userId;
1101 }
1102 // We are in the same process with the user manager and the returned
1103 // user info is a cached instance, so just look up instead of cache.
1104 final long identity = Binder.clearCallingIdentity();
1105 try {
Svetoslav7ec28e82015-05-20 17:01:10 -07001106 // Just a lookup and not reentrant, so holding a lock is fine.
Svetoslav683914b2015-01-15 14:22:26 -08001107 UserInfo userInfo = mUserManager.getProfileParent(userId);
1108 return (userInfo != null) ? userInfo.id : userId;
1109 } finally {
1110 Binder.restoreCallingIdentity(identity);
1111 }
1112 }
1113
Svetoslav683914b2015-01-15 14:22:26 -08001114 private void enforceWritePermission(String permission) {
1115 if (getContext().checkCallingOrSelfPermission(permission)
1116 != PackageManager.PERMISSION_GRANTED) {
1117 throw new SecurityException("Permission denial: writing to settings requires:"
1118 + permission);
1119 }
1120 }
1121
1122 /*
1123 * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
1124 * This setting contains a list of the currently enabled location providers.
1125 * But helper functions in android.providers.Settings can enable or disable
1126 * a single provider by using a "+" or "-" prefix before the provider name.
1127 *
Makoto Onuki28da2e32015-11-20 11:30:44 -08001128 * <p>See also {@link #isGlobalOrSecureSettingRestrictedForUser()}. If DISALLOW_SHARE_LOCATION
1129 * is set, the said method will only allow values with the "-" prefix.
1130 *
Svetoslav683914b2015-01-15 14:22:26 -08001131 * @returns whether the enabled location providers changed.
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001132 */
Svetoslavb596a2c2015-02-17 21:37:09 -08001133 private boolean updateLocationProvidersAllowedLocked(String value, int owningUserId) {
Svetoslav683914b2015-01-15 14:22:26 -08001134 if (TextUtils.isEmpty(value)) {
1135 return false;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001136 }
1137
Svetoslav683914b2015-01-15 14:22:26 -08001138 final char prefix = value.charAt(0);
1139 if (prefix != '+' && prefix != '-') {
1140 return false;
1141 }
1142
1143 // skip prefix
1144 value = value.substring(1);
1145
Svetoslav7ec28e82015-05-20 17:01:10 -07001146 Setting settingValue = getSecureSetting(
Svetoslav683914b2015-01-15 14:22:26 -08001147 Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
1148
1149 String oldProviders = (settingValue != null) ? settingValue.getValue() : "";
1150
1151 int index = oldProviders.indexOf(value);
1152 int end = index + value.length();
1153
1154 // check for commas to avoid matching on partial string
1155 if (index > 0 && oldProviders.charAt(index - 1) != ',') {
1156 index = -1;
1157 }
1158
1159 // check for commas to avoid matching on partial string
1160 if (end < oldProviders.length() && oldProviders.charAt(end) != ',') {
1161 index = -1;
1162 }
1163
1164 String newProviders;
1165
1166 if (prefix == '+' && index < 0) {
1167 // append the provider to the list if not present
1168 if (oldProviders.length() == 0) {
1169 newProviders = value;
1170 } else {
1171 newProviders = oldProviders + ',' + value;
1172 }
1173 } else if (prefix == '-' && index >= 0) {
1174 // remove the provider from the list if present
1175 // remove leading or trailing comma
1176 if (index > 0) {
1177 index--;
1178 } else if (end < oldProviders.length()) {
1179 end++;
1180 }
1181
1182 newProviders = oldProviders.substring(0, index);
1183 if (end < oldProviders.length()) {
1184 newProviders += oldProviders.substring(end);
1185 }
1186 } else {
1187 // nothing changed, so no need to update the database
1188 return false;
1189 }
1190
Svetoslavb596a2c2015-02-17 21:37:09 -08001191 return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
1192 owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders,
1193 getCallingPackage());
Svetoslav683914b2015-01-15 14:22:26 -08001194 }
1195
Svetoslav683914b2015-01-15 14:22:26 -08001196 private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1197 int targetSdkVersion, String name) {
1198 // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash.
1199 if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
1200 if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
1201 Slog.w(LOG_TAG, "You shouldn't not change private system settings."
1202 + " This will soon become an error.");
1203 } else {
1204 Slog.w(LOG_TAG, "You shouldn't keep your settings in the secure settings."
1205 + " This will soon become an error.");
1206 }
1207 } else {
1208 if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
1209 throw new IllegalArgumentException("You cannot change private secure settings.");
1210 } else {
1211 throw new IllegalArgumentException("You cannot keep your settings in"
1212 + " the secure settings.");
1213 }
1214 }
1215 }
1216
1217 private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) {
1218 if (requestingUserId == UserHandle.getCallingUserId()) {
1219 return requestingUserId;
1220 }
1221 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1222 Binder.getCallingUid(), requestingUserId, false, true,
1223 "get/set setting for user", null);
1224 }
1225
1226 private static Bundle packageValueForCallResult(Setting setting) {
1227 if (setting == null) {
1228 return NULL_SETTING;
1229 }
1230 return Bundle.forPair(Settings.NameValueTable.VALUE, setting.getValue());
1231 }
1232
1233 private static int getRequestingUserId(Bundle args) {
1234 final int callingUserId = UserHandle.getCallingUserId();
1235 return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId)
1236 : callingUserId;
1237 }
1238
1239 private static String getSettingValue(Bundle args) {
1240 return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null;
1241 }
1242
1243 private static String getValidTableOrThrow(Uri uri) {
1244 if (uri.getPathSegments().size() > 0) {
1245 String table = uri.getPathSegments().get(0);
1246 if (DatabaseHelper.isValidTable(table)) {
1247 return table;
1248 }
1249 throw new IllegalArgumentException("Bad root path: " + table);
1250 }
1251 throw new IllegalArgumentException("Invalid URI:" + uri);
1252 }
1253
1254 private static MatrixCursor packageSettingForQuery(Setting setting, String[] projection) {
1255 if (setting == null) {
1256 return new MatrixCursor(projection, 0);
1257 }
1258 MatrixCursor cursor = new MatrixCursor(projection, 1);
1259 appendSettingToCursor(cursor, setting);
1260 return cursor;
1261 }
1262
1263 private static String[] normalizeProjection(String[] projection) {
1264 if (projection == null) {
1265 return ALL_COLUMNS;
1266 }
1267
1268 final int columnCount = projection.length;
1269 for (int i = 0; i < columnCount; i++) {
1270 String column = projection[i];
1271 if (!ArrayUtils.contains(ALL_COLUMNS, column)) {
1272 throw new IllegalArgumentException("Invalid column: " + column);
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001273 }
1274 }
1275
Svetoslav683914b2015-01-15 14:22:26 -08001276 return projection;
1277 }
1278
1279 private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) {
1280 final int columnCount = cursor.getColumnCount();
1281
1282 String[] values = new String[columnCount];
1283
1284 for (int i = 0; i < columnCount; i++) {
1285 String column = cursor.getColumnName(i);
1286
1287 switch (column) {
1288 case Settings.NameValueTable._ID: {
1289 values[i] = setting.getId();
1290 } break;
1291
1292 case Settings.NameValueTable.NAME: {
1293 values[i] = setting.getName();
1294 } break;
1295
1296 case Settings.NameValueTable.VALUE: {
1297 values[i] = setting.getValue();
1298 } break;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001299 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001300 }
1301
Svetoslav683914b2015-01-15 14:22:26 -08001302 cursor.addRow(values);
1303 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001304
Makoto Onuki3a2c35782015-06-18 11:21:58 -07001305 private static boolean isKeyValid(String key) {
1306 return !(TextUtils.isEmpty(key) || SettingsState.isBinary(key));
1307 }
1308
Svetoslav683914b2015-01-15 14:22:26 -08001309 private static final class Arguments {
1310 private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
1311 Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
1312
1313 private static final Pattern WHERE_PATTERN_WITH_PARAM_IN_BRACKETS =
1314 Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*\\?[\\s]*\\)[\\s]*");
1315
1316 private static final Pattern WHERE_PATTERN_NO_PARAM_IN_BRACKETS =
1317 Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*\\)[\\s]*");
1318
1319 private static final Pattern WHERE_PATTERN_NO_PARAM_NO_BRACKETS =
1320 Pattern.compile("[\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*");
1321
1322 public final String table;
1323 public final String name;
1324
1325 public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) {
1326 final int segmentSize = uri.getPathSegments().size();
1327 switch (segmentSize) {
1328 case 1: {
1329 if (where != null
1330 && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches()
1331 || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
1332 && whereArgs.length == 1) {
1333 name = whereArgs[0];
1334 table = computeTableForSetting(uri, name);
Svetoslav28494652015-02-12 14:11:42 -08001335 return;
Svetoslav683914b2015-01-15 14:22:26 -08001336 } else if (where != null
1337 && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
1338 || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
1339 final int startIndex = Math.max(where.indexOf("'"),
1340 where.indexOf("\"")) + 1;
1341 final int endIndex = Math.max(where.lastIndexOf("'"),
1342 where.lastIndexOf("\""));
1343 name = where.substring(startIndex, endIndex);
1344 table = computeTableForSetting(uri, name);
Svetoslav28494652015-02-12 14:11:42 -08001345 return;
Svetoslav683914b2015-01-15 14:22:26 -08001346 } else if (supportAll && where == null && whereArgs == null) {
1347 name = null;
1348 table = computeTableForSetting(uri, null);
Svetoslav28494652015-02-12 14:11:42 -08001349 return;
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001350 }
Svetoslav683914b2015-01-15 14:22:26 -08001351 } break;
1352
Svetoslav28494652015-02-12 14:11:42 -08001353 case 2: {
1354 if (where == null && whereArgs == null) {
1355 name = uri.getPathSegments().get(1);
1356 table = computeTableForSetting(uri, name);
1357 return;
1358 }
1359 } break;
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001360 }
Svetoslav28494652015-02-12 14:11:42 -08001361
1362 EventLogTags.writeUnsupportedSettingsQuery(
1363 uri.toSafeString(), where, Arrays.toString(whereArgs));
1364 String message = String.format( "Supported SQL:\n"
1365 + " uri content://some_table/some_property with null where and where args\n"
1366 + " uri content://some_table with query name=? and single name as arg\n"
1367 + " uri content://some_table with query name=some_name and null args\n"
1368 + " but got - uri:%1s, where:%2s whereArgs:%3s", uri, where,
1369 Arrays.toString(whereArgs));
1370 throw new IllegalArgumentException(message);
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001371 }
1372
Svetoslav28494652015-02-12 14:11:42 -08001373 private static String computeTableForSetting(Uri uri, String name) {
Svetoslav683914b2015-01-15 14:22:26 -08001374 String table = getValidTableOrThrow(uri);
1375
1376 if (name != null) {
1377 if (sSystemMovedToSecureSettings.contains(name)) {
1378 table = TABLE_SECURE;
1379 }
1380
1381 if (sSystemMovedToGlobalSettings.contains(name)) {
1382 table = TABLE_GLOBAL;
1383 }
1384
1385 if (sSecureMovedToGlobalSettings.contains(name)) {
1386 table = TABLE_GLOBAL;
1387 }
1388
1389 if (sGlobalMovedToSecureSettings.contains(name)) {
1390 table = TABLE_SECURE;
1391 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001392 }
Svetoslav683914b2015-01-15 14:22:26 -08001393
1394 return table;
1395 }
1396 }
1397
1398 final class SettingsRegistry {
1399 private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
1400
1401 private static final int SETTINGS_TYPE_GLOBAL = 0;
1402 private static final int SETTINGS_TYPE_SYSTEM = 1;
1403 private static final int SETTINGS_TYPE_SECURE = 2;
1404
1405 private static final int SETTINGS_TYPE_MASK = 0xF0000000;
1406 private static final int SETTINGS_TYPE_SHIFT = 28;
1407
1408 private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
1409 private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
1410 private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
1411
1412 private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
1413
1414 private final BackupManager mBackupManager;
1415
Svetoslav7e0683b2015-08-03 16:02:52 -07001416 private final Handler mHandler;
1417
Svetoslav683914b2015-01-15 14:22:26 -08001418 public SettingsRegistry() {
1419 mBackupManager = new BackupManager(getContext());
Svetoslav7e0683b2015-08-03 16:02:52 -07001420 mHandler = new MyHandler(getContext().getMainLooper());
Svetoslav683914b2015-01-15 14:22:26 -08001421 migrateAllLegacySettingsIfNeeded();
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001422 }
1423
Svetoslav683914b2015-01-15 14:22:26 -08001424 public List<String> getSettingsNamesLocked(int type, int userId) {
1425 final int key = makeKey(type, userId);
1426 SettingsState settingsState = peekSettingsStateLocked(key);
1427 return settingsState.getSettingNamesLocked();
1428 }
1429
1430 public SettingsState getSettingsLocked(int type, int userId) {
1431 final int key = makeKey(type, userId);
1432 return peekSettingsStateLocked(key);
1433 }
1434
1435 public void ensureSettingsForUserLocked(int userId) {
1436 // Migrate the setting for this user if needed.
1437 migrateLegacySettingsForUserIfNeededLocked(userId);
1438
1439 // Ensure global settings loaded if owner.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001440 if (userId == UserHandle.USER_SYSTEM) {
1441 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -08001442 ensureSettingsStateLocked(globalKey);
1443 }
1444
1445 // Ensure secure settings loaded.
1446 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1447 ensureSettingsStateLocked(secureKey);
1448
1449 // Make sure the secure settings have an Android id set.
1450 SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
1451 ensureSecureSettingAndroidIdSetLocked(secureSettings);
1452
1453 // Ensure system settings loaded.
1454 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1455 ensureSettingsStateLocked(systemKey);
1456
1457 // Upgrade the settings to the latest version.
1458 UpgradeController upgrader = new UpgradeController(userId);
1459 upgrader.upgradeIfNeededLocked();
1460 }
1461
1462 private void ensureSettingsStateLocked(int key) {
1463 if (mSettingsStates.get(key) == null) {
1464 final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
1465 SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
1466 maxBytesPerPackage);
1467 mSettingsStates.put(key, settingsState);
1468 }
1469 }
1470
1471 public void removeUserStateLocked(int userId, boolean permanently) {
1472 // We always keep the global settings in memory.
1473
1474 // Nuke system settings.
1475 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1476 final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
1477 if (systemSettingsState != null) {
1478 if (permanently) {
1479 mSettingsStates.remove(systemKey);
1480 systemSettingsState.destroyLocked(null);
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001481 } else {
Svetoslav683914b2015-01-15 14:22:26 -08001482 systemSettingsState.destroyLocked(new Runnable() {
1483 @Override
1484 public void run() {
1485 mSettingsStates.remove(systemKey);
1486 }
1487 });
1488 }
1489 }
1490
1491 // Nuke secure settings.
1492 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1493 final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
1494 if (secureSettingsState != null) {
1495 if (permanently) {
1496 mSettingsStates.remove(secureKey);
1497 secureSettingsState.destroyLocked(null);
1498 } else {
1499 secureSettingsState.destroyLocked(new Runnable() {
1500 @Override
1501 public void run() {
1502 mSettingsStates.remove(secureKey);
1503 }
1504 });
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001505 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001506 }
1507 }
1508
Svetoslav683914b2015-01-15 14:22:26 -08001509 public boolean insertSettingLocked(int type, int userId, String name, String value,
1510 String packageName) {
1511 final int key = makeKey(type, userId);
1512
1513 SettingsState settingsState = peekSettingsStateLocked(key);
1514 final boolean success = settingsState.insertSettingLocked(name, value, packageName);
1515
1516 if (success) {
1517 notifyForSettingsChange(key, name);
1518 }
1519 return success;
1520 }
1521
1522 public boolean deleteSettingLocked(int type, int userId, String name) {
1523 final int key = makeKey(type, userId);
1524
1525 SettingsState settingsState = peekSettingsStateLocked(key);
1526 final boolean success = settingsState.deleteSettingLocked(name);
1527
1528 if (success) {
1529 notifyForSettingsChange(key, name);
1530 }
1531 return success;
1532 }
1533
1534 public Setting getSettingLocked(int type, int userId, String name) {
1535 final int key = makeKey(type, userId);
1536
1537 SettingsState settingsState = peekSettingsStateLocked(key);
1538 return settingsState.getSettingLocked(name);
1539 }
1540
1541 public boolean updateSettingLocked(int type, int userId, String name, String value,
1542 String packageName) {
1543 final int key = makeKey(type, userId);
1544
1545 SettingsState settingsState = peekSettingsStateLocked(key);
1546 final boolean success = settingsState.updateSettingLocked(name, value, packageName);
1547
1548 if (success) {
1549 notifyForSettingsChange(key, name);
1550 }
1551
1552 return success;
1553 }
1554
1555 public void onPackageRemovedLocked(String packageName, int userId) {
Svet Ganov8de34802015-04-27 09:33:40 -07001556 // Global and secure settings are signature protected. Apps signed
1557 // by the platform certificate are generally not uninstalled and
1558 // the main exception is tests. We trust components signed
1559 // by the platform certificate and do not do a clean up after them.
Svetoslav683914b2015-01-15 14:22:26 -08001560
1561 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1562 SettingsState systemSettings = mSettingsStates.get(systemKey);
Svet Ganov8de34802015-04-27 09:33:40 -07001563 if (systemSettings != null) {
1564 systemSettings.onPackageRemovedLocked(packageName);
1565 }
Svetoslav683914b2015-01-15 14:22:26 -08001566 }
1567
1568 private SettingsState peekSettingsStateLocked(int key) {
1569 SettingsState settingsState = mSettingsStates.get(key);
1570 if (settingsState != null) {
1571 return settingsState;
1572 }
1573
1574 ensureSettingsForUserLocked(getUserIdFromKey(key));
1575 return mSettingsStates.get(key);
1576 }
1577
1578 private void migrateAllLegacySettingsIfNeeded() {
1579 synchronized (mLock) {
Xiaohui Chen43765b72015-08-31 10:57:33 -07001580 final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -08001581 File globalFile = getSettingsFile(key);
1582 if (globalFile.exists()) {
1583 return;
1584 }
1585
1586 final long identity = Binder.clearCallingIdentity();
1587 try {
1588 List<UserInfo> users = mUserManager.getUsers(true);
1589
1590 final int userCount = users.size();
1591 for (int i = 0; i < userCount; i++) {
1592 final int userId = users.get(i).id;
1593
1594 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1595 SQLiteDatabase database = dbHelper.getWritableDatabase();
1596 migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1597
1598 // Upgrade to the latest version.
1599 UpgradeController upgrader = new UpgradeController(userId);
1600 upgrader.upgradeIfNeededLocked();
1601
1602 // Drop from memory if not a running user.
1603 if (!mUserManager.isUserRunning(new UserHandle(userId))) {
1604 removeUserStateLocked(userId, false);
1605 }
1606 }
1607 } finally {
1608 Binder.restoreCallingIdentity(identity);
1609 }
1610 }
1611 }
1612
1613 private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
1614 // Every user has secure settings and if no file we need to migrate.
1615 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1616 File secureFile = getSettingsFile(secureKey);
1617 if (secureFile.exists()) {
1618 return;
1619 }
1620
1621 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1622 SQLiteDatabase database = dbHelper.getWritableDatabase();
1623
1624 migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1625 }
1626
1627 private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
1628 SQLiteDatabase database, int userId) {
1629 // Move over the global settings if owner.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001630 if (userId == UserHandle.USER_SYSTEM) {
Svetoslav683914b2015-01-15 14:22:26 -08001631 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
1632 ensureSettingsStateLocked(globalKey);
1633 SettingsState globalSettings = mSettingsStates.get(globalKey);
1634 migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
1635 globalSettings.persistSyncLocked();
1636 }
1637
1638 // Move over the secure settings.
1639 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1640 ensureSettingsStateLocked(secureKey);
1641 SettingsState secureSettings = mSettingsStates.get(secureKey);
1642 migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
1643 ensureSecureSettingAndroidIdSetLocked(secureSettings);
1644 secureSettings.persistSyncLocked();
1645
1646 // Move over the system settings.
1647 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1648 ensureSettingsStateLocked(systemKey);
1649 SettingsState systemSettings = mSettingsStates.get(systemKey);
1650 migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
1651 systemSettings.persistSyncLocked();
1652
1653 // Drop the database as now all is moved and persisted.
1654 if (DROP_DATABASE_ON_MIGRATION) {
1655 dbHelper.dropDatabase();
1656 } else {
1657 dbHelper.backupDatabase();
1658 }
1659 }
1660
1661 private void migrateLegacySettingsLocked(SettingsState settingsState,
1662 SQLiteDatabase database, String table) {
1663 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
1664 queryBuilder.setTables(table);
1665
1666 Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
1667 null, null, null, null, null);
1668
1669 if (cursor == null) {
1670 return;
1671 }
1672
1673 try {
1674 if (!cursor.moveToFirst()) {
1675 return;
1676 }
1677
1678 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
1679 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
1680
1681 settingsState.setVersionLocked(database.getVersion());
1682
1683 while (!cursor.isAfterLast()) {
1684 String name = cursor.getString(nameColumnIdx);
1685 String value = cursor.getString(valueColumnIdx);
1686 settingsState.insertSettingLocked(name, value,
1687 SettingsState.SYSTEM_PACKAGE_NAME);
1688 cursor.moveToNext();
1689 }
1690 } finally {
1691 cursor.close();
1692 }
1693 }
1694
1695 private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
1696 Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
1697
1698 if (value != null) {
1699 return;
1700 }
1701
1702 final int userId = getUserIdFromKey(secureSettings.mKey);
1703
1704 final UserInfo user;
1705 final long identity = Binder.clearCallingIdentity();
1706 try {
1707 user = mUserManager.getUserInfo(userId);
1708 } finally {
1709 Binder.restoreCallingIdentity(identity);
1710 }
1711 if (user == null) {
1712 // Can happen due to races when deleting users - treat as benign.
1713 return;
1714 }
1715
1716 String androidId = Long.toHexString(new SecureRandom().nextLong());
1717 secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
1718 SettingsState.SYSTEM_PACKAGE_NAME);
1719
1720 Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
1721 + "] for user " + userId);
1722
1723 // Write a drop box entry if it's a restricted profile
1724 if (user.isRestricted()) {
1725 DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
1726 Context.DROPBOX_SERVICE);
1727 if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
1728 dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
1729 + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
1730 }
1731 }
1732 }
1733
1734 private void notifyForSettingsChange(int key, String name) {
1735 // Update the system property *first*, so if someone is listening for
1736 // a notification and then using the contract class to get their data,
1737 // the system property will be updated and they'll get the new data.
1738
1739 boolean backedUpDataChanged = false;
1740 String property = null;
1741 if (isGlobalSettingsKey(key)) {
1742 property = Settings.Global.SYS_PROP_SETTING_VERSION;
1743 backedUpDataChanged = true;
1744 } else if (isSecureSettingsKey(key)) {
1745 property = Settings.Secure.SYS_PROP_SETTING_VERSION;
1746 backedUpDataChanged = true;
1747 } else if (isSystemSettingsKey(key)) {
1748 property = Settings.System.SYS_PROP_SETTING_VERSION;
1749 backedUpDataChanged = true;
1750 }
1751
1752 if (property != null) {
1753 final long version = SystemProperties.getLong(property, 0) + 1;
1754 SystemProperties.set(property, Long.toString(version));
1755 if (DEBUG) {
1756 Slog.v(LOG_TAG, "System property " + property + "=" + version);
1757 }
1758 }
1759
1760 // Inform the backup manager about a data change
1761 if (backedUpDataChanged) {
Svetoslav7e0683b2015-08-03 16:02:52 -07001762 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_DATA_CHANGED).sendToTarget();
Svetoslav683914b2015-01-15 14:22:26 -08001763 }
1764
1765 // Now send the notification through the content framework.
1766
1767 final int userId = getUserIdFromKey(key);
1768 Uri uri = getNotificationUriFor(key, name);
1769
Svetoslav7e0683b2015-08-03 16:02:52 -07001770 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
1771 userId, 0, uri).sendToTarget();
1772
Nicolas Prevot310e1ee2015-07-02 14:03:06 +01001773 if (isSecureSettingsKey(key)) {
1774 maybeNotifyProfiles(userId, uri, name, sSecureCloneToManagedSettings);
1775 } else if (isSystemSettingsKey(key)) {
1776 maybeNotifyProfiles(userId, uri, name, sSystemCloneToManagedSettings);
1777 }
1778 }
1779
1780 private void maybeNotifyProfiles(int userId, Uri uri, String name,
1781 Set<String> keysCloned) {
1782 if (keysCloned.contains(name)) {
1783 List<UserInfo> profiles = mUserManager.getProfiles(userId);
1784 int size = profiles.size();
1785 for (int i = 0; i < size; i++) {
1786 UserInfo profile = profiles.get(i);
1787 // the notification for userId has already been sent.
1788 if (profile.id != userId) {
Svetoslav7e0683b2015-08-03 16:02:52 -07001789 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
1790 profile.id, 0, uri).sendToTarget();
Nicolas Prevot310e1ee2015-07-02 14:03:06 +01001791 }
1792 }
1793 }
Svetoslav683914b2015-01-15 14:22:26 -08001794 }
1795
1796 private int makeKey(int type, int userId) {
1797 return (type << SETTINGS_TYPE_SHIFT) | userId;
1798 }
1799
1800 private int getTypeFromKey(int key) {
1801 return key >> SETTINGS_TYPE_SHIFT;
1802 }
1803
1804 private int getUserIdFromKey(int key) {
1805 return key & ~SETTINGS_TYPE_MASK;
1806 }
1807
1808 private boolean isGlobalSettingsKey(int key) {
1809 return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
1810 }
1811
1812 private boolean isSystemSettingsKey(int key) {
1813 return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
1814 }
1815
1816 private boolean isSecureSettingsKey(int key) {
1817 return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
1818 }
1819
1820 private File getSettingsFile(int key) {
1821 if (isGlobalSettingsKey(key)) {
1822 final int userId = getUserIdFromKey(key);
1823 return new File(Environment.getUserSystemDirectory(userId),
1824 SETTINGS_FILE_GLOBAL);
1825 } else if (isSystemSettingsKey(key)) {
1826 final int userId = getUserIdFromKey(key);
1827 return new File(Environment.getUserSystemDirectory(userId),
1828 SETTINGS_FILE_SYSTEM);
1829 } else if (isSecureSettingsKey(key)) {
1830 final int userId = getUserIdFromKey(key);
1831 return new File(Environment.getUserSystemDirectory(userId),
1832 SETTINGS_FILE_SECURE);
1833 } else {
1834 throw new IllegalArgumentException("Invalid settings key:" + key);
1835 }
1836 }
1837
1838 private Uri getNotificationUriFor(int key, String name) {
1839 if (isGlobalSettingsKey(key)) {
1840 return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
1841 : Settings.Global.CONTENT_URI;
1842 } else if (isSecureSettingsKey(key)) {
1843 return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
1844 : Settings.Secure.CONTENT_URI;
1845 } else if (isSystemSettingsKey(key)) {
1846 return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
1847 : Settings.System.CONTENT_URI;
1848 } else {
1849 throw new IllegalArgumentException("Invalid settings key:" + key);
1850 }
1851 }
1852
1853 private int getMaxBytesPerPackageForType(int type) {
1854 switch (type) {
1855 case SETTINGS_TYPE_GLOBAL:
1856 case SETTINGS_TYPE_SECURE: {
1857 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
1858 }
1859
1860 default: {
1861 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
1862 }
1863 }
1864 }
1865
Svetoslav7e0683b2015-08-03 16:02:52 -07001866 private final class MyHandler extends Handler {
1867 private static final int MSG_NOTIFY_URI_CHANGED = 1;
1868 private static final int MSG_NOTIFY_DATA_CHANGED = 2;
1869
1870 public MyHandler(Looper looper) {
1871 super(looper);
1872 }
1873
1874 @Override
1875 public void handleMessage(Message msg) {
1876 switch (msg.what) {
1877 case MSG_NOTIFY_URI_CHANGED: {
1878 final int userId = msg.arg1;
1879 Uri uri = (Uri) msg.obj;
1880 getContext().getContentResolver().notifyChange(uri, null, true, userId);
1881 if (DEBUG) {
1882 Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
1883 }
1884 } break;
1885
1886 case MSG_NOTIFY_DATA_CHANGED: {
1887 mBackupManager.dataChanged();
1888 } break;
1889 }
1890 }
1891 }
1892
Svetoslav683914b2015-01-15 14:22:26 -08001893 private final class UpgradeController {
Martijn Coenen7ab4b7f2015-07-27 15:58:32 +02001894 private static final int SETTINGS_VERSION = 122;
Svetoslav683914b2015-01-15 14:22:26 -08001895
1896 private final int mUserId;
1897
1898 public UpgradeController(int userId) {
1899 mUserId = userId;
1900 }
1901
1902 public void upgradeIfNeededLocked() {
1903 // The version of all settings for a user is the same (all users have secure).
1904 SettingsState secureSettings = getSettingsLocked(
1905 SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
1906
1907 // Try an update from the current state.
1908 final int oldVersion = secureSettings.getVersionLocked();
1909 final int newVersion = SETTINGS_VERSION;
1910
Svet Ganovc9755bc2015-03-28 13:21:22 -07001911 // If up do date - done.
Svetoslav683914b2015-01-15 14:22:26 -08001912 if (oldVersion == newVersion) {
1913 return;
1914 }
1915
1916 // Try to upgrade.
1917 final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
1918
1919 // If upgrade failed start from scratch and upgrade.
1920 if (curVersion != newVersion) {
1921 // Drop state we have for this user.
1922 removeUserStateLocked(mUserId, true);
1923
1924 // Recreate the database.
1925 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
1926 SQLiteDatabase database = dbHelper.getWritableDatabase();
1927 dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
1928
1929 // Migrate the settings for this user.
1930 migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
1931
1932 // Now upgrade should work fine.
1933 onUpgradeLocked(mUserId, oldVersion, newVersion);
1934 }
1935
1936 // Set the global settings version if owner.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001937 if (mUserId == UserHandle.USER_SYSTEM) {
Svetoslav683914b2015-01-15 14:22:26 -08001938 SettingsState globalSettings = getSettingsLocked(
1939 SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
1940 globalSettings.setVersionLocked(newVersion);
1941 }
1942
1943 // Set the secure settings version.
1944 secureSettings.setVersionLocked(newVersion);
1945
1946 // Set the system settings version.
1947 SettingsState systemSettings = getSettingsLocked(
1948 SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
1949 systemSettings.setVersionLocked(newVersion);
1950 }
1951
1952 private SettingsState getGlobalSettingsLocked() {
Xiaohui Chen43765b72015-08-31 10:57:33 -07001953 return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -08001954 }
1955
1956 private SettingsState getSecureSettingsLocked(int userId) {
1957 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
1958 }
1959
1960 private SettingsState getSystemSettingsLocked(int userId) {
1961 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
1962 }
1963
Jeff Brown503cffc2015-03-26 18:08:51 -07001964 /**
1965 * You must perform all necessary mutations to bring the settings
1966 * for this user from the old to the new version. When you add a new
1967 * upgrade step you *must* update SETTINGS_VERSION.
1968 *
1969 * This is an example of moving a setting from secure to global.
1970 *
1971 * // v119: Example settings changes.
1972 * if (currentVersion == 118) {
1973 * if (userId == UserHandle.USER_OWNER) {
1974 * // Remove from the secure settings.
1975 * SettingsState secureSettings = getSecureSettingsLocked(userId);
1976 * String name = "example_setting_to_move";
1977 * String value = secureSettings.getSetting(name);
1978 * secureSettings.deleteSetting(name);
1979 *
1980 * // Add to the global settings.
1981 * SettingsState globalSettings = getGlobalSettingsLocked();
1982 * globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
1983 * }
1984 *
1985 * // Update the current version.
1986 * currentVersion = 119;
1987 * }
1988 */
Svetoslav683914b2015-01-15 14:22:26 -08001989 private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
1990 if (DEBUG) {
1991 Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
1992 + oldVersion + " to version: " + newVersion);
1993 }
1994
Jeff Brown503cffc2015-03-26 18:08:51 -07001995 int currentVersion = oldVersion;
Svetoslav683914b2015-01-15 14:22:26 -08001996
John Spurlocke11ae112015-05-11 16:09:03 -04001997 // v119: Reset zen + ringer mode.
1998 if (currentVersion == 118) {
Xiaohui Chen43765b72015-08-31 10:57:33 -07001999 if (userId == UserHandle.USER_SYSTEM) {
John Spurlocke11ae112015-05-11 16:09:03 -04002000 final SettingsState globalSettings = getGlobalSettingsLocked();
2001 globalSettings.updateSettingLocked(Settings.Global.ZEN_MODE,
2002 Integer.toString(Settings.Global.ZEN_MODE_OFF),
2003 SettingsState.SYSTEM_PACKAGE_NAME);
2004 globalSettings.updateSettingLocked(Settings.Global.MODE_RINGER,
2005 Integer.toString(AudioManager.RINGER_MODE_NORMAL),
2006 SettingsState.SYSTEM_PACKAGE_NAME);
2007 }
2008 currentVersion = 119;
2009 }
2010
Jason Monk27bbb2d2015-03-31 16:46:39 -04002011 // v120: Add double tap to wake setting.
2012 if (currentVersion == 119) {
2013 SettingsState secureSettings = getSecureSettingsLocked(userId);
2014 secureSettings.insertSettingLocked(Settings.Secure.DOUBLE_TAP_TO_WAKE,
2015 getContext().getResources().getBoolean(
2016 R.bool.def_double_tap_to_wake) ? "1" : "0",
2017 SettingsState.SYSTEM_PACKAGE_NAME);
2018
2019 currentVersion = 120;
2020 }
2021
Svetoslav7e0683b2015-08-03 16:02:52 -07002022 if (currentVersion == 120) {
2023 // Before 121, we used a different string encoding logic. We just bump the
2024 // version here; SettingsState knows how to handle pre-version 120 files.
2025 currentVersion = 121;
2026 }
Makoto Onuki3a2c35782015-06-18 11:21:58 -07002027
Martijn Coenen7ab4b7f2015-07-27 15:58:32 +02002028 if (currentVersion == 121) {
2029 // Version 122: allow OEMs to set a default payment component in resources.
2030 // Note that we only write the default if no default has been set;
2031 // if there is, we just leave the default at whatever it currently is.
2032 final SettingsState secureSettings = getSecureSettingsLocked(userId);
2033 String defaultComponent = (getContext().getResources().getString(
2034 R.string.def_nfc_payment_component));
2035 Setting currentSetting = secureSettings.getSettingLocked(
2036 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
2037 if (defaultComponent != null && !defaultComponent.isEmpty() &&
2038 currentSetting == null) {
2039 secureSettings.insertSettingLocked(
2040 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
2041 defaultComponent,
2042 SettingsState.SYSTEM_PACKAGE_NAME);
2043 }
2044 currentVersion = 122;
2045 }
Jeff Brown503cffc2015-03-26 18:08:51 -07002046 // vXXX: Add new settings above this point.
Svetoslav683914b2015-01-15 14:22:26 -08002047
Jeff Brown503cffc2015-03-26 18:08:51 -07002048 // Return the current version.
2049 return currentVersion;
Brad Fitzpatrick547a96b2010-03-09 17:58:53 -08002050 }
2051 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08002052 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002053}