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