blob: ff2c004e06114d9b41058b25d75c31c3d025021e [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);
1231 } else if (where != null
1232 && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
1233 || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
1234 final int startIndex = Math.max(where.indexOf("'"),
1235 where.indexOf("\"")) + 1;
1236 final int endIndex = Math.max(where.lastIndexOf("'"),
1237 where.lastIndexOf("\""));
1238 name = where.substring(startIndex, endIndex);
1239 table = computeTableForSetting(uri, name);
1240 } else if (supportAll && where == null && whereArgs == null) {
1241 name = null;
1242 table = computeTableForSetting(uri, null);
1243 } else if (uri.getPathSegments().size() == 2
1244 && where == null && whereArgs == null) {
1245 name = uri.getPathSegments().get(1);
1246 table = computeTableForSetting(uri, name);
1247 } else {
1248 EventLogTags.writeUnsupportedSettingsQuery(
1249 uri.toSafeString(), where, Arrays.toString(whereArgs));
1250 throw new IllegalArgumentException("Only null where and args"
1251 + " or name=? where and a single arg or name='SOME_SETTING' "
1252 + "are supported uri: " + uri + " where: " + where + " args: "
1253 + Arrays.toString(whereArgs));
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001254 }
Svetoslav683914b2015-01-15 14:22:26 -08001255 } break;
1256
1257 default: {
1258 throw new IllegalArgumentException("Invalid URI: " + uri);
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001259 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001260 }
1261 }
1262
Svetoslav683914b2015-01-15 14:22:26 -08001263 public static String computeTableForSetting(Uri uri, String name) {
1264 String table = getValidTableOrThrow(uri);
1265
1266 if (name != null) {
1267 if (sSystemMovedToSecureSettings.contains(name)) {
1268 table = TABLE_SECURE;
1269 }
1270
1271 if (sSystemMovedToGlobalSettings.contains(name)) {
1272 table = TABLE_GLOBAL;
1273 }
1274
1275 if (sSecureMovedToGlobalSettings.contains(name)) {
1276 table = TABLE_GLOBAL;
1277 }
1278
1279 if (sGlobalMovedToSecureSettings.contains(name)) {
1280 table = TABLE_SECURE;
1281 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001282 }
Svetoslav683914b2015-01-15 14:22:26 -08001283
1284 return table;
1285 }
1286 }
1287
1288 final class SettingsRegistry {
1289 private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
1290
1291 private static final int SETTINGS_TYPE_GLOBAL = 0;
1292 private static final int SETTINGS_TYPE_SYSTEM = 1;
1293 private static final int SETTINGS_TYPE_SECURE = 2;
1294
1295 private static final int SETTINGS_TYPE_MASK = 0xF0000000;
1296 private static final int SETTINGS_TYPE_SHIFT = 28;
1297
1298 private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
1299 private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
1300 private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
1301
1302 private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
1303
1304 private final BackupManager mBackupManager;
1305
1306 public SettingsRegistry() {
1307 mBackupManager = new BackupManager(getContext());
1308 migrateAllLegacySettingsIfNeeded();
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001309 }
1310
Svetoslav683914b2015-01-15 14:22:26 -08001311 public List<String> getSettingsNamesLocked(int type, int userId) {
1312 final int key = makeKey(type, userId);
1313 SettingsState settingsState = peekSettingsStateLocked(key);
1314 return settingsState.getSettingNamesLocked();
1315 }
1316
1317 public SettingsState getSettingsLocked(int type, int userId) {
1318 final int key = makeKey(type, userId);
1319 return peekSettingsStateLocked(key);
1320 }
1321
1322 public void ensureSettingsForUserLocked(int userId) {
1323 // Migrate the setting for this user if needed.
1324 migrateLegacySettingsForUserIfNeededLocked(userId);
1325
1326 // Ensure global settings loaded if owner.
1327 if (userId == UserHandle.USER_OWNER) {
1328 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
1329 ensureSettingsStateLocked(globalKey);
1330 }
1331
1332 // Ensure secure settings loaded.
1333 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1334 ensureSettingsStateLocked(secureKey);
1335
1336 // Make sure the secure settings have an Android id set.
1337 SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
1338 ensureSecureSettingAndroidIdSetLocked(secureSettings);
1339
1340 // Ensure system settings loaded.
1341 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1342 ensureSettingsStateLocked(systemKey);
1343
1344 // Upgrade the settings to the latest version.
1345 UpgradeController upgrader = new UpgradeController(userId);
1346 upgrader.upgradeIfNeededLocked();
1347 }
1348
1349 private void ensureSettingsStateLocked(int key) {
1350 if (mSettingsStates.get(key) == null) {
1351 final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
1352 SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
1353 maxBytesPerPackage);
1354 mSettingsStates.put(key, settingsState);
1355 }
1356 }
1357
1358 public void removeUserStateLocked(int userId, boolean permanently) {
1359 // We always keep the global settings in memory.
1360
1361 // Nuke system settings.
1362 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1363 final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
1364 if (systemSettingsState != null) {
1365 if (permanently) {
1366 mSettingsStates.remove(systemKey);
1367 systemSettingsState.destroyLocked(null);
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001368 } else {
Svetoslav683914b2015-01-15 14:22:26 -08001369 systemSettingsState.destroyLocked(new Runnable() {
1370 @Override
1371 public void run() {
1372 mSettingsStates.remove(systemKey);
1373 }
1374 });
1375 }
1376 }
1377
1378 // Nuke secure settings.
1379 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1380 final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
1381 if (secureSettingsState != null) {
1382 if (permanently) {
1383 mSettingsStates.remove(secureKey);
1384 secureSettingsState.destroyLocked(null);
1385 } else {
1386 secureSettingsState.destroyLocked(new Runnable() {
1387 @Override
1388 public void run() {
1389 mSettingsStates.remove(secureKey);
1390 }
1391 });
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001392 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001393 }
1394 }
1395
Svetoslav683914b2015-01-15 14:22:26 -08001396 public boolean insertSettingLocked(int type, int userId, String name, String value,
1397 String packageName) {
1398 final int key = makeKey(type, userId);
1399
1400 SettingsState settingsState = peekSettingsStateLocked(key);
1401 final boolean success = settingsState.insertSettingLocked(name, value, packageName);
1402
1403 if (success) {
1404 notifyForSettingsChange(key, name);
1405 }
1406 return success;
1407 }
1408
1409 public boolean deleteSettingLocked(int type, int userId, String name) {
1410 final int key = makeKey(type, userId);
1411
1412 SettingsState settingsState = peekSettingsStateLocked(key);
1413 final boolean success = settingsState.deleteSettingLocked(name);
1414
1415 if (success) {
1416 notifyForSettingsChange(key, name);
1417 }
1418 return success;
1419 }
1420
1421 public Setting getSettingLocked(int type, int userId, String name) {
1422 final int key = makeKey(type, userId);
1423
1424 SettingsState settingsState = peekSettingsStateLocked(key);
1425 return settingsState.getSettingLocked(name);
1426 }
1427
1428 public boolean updateSettingLocked(int type, int userId, String name, String value,
1429 String packageName) {
1430 final int key = makeKey(type, userId);
1431
1432 SettingsState settingsState = peekSettingsStateLocked(key);
1433 final boolean success = settingsState.updateSettingLocked(name, value, packageName);
1434
1435 if (success) {
1436 notifyForSettingsChange(key, name);
1437 }
1438
1439 return success;
1440 }
1441
1442 public void onPackageRemovedLocked(String packageName, int userId) {
1443 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
1444 SettingsState globalSettings = mSettingsStates.get(globalKey);
1445 globalSettings.onPackageRemovedLocked(packageName);
1446
1447 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1448 SettingsState secureSettings = mSettingsStates.get(secureKey);
1449 secureSettings.onPackageRemovedLocked(packageName);
1450
1451 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1452 SettingsState systemSettings = mSettingsStates.get(systemKey);
1453 systemSettings.onPackageRemovedLocked(packageName);
1454 }
1455
1456 private SettingsState peekSettingsStateLocked(int key) {
1457 SettingsState settingsState = mSettingsStates.get(key);
1458 if (settingsState != null) {
1459 return settingsState;
1460 }
1461
1462 ensureSettingsForUserLocked(getUserIdFromKey(key));
1463 return mSettingsStates.get(key);
1464 }
1465
1466 private void migrateAllLegacySettingsIfNeeded() {
1467 synchronized (mLock) {
1468 final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
1469 File globalFile = getSettingsFile(key);
1470 if (globalFile.exists()) {
1471 return;
1472 }
1473
1474 final long identity = Binder.clearCallingIdentity();
1475 try {
1476 List<UserInfo> users = mUserManager.getUsers(true);
1477
1478 final int userCount = users.size();
1479 for (int i = 0; i < userCount; i++) {
1480 final int userId = users.get(i).id;
1481
1482 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1483 SQLiteDatabase database = dbHelper.getWritableDatabase();
1484 migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1485
1486 // Upgrade to the latest version.
1487 UpgradeController upgrader = new UpgradeController(userId);
1488 upgrader.upgradeIfNeededLocked();
1489
1490 // Drop from memory if not a running user.
1491 if (!mUserManager.isUserRunning(new UserHandle(userId))) {
1492 removeUserStateLocked(userId, false);
1493 }
1494 }
1495 } finally {
1496 Binder.restoreCallingIdentity(identity);
1497 }
1498 }
1499 }
1500
1501 private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
1502 // Every user has secure settings and if no file we need to migrate.
1503 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1504 File secureFile = getSettingsFile(secureKey);
1505 if (secureFile.exists()) {
1506 return;
1507 }
1508
1509 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1510 SQLiteDatabase database = dbHelper.getWritableDatabase();
1511
1512 migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1513 }
1514
1515 private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
1516 SQLiteDatabase database, int userId) {
1517 // Move over the global settings if owner.
1518 if (userId == UserHandle.USER_OWNER) {
1519 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
1520 ensureSettingsStateLocked(globalKey);
1521 SettingsState globalSettings = mSettingsStates.get(globalKey);
1522 migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
1523 globalSettings.persistSyncLocked();
1524 }
1525
1526 // Move over the secure settings.
1527 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1528 ensureSettingsStateLocked(secureKey);
1529 SettingsState secureSettings = mSettingsStates.get(secureKey);
1530 migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
1531 ensureSecureSettingAndroidIdSetLocked(secureSettings);
1532 secureSettings.persistSyncLocked();
1533
1534 // Move over the system settings.
1535 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1536 ensureSettingsStateLocked(systemKey);
1537 SettingsState systemSettings = mSettingsStates.get(systemKey);
1538 migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
1539 systemSettings.persistSyncLocked();
1540
1541 // Drop the database as now all is moved and persisted.
1542 if (DROP_DATABASE_ON_MIGRATION) {
1543 dbHelper.dropDatabase();
1544 } else {
1545 dbHelper.backupDatabase();
1546 }
1547 }
1548
1549 private void migrateLegacySettingsLocked(SettingsState settingsState,
1550 SQLiteDatabase database, String table) {
1551 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
1552 queryBuilder.setTables(table);
1553
1554 Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
1555 null, null, null, null, null);
1556
1557 if (cursor == null) {
1558 return;
1559 }
1560
1561 try {
1562 if (!cursor.moveToFirst()) {
1563 return;
1564 }
1565
1566 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
1567 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
1568
1569 settingsState.setVersionLocked(database.getVersion());
1570
1571 while (!cursor.isAfterLast()) {
1572 String name = cursor.getString(nameColumnIdx);
1573 String value = cursor.getString(valueColumnIdx);
1574 settingsState.insertSettingLocked(name, value,
1575 SettingsState.SYSTEM_PACKAGE_NAME);
1576 cursor.moveToNext();
1577 }
1578 } finally {
1579 cursor.close();
1580 }
1581 }
1582
1583 private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
1584 Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
1585
1586 if (value != null) {
1587 return;
1588 }
1589
1590 final int userId = getUserIdFromKey(secureSettings.mKey);
1591
1592 final UserInfo user;
1593 final long identity = Binder.clearCallingIdentity();
1594 try {
1595 user = mUserManager.getUserInfo(userId);
1596 } finally {
1597 Binder.restoreCallingIdentity(identity);
1598 }
1599 if (user == null) {
1600 // Can happen due to races when deleting users - treat as benign.
1601 return;
1602 }
1603
1604 String androidId = Long.toHexString(new SecureRandom().nextLong());
1605 secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
1606 SettingsState.SYSTEM_PACKAGE_NAME);
1607
1608 Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
1609 + "] for user " + userId);
1610
1611 // Write a drop box entry if it's a restricted profile
1612 if (user.isRestricted()) {
1613 DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
1614 Context.DROPBOX_SERVICE);
1615 if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
1616 dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
1617 + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
1618 }
1619 }
1620 }
1621
1622 private void notifyForSettingsChange(int key, String name) {
1623 // Update the system property *first*, so if someone is listening for
1624 // a notification and then using the contract class to get their data,
1625 // the system property will be updated and they'll get the new data.
1626
1627 boolean backedUpDataChanged = false;
1628 String property = null;
1629 if (isGlobalSettingsKey(key)) {
1630 property = Settings.Global.SYS_PROP_SETTING_VERSION;
1631 backedUpDataChanged = true;
1632 } else if (isSecureSettingsKey(key)) {
1633 property = Settings.Secure.SYS_PROP_SETTING_VERSION;
1634 backedUpDataChanged = true;
1635 } else if (isSystemSettingsKey(key)) {
1636 property = Settings.System.SYS_PROP_SETTING_VERSION;
1637 backedUpDataChanged = true;
1638 }
1639
1640 if (property != null) {
1641 final long version = SystemProperties.getLong(property, 0) + 1;
1642 SystemProperties.set(property, Long.toString(version));
1643 if (DEBUG) {
1644 Slog.v(LOG_TAG, "System property " + property + "=" + version);
1645 }
1646 }
1647
1648 // Inform the backup manager about a data change
1649 if (backedUpDataChanged) {
1650 mBackupManager.dataChanged();
1651 }
1652
1653 // Now send the notification through the content framework.
1654
1655 final int userId = getUserIdFromKey(key);
1656 Uri uri = getNotificationUriFor(key, name);
1657
1658 sendNotify(uri, userId);
1659 }
1660
1661 private int makeKey(int type, int userId) {
1662 return (type << SETTINGS_TYPE_SHIFT) | userId;
1663 }
1664
1665 private int getTypeFromKey(int key) {
1666 return key >> SETTINGS_TYPE_SHIFT;
1667 }
1668
1669 private int getUserIdFromKey(int key) {
1670 return key & ~SETTINGS_TYPE_MASK;
1671 }
1672
1673 private boolean isGlobalSettingsKey(int key) {
1674 return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
1675 }
1676
1677 private boolean isSystemSettingsKey(int key) {
1678 return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
1679 }
1680
1681 private boolean isSecureSettingsKey(int key) {
1682 return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
1683 }
1684
1685 private File getSettingsFile(int key) {
1686 if (isGlobalSettingsKey(key)) {
1687 final int userId = getUserIdFromKey(key);
1688 return new File(Environment.getUserSystemDirectory(userId),
1689 SETTINGS_FILE_GLOBAL);
1690 } else if (isSystemSettingsKey(key)) {
1691 final int userId = getUserIdFromKey(key);
1692 return new File(Environment.getUserSystemDirectory(userId),
1693 SETTINGS_FILE_SYSTEM);
1694 } else if (isSecureSettingsKey(key)) {
1695 final int userId = getUserIdFromKey(key);
1696 return new File(Environment.getUserSystemDirectory(userId),
1697 SETTINGS_FILE_SECURE);
1698 } else {
1699 throw new IllegalArgumentException("Invalid settings key:" + key);
1700 }
1701 }
1702
1703 private Uri getNotificationUriFor(int key, String name) {
1704 if (isGlobalSettingsKey(key)) {
1705 return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
1706 : Settings.Global.CONTENT_URI;
1707 } else if (isSecureSettingsKey(key)) {
1708 return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
1709 : Settings.Secure.CONTENT_URI;
1710 } else if (isSystemSettingsKey(key)) {
1711 return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
1712 : Settings.System.CONTENT_URI;
1713 } else {
1714 throw new IllegalArgumentException("Invalid settings key:" + key);
1715 }
1716 }
1717
1718 private int getMaxBytesPerPackageForType(int type) {
1719 switch (type) {
1720 case SETTINGS_TYPE_GLOBAL:
1721 case SETTINGS_TYPE_SECURE: {
1722 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
1723 }
1724
1725 default: {
1726 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
1727 }
1728 }
1729 }
1730
1731 private final class UpgradeController {
1732 private static final int SETTINGS_VERSION = 118;
1733
1734 private final int mUserId;
1735
1736 public UpgradeController(int userId) {
1737 mUserId = userId;
1738 }
1739
1740 public void upgradeIfNeededLocked() {
1741 // The version of all settings for a user is the same (all users have secure).
1742 SettingsState secureSettings = getSettingsLocked(
1743 SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
1744
1745 // Try an update from the current state.
1746 final int oldVersion = secureSettings.getVersionLocked();
1747 final int newVersion = SETTINGS_VERSION;
1748
1749 // If up do data - done.
1750 if (oldVersion == newVersion) {
1751 return;
1752 }
1753
1754 // Try to upgrade.
1755 final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
1756
1757 // If upgrade failed start from scratch and upgrade.
1758 if (curVersion != newVersion) {
1759 // Drop state we have for this user.
1760 removeUserStateLocked(mUserId, true);
1761
1762 // Recreate the database.
1763 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
1764 SQLiteDatabase database = dbHelper.getWritableDatabase();
1765 dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
1766
1767 // Migrate the settings for this user.
1768 migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
1769
1770 // Now upgrade should work fine.
1771 onUpgradeLocked(mUserId, oldVersion, newVersion);
1772 }
1773
1774 // Set the global settings version if owner.
1775 if (mUserId == UserHandle.USER_OWNER) {
1776 SettingsState globalSettings = getSettingsLocked(
1777 SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
1778 globalSettings.setVersionLocked(newVersion);
1779 }
1780
1781 // Set the secure settings version.
1782 secureSettings.setVersionLocked(newVersion);
1783
1784 // Set the system settings version.
1785 SettingsState systemSettings = getSettingsLocked(
1786 SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
1787 systemSettings.setVersionLocked(newVersion);
1788 }
1789
1790 private SettingsState getGlobalSettingsLocked() {
1791 return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
1792 }
1793
1794 private SettingsState getSecureSettingsLocked(int userId) {
1795 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
1796 }
1797
1798 private SettingsState getSystemSettingsLocked(int userId) {
1799 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
1800 }
1801
1802 private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
1803 if (DEBUG) {
1804 Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
1805 + oldVersion + " to version: " + newVersion);
1806 }
1807
1808 // You must perform all necessary mutations to bring the settings
1809 // for this user from the old to the new version. When you add a new
1810 // upgrade step you *must* update SETTINGS_VERSION.
1811
1812 /**
1813 * This is an example of moving a setting from secure to global.
1814 *
1815 * int currentVersion = oldVersion;
1816 * if (currentVersion == 118) {
1817 * // Remove from the secure settings.
1818 * SettingsState secureSettings = getSecureSettingsLocked(userId);
1819 * String name = "example_setting_to_move";
1820 * String value = secureSettings.getSetting(name);
1821 * secureSettings.deleteSetting(name);
1822 *
1823 * // Add to the global settings.
1824 * SettingsState globalSettings = getGlobalSettingsLocked();
1825 * globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
1826 *
1827 * // Update the current version.
1828 * currentVersion = 119;
1829 * }
1830 *
1831 * // Return the current version.
1832 * return currentVersion;
1833 */
1834
1835 return SettingsState.VERSION_UNDEFINED;
Brad Fitzpatrick547a96b2010-03-09 17:58:53 -08001836 }
1837 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001838 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001839}