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