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