blob: 0a1dab4ef2fce8afc78da4b99337183344e27ba3 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.settings;
18
Svetoslav683914b2015-01-15 14:22:26 -080019import android.Manifest;
Christopher Tated5fe1472012-09-10 15:48:38 -070020import android.app.ActivityManager;
Xiaohui Chen43765b72015-08-31 10:57:33 -070021import android.app.AppGlobals;
Christopher Tate45281862010-03-05 15:46:30 -080022import android.app.backup.BackupManager;
Christopher Tate06efb532012-08-24 15:29:27 -070023import android.content.BroadcastReceiver;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070024import android.content.ContentProvider;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070025import android.content.ContentValues;
26import android.content.Context;
Christopher Tate06efb532012-08-24 15:29:27 -070027import android.content.Intent;
28import android.content.IntentFilter;
Svetoslav683914b2015-01-15 14:22:26 -080029import android.content.pm.ApplicationInfo;
Xiaohui Chen43765b72015-08-31 10:57:33 -070030import android.content.pm.IPackageManager;
Svetoslav683914b2015-01-15 14:22:26 -080031import android.content.pm.PackageInfo;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070032import android.content.pm.PackageManager;
Christopher Tate38e7a602013-09-03 16:57:34 -070033import android.content.pm.UserInfo;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070034import android.database.Cursor;
Svetoslav683914b2015-01-15 14:22:26 -080035import android.database.MatrixCursor;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070036import android.database.sqlite.SQLiteDatabase;
37import android.database.sqlite.SQLiteQueryBuilder;
Svetoslav683914b2015-01-15 14:22:26 -080038import android.hardware.camera2.utils.ArrayUtils;
John Spurlocke11ae112015-05-11 16:09:03 -040039import android.media.AudioManager;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070040import android.net.Uri;
Christopher Tate06efb532012-08-24 15:29:27 -070041import android.os.Binder;
Svetoslav683914b2015-01-15 14:22:26 -080042import android.os.Build;
Brad Fitzpatrick1877d012010-03-04 17:48:13 -080043import android.os.Bundle;
Amith Yamasani5cdf7f52013-06-27 15:12:01 -070044import android.os.DropBoxManager;
Svetoslav683914b2015-01-15 14:22:26 -080045import android.os.Environment;
Svetoslav7e0683b2015-08-03 16:02:52 -070046import android.os.Handler;
47import android.os.Looper;
48import android.os.Message;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070049import android.os.ParcelFileDescriptor;
Christopher Tate0da13572013-10-13 17:34:49 -070050import android.os.Process;
Xiaohui Chen43765b72015-08-31 10:57:33 -070051import android.os.RemoteException;
Jeff Sharkey413573a2016-02-22 17:52:45 -070052import android.os.SELinux;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070053import android.os.SystemProperties;
Christopher Tate06efb532012-08-24 15:29:27 -070054import android.os.UserHandle;
55import android.os.UserManager;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070056import android.provider.Settings;
57import android.text.TextUtils;
Svetoslav683914b2015-01-15 14:22:26 -080058import android.util.ArraySet;
Christopher Tate06efb532012-08-24 15:29:27 -070059import android.util.Slog;
60import android.util.SparseArray;
John Spurlocke11ae112015-05-11 16:09:03 -040061
Svetoslav683914b2015-01-15 14:22:26 -080062import com.android.internal.annotations.GuardedBy;
63import com.android.internal.content.PackageMonitor;
64import com.android.internal.os.BackgroundThread;
Suprabh Shukla269c11e2015-12-02 16:51:16 -080065import com.android.providers.settings.SettingsState.Setting;
John Spurlocke11ae112015-05-11 16:09:03 -040066
Svetoslav683914b2015-01-15 14:22:26 -080067import java.io.File;
Svetoslavb505ccc2015-02-17 12:41:04 -080068import java.io.FileDescriptor;
Svetoslav683914b2015-01-15 14:22:26 -080069import java.io.FileNotFoundException;
Svetoslavb505ccc2015-02-17 12:41:04 -080070import java.io.PrintWriter;
Svetoslav683914b2015-01-15 14:22:26 -080071import java.security.SecureRandom;
72import java.util.Arrays;
73import java.util.List;
Svetoslav683914b2015-01-15 14:22:26 -080074import java.util.Set;
75import java.util.regex.Pattern;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070076
Svetoslav683914b2015-01-15 14:22:26 -080077/**
78 * <p>
79 * This class is a content provider that publishes the system settings.
80 * It can be accessed via the content provider APIs or via custom call
81 * commands. The latter is a bit faster and is the preferred way to access
82 * the platform settings.
83 * </p>
84 * <p>
85 * There are three settings types, global (with signature level protection
86 * and shared across users), secure (with signature permission level
87 * protection and per user), and system (with dangerous permission level
88 * protection and per user). Global settings are stored under the device owner.
89 * Each of these settings is represented by a {@link
90 * com.android.providers.settings.SettingsState} object mapped to an integer
91 * key derived from the setting type in the most significant bits and user
92 * id in the least significant bits. Settings are synchronously loaded on
93 * instantiation of a SettingsState and asynchronously persisted on mutation.
94 * Settings are stored in the user specific system directory.
95 * </p>
96 * <p>
97 * Apps targeting APIs Lollipop MR1 and lower can add custom settings entries
98 * and get a warning. Targeting higher API version prohibits this as the
99 * system settings are not a place for apps to save their state. When a package
100 * is removed the settings it added are deleted. Apps cannot delete system
101 * settings added by the platform. System settings values are validated to
102 * ensure the clients do not put bad values. Global and secure settings are
103 * changed only by trusted parties, therefore no validation is performed. Also
104 * there is a limit on the amount of app specific settings that can be added
105 * to prevent unlimited growth of the system process memory footprint.
106 * </p>
107 */
108@SuppressWarnings("deprecation")
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700109public class SettingsProvider extends ContentProvider {
Svetoslav683914b2015-01-15 14:22:26 -0800110 private static final boolean DEBUG = false;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700111
Svetoslav683914b2015-01-15 14:22:26 -0800112 private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
113
114 private static final String LOG_TAG = "SettingsProvider";
Christopher Tate0da13572013-10-13 17:34:49 -0700115
Christopher Tate06efb532012-08-24 15:29:27 -0700116 private static final String TABLE_SYSTEM = "system";
117 private static final String TABLE_SECURE = "secure";
118 private static final String TABLE_GLOBAL = "global";
Svetoslav683914b2015-01-15 14:22:26 -0800119
120 // Old tables no longer exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private static final String TABLE_FAVORITES = "favorites";
122 private static final String TABLE_OLD_FAVORITES = "old_favorites";
Svetoslav683914b2015-01-15 14:22:26 -0800123 private static final String TABLE_BLUETOOTH_DEVICES = "bluetooth_devices";
124 private static final String TABLE_BOOKMARKS = "bookmarks";
125 private static final String TABLE_ANDROID_METADATA = "android_metadata";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
Svetoslav683914b2015-01-15 14:22:26 -0800127 // The set of removed legacy tables.
128 private static final Set<String> REMOVED_LEGACY_TABLES = new ArraySet<>();
Christopher Tate06efb532012-08-24 15:29:27 -0700129 static {
Svetoslav683914b2015-01-15 14:22:26 -0800130 REMOVED_LEGACY_TABLES.add(TABLE_FAVORITES);
131 REMOVED_LEGACY_TABLES.add(TABLE_OLD_FAVORITES);
132 REMOVED_LEGACY_TABLES.add(TABLE_BLUETOOTH_DEVICES);
133 REMOVED_LEGACY_TABLES.add(TABLE_BOOKMARKS);
134 REMOVED_LEGACY_TABLES.add(TABLE_ANDROID_METADATA);
135 }
Christopher Tate06efb532012-08-24 15:29:27 -0700136
Svetoslav683914b2015-01-15 14:22:26 -0800137 private static final int MUTATION_OPERATION_INSERT = 1;
138 private static final int MUTATION_OPERATION_DELETE = 2;
139 private static final int MUTATION_OPERATION_UPDATE = 3;
Julia Reynolds5e458dd2014-07-07 16:07:01 -0400140
Svetoslav683914b2015-01-15 14:22:26 -0800141 private static final String[] ALL_COLUMNS = new String[] {
142 Settings.NameValueTable._ID,
143 Settings.NameValueTable.NAME,
144 Settings.NameValueTable.VALUE
145 };
146
147 private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null);
148
Christopher Tate06efb532012-08-24 15:29:27 -0700149
Svetoslav683914b2015-01-15 14:22:26 -0800150 // Per user secure settings that moved to the for all users global settings.
151 static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
152 static {
153 Settings.Secure.getMovedToGlobalSettings(sSecureMovedToGlobalSettings);
Christopher Tate06efb532012-08-24 15:29:27 -0700154 }
155
Svetoslav683914b2015-01-15 14:22:26 -0800156 // Per user system settings that moved to the for all users global settings.
157 static final Set<String> sSystemMovedToGlobalSettings = new ArraySet<>();
158 static {
159 Settings.System.getMovedToGlobalSettings(sSystemMovedToGlobalSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700160 }
161
Svetoslav683914b2015-01-15 14:22:26 -0800162 // Per user system settings that moved to the per user secure settings.
163 static final Set<String> sSystemMovedToSecureSettings = new ArraySet<>();
164 static {
165 Settings.System.getMovedToSecureSettings(sSystemMovedToSecureSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700166 }
167
Svetoslav683914b2015-01-15 14:22:26 -0800168 // Per all users global settings that moved to the per user secure settings.
169 static final Set<String> sGlobalMovedToSecureSettings = new ArraySet<>();
170 static {
171 Settings.Global.getMovedToSecureSettings(sGlobalMovedToSecureSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700172 }
173
Svetoslav683914b2015-01-15 14:22:26 -0800174 // Per user secure settings that are cloned for the managed profiles of the user.
175 private static final Set<String> sSecureCloneToManagedSettings = new ArraySet<>();
176 static {
177 Settings.Secure.getCloneToManagedProfileSettings(sSecureCloneToManagedSettings);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700178 }
179
Svetoslav683914b2015-01-15 14:22:26 -0800180 // Per user system settings that are cloned for the managed profiles of the user.
181 private static final Set<String> sSystemCloneToManagedSettings = new ArraySet<>();
182 static {
183 Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings);
Julia Reynolds5e458dd2014-07-07 16:07:01 -0400184 }
185
Svetoslav683914b2015-01-15 14:22:26 -0800186 private final Object mLock = new Object();
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -0700187
Svetoslav683914b2015-01-15 14:22:26 -0800188 @GuardedBy("mLock")
189 private SettingsRegistry mSettingsRegistry;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -0700190
Svetoslav7ec28e82015-05-20 17:01:10 -0700191 // We have to call in the user manager with no lock held,
192 private volatile UserManager mUserManager;
Svetoslav683914b2015-01-15 14:22:26 -0800193
Svetoslav7ec28e82015-05-20 17:01:10 -0700194 // We have to call in the package manager with no lock held,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700195 private volatile IPackageManager mPackageManager;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -0700196
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700197 @Override
198 public boolean onCreate() {
Svetoslav683914b2015-01-15 14:22:26 -0800199 synchronized (mLock) {
Xiaohui Chen43765b72015-08-31 10:57:33 -0700200 mUserManager = UserManager.get(getContext());
201 mPackageManager = AppGlobals.getPackageManager();
Svetoslav683914b2015-01-15 14:22:26 -0800202 mSettingsRegistry = new SettingsRegistry();
203 }
204 registerBroadcastReceivers();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700205 return true;
206 }
207
Svetoslav683914b2015-01-15 14:22:26 -0800208 @Override
209 public Bundle call(String method, String name, Bundle args) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700210 final int requestingUserId = getRequestingUserId(args);
211 switch (method) {
212 case Settings.CALL_METHOD_GET_GLOBAL: {
213 Setting setting = getGlobalSetting(name);
214 return packageValueForCallResult(setting);
Svetoslav683914b2015-01-15 14:22:26 -0800215 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700216
217 case Settings.CALL_METHOD_GET_SECURE: {
218 Setting setting = getSecureSetting(name, requestingUserId);
219 return packageValueForCallResult(setting);
220 }
221
222 case Settings.CALL_METHOD_GET_SYSTEM: {
223 Setting setting = getSystemSetting(name, requestingUserId);
224 return packageValueForCallResult(setting);
225 }
226
227 case Settings.CALL_METHOD_PUT_GLOBAL: {
228 String value = getSettingValue(args);
229 insertGlobalSetting(name, value, requestingUserId);
230 break;
231 }
232
233 case Settings.CALL_METHOD_PUT_SECURE: {
234 String value = getSettingValue(args);
235 insertSecureSetting(name, value, requestingUserId);
236 break;
237 }
238
239 case Settings.CALL_METHOD_PUT_SYSTEM: {
240 String value = getSettingValue(args);
241 insertSystemSetting(name, value, requestingUserId);
242 break;
243 }
244
245 default: {
246 Slog.w(LOG_TAG, "call() with invalid method: " + method);
247 } break;
Christopher Tate06efb532012-08-24 15:29:27 -0700248 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700249
Christopher Tate06efb532012-08-24 15:29:27 -0700250 return null;
251 }
252
Brad Fitzpatrick1877d012010-03-04 17:48:13 -0800253 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800254 public String getType(Uri uri) {
255 Arguments args = new Arguments(uri, null, null, true);
256 if (TextUtils.isEmpty(args.name)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700257 return "vnd.android.cursor.dir/" + args.table;
258 } else {
Svetoslav7ec28e82015-05-20 17:01:10 -0700259 return "vnd.android.cursor.item/" + args.table;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700260 }
261 }
262
263 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800264 public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs,
265 String order) {
266 if (DEBUG) {
267 Slog.v(LOG_TAG, "query() for user: " + UserHandle.getCallingUserId());
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700268 }
269
Svetoslav683914b2015-01-15 14:22:26 -0800270 Arguments args = new Arguments(uri, where, whereArgs, true);
271 String[] normalizedProjection = normalizeProjection(projection);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700272
Svetoslav683914b2015-01-15 14:22:26 -0800273 // If a legacy table that is gone, done.
274 if (REMOVED_LEGACY_TABLES.contains(args.table)) {
275 return new MatrixCursor(normalizedProjection, 0);
276 }
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700277
Svetoslav7ec28e82015-05-20 17:01:10 -0700278 switch (args.table) {
279 case TABLE_GLOBAL: {
280 if (args.name != null) {
281 Setting setting = getGlobalSetting(args.name);
282 return packageSettingForQuery(setting, normalizedProjection);
283 } else {
284 return getAllGlobalSettings(projection);
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700285 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700286 }
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700287
Svetoslav7ec28e82015-05-20 17:01:10 -0700288 case TABLE_SECURE: {
289 final int userId = UserHandle.getCallingUserId();
290 if (args.name != null) {
291 Setting setting = getSecureSetting(args.name, userId);
292 return packageSettingForQuery(setting, normalizedProjection);
293 } else {
294 return getAllSecureSettings(userId, projection);
Svetoslav683914b2015-01-15 14:22:26 -0800295 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700296 }
Svetoslav683914b2015-01-15 14:22:26 -0800297
Svetoslav7ec28e82015-05-20 17:01:10 -0700298 case TABLE_SYSTEM: {
299 final int userId = UserHandle.getCallingUserId();
300 if (args.name != null) {
301 Setting setting = getSystemSetting(args.name, userId);
302 return packageSettingForQuery(setting, normalizedProjection);
303 } else {
304 return getAllSystemSettings(userId, projection);
Svetoslav683914b2015-01-15 14:22:26 -0800305 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700306 }
Svetoslav683914b2015-01-15 14:22:26 -0800307
Svetoslav7ec28e82015-05-20 17:01:10 -0700308 default: {
309 throw new IllegalArgumentException("Invalid Uri path:" + uri);
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700310 }
311 }
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700312 }
313
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700314 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800315 public Uri insert(Uri uri, ContentValues values) {
316 if (DEBUG) {
317 Slog.v(LOG_TAG, "insert() for user: " + UserHandle.getCallingUserId());
Christopher Tate06efb532012-08-24 15:29:27 -0700318 }
319
Svetoslav683914b2015-01-15 14:22:26 -0800320 String table = getValidTableOrThrow(uri);
Christopher Tate06efb532012-08-24 15:29:27 -0700321
Svetoslav683914b2015-01-15 14:22:26 -0800322 // If a legacy table that is gone, done.
323 if (REMOVED_LEGACY_TABLES.contains(table)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 return null;
325 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700326
Svetoslav683914b2015-01-15 14:22:26 -0800327 String name = values.getAsString(Settings.Secure.NAME);
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700328 if (!isKeyValid(name)) {
Svetoslav683914b2015-01-15 14:22:26 -0800329 return null;
Mike Lockwoodbd2a7122009-04-02 23:41:33 -0700330 }
331
Svetoslav683914b2015-01-15 14:22:26 -0800332 String value = values.getAsString(Settings.Secure.VALUE);
333
Svetoslav7ec28e82015-05-20 17:01:10 -0700334 switch (table) {
335 case TABLE_GLOBAL: {
336 if (insertGlobalSetting(name, value, UserHandle.getCallingUserId())) {
337 return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
Christopher Tatec221d2b2012-10-03 18:33:52 -0700338 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700339 } break;
340
341 case TABLE_SECURE: {
342 if (insertSecureSetting(name, value, UserHandle.getCallingUserId())) {
343 return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
344 }
345 } break;
346
347 case TABLE_SYSTEM: {
348 if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) {
349 return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
350 }
351 } break;
352
353 default: {
354 throw new IllegalArgumentException("Bad Uri path:" + uri);
Christopher Tatec221d2b2012-10-03 18:33:52 -0700355 }
356 }
357
Svetoslav683914b2015-01-15 14:22:26 -0800358 return null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700359 }
360
361 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800362 public int bulkInsert(Uri uri, ContentValues[] allValues) {
363 if (DEBUG) {
364 Slog.v(LOG_TAG, "bulkInsert() for user: " + UserHandle.getCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700366
Svetoslav683914b2015-01-15 14:22:26 -0800367 int insertionCount = 0;
368 final int valuesCount = allValues.length;
369 for (int i = 0; i < valuesCount; i++) {
370 ContentValues values = allValues[i];
371 if (insert(uri, values) != null) {
372 insertionCount++;
373 }
Dianne Hackborn8d051722014-10-01 14:59:58 -0700374 }
Svetoslav683914b2015-01-15 14:22:26 -0800375
376 return insertionCount;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700377 }
378
379 @Override
Svetoslav683914b2015-01-15 14:22:26 -0800380 public int delete(Uri uri, String where, String[] whereArgs) {
381 if (DEBUG) {
382 Slog.v(LOG_TAG, "delete() for user: " + UserHandle.getCallingUserId());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700384
Svetoslav683914b2015-01-15 14:22:26 -0800385 Arguments args = new Arguments(uri, where, whereArgs, false);
386
387 // If a legacy table that is gone, done.
388 if (REMOVED_LEGACY_TABLES.contains(args.table)) {
389 return 0;
Dianne Hackborn8d051722014-10-01 14:59:58 -0700390 }
Svetoslav683914b2015-01-15 14:22:26 -0800391
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700392 if (!isKeyValid(args.name)) {
Svetoslav683914b2015-01-15 14:22:26 -0800393 return 0;
Dianne Hackborn8d051722014-10-01 14:59:58 -0700394 }
Svetoslav683914b2015-01-15 14:22:26 -0800395
Svetoslav7ec28e82015-05-20 17:01:10 -0700396 switch (args.table) {
397 case TABLE_GLOBAL: {
398 final int userId = UserHandle.getCallingUserId();
399 return deleteGlobalSetting(args.name, userId) ? 1 : 0;
400 }
Svetoslav683914b2015-01-15 14:22:26 -0800401
Svetoslav7ec28e82015-05-20 17:01:10 -0700402 case TABLE_SECURE: {
403 final int userId = UserHandle.getCallingUserId();
404 return deleteSecureSetting(args.name, userId) ? 1 : 0;
405 }
Svetoslav683914b2015-01-15 14:22:26 -0800406
Svetoslav7ec28e82015-05-20 17:01:10 -0700407 case TABLE_SYSTEM: {
408 final int userId = UserHandle.getCallingUserId();
409 return deleteSystemSetting(args.name, userId) ? 1 : 0;
410 }
411
412 default: {
413 throw new IllegalArgumentException("Bad Uri path:" + uri);
Svetoslav683914b2015-01-15 14:22:26 -0800414 }
Dianne Hackborn8d051722014-10-01 14:59:58 -0700415 }
Svetoslav683914b2015-01-15 14:22:26 -0800416 }
417
418 @Override
419 public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
420 if (DEBUG) {
421 Slog.v(LOG_TAG, "update() for user: " + UserHandle.getCallingUserId());
Christopher Tate06efb532012-08-24 15:29:27 -0700422 }
Svetoslav683914b2015-01-15 14:22:26 -0800423
424 Arguments args = new Arguments(uri, where, whereArgs, false);
425
426 // If a legacy table that is gone, done.
427 if (REMOVED_LEGACY_TABLES.contains(args.table)) {
428 return 0;
429 }
430
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700431 String name = values.getAsString(Settings.Secure.NAME);
432 if (!isKeyValid(name)) {
Svetoslav683914b2015-01-15 14:22:26 -0800433 return 0;
434 }
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700435 String value = values.getAsString(Settings.Secure.VALUE);
Svetoslav683914b2015-01-15 14:22:26 -0800436
Svetoslav7ec28e82015-05-20 17:01:10 -0700437 switch (args.table) {
438 case TABLE_GLOBAL: {
439 final int userId = UserHandle.getCallingUserId();
440 return updateGlobalSetting(args.name, value, userId) ? 1 : 0;
441 }
Svetoslav683914b2015-01-15 14:22:26 -0800442
Svetoslav7ec28e82015-05-20 17:01:10 -0700443 case TABLE_SECURE: {
444 final int userId = UserHandle.getCallingUserId();
445 return updateSecureSetting(args.name, value, userId) ? 1 : 0;
446 }
Svetoslav683914b2015-01-15 14:22:26 -0800447
Svetoslav7ec28e82015-05-20 17:01:10 -0700448 case TABLE_SYSTEM: {
449 final int userId = UserHandle.getCallingUserId();
450 return updateSystemSetting(args.name, value, userId) ? 1 : 0;
451 }
Svetoslav683914b2015-01-15 14:22:26 -0800452
Svetoslav7ec28e82015-05-20 17:01:10 -0700453 default: {
454 throw new IllegalArgumentException("Invalid Uri path:" + uri);
Svetoslav683914b2015-01-15 14:22:26 -0800455 }
456 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700457 }
458
459 @Override
460 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
Jeff Sharkey413573a2016-02-22 17:52:45 -0700461 final String cacheName;
462 if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
463 cacheName = Settings.System.RINGTONE_CACHE;
464 } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) {
465 cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
466 } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) {
467 cacheName = Settings.System.ALARM_ALERT_CACHE;
468 } else {
469 throw new FileNotFoundException("Direct file access no longer supported; "
470 + "ringtone playback is available through android.media.Ringtone");
471 }
472
473 final File cacheFile = new File(
474 getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
475 return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
476 }
477
478 private File getRingtoneCacheDir(int userId) {
479 final File cacheDir = new File(Environment.getDataSystemDeDirectory(userId), "ringtones");
480 cacheDir.mkdir();
481 SELinux.restorecon(cacheDir);
482 return cacheDir;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700483 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -0800484
Svetoslavb505ccc2015-02-17 12:41:04 -0800485 @Override
486 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
487 synchronized (mLock) {
488 final long identity = Binder.clearCallingIdentity();
489 try {
490 List<UserInfo> users = mUserManager.getUsers(true);
491 final int userCount = users.size();
492 for (int i = 0; i < userCount; i++) {
493 UserInfo user = users.get(i);
494 dumpForUser(user.id, pw);
495 }
496 } finally {
497 Binder.restoreCallingIdentity(identity);
498 }
499 }
500 }
501
502 private void dumpForUser(int userId, PrintWriter pw) {
Xiaohui Chen43765b72015-08-31 10:57:33 -0700503 if (userId == UserHandle.USER_SYSTEM) {
Svetoslavb505ccc2015-02-17 12:41:04 -0800504 pw.println("GLOBAL SETTINGS (user " + userId + ")");
Svetoslav7ec28e82015-05-20 17:01:10 -0700505 Cursor globalCursor = getAllGlobalSettings(ALL_COLUMNS);
Svetoslavb505ccc2015-02-17 12:41:04 -0800506 dumpSettings(globalCursor, pw);
507 pw.println();
508 }
509
510 pw.println("SECURE SETTINGS (user " + userId + ")");
Svetoslav7ec28e82015-05-20 17:01:10 -0700511 Cursor secureCursor = getAllSecureSettings(userId, ALL_COLUMNS);
Svetoslavb505ccc2015-02-17 12:41:04 -0800512 dumpSettings(secureCursor, pw);
513 pw.println();
514
515 pw.println("SYSTEM SETTINGS (user " + userId + ")");
Svetoslav7ec28e82015-05-20 17:01:10 -0700516 Cursor systemCursor = getAllSystemSettings(userId, ALL_COLUMNS);
Svetoslavb505ccc2015-02-17 12:41:04 -0800517 dumpSettings(systemCursor, pw);
518 pw.println();
519 }
520
521 private void dumpSettings(Cursor cursor, PrintWriter pw) {
Fyodor Kupolov1f450db2015-06-11 15:25:59 -0700522 if (cursor == null || !cursor.moveToFirst()) {
Svetoslavb505ccc2015-02-17 12:41:04 -0800523 return;
524 }
525
526 final int idColumnIdx = cursor.getColumnIndex(Settings.NameValueTable._ID);
527 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
528 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
529
530 do {
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700531 pw.append("_id:").append(toDumpString(cursor.getString(idColumnIdx)));
532 pw.append(" name:").append(toDumpString(cursor.getString(nameColumnIdx)));
533 pw.append(" value:").append(toDumpString(cursor.getString(valueColumnIdx)));
Svetoslavb505ccc2015-02-17 12:41:04 -0800534 pw.println();
535 } while (cursor.moveToNext());
536 }
537
Svetoslav7e0683b2015-08-03 16:02:52 -0700538 private static String toDumpString(String s) {
Makoto Onuki3a2c35782015-06-18 11:21:58 -0700539 if (s != null) {
540 return s;
541 }
542 return "{null}";
543 }
544
Svetoslav683914b2015-01-15 14:22:26 -0800545 private void registerBroadcastReceivers() {
546 IntentFilter userFilter = new IntentFilter();
547 userFilter.addAction(Intent.ACTION_USER_REMOVED);
548 userFilter.addAction(Intent.ACTION_USER_STOPPED);
549
550 getContext().registerReceiver(new BroadcastReceiver() {
551 @Override
552 public void onReceive(Context context, Intent intent) {
553 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700554 UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -0800555
556 switch (intent.getAction()) {
557 case Intent.ACTION_USER_REMOVED: {
558 mSettingsRegistry.removeUserStateLocked(userId, true);
559 } break;
560
561 case Intent.ACTION_USER_STOPPED: {
562 mSettingsRegistry.removeUserStateLocked(userId, false);
563 } break;
564 }
565 }
566 }, userFilter);
567
568 PackageMonitor monitor = new PackageMonitor() {
569 @Override
570 public void onPackageRemoved(String packageName, int uid) {
571 synchronized (mLock) {
572 mSettingsRegistry.onPackageRemovedLocked(packageName,
573 UserHandle.getUserId(uid));
574 }
575 }
576 };
577
578 // package changes
579 monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
580 UserHandle.ALL, true);
581 }
582
Svetoslav7ec28e82015-05-20 17:01:10 -0700583 private Cursor getAllGlobalSettings(String[] projection) {
Svetoslav683914b2015-01-15 14:22:26 -0800584 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700585 Slog.v(LOG_TAG, "getAllGlobalSettings()");
Svetoslav683914b2015-01-15 14:22:26 -0800586 }
587
Svetoslav7ec28e82015-05-20 17:01:10 -0700588 synchronized (mLock) {
589 // Get the settings.
590 SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
Xiaohui Chen43765b72015-08-31 10:57:33 -0700591 SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -0800592
Svetoslav7ec28e82015-05-20 17:01:10 -0700593 List<String> names = settingsState.getSettingNamesLocked();
Svetoslav683914b2015-01-15 14:22:26 -0800594
Svetoslav7ec28e82015-05-20 17:01:10 -0700595 final int nameCount = names.size();
Svetoslav683914b2015-01-15 14:22:26 -0800596
Svetoslav7ec28e82015-05-20 17:01:10 -0700597 String[] normalizedProjection = normalizeProjection(projection);
598 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
Svetoslav683914b2015-01-15 14:22:26 -0800599
Svetoslav7ec28e82015-05-20 17:01:10 -0700600 // Anyone can get the global settings, so no security checks.
601 for (int i = 0; i < nameCount; i++) {
602 String name = names.get(i);
603 Setting setting = settingsState.getSettingLocked(name);
604 appendSettingToCursor(result, setting);
605 }
606
607 return result;
Svetoslav683914b2015-01-15 14:22:26 -0800608 }
Svetoslav683914b2015-01-15 14:22:26 -0800609 }
610
Svetoslav7ec28e82015-05-20 17:01:10 -0700611 private Setting getGlobalSetting(String name) {
Svetoslav683914b2015-01-15 14:22:26 -0800612 if (DEBUG) {
613 Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
614 }
615
616 // Get the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700617 synchronized (mLock) {
618 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700619 UserHandle.USER_SYSTEM, name);
Svetoslav683914b2015-01-15 14:22:26 -0800620 }
Svetoslav683914b2015-01-15 14:22:26 -0800621 }
622
Svetoslav7ec28e82015-05-20 17:01:10 -0700623 private boolean updateGlobalSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800624 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700625 Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800626 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700627 return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
Svetoslav683914b2015-01-15 14:22:26 -0800628 }
629
Svetoslav7ec28e82015-05-20 17:01:10 -0700630 private boolean insertGlobalSetting(String name, String value, int requestingUserId) {
631 if (DEBUG) {
632 Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ")");
633 }
634 return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
635 }
636
637 private boolean deleteGlobalSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800638 if (DEBUG) {
639 Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
640 }
Svetoslav7ec28e82015-05-20 17:01:10 -0700641 return mutateGlobalSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
Svetoslav683914b2015-01-15 14:22:26 -0800642 }
643
Svetoslav7ec28e82015-05-20 17:01:10 -0700644 private boolean mutateGlobalSetting(String name, String value, int requestingUserId,
Svetoslav683914b2015-01-15 14:22:26 -0800645 int operation) {
646 // Make sure the caller can change the settings - treated as secure.
647 enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
648
Svetoslav683914b2015-01-15 14:22:26 -0800649 // Resolve the userId on whose behalf the call is made.
650 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
651
Makoto Onuki28da2e32015-11-20 11:30:44 -0800652 // If this is a setting that is currently restricted for this user, do not allow
653 // unrestricting changes.
654 if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
Svetoslav683914b2015-01-15 14:22:26 -0800655 return false;
656 }
657
658 // Perform the mutation.
Svetoslav7ec28e82015-05-20 17:01:10 -0700659 synchronized (mLock) {
660 switch (operation) {
661 case MUTATION_OPERATION_INSERT: {
662 return mSettingsRegistry
663 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700664 UserHandle.USER_SYSTEM, name, value, getCallingPackage());
Svetoslav7ec28e82015-05-20 17:01:10 -0700665 }
Svetoslav683914b2015-01-15 14:22:26 -0800666
Svetoslav7ec28e82015-05-20 17:01:10 -0700667 case MUTATION_OPERATION_DELETE: {
668 return mSettingsRegistry.deleteSettingLocked(
669 SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700670 UserHandle.USER_SYSTEM, name);
Svetoslav7ec28e82015-05-20 17:01:10 -0700671 }
Svetoslav683914b2015-01-15 14:22:26 -0800672
Svetoslav7ec28e82015-05-20 17:01:10 -0700673 case MUTATION_OPERATION_UPDATE: {
674 return mSettingsRegistry
675 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
Xiaohui Chen43765b72015-08-31 10:57:33 -0700676 UserHandle.USER_SYSTEM, name, value, getCallingPackage());
Svetoslav7ec28e82015-05-20 17:01:10 -0700677 }
Svetoslav683914b2015-01-15 14:22:26 -0800678 }
679 }
680
681 return false;
682 }
683
Svetoslav7ec28e82015-05-20 17:01:10 -0700684 private Cursor getAllSecureSettings(int userId, String[] projection) {
Svetoslav683914b2015-01-15 14:22:26 -0800685 if (DEBUG) {
686 Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
687 }
688
689 // Resolve the userId on whose behalf the call is made.
690 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
691
Svetoslav7ec28e82015-05-20 17:01:10 -0700692 synchronized (mLock) {
693 List<String> names = mSettingsRegistry.getSettingsNamesLocked(
694 SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
Svetoslav683914b2015-01-15 14:22:26 -0800695
Svetoslav7ec28e82015-05-20 17:01:10 -0700696 final int nameCount = names.size();
Svetoslav683914b2015-01-15 14:22:26 -0800697
Svetoslav7ec28e82015-05-20 17:01:10 -0700698 String[] normalizedProjection = normalizeProjection(projection);
699 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
Svetoslav683914b2015-01-15 14:22:26 -0800700
Svetoslav7ec28e82015-05-20 17:01:10 -0700701 for (int i = 0; i < nameCount; i++) {
702 String name = names.get(i);
703 // Determine the owning user as some profile settings are cloned from the parent.
704 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
705 name);
Svetoslav683914b2015-01-15 14:22:26 -0800706
Svetoslav7ec28e82015-05-20 17:01:10 -0700707 // Special case for location (sigh).
708 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
709 return null;
710 }
Svetoslav683914b2015-01-15 14:22:26 -0800711
Svetoslav7ec28e82015-05-20 17:01:10 -0700712 Setting setting = mSettingsRegistry.getSettingLocked(
713 SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
714 appendSettingToCursor(result, setting);
Svetoslav683914b2015-01-15 14:22:26 -0800715 }
716
Svetoslav7ec28e82015-05-20 17:01:10 -0700717 return result;
Svetoslav683914b2015-01-15 14:22:26 -0800718 }
Svetoslav683914b2015-01-15 14:22:26 -0800719 }
720
Svetoslav7ec28e82015-05-20 17:01:10 -0700721 private Setting getSecureSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800722 if (DEBUG) {
723 Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
724 }
725
726 // Resolve the userId on whose behalf the call is made.
727 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
728
729 // Determine the owning user as some profile settings are cloned from the parent.
730 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
731
732 // Special case for location (sigh).
733 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
734 return null;
735 }
736
737 // Get the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700738 synchronized (mLock) {
739 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
740 owningUserId, name);
741 }
Svetoslav683914b2015-01-15 14:22:26 -0800742 }
743
Svetoslav7ec28e82015-05-20 17:01:10 -0700744 private boolean insertSecureSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800745 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700746 Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800747 + requestingUserId + ")");
748 }
749
Svetoslav7ec28e82015-05-20 17:01:10 -0700750 return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
Svetoslav683914b2015-01-15 14:22:26 -0800751 }
752
Svetoslav7ec28e82015-05-20 17:01:10 -0700753 private boolean deleteSecureSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800754 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700755 Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800756 }
757
Svetoslav7ec28e82015-05-20 17:01:10 -0700758 return mutateSecureSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
Svetoslav683914b2015-01-15 14:22:26 -0800759 }
760
Svetoslav7ec28e82015-05-20 17:01:10 -0700761 private boolean updateSecureSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800762 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700763 Slog.v(LOG_TAG, "updateSecureSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800764 + requestingUserId + ")");
765 }
766
Svetoslav7ec28e82015-05-20 17:01:10 -0700767 return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
Svetoslav683914b2015-01-15 14:22:26 -0800768 }
769
Svetoslav7ec28e82015-05-20 17:01:10 -0700770 private boolean mutateSecureSetting(String name, String value, int requestingUserId,
Svetoslav683914b2015-01-15 14:22:26 -0800771 int operation) {
772 // Make sure the caller can change the settings.
773 enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
774
Svetoslav683914b2015-01-15 14:22:26 -0800775 // Resolve the userId on whose behalf the call is made.
776 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
777
Makoto Onuki28da2e32015-11-20 11:30:44 -0800778 // If this is a setting that is currently restricted for this user, do not allow
779 // unrestricting changes.
780 if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value)) {
Svetoslav683914b2015-01-15 14:22:26 -0800781 return false;
782 }
783
784 // Determine the owning user as some profile settings are cloned from the parent.
785 final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
786
787 // Only the owning user can change the setting.
788 if (owningUserId != callingUserId) {
789 return false;
790 }
791
792 // Special cases for location providers (sigh).
793 if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
Svetoslavb596a2c2015-02-17 21:37:09 -0800794 return updateLocationProvidersAllowedLocked(value, owningUserId);
Svetoslav683914b2015-01-15 14:22:26 -0800795 }
796
797 // Mutate the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700798 synchronized (mLock) {
799 switch (operation) {
800 case MUTATION_OPERATION_INSERT: {
801 return mSettingsRegistry
802 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
803 owningUserId, name, value, getCallingPackage());
804 }
Svetoslav683914b2015-01-15 14:22:26 -0800805
Svetoslav7ec28e82015-05-20 17:01:10 -0700806 case MUTATION_OPERATION_DELETE: {
807 return mSettingsRegistry.deleteSettingLocked(
808 SettingsRegistry.SETTINGS_TYPE_SECURE,
809 owningUserId, name);
810 }
Svetoslav683914b2015-01-15 14:22:26 -0800811
Svetoslav7ec28e82015-05-20 17:01:10 -0700812 case MUTATION_OPERATION_UPDATE: {
813 return mSettingsRegistry
814 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
815 owningUserId, name, value, getCallingPackage());
816 }
Svetoslav683914b2015-01-15 14:22:26 -0800817 }
818 }
819
820 return false;
821 }
822
Svetoslav7ec28e82015-05-20 17:01:10 -0700823 private Cursor getAllSystemSettings(int userId, String[] projection) {
Svetoslav683914b2015-01-15 14:22:26 -0800824 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700825 Slog.v(LOG_TAG, "getAllSecureSystem(" + userId + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800826 }
827
828 // Resolve the userId on whose behalf the call is made.
829 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
830
Svetoslav7ec28e82015-05-20 17:01:10 -0700831 synchronized (mLock) {
832 List<String> names = mSettingsRegistry.getSettingsNamesLocked(
833 SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
Svetoslav683914b2015-01-15 14:22:26 -0800834
Svetoslav7ec28e82015-05-20 17:01:10 -0700835 final int nameCount = names.size();
Svetoslav683914b2015-01-15 14:22:26 -0800836
Svetoslav7ec28e82015-05-20 17:01:10 -0700837 String[] normalizedProjection = normalizeProjection(projection);
838 MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
Svetoslav683914b2015-01-15 14:22:26 -0800839
Svetoslav7ec28e82015-05-20 17:01:10 -0700840 for (int i = 0; i < nameCount; i++) {
841 String name = names.get(i);
Svetoslav683914b2015-01-15 14:22:26 -0800842
Svetoslav7ec28e82015-05-20 17:01:10 -0700843 // Determine the owning user as some profile settings are cloned from the parent.
844 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId,
845 name);
Svetoslav683914b2015-01-15 14:22:26 -0800846
Svetoslav7ec28e82015-05-20 17:01:10 -0700847 Setting setting = mSettingsRegistry.getSettingLocked(
848 SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
849 appendSettingToCursor(result, setting);
850 }
851
852 return result;
Svetoslav683914b2015-01-15 14:22:26 -0800853 }
Svetoslav683914b2015-01-15 14:22:26 -0800854 }
855
Svetoslav7ec28e82015-05-20 17:01:10 -0700856 private Setting getSystemSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800857 if (DEBUG) {
858 Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")");
859 }
860
861 // Resolve the userId on whose behalf the call is made.
862 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
863
864 // Determine the owning user as some profile settings are cloned from the parent.
865 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
866
867 // Get the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700868 synchronized (mLock) {
869 return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
870 owningUserId, name);
871 }
Svetoslav683914b2015-01-15 14:22:26 -0800872 }
873
Svetoslav7ec28e82015-05-20 17:01:10 -0700874 private boolean insertSystemSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800875 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700876 Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800877 + requestingUserId + ")");
878 }
879
Svetoslav7ec28e82015-05-20 17:01:10 -0700880 return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
Svetoslav683914b2015-01-15 14:22:26 -0800881 }
882
Svetoslav7ec28e82015-05-20 17:01:10 -0700883 private boolean deleteSystemSetting(String name, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800884 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700885 Slog.v(LOG_TAG, "deleteSystemSetting(" + name + ", " + requestingUserId + ")");
Svetoslav683914b2015-01-15 14:22:26 -0800886 }
887
Svetoslav7ec28e82015-05-20 17:01:10 -0700888 return mutateSystemSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
Svetoslav683914b2015-01-15 14:22:26 -0800889 }
890
Svetoslav7ec28e82015-05-20 17:01:10 -0700891 private boolean updateSystemSetting(String name, String value, int requestingUserId) {
Svetoslav683914b2015-01-15 14:22:26 -0800892 if (DEBUG) {
Svetoslav7ec28e82015-05-20 17:01:10 -0700893 Slog.v(LOG_TAG, "updateSystemSetting(" + name + ", " + value + ", "
Svetoslav683914b2015-01-15 14:22:26 -0800894 + requestingUserId + ")");
895 }
896
Svetoslav7ec28e82015-05-20 17:01:10 -0700897 return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
Svetoslav683914b2015-01-15 14:22:26 -0800898 }
899
Svetoslav7ec28e82015-05-20 17:01:10 -0700900 private boolean mutateSystemSetting(String name, String value, int runAsUserId,
Svetoslav683914b2015-01-15 14:22:26 -0800901 int operation) {
Billy Lau6ad2d662015-07-18 00:26:58 +0100902 if (!hasWriteSecureSettingsPermission()) {
903 // If the caller doesn't hold WRITE_SECURE_SETTINGS, we verify whether this
904 // operation is allowed for the calling package through appops.
905 if (!Settings.checkAndNoteWriteSettingsOperation(getContext(),
906 Binder.getCallingUid(), getCallingPackage(), true)) {
907 return false;
908 }
Svetoslav683914b2015-01-15 14:22:26 -0800909 }
910
Svetoslav683914b2015-01-15 14:22:26 -0800911 // Resolve the userId on whose behalf the call is made.
912 final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
913
Svetoslavd8d25e02015-11-20 13:09:26 -0800914 // Enforce what the calling package can mutate the system settings.
915 enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name, callingUserId);
916
Svetoslav683914b2015-01-15 14:22:26 -0800917 // Determine the owning user as some profile settings are cloned from the parent.
918 final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
919
920 // Only the owning user id can change the setting.
921 if (owningUserId != callingUserId) {
922 return false;
923 }
924
Jeff Sharkey413573a2016-02-22 17:52:45 -0700925 // Invalidate any relevant cache files
926 String cacheName = null;
927 if (Settings.System.RINGTONE.equals(name)) {
928 cacheName = Settings.System.RINGTONE_CACHE;
929 } else if (Settings.System.NOTIFICATION_SOUND.equals(name)) {
930 cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
931 } else if (Settings.System.ALARM_ALERT.equals(name)) {
932 cacheName = Settings.System.ALARM_ALERT_CACHE;
933 }
934 if (cacheName != null) {
935 final File cacheFile = new File(
936 getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
937 cacheFile.delete();
938 }
939
Svetoslav683914b2015-01-15 14:22:26 -0800940 // Mutate the value.
Svetoslav7ec28e82015-05-20 17:01:10 -0700941 synchronized (mLock) {
942 switch (operation) {
943 case MUTATION_OPERATION_INSERT: {
944 validateSystemSettingValue(name, value);
945 return mSettingsRegistry
946 .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
947 owningUserId, name, value, getCallingPackage());
948 }
949
950 case MUTATION_OPERATION_DELETE: {
951 return mSettingsRegistry.deleteSettingLocked(
952 SettingsRegistry.SETTINGS_TYPE_SYSTEM,
953 owningUserId, name);
954 }
955
956 case MUTATION_OPERATION_UPDATE: {
957 validateSystemSettingValue(name, value);
958 return mSettingsRegistry
959 .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
960 owningUserId, name, value, getCallingPackage());
961 }
Svetoslav683914b2015-01-15 14:22:26 -0800962 }
963
Svetoslav7ec28e82015-05-20 17:01:10 -0700964 return false;
Svetoslav683914b2015-01-15 14:22:26 -0800965 }
Svetoslav683914b2015-01-15 14:22:26 -0800966 }
967
Billy Lau6ad2d662015-07-18 00:26:58 +0100968 private boolean hasWriteSecureSettingsPermission() {
Svetoslavf41334b2015-06-23 12:06:03 -0700969 // Write secure settings is a more protected permission. If caller has it we are good.
970 if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
971 == PackageManager.PERMISSION_GRANTED) {
972 return true;
973 }
974
Svetoslavf41334b2015-06-23 12:06:03 -0700975 return false;
976 }
977
Svetoslav683914b2015-01-15 14:22:26 -0800978 private void validateSystemSettingValue(String name, String value) {
979 Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
980 if (validator != null && !validator.validate(value)) {
981 throw new IllegalArgumentException("Invalid value: " + value
982 + " for setting: " + name);
983 }
984 }
985
986 private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId,
987 int owningUserId) {
988 // Optimization - location providers are restricted only for managed profiles.
989 if (callingUserId == owningUserId) {
990 return false;
991 }
992 if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)
993 && mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
994 new UserHandle(callingUserId))) {
995 return true;
996 }
997 return false;
998 }
999
Makoto Onuki28da2e32015-11-20 11:30:44 -08001000 /**
1001 * Checks whether changing a setting to a value is prohibited by the corresponding user
1002 * restriction.
1003 *
1004 * <p>See also {@link com.android.server.pm.UserRestrictionsUtils#applyUserRestrictionLR},
1005 * which should be in sync with this method.
1006 *
1007 * @return true if the change is prohibited, false if the change is allowed.
1008 */
1009 private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
1010 String value) {
1011 String restriction;
1012 switch (setting) {
1013 case Settings.Secure.LOCATION_MODE:
1014 // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
1015 // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come
1016 // here normally, but we still protect it here from a direct provider write.
1017 if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) return false;
1018 restriction = UserManager.DISALLOW_SHARE_LOCATION;
1019 break;
1020
1021 case Settings.Secure.LOCATION_PROVIDERS_ALLOWED:
1022 // See SettingsProvider.updateLocationProvidersAllowedLocked. "-" is to disable
1023 // a provider, which should be allowed even if the user restriction is set.
1024 if (value != null && value.startsWith("-")) return false;
1025 restriction = UserManager.DISALLOW_SHARE_LOCATION;
1026 break;
1027
1028 case Settings.Secure.INSTALL_NON_MARKET_APPS:
1029 if ("0".equals(value)) return false;
1030 restriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
1031 break;
1032
1033 case Settings.Global.ADB_ENABLED:
1034 if ("0".equals(value)) return false;
1035 restriction = UserManager.DISALLOW_DEBUGGING_FEATURES;
1036 break;
1037
1038 case Settings.Global.PACKAGE_VERIFIER_ENABLE:
1039 case Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB:
1040 if ("1".equals(value)) return false;
1041 restriction = UserManager.ENSURE_VERIFY_APPS;
1042 break;
1043
1044 case Settings.Global.PREFERRED_NETWORK_MODE:
1045 restriction = UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
1046 break;
1047
1048 default:
Mahaver Chopra87648752016-01-08 19:23:57 +00001049 if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
Mahaver Chopradea471e2015-12-17 11:02:37 +00001050 if ("0".equals(value)) return false;
1051 restriction = UserManager.DISALLOW_DATA_ROAMING;
1052 break;
1053 }
Makoto Onuki28da2e32015-11-20 11:30:44 -08001054 return false;
Svetoslav683914b2015-01-15 14:22:26 -08001055 }
Makoto Onuki28da2e32015-11-20 11:30:44 -08001056
1057 return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
Svetoslav683914b2015-01-15 14:22:26 -08001058 }
1059
1060 private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
1061 return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting);
1062 }
1063
1064 private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
1065 return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
1066 }
1067
1068 private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) {
1069 final int parentId = getGroupParentLocked(userId);
1070 if (parentId != userId && keys.contains(name)) {
1071 return parentId;
1072 }
1073 return userId;
1074 }
1075
Svetoslavf41334b2015-06-23 12:06:03 -07001076 private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
Xiaohui Chen43765b72015-08-31 10:57:33 -07001077 String name, int userId) {
Svetoslav683914b2015-01-15 14:22:26 -08001078 // System/root/shell can mutate whatever secure settings they want.
1079 final int callingUid = Binder.getCallingUid();
1080 if (callingUid == android.os.Process.SYSTEM_UID
1081 || callingUid == Process.SHELL_UID
1082 || callingUid == Process.ROOT_UID) {
1083 return;
1084 }
1085
1086 switch (operation) {
1087 case MUTATION_OPERATION_INSERT:
1088 // Insert updates.
1089 case MUTATION_OPERATION_UPDATE: {
1090 if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
1091 return;
1092 }
1093
1094 // The calling package is already verified.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001095 PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
Svetoslav683914b2015-01-15 14:22:26 -08001096
1097 // Privileged apps can do whatever they want.
1098 if ((packageInfo.applicationInfo.privateFlags
1099 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1100 return;
1101 }
1102
1103 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1104 packageInfo.applicationInfo.targetSdkVersion, name);
1105 } break;
1106
1107 case MUTATION_OPERATION_DELETE: {
1108 if (Settings.System.PUBLIC_SETTINGS.contains(name)
1109 || Settings.System.PRIVATE_SETTINGS.contains(name)) {
1110 throw new IllegalArgumentException("You cannot delete system defined"
1111 + " secure settings.");
1112 }
1113
1114 // The calling package is already verified.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001115 PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
Svetoslav683914b2015-01-15 14:22:26 -08001116
1117 // Privileged apps can do whatever they want.
1118 if ((packageInfo.applicationInfo.privateFlags &
1119 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1120 return;
1121 }
1122
1123 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1124 packageInfo.applicationInfo.targetSdkVersion, name);
1125 } break;
1126 }
1127 }
1128
Xiaohui Chen43765b72015-08-31 10:57:33 -07001129 private PackageInfo getCallingPackageInfoOrThrow(int userId) {
Svetoslav683914b2015-01-15 14:22:26 -08001130 try {
Svetoslav Ganov67a8d352016-03-02 13:26:40 -08001131 PackageInfo packageInfo = mPackageManager.getPackageInfo(
1132 getCallingPackage(), 0, userId);
1133 if (packageInfo != null) {
1134 return packageInfo;
1135 }
Xiaohui Chen43765b72015-08-31 10:57:33 -07001136 } catch (RemoteException e) {
Svetoslav Ganov67a8d352016-03-02 13:26:40 -08001137 /* ignore */
Svetoslav683914b2015-01-15 14:22:26 -08001138 }
Svetoslav Ganov67a8d352016-03-02 13:26:40 -08001139 throw new IllegalStateException("Calling package doesn't exist");
Svetoslav683914b2015-01-15 14:22:26 -08001140 }
1141
1142 private int getGroupParentLocked(int userId) {
1143 // Most frequent use case.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001144 if (userId == UserHandle.USER_SYSTEM) {
Svetoslav683914b2015-01-15 14:22:26 -08001145 return userId;
1146 }
1147 // We are in the same process with the user manager and the returned
1148 // user info is a cached instance, so just look up instead of cache.
1149 final long identity = Binder.clearCallingIdentity();
1150 try {
Svetoslav7ec28e82015-05-20 17:01:10 -07001151 // Just a lookup and not reentrant, so holding a lock is fine.
Svetoslav683914b2015-01-15 14:22:26 -08001152 UserInfo userInfo = mUserManager.getProfileParent(userId);
1153 return (userInfo != null) ? userInfo.id : userId;
1154 } finally {
1155 Binder.restoreCallingIdentity(identity);
1156 }
1157 }
1158
Svetoslav683914b2015-01-15 14:22:26 -08001159 private void enforceWritePermission(String permission) {
1160 if (getContext().checkCallingOrSelfPermission(permission)
1161 != PackageManager.PERMISSION_GRANTED) {
1162 throw new SecurityException("Permission denial: writing to settings requires:"
1163 + permission);
1164 }
1165 }
1166
1167 /*
1168 * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
1169 * This setting contains a list of the currently enabled location providers.
1170 * But helper functions in android.providers.Settings can enable or disable
1171 * a single provider by using a "+" or "-" prefix before the provider name.
1172 *
Makoto Onuki28da2e32015-11-20 11:30:44 -08001173 * <p>See also {@link #isGlobalOrSecureSettingRestrictedForUser()}. If DISALLOW_SHARE_LOCATION
1174 * is set, the said method will only allow values with the "-" prefix.
1175 *
Svetoslav683914b2015-01-15 14:22:26 -08001176 * @returns whether the enabled location providers changed.
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001177 */
Svetoslavb596a2c2015-02-17 21:37:09 -08001178 private boolean updateLocationProvidersAllowedLocked(String value, int owningUserId) {
Svetoslav683914b2015-01-15 14:22:26 -08001179 if (TextUtils.isEmpty(value)) {
1180 return false;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001181 }
1182
Svetoslav683914b2015-01-15 14:22:26 -08001183 final char prefix = value.charAt(0);
1184 if (prefix != '+' && prefix != '-') {
1185 return false;
1186 }
1187
1188 // skip prefix
1189 value = value.substring(1);
1190
Svetoslav7ec28e82015-05-20 17:01:10 -07001191 Setting settingValue = getSecureSetting(
Svetoslav683914b2015-01-15 14:22:26 -08001192 Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
1193
1194 String oldProviders = (settingValue != null) ? settingValue.getValue() : "";
1195
1196 int index = oldProviders.indexOf(value);
1197 int end = index + value.length();
1198
1199 // check for commas to avoid matching on partial string
1200 if (index > 0 && oldProviders.charAt(index - 1) != ',') {
1201 index = -1;
1202 }
1203
1204 // check for commas to avoid matching on partial string
1205 if (end < oldProviders.length() && oldProviders.charAt(end) != ',') {
1206 index = -1;
1207 }
1208
1209 String newProviders;
1210
1211 if (prefix == '+' && index < 0) {
1212 // append the provider to the list if not present
1213 if (oldProviders.length() == 0) {
1214 newProviders = value;
1215 } else {
1216 newProviders = oldProviders + ',' + value;
1217 }
1218 } else if (prefix == '-' && index >= 0) {
1219 // remove the provider from the list if present
1220 // remove leading or trailing comma
1221 if (index > 0) {
1222 index--;
1223 } else if (end < oldProviders.length()) {
1224 end++;
1225 }
1226
1227 newProviders = oldProviders.substring(0, index);
1228 if (end < oldProviders.length()) {
1229 newProviders += oldProviders.substring(end);
1230 }
1231 } else {
1232 // nothing changed, so no need to update the database
1233 return false;
1234 }
1235
Svetoslavb596a2c2015-02-17 21:37:09 -08001236 return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
1237 owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders,
1238 getCallingPackage());
Svetoslav683914b2015-01-15 14:22:26 -08001239 }
1240
Svetoslav683914b2015-01-15 14:22:26 -08001241 private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1242 int targetSdkVersion, String name) {
1243 // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash.
1244 if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
1245 if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
1246 Slog.w(LOG_TAG, "You shouldn't not change private system settings."
1247 + " This will soon become an error.");
1248 } else {
1249 Slog.w(LOG_TAG, "You shouldn't keep your settings in the secure settings."
1250 + " This will soon become an error.");
1251 }
1252 } else {
1253 if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
1254 throw new IllegalArgumentException("You cannot change private secure settings.");
1255 } else {
1256 throw new IllegalArgumentException("You cannot keep your settings in"
1257 + " the secure settings.");
1258 }
1259 }
1260 }
1261
1262 private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) {
1263 if (requestingUserId == UserHandle.getCallingUserId()) {
1264 return requestingUserId;
1265 }
1266 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1267 Binder.getCallingUid(), requestingUserId, false, true,
1268 "get/set setting for user", null);
1269 }
1270
1271 private static Bundle packageValueForCallResult(Setting setting) {
1272 if (setting == null) {
1273 return NULL_SETTING;
1274 }
1275 return Bundle.forPair(Settings.NameValueTable.VALUE, setting.getValue());
1276 }
1277
1278 private static int getRequestingUserId(Bundle args) {
1279 final int callingUserId = UserHandle.getCallingUserId();
1280 return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId)
1281 : callingUserId;
1282 }
1283
1284 private static String getSettingValue(Bundle args) {
1285 return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null;
1286 }
1287
1288 private static String getValidTableOrThrow(Uri uri) {
1289 if (uri.getPathSegments().size() > 0) {
1290 String table = uri.getPathSegments().get(0);
1291 if (DatabaseHelper.isValidTable(table)) {
1292 return table;
1293 }
1294 throw new IllegalArgumentException("Bad root path: " + table);
1295 }
1296 throw new IllegalArgumentException("Invalid URI:" + uri);
1297 }
1298
1299 private static MatrixCursor packageSettingForQuery(Setting setting, String[] projection) {
1300 if (setting == null) {
1301 return new MatrixCursor(projection, 0);
1302 }
1303 MatrixCursor cursor = new MatrixCursor(projection, 1);
1304 appendSettingToCursor(cursor, setting);
1305 return cursor;
1306 }
1307
1308 private static String[] normalizeProjection(String[] projection) {
1309 if (projection == null) {
1310 return ALL_COLUMNS;
1311 }
1312
1313 final int columnCount = projection.length;
1314 for (int i = 0; i < columnCount; i++) {
1315 String column = projection[i];
1316 if (!ArrayUtils.contains(ALL_COLUMNS, column)) {
1317 throw new IllegalArgumentException("Invalid column: " + column);
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001318 }
1319 }
1320
Svetoslav683914b2015-01-15 14:22:26 -08001321 return projection;
1322 }
1323
1324 private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) {
1325 final int columnCount = cursor.getColumnCount();
1326
1327 String[] values = new String[columnCount];
1328
1329 for (int i = 0; i < columnCount; i++) {
1330 String column = cursor.getColumnName(i);
1331
1332 switch (column) {
1333 case Settings.NameValueTable._ID: {
1334 values[i] = setting.getId();
1335 } break;
1336
1337 case Settings.NameValueTable.NAME: {
1338 values[i] = setting.getName();
1339 } break;
1340
1341 case Settings.NameValueTable.VALUE: {
1342 values[i] = setting.getValue();
1343 } break;
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001344 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001345 }
1346
Svetoslav683914b2015-01-15 14:22:26 -08001347 cursor.addRow(values);
1348 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001349
Makoto Onuki3a2c35782015-06-18 11:21:58 -07001350 private static boolean isKeyValid(String key) {
1351 return !(TextUtils.isEmpty(key) || SettingsState.isBinary(key));
1352 }
1353
Svetoslav683914b2015-01-15 14:22:26 -08001354 private static final class Arguments {
1355 private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
1356 Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
1357
1358 private static final Pattern WHERE_PATTERN_WITH_PARAM_IN_BRACKETS =
1359 Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*\\?[\\s]*\\)[\\s]*");
1360
1361 private static final Pattern WHERE_PATTERN_NO_PARAM_IN_BRACKETS =
1362 Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*\\)[\\s]*");
1363
1364 private static final Pattern WHERE_PATTERN_NO_PARAM_NO_BRACKETS =
1365 Pattern.compile("[\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*");
1366
1367 public final String table;
1368 public final String name;
1369
1370 public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) {
1371 final int segmentSize = uri.getPathSegments().size();
1372 switch (segmentSize) {
1373 case 1: {
1374 if (where != null
1375 && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches()
1376 || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
1377 && whereArgs.length == 1) {
1378 name = whereArgs[0];
1379 table = computeTableForSetting(uri, name);
Svetoslav28494652015-02-12 14:11:42 -08001380 return;
Svetoslav683914b2015-01-15 14:22:26 -08001381 } else if (where != null
1382 && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
1383 || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
1384 final int startIndex = Math.max(where.indexOf("'"),
1385 where.indexOf("\"")) + 1;
1386 final int endIndex = Math.max(where.lastIndexOf("'"),
1387 where.lastIndexOf("\""));
1388 name = where.substring(startIndex, endIndex);
1389 table = computeTableForSetting(uri, name);
Svetoslav28494652015-02-12 14:11:42 -08001390 return;
Svetoslav683914b2015-01-15 14:22:26 -08001391 } else if (supportAll && where == null && whereArgs == null) {
1392 name = null;
1393 table = computeTableForSetting(uri, null);
Svetoslav28494652015-02-12 14:11:42 -08001394 return;
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001395 }
Svetoslav683914b2015-01-15 14:22:26 -08001396 } break;
1397
Svetoslav28494652015-02-12 14:11:42 -08001398 case 2: {
1399 if (where == null && whereArgs == null) {
1400 name = uri.getPathSegments().get(1);
1401 table = computeTableForSetting(uri, name);
1402 return;
1403 }
1404 } break;
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001405 }
Svetoslav28494652015-02-12 14:11:42 -08001406
1407 EventLogTags.writeUnsupportedSettingsQuery(
1408 uri.toSafeString(), where, Arrays.toString(whereArgs));
1409 String message = String.format( "Supported SQL:\n"
1410 + " uri content://some_table/some_property with null where and where args\n"
1411 + " uri content://some_table with query name=? and single name as arg\n"
1412 + " uri content://some_table with query name=some_name and null args\n"
1413 + " but got - uri:%1s, where:%2s whereArgs:%3s", uri, where,
1414 Arrays.toString(whereArgs));
1415 throw new IllegalArgumentException(message);
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001416 }
1417
Svetoslav28494652015-02-12 14:11:42 -08001418 private static String computeTableForSetting(Uri uri, String name) {
Svetoslav683914b2015-01-15 14:22:26 -08001419 String table = getValidTableOrThrow(uri);
1420
1421 if (name != null) {
1422 if (sSystemMovedToSecureSettings.contains(name)) {
1423 table = TABLE_SECURE;
1424 }
1425
1426 if (sSystemMovedToGlobalSettings.contains(name)) {
1427 table = TABLE_GLOBAL;
1428 }
1429
1430 if (sSecureMovedToGlobalSettings.contains(name)) {
1431 table = TABLE_GLOBAL;
1432 }
1433
1434 if (sGlobalMovedToSecureSettings.contains(name)) {
1435 table = TABLE_SECURE;
1436 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001437 }
Svetoslav683914b2015-01-15 14:22:26 -08001438
1439 return table;
1440 }
1441 }
1442
1443 final class SettingsRegistry {
1444 private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
1445
1446 private static final int SETTINGS_TYPE_GLOBAL = 0;
1447 private static final int SETTINGS_TYPE_SYSTEM = 1;
1448 private static final int SETTINGS_TYPE_SECURE = 2;
1449
1450 private static final int SETTINGS_TYPE_MASK = 0xF0000000;
1451 private static final int SETTINGS_TYPE_SHIFT = 28;
1452
1453 private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
1454 private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
1455 private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
1456
1457 private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
1458
1459 private final BackupManager mBackupManager;
1460
Svetoslav7e0683b2015-08-03 16:02:52 -07001461 private final Handler mHandler;
1462
Svetoslav683914b2015-01-15 14:22:26 -08001463 public SettingsRegistry() {
1464 mBackupManager = new BackupManager(getContext());
Svetoslav7e0683b2015-08-03 16:02:52 -07001465 mHandler = new MyHandler(getContext().getMainLooper());
Svetoslav683914b2015-01-15 14:22:26 -08001466 migrateAllLegacySettingsIfNeeded();
Brad Fitzpatrickf366a9b2010-08-24 16:14:07 -07001467 }
1468
Svetoslav683914b2015-01-15 14:22:26 -08001469 public List<String> getSettingsNamesLocked(int type, int userId) {
1470 final int key = makeKey(type, userId);
1471 SettingsState settingsState = peekSettingsStateLocked(key);
1472 return settingsState.getSettingNamesLocked();
1473 }
1474
1475 public SettingsState getSettingsLocked(int type, int userId) {
1476 final int key = makeKey(type, userId);
1477 return peekSettingsStateLocked(key);
1478 }
1479
1480 public void ensureSettingsForUserLocked(int userId) {
1481 // Migrate the setting for this user if needed.
1482 migrateLegacySettingsForUserIfNeededLocked(userId);
1483
1484 // Ensure global settings loaded if owner.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001485 if (userId == UserHandle.USER_SYSTEM) {
1486 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -08001487 ensureSettingsStateLocked(globalKey);
1488 }
1489
1490 // Ensure secure settings loaded.
1491 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1492 ensureSettingsStateLocked(secureKey);
1493
1494 // Make sure the secure settings have an Android id set.
1495 SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
1496 ensureSecureSettingAndroidIdSetLocked(secureSettings);
1497
1498 // Ensure system settings loaded.
1499 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1500 ensureSettingsStateLocked(systemKey);
1501
1502 // Upgrade the settings to the latest version.
1503 UpgradeController upgrader = new UpgradeController(userId);
1504 upgrader.upgradeIfNeededLocked();
1505 }
1506
1507 private void ensureSettingsStateLocked(int key) {
1508 if (mSettingsStates.get(key) == null) {
1509 final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
1510 SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
1511 maxBytesPerPackage);
1512 mSettingsStates.put(key, settingsState);
1513 }
1514 }
1515
1516 public void removeUserStateLocked(int userId, boolean permanently) {
1517 // We always keep the global settings in memory.
1518
1519 // Nuke system settings.
1520 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1521 final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
1522 if (systemSettingsState != null) {
1523 if (permanently) {
1524 mSettingsStates.remove(systemKey);
1525 systemSettingsState.destroyLocked(null);
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001526 } else {
Svetoslav683914b2015-01-15 14:22:26 -08001527 systemSettingsState.destroyLocked(new Runnable() {
1528 @Override
1529 public void run() {
1530 mSettingsStates.remove(systemKey);
1531 }
1532 });
1533 }
1534 }
1535
1536 // Nuke secure settings.
1537 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1538 final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
1539 if (secureSettingsState != null) {
1540 if (permanently) {
1541 mSettingsStates.remove(secureKey);
1542 secureSettingsState.destroyLocked(null);
1543 } else {
1544 secureSettingsState.destroyLocked(new Runnable() {
1545 @Override
1546 public void run() {
1547 mSettingsStates.remove(secureKey);
1548 }
1549 });
Brad Fitzpatrick342984a2010-03-09 16:59:30 -08001550 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08001551 }
1552 }
1553
Svetoslav683914b2015-01-15 14:22:26 -08001554 public boolean insertSettingLocked(int type, int userId, String name, String value,
1555 String packageName) {
1556 final int key = makeKey(type, userId);
1557
1558 SettingsState settingsState = peekSettingsStateLocked(key);
1559 final boolean success = settingsState.insertSettingLocked(name, value, packageName);
1560
1561 if (success) {
1562 notifyForSettingsChange(key, name);
1563 }
1564 return success;
1565 }
1566
1567 public boolean deleteSettingLocked(int type, int userId, String name) {
1568 final int key = makeKey(type, userId);
1569
1570 SettingsState settingsState = peekSettingsStateLocked(key);
1571 final boolean success = settingsState.deleteSettingLocked(name);
1572
1573 if (success) {
1574 notifyForSettingsChange(key, name);
1575 }
1576 return success;
1577 }
1578
1579 public Setting getSettingLocked(int type, int userId, String name) {
1580 final int key = makeKey(type, userId);
1581
1582 SettingsState settingsState = peekSettingsStateLocked(key);
1583 return settingsState.getSettingLocked(name);
1584 }
1585
1586 public boolean updateSettingLocked(int type, int userId, String name, String value,
1587 String packageName) {
1588 final int key = makeKey(type, userId);
1589
1590 SettingsState settingsState = peekSettingsStateLocked(key);
1591 final boolean success = settingsState.updateSettingLocked(name, value, packageName);
1592
1593 if (success) {
1594 notifyForSettingsChange(key, name);
1595 }
1596
1597 return success;
1598 }
1599
1600 public void onPackageRemovedLocked(String packageName, int userId) {
Svet Ganov8de34802015-04-27 09:33:40 -07001601 // Global and secure settings are signature protected. Apps signed
1602 // by the platform certificate are generally not uninstalled and
1603 // the main exception is tests. We trust components signed
1604 // by the platform certificate and do not do a clean up after them.
Svetoslav683914b2015-01-15 14:22:26 -08001605
1606 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1607 SettingsState systemSettings = mSettingsStates.get(systemKey);
Svet Ganov8de34802015-04-27 09:33:40 -07001608 if (systemSettings != null) {
1609 systemSettings.onPackageRemovedLocked(packageName);
1610 }
Svetoslav683914b2015-01-15 14:22:26 -08001611 }
1612
1613 private SettingsState peekSettingsStateLocked(int key) {
1614 SettingsState settingsState = mSettingsStates.get(key);
1615 if (settingsState != null) {
1616 return settingsState;
1617 }
1618
1619 ensureSettingsForUserLocked(getUserIdFromKey(key));
1620 return mSettingsStates.get(key);
1621 }
1622
1623 private void migrateAllLegacySettingsIfNeeded() {
1624 synchronized (mLock) {
Xiaohui Chen43765b72015-08-31 10:57:33 -07001625 final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -08001626 File globalFile = getSettingsFile(key);
1627 if (globalFile.exists()) {
1628 return;
1629 }
1630
1631 final long identity = Binder.clearCallingIdentity();
1632 try {
1633 List<UserInfo> users = mUserManager.getUsers(true);
1634
1635 final int userCount = users.size();
1636 for (int i = 0; i < userCount; i++) {
1637 final int userId = users.get(i).id;
1638
1639 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1640 SQLiteDatabase database = dbHelper.getWritableDatabase();
1641 migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1642
1643 // Upgrade to the latest version.
1644 UpgradeController upgrader = new UpgradeController(userId);
1645 upgrader.upgradeIfNeededLocked();
1646
1647 // Drop from memory if not a running user.
1648 if (!mUserManager.isUserRunning(new UserHandle(userId))) {
1649 removeUserStateLocked(userId, false);
1650 }
1651 }
1652 } finally {
1653 Binder.restoreCallingIdentity(identity);
1654 }
1655 }
1656 }
1657
1658 private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
1659 // Every user has secure settings and if no file we need to migrate.
1660 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1661 File secureFile = getSettingsFile(secureKey);
1662 if (secureFile.exists()) {
1663 return;
1664 }
1665
1666 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
1667 SQLiteDatabase database = dbHelper.getWritableDatabase();
1668
1669 migrateLegacySettingsForUserLocked(dbHelper, database, userId);
1670 }
1671
1672 private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
1673 SQLiteDatabase database, int userId) {
1674 // Move over the global settings if owner.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001675 if (userId == UserHandle.USER_SYSTEM) {
Svetoslav683914b2015-01-15 14:22:26 -08001676 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
1677 ensureSettingsStateLocked(globalKey);
1678 SettingsState globalSettings = mSettingsStates.get(globalKey);
1679 migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
1680 globalSettings.persistSyncLocked();
1681 }
1682
1683 // Move over the secure settings.
1684 final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
1685 ensureSettingsStateLocked(secureKey);
1686 SettingsState secureSettings = mSettingsStates.get(secureKey);
1687 migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
1688 ensureSecureSettingAndroidIdSetLocked(secureSettings);
1689 secureSettings.persistSyncLocked();
1690
1691 // Move over the system settings.
1692 final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
1693 ensureSettingsStateLocked(systemKey);
1694 SettingsState systemSettings = mSettingsStates.get(systemKey);
1695 migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
1696 systemSettings.persistSyncLocked();
1697
1698 // Drop the database as now all is moved and persisted.
1699 if (DROP_DATABASE_ON_MIGRATION) {
1700 dbHelper.dropDatabase();
1701 } else {
1702 dbHelper.backupDatabase();
1703 }
1704 }
1705
1706 private void migrateLegacySettingsLocked(SettingsState settingsState,
1707 SQLiteDatabase database, String table) {
1708 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
1709 queryBuilder.setTables(table);
1710
1711 Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
1712 null, null, null, null, null);
1713
1714 if (cursor == null) {
1715 return;
1716 }
1717
1718 try {
1719 if (!cursor.moveToFirst()) {
1720 return;
1721 }
1722
1723 final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
1724 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
1725
1726 settingsState.setVersionLocked(database.getVersion());
1727
1728 while (!cursor.isAfterLast()) {
1729 String name = cursor.getString(nameColumnIdx);
1730 String value = cursor.getString(valueColumnIdx);
1731 settingsState.insertSettingLocked(name, value,
1732 SettingsState.SYSTEM_PACKAGE_NAME);
1733 cursor.moveToNext();
1734 }
1735 } finally {
1736 cursor.close();
1737 }
1738 }
1739
1740 private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
1741 Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
1742
1743 if (value != null) {
1744 return;
1745 }
1746
1747 final int userId = getUserIdFromKey(secureSettings.mKey);
1748
1749 final UserInfo user;
1750 final long identity = Binder.clearCallingIdentity();
1751 try {
1752 user = mUserManager.getUserInfo(userId);
1753 } finally {
1754 Binder.restoreCallingIdentity(identity);
1755 }
1756 if (user == null) {
1757 // Can happen due to races when deleting users - treat as benign.
1758 return;
1759 }
1760
1761 String androidId = Long.toHexString(new SecureRandom().nextLong());
1762 secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
1763 SettingsState.SYSTEM_PACKAGE_NAME);
1764
1765 Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
1766 + "] for user " + userId);
1767
1768 // Write a drop box entry if it's a restricted profile
1769 if (user.isRestricted()) {
1770 DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
1771 Context.DROPBOX_SERVICE);
1772 if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
1773 dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
1774 + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
1775 }
1776 }
1777 }
1778
1779 private void notifyForSettingsChange(int key, String name) {
1780 // Update the system property *first*, so if someone is listening for
1781 // a notification and then using the contract class to get their data,
1782 // the system property will be updated and they'll get the new data.
1783
1784 boolean backedUpDataChanged = false;
1785 String property = null;
1786 if (isGlobalSettingsKey(key)) {
1787 property = Settings.Global.SYS_PROP_SETTING_VERSION;
1788 backedUpDataChanged = true;
1789 } else if (isSecureSettingsKey(key)) {
1790 property = Settings.Secure.SYS_PROP_SETTING_VERSION;
1791 backedUpDataChanged = true;
1792 } else if (isSystemSettingsKey(key)) {
1793 property = Settings.System.SYS_PROP_SETTING_VERSION;
1794 backedUpDataChanged = true;
1795 }
1796
1797 if (property != null) {
1798 final long version = SystemProperties.getLong(property, 0) + 1;
1799 SystemProperties.set(property, Long.toString(version));
1800 if (DEBUG) {
1801 Slog.v(LOG_TAG, "System property " + property + "=" + version);
1802 }
1803 }
1804
1805 // Inform the backup manager about a data change
1806 if (backedUpDataChanged) {
Svetoslav7e0683b2015-08-03 16:02:52 -07001807 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_DATA_CHANGED).sendToTarget();
Svetoslav683914b2015-01-15 14:22:26 -08001808 }
1809
1810 // Now send the notification through the content framework.
1811
1812 final int userId = getUserIdFromKey(key);
1813 Uri uri = getNotificationUriFor(key, name);
1814
Svetoslav7e0683b2015-08-03 16:02:52 -07001815 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
1816 userId, 0, uri).sendToTarget();
1817
Nicolas Prevot310e1ee2015-07-02 14:03:06 +01001818 if (isSecureSettingsKey(key)) {
1819 maybeNotifyProfiles(userId, uri, name, sSecureCloneToManagedSettings);
1820 } else if (isSystemSettingsKey(key)) {
1821 maybeNotifyProfiles(userId, uri, name, sSystemCloneToManagedSettings);
1822 }
1823 }
1824
1825 private void maybeNotifyProfiles(int userId, Uri uri, String name,
1826 Set<String> keysCloned) {
1827 if (keysCloned.contains(name)) {
1828 List<UserInfo> profiles = mUserManager.getProfiles(userId);
1829 int size = profiles.size();
1830 for (int i = 0; i < size; i++) {
1831 UserInfo profile = profiles.get(i);
1832 // the notification for userId has already been sent.
1833 if (profile.id != userId) {
Svetoslav7e0683b2015-08-03 16:02:52 -07001834 mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
1835 profile.id, 0, uri).sendToTarget();
Nicolas Prevot310e1ee2015-07-02 14:03:06 +01001836 }
1837 }
1838 }
Svetoslav683914b2015-01-15 14:22:26 -08001839 }
1840
1841 private int makeKey(int type, int userId) {
1842 return (type << SETTINGS_TYPE_SHIFT) | userId;
1843 }
1844
1845 private int getTypeFromKey(int key) {
1846 return key >> SETTINGS_TYPE_SHIFT;
1847 }
1848
1849 private int getUserIdFromKey(int key) {
1850 return key & ~SETTINGS_TYPE_MASK;
1851 }
1852
1853 private boolean isGlobalSettingsKey(int key) {
1854 return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
1855 }
1856
1857 private boolean isSystemSettingsKey(int key) {
1858 return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
1859 }
1860
1861 private boolean isSecureSettingsKey(int key) {
1862 return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
1863 }
1864
1865 private File getSettingsFile(int key) {
1866 if (isGlobalSettingsKey(key)) {
1867 final int userId = getUserIdFromKey(key);
1868 return new File(Environment.getUserSystemDirectory(userId),
1869 SETTINGS_FILE_GLOBAL);
1870 } else if (isSystemSettingsKey(key)) {
1871 final int userId = getUserIdFromKey(key);
1872 return new File(Environment.getUserSystemDirectory(userId),
1873 SETTINGS_FILE_SYSTEM);
1874 } else if (isSecureSettingsKey(key)) {
1875 final int userId = getUserIdFromKey(key);
1876 return new File(Environment.getUserSystemDirectory(userId),
1877 SETTINGS_FILE_SECURE);
1878 } else {
1879 throw new IllegalArgumentException("Invalid settings key:" + key);
1880 }
1881 }
1882
1883 private Uri getNotificationUriFor(int key, String name) {
1884 if (isGlobalSettingsKey(key)) {
1885 return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
1886 : Settings.Global.CONTENT_URI;
1887 } else if (isSecureSettingsKey(key)) {
1888 return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
1889 : Settings.Secure.CONTENT_URI;
1890 } else if (isSystemSettingsKey(key)) {
1891 return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
1892 : Settings.System.CONTENT_URI;
1893 } else {
1894 throw new IllegalArgumentException("Invalid settings key:" + key);
1895 }
1896 }
1897
1898 private int getMaxBytesPerPackageForType(int type) {
1899 switch (type) {
1900 case SETTINGS_TYPE_GLOBAL:
1901 case SETTINGS_TYPE_SECURE: {
1902 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
1903 }
1904
1905 default: {
1906 return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
1907 }
1908 }
1909 }
1910
Svetoslav7e0683b2015-08-03 16:02:52 -07001911 private final class MyHandler extends Handler {
1912 private static final int MSG_NOTIFY_URI_CHANGED = 1;
1913 private static final int MSG_NOTIFY_DATA_CHANGED = 2;
1914
1915 public MyHandler(Looper looper) {
1916 super(looper);
1917 }
1918
1919 @Override
1920 public void handleMessage(Message msg) {
1921 switch (msg.what) {
1922 case MSG_NOTIFY_URI_CHANGED: {
1923 final int userId = msg.arg1;
1924 Uri uri = (Uri) msg.obj;
1925 getContext().getContentResolver().notifyChange(uri, null, true, userId);
1926 if (DEBUG) {
1927 Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
1928 }
1929 } break;
1930
1931 case MSG_NOTIFY_DATA_CHANGED: {
1932 mBackupManager.dataChanged();
1933 } break;
1934 }
1935 }
1936 }
1937
Svetoslav683914b2015-01-15 14:22:26 -08001938 private final class UpgradeController {
Prathmesh Prabhude16b862016-03-04 15:22:24 -08001939 private static final int SETTINGS_VERSION = 125;
Svetoslav683914b2015-01-15 14:22:26 -08001940
1941 private final int mUserId;
1942
1943 public UpgradeController(int userId) {
1944 mUserId = userId;
1945 }
1946
1947 public void upgradeIfNeededLocked() {
1948 // The version of all settings for a user is the same (all users have secure).
1949 SettingsState secureSettings = getSettingsLocked(
1950 SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
1951
1952 // Try an update from the current state.
1953 final int oldVersion = secureSettings.getVersionLocked();
1954 final int newVersion = SETTINGS_VERSION;
1955
Svet Ganovc9755bc2015-03-28 13:21:22 -07001956 // If up do date - done.
Svetoslav683914b2015-01-15 14:22:26 -08001957 if (oldVersion == newVersion) {
1958 return;
1959 }
1960
1961 // Try to upgrade.
1962 final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
1963
1964 // If upgrade failed start from scratch and upgrade.
1965 if (curVersion != newVersion) {
1966 // Drop state we have for this user.
1967 removeUserStateLocked(mUserId, true);
1968
1969 // Recreate the database.
1970 DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
1971 SQLiteDatabase database = dbHelper.getWritableDatabase();
1972 dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
1973
1974 // Migrate the settings for this user.
1975 migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
1976
1977 // Now upgrade should work fine.
1978 onUpgradeLocked(mUserId, oldVersion, newVersion);
1979 }
1980
1981 // Set the global settings version if owner.
Xiaohui Chen43765b72015-08-31 10:57:33 -07001982 if (mUserId == UserHandle.USER_SYSTEM) {
Svetoslav683914b2015-01-15 14:22:26 -08001983 SettingsState globalSettings = getSettingsLocked(
1984 SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
1985 globalSettings.setVersionLocked(newVersion);
1986 }
1987
1988 // Set the secure settings version.
1989 secureSettings.setVersionLocked(newVersion);
1990
1991 // Set the system settings version.
1992 SettingsState systemSettings = getSettingsLocked(
1993 SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
1994 systemSettings.setVersionLocked(newVersion);
1995 }
1996
1997 private SettingsState getGlobalSettingsLocked() {
Xiaohui Chen43765b72015-08-31 10:57:33 -07001998 return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
Svetoslav683914b2015-01-15 14:22:26 -08001999 }
2000
2001 private SettingsState getSecureSettingsLocked(int userId) {
2002 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
2003 }
2004
2005 private SettingsState getSystemSettingsLocked(int userId) {
2006 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
2007 }
2008
Jeff Brown503cffc2015-03-26 18:08:51 -07002009 /**
2010 * You must perform all necessary mutations to bring the settings
2011 * for this user from the old to the new version. When you add a new
2012 * upgrade step you *must* update SETTINGS_VERSION.
2013 *
2014 * This is an example of moving a setting from secure to global.
2015 *
2016 * // v119: Example settings changes.
2017 * if (currentVersion == 118) {
2018 * if (userId == UserHandle.USER_OWNER) {
2019 * // Remove from the secure settings.
2020 * SettingsState secureSettings = getSecureSettingsLocked(userId);
2021 * String name = "example_setting_to_move";
2022 * String value = secureSettings.getSetting(name);
2023 * secureSettings.deleteSetting(name);
2024 *
2025 * // Add to the global settings.
2026 * SettingsState globalSettings = getGlobalSettingsLocked();
2027 * globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
2028 * }
2029 *
2030 * // Update the current version.
2031 * currentVersion = 119;
2032 * }
2033 */
Svetoslav683914b2015-01-15 14:22:26 -08002034 private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
2035 if (DEBUG) {
2036 Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
2037 + oldVersion + " to version: " + newVersion);
2038 }
2039
Jeff Brown503cffc2015-03-26 18:08:51 -07002040 int currentVersion = oldVersion;
Svetoslav683914b2015-01-15 14:22:26 -08002041
John Spurlocke11ae112015-05-11 16:09:03 -04002042 // v119: Reset zen + ringer mode.
2043 if (currentVersion == 118) {
Xiaohui Chen43765b72015-08-31 10:57:33 -07002044 if (userId == UserHandle.USER_SYSTEM) {
John Spurlocke11ae112015-05-11 16:09:03 -04002045 final SettingsState globalSettings = getGlobalSettingsLocked();
2046 globalSettings.updateSettingLocked(Settings.Global.ZEN_MODE,
2047 Integer.toString(Settings.Global.ZEN_MODE_OFF),
2048 SettingsState.SYSTEM_PACKAGE_NAME);
2049 globalSettings.updateSettingLocked(Settings.Global.MODE_RINGER,
2050 Integer.toString(AudioManager.RINGER_MODE_NORMAL),
2051 SettingsState.SYSTEM_PACKAGE_NAME);
2052 }
2053 currentVersion = 119;
2054 }
2055
Jason Monk27bbb2d2015-03-31 16:46:39 -04002056 // v120: Add double tap to wake setting.
2057 if (currentVersion == 119) {
2058 SettingsState secureSettings = getSecureSettingsLocked(userId);
2059 secureSettings.insertSettingLocked(Settings.Secure.DOUBLE_TAP_TO_WAKE,
2060 getContext().getResources().getBoolean(
2061 R.bool.def_double_tap_to_wake) ? "1" : "0",
2062 SettingsState.SYSTEM_PACKAGE_NAME);
2063
2064 currentVersion = 120;
2065 }
2066
Svetoslav7e0683b2015-08-03 16:02:52 -07002067 if (currentVersion == 120) {
2068 // Before 121, we used a different string encoding logic. We just bump the
2069 // version here; SettingsState knows how to handle pre-version 120 files.
2070 currentVersion = 121;
2071 }
Makoto Onuki3a2c35782015-06-18 11:21:58 -07002072
Martijn Coenen7ab4b7f2015-07-27 15:58:32 +02002073 if (currentVersion == 121) {
2074 // Version 122: allow OEMs to set a default payment component in resources.
2075 // Note that we only write the default if no default has been set;
2076 // if there is, we just leave the default at whatever it currently is.
2077 final SettingsState secureSettings = getSecureSettingsLocked(userId);
2078 String defaultComponent = (getContext().getResources().getString(
2079 R.string.def_nfc_payment_component));
2080 Setting currentSetting = secureSettings.getSettingLocked(
2081 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
2082 if (defaultComponent != null && !defaultComponent.isEmpty() &&
2083 currentSetting == null) {
2084 secureSettings.insertSettingLocked(
2085 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
2086 defaultComponent,
2087 SettingsState.SYSTEM_PACKAGE_NAME);
2088 }
2089 currentVersion = 122;
2090 }
Suprabh Shukla269c11e2015-12-02 16:51:16 -08002091
2092 if (currentVersion == 122) {
2093 // Version 123: Adding a default value for the ability to add a user from
2094 // the lock screen.
2095 if (userId == UserHandle.USER_SYSTEM) {
2096 final SettingsState globalSettings = getGlobalSettingsLocked();
2097 Setting currentSetting = globalSettings.getSettingLocked(
2098 Settings.Global.ADD_USERS_WHEN_LOCKED);
2099 if (currentSetting == null) {
2100 globalSettings.insertSettingLocked(
2101 Settings.Global.ADD_USERS_WHEN_LOCKED,
2102 getContext().getResources().getBoolean(
2103 R.bool.def_add_users_from_lockscreen) ? "1" : "0",
2104 SettingsState.SYSTEM_PACKAGE_NAME);
2105 }
2106 }
2107 currentVersion = 123;
2108 }
Bryce Leebd179282015-12-17 19:01:37 -08002109
2110 if (currentVersion == 123) {
Bryce Leeec85f342015-12-16 13:32:28 -08002111 final SettingsState globalSettings = getGlobalSettingsLocked();
2112 String defaultDisabledProfiles = (getContext().getResources().getString(
2113 R.string.def_bluetooth_disabled_profiles));
2114 globalSettings.insertSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES,
2115 defaultDisabledProfiles, SettingsState.SYSTEM_PACKAGE_NAME);
Bryce Leebd179282015-12-17 19:01:37 -08002116 currentVersion = 124;
Bryce Leeec85f342015-12-16 13:32:28 -08002117 }
2118
Prathmesh Prabhude16b862016-03-04 15:22:24 -08002119 if (currentVersion == 124) {
2120 // Version 124: allow OEMs to set a default value for whether IME should be
2121 // shown when a physical keyboard is connected.
2122 final SettingsState secureSettings = getSecureSettingsLocked(userId);
2123 Setting currentSetting = secureSettings.getSettingLocked(
2124 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
2125 if (currentSetting == null) {
2126 secureSettings.insertSettingLocked(
2127 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
2128 getContext().getResources().getBoolean(
2129 R.bool.def_show_ime_with_hard_keyboard) ? "1" : "0",
2130 SettingsState.SYSTEM_PACKAGE_NAME);
2131 }
2132 currentVersion = 125;
2133 }
2134
Jeff Brown503cffc2015-03-26 18:08:51 -07002135 // vXXX: Add new settings above this point.
Svetoslav683914b2015-01-15 14:22:26 -08002136
Jeff Brown503cffc2015-03-26 18:08:51 -07002137 // Return the current version.
2138 return currentVersion;
Brad Fitzpatrick547a96b2010-03-09 17:58:53 -08002139 }
2140 }
Brad Fitzpatrick1bd62bd2010-03-08 18:30:52 -08002141 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002142}