Settings recovery support

This change allows the system to perform iterative reset
of changes to settings in order to recover from bad a
state such as a reboot loop.

To enable this we add the notion of a default value. The
default can be set by any package but if the package that
set it is a part of the system, i.e. trusted, then other
packages that are not a part of the system, i.e. untrusted,
cannot change the default. The settings setter APIs that
do not take a default effectively clear the default. Putting
a setting from a system component always makes it the
default and if the package in not trusted then value is
not made the default. The rationale is that the system is
tested and its values are safe but third-party components
are not trusted and their values are not safe.

The reset modes from the least intrusive are: untrusted
defaults - reset only settings set by untrusted components
to their defaults or clear them otherwise; untrusted clear
- clear settings set by untrusted components (or snap to
default if provided by the system); trusted defaults - reset
all settings to defaults set by the system or clear them
otherwise.

Also a package can reset to defaults changes it made to
the global and secure settings. It is also possible to
associate a setting with an optional token which can then
be used to reset settings set by this package and
associated with the token allowing parallel experiments
over disjoint settings subsets.

The default values are also useful for experiment (or
more precisely iterative tuning of devices' behavior in
production) as the stable configuration can be set to
the "graduated" safe defaults and set the values to the
experimental ones to measure impact.

Test: tests pass

Change-Id: I838955ea3bb28337f416ee244dff2fb1199b6943
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 2b833b2..710214c 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -3,7 +3,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     src/com/android/providers/settings/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := telephony-common ims-common
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c149876..3e62158 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -84,6 +84,10 @@
 import java.util.Set;
 import java.util.regex.Pattern;
 
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.SHELL_UID;
+
 /**
  * <p>
  * This class is a content provider that publishes the system settings.
@@ -147,6 +151,7 @@
     private static final int MUTATION_OPERATION_INSERT = 1;
     private static final int MUTATION_OPERATION_DELETE = 2;
     private static final int MUTATION_OPERATION_UPDATE = 3;
+    private static final int MUTATION_OPERATION_RESET = 4;
 
     private static final String[] ALL_COLUMNS = new String[] {
             Settings.NameValueTable._ID,
@@ -292,13 +297,17 @@
 
             case Settings.CALL_METHOD_PUT_GLOBAL: {
                 String value = getSettingValue(args);
-                insertGlobalSetting(name, value, requestingUserId, false);
+                String tag = getSettingTag(args);
+                final boolean makeDefault = getSettingMakeDefault(args);
+                insertGlobalSetting(name, value, tag, makeDefault, requestingUserId, false);
                 break;
             }
 
             case Settings.CALL_METHOD_PUT_SECURE: {
                 String value = getSettingValue(args);
-                insertSecureSetting(name, value, requestingUserId, false);
+                String tag = getSettingTag(args);
+                final boolean makeDefault = getSettingMakeDefault(args);
+                insertSecureSetting(name, value, tag, makeDefault, requestingUserId, false);
                 break;
             }
 
@@ -308,6 +317,20 @@
                 break;
             }
 
+            case Settings.CALL_METHOD_RESET_GLOBAL: {
+                final int mode = getResetModeEnforcingPermission(args);
+                String tag = getSettingTag(args);
+                resetGlobalSetting(requestingUserId, mode, tag);
+                break;
+            }
+
+            case Settings.CALL_METHOD_RESET_SECURE: {
+                final int mode = getResetModeEnforcingPermission(args);
+                String tag = getSettingTag(args);
+                resetSecureSetting(requestingUserId, mode, tag);
+                break;
+            }
+
             default: {
                 Slog.w(LOG_TAG, "call() with invalid method: " + method);
             } break;
@@ -399,13 +422,15 @@
 
         switch (table) {
             case TABLE_GLOBAL: {
-                if (insertGlobalSetting(name, value, UserHandle.getCallingUserId(), false)) {
+                if (insertGlobalSetting(name, value, null, false,
+                        UserHandle.getCallingUserId(), false)) {
                     return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
                 }
             } break;
 
             case TABLE_SECURE: {
-                if (insertSecureSetting(name, value, UserHandle.getCallingUserId(), false)) {
+                if (insertSecureSetting(name, value, null, false,
+                        UserHandle.getCallingUserId(), false)) {
                     return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
                 }
             } break;
@@ -503,12 +528,14 @@
         switch (args.table) {
             case TABLE_GLOBAL: {
                 final int userId = UserHandle.getCallingUserId();
-                return updateGlobalSetting(args.name, value, userId, false) ? 1 : 0;
+                return updateGlobalSetting(args.name, value, null, false,
+                        userId, false) ? 1 : 0;
             }
 
             case TABLE_SECURE: {
                 final int userId = UserHandle.getCallingUserId();
-                return updateSecureSetting(args.name, value, userId, false) ? 1 : 0;
+                return updateSecureSetting(args.name, value, null, false,
+                        userId, false) ? 1 : 0;
             }
 
             case TABLE_SYSTEM: {
@@ -586,10 +613,9 @@
                     SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
             if (globalSettings != null) {
                 dumpSettingsLocked(globalSettings, pw);
+                pw.println();
+                globalSettings.dumpHistoricalOperations(pw);
             }
-            pw.println();
-
-            globalSettings.dumpHistoricalOperations(pw);
         }
 
         pw.println("SECURE SETTINGS (user " + userId + ")");
@@ -597,20 +623,18 @@
                 SETTINGS_TYPE_SECURE, userId);
         if (secureSettings != null) {
             dumpSettingsLocked(secureSettings, pw);
+            pw.println();
+            secureSettings.dumpHistoricalOperations(pw);
         }
-        pw.println();
-
-        secureSettings.dumpHistoricalOperations(pw);
 
         pw.println("SYSTEM SETTINGS (user " + userId + ")");
         SettingsState systemSettings = mSettingsRegistry.getSettingsLocked(
                 SETTINGS_TYPE_SYSTEM, userId);
         if (systemSettings != null) {
             dumpSettingsLocked(systemSettings, pw);
+            pw.println();
+            systemSettings.dumpHistoricalOperations(pw);
         }
-        pw.println();
-
-        systemSettings.dumpHistoricalOperations(pw);
     }
 
     private void dumpSettingsLocked(SettingsState settingsState, PrintWriter pw) {
@@ -624,9 +648,16 @@
             pw.print("_id:"); pw.print(toDumpString(setting.getId()));
             pw.print(" name:"); pw.print(toDumpString(name));
             if (setting.getPackageName() != null) {
-                pw.print(" pkg:"); pw.print(toDumpString(setting.getPackageName()));
+                pw.print(" pkg:"); pw.print(setting.getPackageName());
             }
             pw.print(" value:"); pw.print(toDumpString(setting.getValue()));
+            if (setting.getDefaultValue() != null) {
+                pw.print(" default:"); pw.print(setting.getDefaultValue());
+                pw.print(" defaultSystemSet:"); pw.print(setting.isDefaultSystemSet());
+            }
+            if (setting.getTag() != null) {
+                pw.print(" tag:"); pw.print(setting.getTag());
+            }
             pw.println();
         }
     }
@@ -691,73 +722,79 @@
             // value with a forced update to ensure that all cross profile dependencies
             // are taken into account. Also make sure the settings update to.. the same
             // value passes the security checks, so clear binder calling id.
-            if (newRestrictions.containsKey(UserManager.DISALLOW_SHARE_LOCATION)
-                    != prevRestrictions.containsKey(UserManager.DISALLOW_SHARE_LOCATION)) {
+            if (newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION)
+                    != prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         Setting setting = getSecureSetting(
                                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
                         updateSecureSetting(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                                setting != null ? setting.getValue() : null, userId, true);
+                                setting != null ? setting.getValue() : null, null,
+                                true, userId, true);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.containsKey(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
-                    != prevRestrictions.containsKey(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)) {
+            if (newRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
+                    != prevRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         Setting setting = getGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS);
+                        String value = setting != null ? setting.getValue() : null;
                         updateGlobalSetting(Settings.Global.INSTALL_NON_MARKET_APPS,
-                                setting != null ? setting.getValue() : null, userId, true);
+                                value, null, true, userId, true);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.containsKey(UserManager.DISALLOW_DEBUGGING_FEATURES)
-                    != prevRestrictions.containsKey(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
+            if (newRestrictions.getBoolean(UserManager.DISALLOW_DEBUGGING_FEATURES)
+                    != prevRestrictions.getBoolean(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         Setting setting = getGlobalSetting(Settings.Global.ADB_ENABLED);
+                        String value = setting != null ? setting.getValue() : null;
                         updateGlobalSetting(Settings.Global.ADB_ENABLED,
-                                setting != null ? setting.getValue() : null, userId, true);
+                                value, null, true, userId, true);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.containsKey(UserManager.ENSURE_VERIFY_APPS)
-                    != prevRestrictions.containsKey(UserManager.ENSURE_VERIFY_APPS)) {
+            if (newRestrictions.getBoolean(UserManager.ENSURE_VERIFY_APPS)
+                    != prevRestrictions.getBoolean(UserManager.ENSURE_VERIFY_APPS)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         Setting enable = getGlobalSetting(
                                 Settings.Global.PACKAGE_VERIFIER_ENABLE);
+                        String enableValue = enable != null ? enable.getValue() : null;
                         updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                                enable != null ? enable.getValue() : null, userId, true);
+                                enableValue, null, true, userId, true);
                         Setting include = getGlobalSetting(
                                 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB);
+                        String includeValue = include != null ? include.getValue() : null;
                         updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB,
-                                include != null ? include.getValue() : null, userId, true);
+                                includeValue, null, true, userId, true);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.containsKey(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
-                    != prevRestrictions.containsKey(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
+            if (newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
+                    != prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         Setting setting = getGlobalSetting(
                                 Settings.Global.PREFERRED_NETWORK_MODE);
+                        String value = setting != null ? setting.getValue() : null;
                         updateGlobalSetting(Settings.Global.PREFERRED_NETWORK_MODE,
-                                setting != null ? setting.getValue() : null, userId, true);
+                                value, null, true, userId, true);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(identity);
@@ -806,34 +843,49 @@
         }
     }
 
-    private boolean updateGlobalSetting(String name, String value, int requestingUserId,
-            boolean forceNotify) {
+    private boolean updateGlobalSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ")");
+            Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ", "
+                    + ", " + tag + ", " + makeDefault + ", " + requestingUserId
+                    + ", " + forceNotify + ")");
         }
-        return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE,
-                forceNotify);
+        return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId,
+                MUTATION_OPERATION_UPDATE, forceNotify, 0);
     }
 
-    private boolean insertGlobalSetting(String name, String value, int requestingUserId,
-            boolean forceNotify) {
+    private boolean insertGlobalSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ")");
+            Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value  + ", "
+                    + ", " + tag + ", " + makeDefault + ", " + requestingUserId
+                    + ", " + forceNotify + ")");
         }
-        return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT,
-                forceNotify);
+        return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId,
+                MUTATION_OPERATION_INSERT, forceNotify, 0);
     }
 
     private boolean deleteGlobalSetting(String name, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
+            Slog.v(LOG_TAG, "deleteGlobalSetting(" + name + ", " + requestingUserId
+                    + ", " + forceNotify + ")");
         }
-        return mutateGlobalSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE,
-                forceNotify);
+        return mutateGlobalSetting(name, null, null, false, requestingUserId,
+                MUTATION_OPERATION_DELETE, forceNotify, 0);
     }
 
-    private boolean mutateGlobalSetting(String name, String value, int requestingUserId,
-            int operation, boolean forceNotify) {
+    private void resetGlobalSetting(int requestingUserId, int mode, String tag) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "resetGlobalSetting(" + requestingUserId + ", "
+                    + mode + ", " + tag + ")");
+        }
+        mutateGlobalSetting(null, null, tag, false, requestingUserId,
+                MUTATION_OPERATION_RESET, false, mode);
+    }
+
+    private boolean mutateGlobalSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
+            int mode) {
         // Make sure the caller can change the settings - treated as secure.
         enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
 
@@ -842,7 +894,7 @@
 
         // If this is a setting that is currently restricted for this user, do not allow
         // unrestricting changes.
-        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value,
+        if (name != null && isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value,
                 Binder.getCallingUid())) {
             return false;
         }
@@ -851,9 +903,9 @@
         synchronized (mLock) {
             switch (operation) {
                 case MUTATION_OPERATION_INSERT: {
-                    return mSettingsRegistry
-                            .insertSettingLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM,
-                                    name, value, getCallingPackage(), forceNotify);
+                    return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL,
+                            UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
+                            getCallingPackage(), forceNotify);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -862,10 +914,15 @@
                 }
 
                 case MUTATION_OPERATION_UPDATE: {
-                    return mSettingsRegistry
-                            .updateSettingLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM,
-                                    name, value, getCallingPackage(), forceNotify);
+                    return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_GLOBAL,
+                            UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
+                            getCallingPackage(), forceNotify);
                 }
+
+                case MUTATION_OPERATION_RESET: {
+                    mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_GLOBAL,
+                            UserHandle.USER_SYSTEM, getCallingPackage(), mode, tag);
+                } return true;
             }
         }
 
@@ -934,39 +991,53 @@
         }
     }
 
-    private boolean insertSecureSetting(String name, String value, int requestingUserId,
-            boolean forceNotify) {
+    private boolean insertSecureSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
-                    + requestingUserId + ")");
+                    + ", " + tag  + ", " + makeDefault + ", "  + requestingUserId
+                    + ", " + forceNotify + ")");
         }
 
-        return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT,
-                forceNotify);
+        return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
+                MUTATION_OPERATION_INSERT, forceNotify, 0);
     }
 
     private boolean deleteSecureSetting(String name, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId + ")");
+            Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId
+                    + ", " + forceNotify + ")");
         }
 
-        return mutateSecureSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE,
-                forceNotify);
+        return mutateSecureSetting(name, null, null, false, requestingUserId,
+                MUTATION_OPERATION_DELETE, forceNotify, 0);
     }
 
-    private boolean updateSecureSetting(String name, String value, int requestingUserId,
-            boolean forceNotify) {
+    private boolean updateSecureSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "updateSecureSetting(" + name + ", " + value + ", "
-                    + requestingUserId + ")");
+                    + ", " + tag  + ", " + makeDefault + ", "  + requestingUserId
+                    + ", "  + forceNotify +")");
         }
 
-        return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE,
-                forceNotify);
+        return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
+                MUTATION_OPERATION_UPDATE, forceNotify, 0);
     }
 
-    private boolean mutateSecureSetting(String name, String value, int requestingUserId,
-            int operation, boolean forceNotify) {
+    private void resetSecureSetting(int requestingUserId, int mode, String tag) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "resetSecureSetting(" + requestingUserId + ", "
+                    + mode + ", " + tag + ")");
+        }
+
+        mutateSecureSetting(null, null, tag, false, requestingUserId,
+                MUTATION_OPERATION_RESET, false, mode);
+    }
+
+    private boolean mutateSecureSetting(String name, String value, String tag,
+            boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
+            int mode) {
         // Make sure the caller can change the settings.
         enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
 
@@ -975,7 +1046,7 @@
 
         // If this is a setting that is currently restricted for this user, do not allow
         // unrestricting changes.
-        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value,
+        if (name != null && isGlobalOrSecureSettingRestrictedForUser(name, callingUserId, value,
                 Binder.getCallingUid())) {
             return false;
         }
@@ -990,7 +1061,8 @@
 
         // Special cases for location providers (sigh).
         if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
-            return updateLocationProvidersAllowedLocked(value, owningUserId, forceNotify);
+            return updateLocationProvidersAllowedLocked(value, tag, owningUserId, makeDefault,
+                    forceNotify);
         }
 
         // Mutate the value.
@@ -998,7 +1070,8 @@
             switch (operation) {
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
-                            owningUserId, name, value, getCallingPackage(), forceNotify);
+                            owningUserId, name, value, tag, makeDefault,
+                            getCallingPackage(), forceNotify);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -1008,8 +1081,14 @@
 
                 case MUTATION_OPERATION_UPDATE: {
                     return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SECURE,
-                            owningUserId, name, value, getCallingPackage(), forceNotify);
+                            owningUserId, name, value, tag, makeDefault,
+                            getCallingPackage(), forceNotify);
                 }
+
+                case MUTATION_OPERATION_RESET: {
+                    mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SECURE,
+                            UserHandle.USER_SYSTEM, getCallingPackage(), mode, tag);
+                } return true;
             }
         }
 
@@ -1138,7 +1217,7 @@
                 case MUTATION_OPERATION_INSERT: {
                     validateSystemSettingValue(name, value);
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SYSTEM,
-                            owningUserId, name, value, getCallingPackage(), false);
+                            owningUserId, name, value, null, false, getCallingPackage(), false);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -1149,7 +1228,7 @@
                 case MUTATION_OPERATION_UPDATE: {
                     validateSystemSettingValue(name, value);
                     return mSettingsRegistry.updateSettingLocked(SETTINGS_TYPE_SYSTEM,
-                            owningUserId, name, value, getCallingPackage(), false);
+                            owningUserId, name, value, null, false, getCallingPackage(), false);
                 }
             }
 
@@ -1240,7 +1319,8 @@
             case Settings.Secure.ALWAYS_ON_VPN_APP:
             case Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN:
                 // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn
-                if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
+                final int appId = UserHandle.getAppId(callingUid);
+                if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
                     return false;
                 }
                 restriction = UserManager.DISALLOW_CONFIG_VPN;
@@ -1294,9 +1374,10 @@
             String name, int userId) {
         // System/root/shell can mutate whatever secure settings they want.
         final int callingUid = Binder.getCallingUid();
-        if (callingUid == android.os.Process.SYSTEM_UID
-                || callingUid == Process.SHELL_UID
-                || callingUid == Process.ROOT_UID) {
+        final int appId = UserHandle.getAppId(callingUid);
+        if (appId == android.os.Process.SYSTEM_UID
+                || appId == Process.SHELL_UID
+                || appId == Process.ROOT_UID) {
             return;
         }
 
@@ -1392,8 +1473,8 @@
      *
      * @returns whether the enabled location providers changed.
      */
-    private boolean updateLocationProvidersAllowedLocked(String value, int owningUserId,
-            boolean forceNotify) {
+    private boolean updateLocationProvidersAllowedLocked(String value, String tag,
+            int owningUserId, boolean makeDefault, boolean forceNotify) {
         if (TextUtils.isEmpty(value)) {
             return false;
         }
@@ -1466,7 +1547,7 @@
 
         return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
                 owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders,
-                getCallingPackage(), forceNotify);
+                tag, makeDefault, getCallingPackage(), forceNotify);
     }
 
     private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
@@ -1509,8 +1590,8 @@
         }
         Bundle result = new Bundle();
         result.putString(Settings.NameValueTable.VALUE,
-                setting != null && !setting.isNull() ? setting.getValue() : null);
-        mSettingsRegistry.mGenerationRegistry.addGenerationData(result, setting.getkey());
+                !setting.isNull() ? setting.getValue() : null);
+        mSettingsRegistry.mGenerationRegistry.addGenerationData(result, setting.getKey());
         return result;
     }
 
@@ -1528,6 +1609,51 @@
         return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null;
     }
 
+    private static String getSettingTag(Bundle args) {
+        return (args != null) ? args.getString(Settings.CALL_METHOD_TAG_KEY) : null;
+    }
+
+    private static boolean getSettingMakeDefault(Bundle args) {
+        return (args != null) && args.getBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY);
+    }
+
+    private static int getResetModeEnforcingPermission(Bundle args) {
+        final int mode = (args != null) ? args.getInt(Settings.CALL_METHOD_RESET_MODE_KEY) : 0;
+        switch (mode) {
+            case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
+                if (!isCallerSystemOrShellOrRootOnDebuggableBuild()) {
+                    throw new SecurityException("Only system, shell/root on a "
+                            + "debuggable build can reset to untrusted defaults");
+                }
+                return mode;
+            }
+            case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
+                if (!isCallerSystemOrShellOrRootOnDebuggableBuild()) {
+                    throw new SecurityException("Only system, shell/root on a "
+                            + "debuggable build can reset untrusted changes");
+                }
+                return mode;
+            }
+            case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
+                if (!isCallerSystemOrShellOrRootOnDebuggableBuild()) {
+                    throw new SecurityException("Only system, shell/root on a "
+                            + "debuggable build can reset to trusted defaults");
+                }
+                return mode;
+            }
+            case Settings.RESET_MODE_PACKAGE_DEFAULTS: {
+                return mode;
+            }
+        }
+        throw new IllegalArgumentException("Invalid reset mode: " + mode);
+    }
+
+    private static boolean isCallerSystemOrShellOrRootOnDebuggableBuild() {
+        final int appId = UserHandle.getAppId(Binder.getCallingUid());
+        return appId == SYSTEM_UID || (Build.IS_DEBUGGABLE
+                && (appId == SHELL_UID || appId == ROOT_UID));
+    }
+
     private static String getValidTableOrThrow(Uri uri) {
         if (uri.getPathSegments().size() > 0) {
             String table = uri.getPathSegments().get(0);
@@ -1767,8 +1893,8 @@
         private void ensureSettingsStateLocked(int key) {
             if (mSettingsStates.get(key) == null) {
                 final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
-                SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
-                        maxBytesPerPackage, mHandlerThread.getLooper());
+                SettingsState settingsState = new SettingsState(getContext(), mLock,
+                        getSettingsFile(key), key, maxBytesPerPackage, mHandlerThread.getLooper());
                 mSettingsStates.put(key, settingsState);
             }
         }
@@ -1815,12 +1941,15 @@
         }
 
         public boolean insertSettingLocked(int type, int userId, String name, String value,
-                String packageName, boolean forceNotify) {
+                String tag, boolean makeDefault, String packageName, boolean forceNotify) {
             final int key = makeKey(type, userId);
 
+            boolean success = false;
             SettingsState settingsState = peekSettingsStateLocked(key);
-            final boolean success = settingsState != null
-                    && settingsState.insertSettingLocked(name, value, packageName);
+            if (settingsState != null) {
+                success = settingsState.insertSettingLocked(name, value,
+                        tag, makeDefault, packageName);
+            }
 
             if (forceNotify || success) {
                 notifyForSettingsChange(key, name);
@@ -1831,11 +1960,11 @@
         public boolean deleteSettingLocked(int type, int userId, String name, boolean forceNotify) {
             final int key = makeKey(type, userId);
 
+            boolean success = false;
             SettingsState settingsState = peekSettingsStateLocked(key);
-            if (settingsState == null) {
-                return false;
+            if (settingsState != null) {
+                success = settingsState.deleteSettingLocked(name);
             }
-            final boolean success = settingsState.deleteSettingLocked(name);
 
             if (forceNotify || success) {
                 notifyForSettingsChange(key, name);
@@ -1854,12 +1983,15 @@
         }
 
         public boolean updateSettingLocked(int type, int userId, String name, String value,
-                String packageName, boolean forceNotify) {
+                String tag, boolean makeDefault, String packageName, boolean forceNotify) {
             final int key = makeKey(type, userId);
 
+            boolean success = false;
             SettingsState settingsState = peekSettingsStateLocked(key);
-            final boolean success = settingsState != null
-                    && settingsState.updateSettingLocked(name, value, packageName);
+            if (settingsState != null) {
+                success = settingsState.updateSettingLocked(name, value, tag,
+                        makeDefault, packageName);
+            }
 
             if (forceNotify || success) {
                 notifyForSettingsChange(key, name);
@@ -1868,6 +2000,72 @@
             return success;
         }
 
+        public void resetSettingsLocked(int type, int userId, String packageName, int mode,
+                String tag) {
+            final int key = makeKey(type, userId);
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            if (settingsState == null) {
+                return;
+            }
+
+            switch (mode) {
+                case Settings.RESET_MODE_PACKAGE_DEFAULTS: {
+                    for (String name : settingsState.getSettingNamesLocked()) {
+                        Setting setting = settingsState.getSettingLocked(name);
+                        if (packageName.equals(setting.getPackageName())) {
+                            if (tag != null && !tag.equals(setting.getTag())) {
+                                continue;
+                            }
+                            if (settingsState.resetSettingLocked(name, packageName)) {
+                                notifyForSettingsChange(key, name);
+                            }
+                        }
+                    }
+                } break;
+
+                case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
+                    for (String name : settingsState.getSettingNamesLocked()) {
+                        Setting setting = settingsState.getSettingLocked(name);
+                        if (!SettingsState.isSystemPackage(getContext(),
+                                setting.getPackageName())) {
+                            if (settingsState.resetSettingLocked(name, packageName)) {
+                                notifyForSettingsChange(key, name);
+                            }
+                        }
+                    }
+                } break;
+
+                case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
+                    for (String name : settingsState.getSettingNamesLocked()) {
+                        Setting setting = settingsState.getSettingLocked(name);
+                        if (!SettingsState.isSystemPackage(getContext(),
+                                setting.getPackageName())) {
+                            if (setting.isDefaultSystemSet()) {
+                                if (settingsState.resetSettingLocked(name, packageName)) {
+                                    notifyForSettingsChange(key, name);
+                                }
+                            } else if (settingsState.deleteSettingLocked(name)) {
+                                notifyForSettingsChange(key, name);
+                            }
+                        }
+                    }
+                } break;
+
+                case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
+                    for (String name : settingsState.getSettingNamesLocked()) {
+                        Setting setting = settingsState.getSettingLocked(name);
+                        if (setting.isDefaultSystemSet()) {
+                            if (settingsState.resetSettingLocked(name, packageName)) {
+                                notifyForSettingsChange(key, name);
+                            }
+                        } else if (settingsState.deleteSettingLocked(name)) {
+                            notifyForSettingsChange(key, name);
+                        }
+                    }
+                } break;
+            }
+        }
+
         public void onPackageRemovedLocked(String packageName, int userId) {
             // Global and secure settings are signature protected. Apps signed
             // by the platform certificate are generally not uninstalled  and
@@ -2005,7 +2203,7 @@
                 while (!cursor.isAfterLast()) {
                     String name = cursor.getString(nameColumnIdx);
                     String value = cursor.getString(valueColumnIdx);
-                    settingsState.insertSettingLocked(name, value,
+                    settingsState.insertSettingLocked(name, value, null, true,
                             SettingsState.SYSTEM_PACKAGE_NAME);
                     cursor.moveToNext();
                 }
@@ -2037,7 +2235,7 @@
 
             String androidId = Long.toHexString(new SecureRandom().nextLong());
             secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
-                    SettingsState.SYSTEM_PACKAGE_NAME);
+                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
 
             Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
                     + "] for user " + userId);
@@ -2221,7 +2419,8 @@
                     String reason = "Settings rebuilt! Current version: "
                             + curVersion + " while expected: " + newVersion;
                     getGlobalSettingsLocked().insertSettingLocked(
-                            Settings.Global.DATABASE_DOWNGRADE_REASON, reason, "android");
+                            Settings.Global.DATABASE_DOWNGRADE_REASON,
+                            reason, null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                 }
 
                 // Set the global settings version if owner.
@@ -2290,11 +2489,11 @@
                     if (userId == UserHandle.USER_SYSTEM) {
                         final SettingsState globalSettings = getGlobalSettingsLocked();
                         globalSettings.updateSettingLocked(Settings.Global.ZEN_MODE,
-                                Integer.toString(Settings.Global.ZEN_MODE_OFF),
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                                Integer.toString(Settings.Global.ZEN_MODE_OFF), null,
+                                true, SettingsState.SYSTEM_PACKAGE_NAME);
                         globalSettings.updateSettingLocked(Settings.Global.MODE_RINGER,
-                                Integer.toString(AudioManager.RINGER_MODE_NORMAL),
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                                Integer.toString(AudioManager.RINGER_MODE_NORMAL), null,
+                                true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 119;
                 }
@@ -2304,7 +2503,7 @@
                     SettingsState secureSettings = getSecureSettingsLocked(userId);
                     secureSettings.insertSettingLocked(Settings.Secure.DOUBLE_TAP_TO_WAKE,
                             getContext().getResources().getBoolean(
-                                    R.bool.def_double_tap_to_wake) ? "1" : "0",
+                                    R.bool.def_double_tap_to_wake) ? "1" : "0", null, true,
                             SettingsState.SYSTEM_PACKAGE_NAME);
 
                     currentVersion = 120;
@@ -2329,8 +2528,7 @@
                         currentSetting.isNull()) {
                         secureSettings.insertSettingLocked(
                                 Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
-                                defaultComponent,
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                                defaultComponent, null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 122;
                 }
@@ -2347,7 +2545,7 @@
                                     Settings.Global.ADD_USERS_WHEN_LOCKED,
                                     getContext().getResources().getBoolean(
                                             R.bool.def_add_users_from_lockscreen) ? "1" : "0",
-                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                         }
                     }
                     currentVersion = 123;
@@ -2358,7 +2556,7 @@
                     String defaultDisabledProfiles = (getContext().getResources().getString(
                             R.string.def_bluetooth_disabled_profiles));
                     globalSettings.insertSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES,
-                            defaultDisabledProfiles, SettingsState.SYSTEM_PACKAGE_NAME);
+                            defaultDisabledProfiles, null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     currentVersion = 124;
                 }
 
@@ -2373,7 +2571,7 @@
                                 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
                                 getContext().getResources().getBoolean(
                                         R.bool.def_show_ime_with_hard_keyboard) ? "1" : "0",
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 125;
                 }
@@ -2400,7 +2598,7 @@
                             }
                             secureSettings.insertSettingLocked(
                                     Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
-                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                         }
 
                     }
@@ -2420,7 +2618,7 @@
                             final SettingsState secureSettings = getSecureSettingsLocked(userId);
                             secureSettings.insertSettingLocked(
                                     Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
-                                    showNotifications.getValue(),
+                                    showNotifications.getValue(), null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
                         }
 
@@ -2430,7 +2628,7 @@
                             final SettingsState secureSettings = getSecureSettingsLocked(userId);
                             secureSettings.insertSettingLocked(
                                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
-                                    allowPrivate.getValue(),
+                                    allowPrivate.getValue(), null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
                         }
                     }
@@ -2456,7 +2654,7 @@
                         if (policyAccess.isNull()) {
                             systemSecureSettings.insertSettingLocked(
                                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
-                                    defaultPolicyAccess,
+                                    defaultPolicyAccess, null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
                         } else {
                             StringBuilder currentSetting =
@@ -2465,7 +2663,7 @@
                             currentSetting.append(defaultPolicyAccess);
                             systemSecureSettings.updateSettingLocked(
                                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
-                                    currentSetting.toString(),
+                                    currentSetting.toString(), null, true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
                         }
                     }
@@ -2485,7 +2683,7 @@
                                 Settings.Secure.LONG_PRESS_TIMEOUT,
                                 String.valueOf(getContext().getResources().getInteger(
                                         R.integer.def_long_press_timeout_millis)),
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 130;
                 }
@@ -2498,9 +2696,9 @@
 
                     if (dozeExplicitlyDisabled) {
                         secureSettings.insertSettingLocked(Settings.Secure.DOZE_PULSE_ON_PICK_UP,
-                                "0", SettingsState.SYSTEM_PACKAGE_NAME);
+                                "0", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                         secureSettings.insertSettingLocked(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
-                                "0", SettingsState.SYSTEM_PACKAGE_NAME);
+                                "0", null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 131;
                 }
@@ -2515,7 +2713,7 @@
                                 Settings.Secure.MULTI_PRESS_TIMEOUT,
                                 String.valueOf(getContext().getResources().getInteger(
                                         R.integer.def_multi_press_timeout_millis)),
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     }
 
                     currentVersion = 132;
@@ -2527,9 +2725,8 @@
                     String defaultSyncParentSounds = (getContext().getResources()
                             .getBoolean(R.bool.def_sync_parent_sounds) ? "1" : "0");
                     systemSecureSettings.insertSettingLocked(
-                            Settings.Secure.SYNC_PARENT_SOUNDS,
-                            defaultSyncParentSounds,
-                            SettingsState.SYSTEM_PACKAGE_NAME);
+                            Settings.Secure.SYNC_PARENT_SOUNDS, defaultSyncParentSounds,
+                            null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                     currentVersion = 133;
                 }
 
@@ -2541,7 +2738,8 @@
                         String defaultEndButtonBehavior = Integer.toString(getContext()
                                 .getResources().getInteger(R.integer.def_end_button_behavior));
                         systemSettings.insertSettingLocked(Settings.System.END_BUTTON_BEHAVIOR,
-                                defaultEndButtonBehavior, SettingsState.SYSTEM_PACKAGE_NAME);
+                                defaultEndButtonBehavior, null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
                     }
                     currentVersion = 134;
                 }
@@ -2565,13 +2763,13 @@
                             // A scorer was set so enable recommendations.
                             globalSettings.insertSettingLocked(
                                 Global.NETWORK_RECOMMENDATIONS_ENABLED,
-                                "1",
+                                "1", null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
 
                             // and clear the scorer setting since it's no longer needed.
                             globalSettings.insertSettingLocked(
                                 Global.NETWORK_SCORER_APP,
-                                null,
+                                null, null, true,
                                 SettingsState.SYSTEM_PACKAGE_NAME);
                         }
                     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index cbeb878..0808051 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -97,6 +97,7 @@
             PUT,
             DELETE,
             LIST,
+            RESET,
         }
 
         int mUser = -1;     // unspecified
@@ -104,7 +105,10 @@
         String mTable = null;
         String mKey = null;
         String mValue = null;
-
+        String mPackageName = null;
+        String mToken = null;
+        int mResetMode = -1;
+        boolean mMakeDefault;
 
         MyShellCommand(SettingsProvider provider, boolean dumping) {
             mProvider = provider;
@@ -142,6 +146,8 @@
                         mVerb = CommandVerb.DELETE;
                     } else if ("list".equalsIgnoreCase(arg)) {
                         mVerb = CommandVerb.LIST;
+                    } else if ("reset".equalsIgnoreCase(arg)) {
+                        mVerb = CommandVerb.RESET;
                     } else {
                         // invalid
                         perr.println("Invalid command: " + arg);
@@ -159,6 +165,35 @@
                         valid = true;
                         break;
                     }
+                } else if (mVerb == CommandVerb.RESET) {
+                    if ("untrusted_defaults".equalsIgnoreCase(arg)) {
+                        mResetMode = Settings.RESET_MODE_UNTRUSTED_DEFAULTS;
+                    } else if ("untrusted_clear".equalsIgnoreCase(arg)) {
+                        mResetMode = Settings.RESET_MODE_UNTRUSTED_CHANGES;
+                    } else if ("trusted_defaults".equalsIgnoreCase(arg)) {
+                        mResetMode = Settings.RESET_MODE_TRUSTED_DEFAULTS;
+                    } else {
+                        mPackageName = arg;
+                        mResetMode = Settings.RESET_MODE_PACKAGE_DEFAULTS;
+                        if (peekNextArg() == null) {
+                            valid = true;
+                        } else {
+                            mToken = getNextArg();
+                            if (peekNextArg() == null) {
+                                valid = true;
+                            } else {
+                                perr.println("Too many arguments");
+                                return -1;
+                            }
+                        }
+                        break;
+                    }
+                    if (peekNextArg() == null) {
+                        valid = true;
+                    } else {
+                        perr.println("Too many arguments");
+                        return -1;
+                    }
                 } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
                     mKey = arg;
                     if (peekNextArg() == null) {
@@ -171,8 +206,32 @@
                 } else if (mKey == null) {
                     mKey = arg;
                     // keep going; there's another PUT arg
-                } else {    // PUT, final arg
+                } else if (mValue == null) {
                     mValue = arg;
+                    // keep going; there may be another PUT arg
+                } else if (mToken == null) {
+                    mToken = arg;
+                    if ("default".equalsIgnoreCase(mToken)) {
+                        mToken = null;
+                        mMakeDefault = true;
+                        if (peekNextArg() == null) {
+                            valid = true;
+                        } else {
+                            perr.println("Too many arguments");
+                            return -1;
+                        }
+                        break;
+                    }
+                    if (peekNextArg() == null) {
+                        valid = true;
+                        break;
+                    }
+                } else { // PUT, final arg
+                    if (!"default".equalsIgnoreCase(arg)) {
+                        perr.println("Argument expected to be 'default'");
+                        return -1;
+                    }
+                    mMakeDefault = true;
                     if (peekNextArg() == null) {
                         valid = true;
                     } else {
@@ -214,7 +273,7 @@
                     pout.println(getForUser(iprovider, mUser, mTable, mKey));
                     break;
                 case PUT:
-                    putForUser(iprovider, mUser, mTable, mKey, mValue);
+                    putForUser(iprovider, mUser, mTable, mKey, mValue, mToken, mMakeDefault);
                     break;
                 case DELETE:
                     pout.println("Deleted "
@@ -225,6 +284,9 @@
                         pout.println(line);
                     }
                     break;
+                case RESET:
+                    resetForUser(iprovider, mUser, mTable, mToken);
+                    break;
                 default:
                     perr.println("Unspecified command");
                     return -1;
@@ -286,11 +348,15 @@
             return result;
         }
 
-        void putForUser(IContentProvider provider, int userHandle,
-                final String table, final String key, final String value) {
+        void putForUser(IContentProvider provider, int userHandle, final String table,
+                final String key, final String value, String token, boolean makeDefault) {
             final String callPutCommand;
-            if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
-            else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE;
+            if ("system".equals(table)) {
+                callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
+                makeDefault = false;
+                getOutPrintWriter().println("Ignored makeDefault - "
+                        + "doesn't apply to system settings");
+            } else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE;
             else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL;
             else {
                 getErrPrintWriter().println("Invalid table; no put performed");
@@ -301,6 +367,10 @@
                 Bundle arg = new Bundle();
                 arg.putString(Settings.NameValueTable.VALUE, value);
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+                arg.putString(Settings.CALL_METHOD_TAG_KEY, token);
+                if (makeDefault) {
+                    arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
+                }
                 provider.call(resolveCallingPackage(), callPutCommand, key, arg);
             } catch (RemoteException e) {
                 throw new RuntimeException("Failed in IPC", e);
@@ -327,6 +397,29 @@
             return num;
         }
 
+        void resetForUser(IContentProvider provider, int userHandle,
+                String table, String token) {
+            final String callResetCommand;
+            if ("secure".equals(table)) callResetCommand = Settings.CALL_METHOD_RESET_SECURE;
+            else if ("global".equals(table)) callResetCommand = Settings.CALL_METHOD_RESET_GLOBAL;
+            else {
+                getErrPrintWriter().println("Invalid table; no reset performed");
+                return;
+            }
+
+            try {
+                Bundle arg = new Bundle();
+                arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+                arg.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, mResetMode);
+                arg.putString(Settings.CALL_METHOD_TAG_KEY, token);
+                String packageName = mPackageName != null ? mPackageName : resolveCallingPackage();
+                arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+                provider.call(packageName, callResetCommand, null, arg);
+            } catch (RemoteException e) {
+                throw new RuntimeException("Failed in IPC", e);
+            }
+        }
+
         public static String resolveCallingPackage() {
             switch (Binder.getCallingUid()) {
                 case Process.ROOT_UID: {
@@ -360,14 +453,18 @@
                 pw.println("      Print this help text.");
                 pw.println("  get [--user <USER_ID> | current] NAMESPACE KEY");
                 pw.println("      Retrieve the current value of KEY.");
-                pw.println("  put [--user <USER_ID> | current] NAMESPACE KEY VALUE");
+                pw.println("  put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TOKEN] [default]");
                 pw.println("      Change the contents of KEY to VALUE.");
+                pw.println("      TOKEN to associate with the setting.");
+                pw.println("      {default} to set as the default, case-insensitive only for global/secure namespace");
                 pw.println("  delete NAMESPACE KEY");
                 pw.println("      Delete the entry for KEY.");
+                pw.println("  reset [--user <USER_ID> | current] NAMESPACE {PACKAGE_NAME | RESET_MODE}");
+                pw.println("      Reset the global/secure table for a package with mode.");
+                pw.println("      RESET_MODE is one of {untrusted_defaults, untrusted_clear, trusted_defaults}, case-insensitive");
                 pw.println("  list NAMESPACE");
                 pw.println("      Print all defined keys.");
-                pw.println();
-                pw.println("  NAMESPACE is one of {system, secure, global}, case-insensitive");
+                pw.println("      NAMESPACE is one of {system, secure, global}, case-insensitive");
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index d682fe9..8f37b98 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -16,20 +16,30 @@
 
 package com.android.providers.settings;
 
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.Signature;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Base64;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
 import libcore.io.IoUtils;
 import libcore.util.Objects;
 import org.xmlpull.v1.XmlPullParser;
@@ -46,6 +56,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.os.Process.FIRST_APPLICATION_UID;
+
 /**
  * This class contains the state for one type of settings. It is responsible
  * for saving the state asynchronously to an XML file after a mutation and
@@ -63,6 +75,8 @@
 
     private static final String LOG_TAG = "SettingsState";
 
+    static final String SYSTEM_PACKAGE_NAME = "android";
+
     static final int SETTINGS_VERSION_NEW_ENCODING = 121;
 
     private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
@@ -71,27 +85,32 @@
     public static final int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1;
     public static final int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000;
 
-    public static final String SYSTEM_PACKAGE_NAME = "android";
-
     public static final int VERSION_UNDEFINED = -1;
 
     private static final String TAG_SETTINGS = "settings";
     private static final String TAG_SETTING = "setting";
     private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_DEFAULT_SYS_SET = "defaultSysSet";
+    private static final String ATTR_TAG = "tag";
+    private static final String ATTR_TAG_BASE64 = "tagBase64";
 
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_ID = "id";
     private static final String ATTR_NAME = "name";
 
-    /** Non-binary value will be written in this attribute. */
+    /**
+     * Non-binary value will be written in this attributes.
+     */
     private static final String ATTR_VALUE = "value";
+    private static final String ATTR_DEFAULT_VALUE = "defaultValue";
 
     /**
-     * KXmlSerializer won't like some characters.  We encode such characters in base64 and
-     * store in this attribute.
-     * NOTE: A null value will have NEITHER ATTR_VALUE nor ATTR_VALUE_BASE64.
+     * KXmlSerializer won't like some characters. We encode such characters
+     * in base64 and store in this attribute.
+     * NOTE: A null value will have *neither* ATTR_VALUE nor ATTR_VALUE_BASE64.
      */
     private static final String ATTR_VALUE_BASE64 = "valueBase64";
+    private static final String ATTR_DEFAULT_VALUE_BASE64 = "defaultValueBase64";
 
     // This was used in version 120 and before.
     private static final String NULL_VALUE_OLD_STYLE = "null";
@@ -101,12 +120,29 @@
     private static final String HISTORICAL_OPERATION_DELETE = "delete";
     private static final String HISTORICAL_OPERATION_PERSIST = "persist";
     private static final String HISTORICAL_OPERATION_INITIALIZE = "initialize";
+    private static final String HISTORICAL_OPERATION_RESET = "reset";
+
+    private static final String SHELL_PACKAGE_NAME = "shell";
+    private static final String ROOT_PACKAGE_NAME = "root";
+
+    private static final String NULL_VALUE = "null";
+
+    private static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static final SparseIntArray sSystemUids = new SparseIntArray();
+
+    @GuardedBy("sLock")
+    private static Signature sSystemSignature;
 
     private final Object mLock;
 
     private final Handler mHandler;
 
     @GuardedBy("mLock")
+    private final Context mContext;
+
+    @GuardedBy("mLock")
     private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();
 
     @GuardedBy("mLock")
@@ -118,7 +154,7 @@
     @GuardedBy("mLock")
     private final File mStatePersistFile;
 
-    private final Setting mNullSetting = new Setting(null, null, null) {
+    private final Setting mNullSetting = new Setting(null, null, false, null, null) {
         @Override
         public boolean isNull() {
             return true;
@@ -149,11 +185,12 @@
     @GuardedBy("mLock")
     private int mNextHistoricalOpIdx;
 
-    public SettingsState(Object lock, File file, int key, int maxBytesPerAppPackage,
-            Looper looper) {
+    public SettingsState(Context context, Object lock, File file, int key,
+            int maxBytesPerAppPackage, Looper looper) {
         // It is important that we use the same lock as the settings provider
         // to ensure multiple mutations on this state are atomicaly persisted
         // as the async persistence should be blocked while we make changes.
+        mContext = context;
         mLock = lock;
         mStatePersistFile = file;
         mKey = key;
@@ -241,37 +278,41 @@
     }
 
     // The settings provider must hold its lock when calling here.
-    public boolean updateSettingLocked(String name, String value, String packageName) {
+    public boolean updateSettingLocked(String name, String value, String tag,
+            boolean makeValue, String packageName) {
         if (!hasSettingLocked(name)) {
             return false;
         }
 
-        return insertSettingLocked(name, value, packageName);
+        return insertSettingLocked(name, value, tag, makeValue, packageName);
     }
 
     // The settings provider must hold its lock when calling here.
-    public boolean insertSettingLocked(String name, String value, String packageName) {
+    public boolean insertSettingLocked(String name, String value, String tag,
+            boolean makeDefault, String packageName) {
         if (TextUtils.isEmpty(name)) {
             return false;
         }
 
         Setting oldState = mSettings.get(name);
         String oldValue = (oldState != null) ? oldState.value : null;
+        String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
         Setting newState;
 
         if (oldState != null) {
-            if (!oldState.update(value, packageName)) {
+            if (!oldState.update(value, makeDefault, packageName, tag)) {
                 return false;
             }
             newState = oldState;
         } else {
-            newState = new Setting(name, value, packageName);
+            newState = new Setting(name, value, makeDefault, packageName, tag);
             mSettings.put(name, newState);
         }
 
         addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
 
-        updateMemoryUsagePerPackageLocked(packageName, oldValue, value);
+        updateMemoryUsagePerPackageLocked(packageName, oldValue, value,
+                oldDefaultValue, newState.getDefaultValue());
 
         scheduleWriteIfNeededLocked();
 
@@ -292,7 +333,8 @@
 
         Setting oldState = mSettings.remove(name);
 
-        updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null);
+        updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
+                null, oldState.defaultValue, null);
 
         addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);
 
@@ -302,6 +344,35 @@
     }
 
     // The settings provider must hold its lock when calling here.
+    public boolean resetSettingLocked(String name, String packageName) {
+        if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
+            return false;
+        }
+
+        Setting setting = mSettings.get(name);
+
+        Setting oldSetting = new Setting(setting);
+        String oldValue = setting.getValue();
+        String oldDefaultValue = setting.getDefaultValue();
+
+        if (!setting.reset(packageName)) {
+            return false;
+        }
+
+        String newValue = setting.getValue();
+        String newDefaultValue = setting.getDefaultValue();
+
+        updateMemoryUsagePerPackageLocked(setting.packageName, oldValue,
+                newValue, oldDefaultValue, newDefaultValue);
+
+        addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting);
+
+        scheduleWriteIfNeededLocked();
+
+        return true;
+    }
+
+    // The settings provider must hold its lock when calling here.
     public void destroyLocked(Runnable callback) {
         mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
         if (callback != null) {
@@ -364,7 +435,7 @@
     }
 
     private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
-            String newValue) {
+            String newValue, String oldDefaultValue, String newDefaultValue) {
         if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
             return;
         }
@@ -375,7 +446,10 @@
 
         final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
         final int newValueSize = (newValue != null) ? newValue.length() : 0;
-        final int deltaSize = newValueSize - oldValueSize;
+        final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
+        final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
+        final int deltaSize = newValueSize + newDefaultValueSize
+                - oldValueSize - oldDefaultValueSize;
 
         Integer currentSize = mPackageToMemoryUsage.get(packageName);
         final int newSize = Math.max((currentSize != null)
@@ -469,7 +543,8 @@
                 Setting setting = settings.valueAt(i);
 
                 writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
-                        setting.getValue(), setting.getPackageName());
+                        setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
+                        setting.getTag(), setting.isDefaultSystemSet());
 
                 if (DEBUG_PERSISTENCE) {
                     Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue());
@@ -496,7 +571,8 @@
     }
 
     static void writeSingleSetting(int version, XmlSerializer serializer, String id,
-            String name, String value, String packageName) throws IOException {
+            String name, String value, String defaultValue, String packageName,
+            String tag, boolean defaultSysSet) throws IOException {
         if (id == null || isBinary(id) || name == null || isBinary(name)
                 || packageName == null || isBinary(packageName)) {
             // This shouldn't happen.
@@ -505,38 +581,46 @@
         serializer.startTag(null, TAG_SETTING);
         serializer.attribute(null, ATTR_ID, id);
         serializer.attribute(null, ATTR_NAME, name);
-        setValueAttribute(version, serializer, value);
+        setValueAttribute(ATTR_VALUE, ATTR_VALUE_BASE64,
+                version, serializer, value);
         serializer.attribute(null, ATTR_PACKAGE, packageName);
+        if (defaultValue != null) {
+            setValueAttribute(ATTR_DEFAULT_VALUE, ATTR_DEFAULT_VALUE_BASE64,
+                    version, serializer, defaultValue);
+            serializer.attribute(null, ATTR_DEFAULT_SYS_SET, Boolean.toString(defaultSysSet));
+            setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64,
+                    version, serializer, tag);
+        }
         serializer.endTag(null, TAG_SETTING);
     }
 
-    static void setValueAttribute(int version, XmlSerializer serializer, String value)
-            throws IOException {
+    static void setValueAttribute(String attr, String attrBase64, int version,
+            XmlSerializer serializer, String value) throws IOException {
         if (version >= SETTINGS_VERSION_NEW_ENCODING) {
             if (value == null) {
                 // Null value -> No ATTR_VALUE nor ATTR_VALUE_BASE64.
             } else if (isBinary(value)) {
-                serializer.attribute(null, ATTR_VALUE_BASE64, base64Encode(value));
+                serializer.attribute(null, attrBase64, base64Encode(value));
             } else {
-                serializer.attribute(null, ATTR_VALUE, value);
+                serializer.attribute(null, attr, value);
             }
         } else {
             // Old encoding.
             if (value == null) {
-                serializer.attribute(null, ATTR_VALUE, NULL_VALUE_OLD_STYLE);
+                serializer.attribute(null, attr, NULL_VALUE_OLD_STYLE);
             } else {
-                serializer.attribute(null, ATTR_VALUE, value);
+                serializer.attribute(null, attr, value);
             }
         }
     }
 
-    private String getValueAttribute(XmlPullParser parser) {
+    private String getValueAttribute(XmlPullParser parser, String attr, String base64Attr) {
         if (mVersion >= SETTINGS_VERSION_NEW_ENCODING) {
-            final String value = parser.getAttributeValue(null, ATTR_VALUE);
+            final String value = parser.getAttributeValue(null, attr);
             if (value != null) {
                 return value;
             }
-            final String base64 = parser.getAttributeValue(null, ATTR_VALUE_BASE64);
+            final String base64 = parser.getAttributeValue(null, base64Attr);
             if (base64 != null) {
                 return base64Decode(base64);
             }
@@ -544,7 +628,7 @@
             return null;
         } else {
             // Old encoding.
-            final String stored = parser.getAttributeValue(null, ATTR_VALUE);
+            final String stored = parser.getAttributeValue(null, attr);
             if (NULL_VALUE_OLD_STYLE.equals(stored)) {
                 return null;
             } else {
@@ -575,7 +659,7 @@
         } catch (XmlPullParserException | IOException e) {
             String message = "Failed parsing settings file: " + mStatePersistFile;
             Slog.wtf(LOG_TAG, message);
-            throw new IllegalStateException(message , e);
+            throw new IllegalStateException(message, e);
         } finally {
             IoUtils.closeQuietly(in);
         }
@@ -615,9 +699,19 @@
             if (tagName.equals(TAG_SETTING)) {
                 String id = parser.getAttributeValue(null, ATTR_ID);
                 String name = parser.getAttributeValue(null, ATTR_NAME);
-                String value = getValueAttribute(parser);
+                String value = getValueAttribute(parser, ATTR_VALUE, ATTR_VALUE_BASE64);
                 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                mSettings.put(name, new Setting(name, value, packageName, id));
+                String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE,
+                        ATTR_DEFAULT_VALUE_BASE64);
+                String tag = null;
+                boolean fromSystem = false;
+                if (defaultValue != null) {
+                    fromSystem = Boolean.parseBoolean(parser.getAttributeValue(
+                            null, ATTR_DEFAULT_SYS_SET));
+                    tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64);
+                }
+                mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,
+                        fromSystem, id));
 
                 if (DEBUG_PERSISTENCE) {
                     Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value);
@@ -664,37 +758,54 @@
     class Setting {
         private String name;
         private String value;
+        private String defaultValue;
         private String packageName;
         private String id;
+        private String tag;
+        // Whether the default is set by the system
+        private boolean defaultSystemSet;
 
         public Setting(Setting other) {
             name = other.name;
             value = other.value;
+            defaultValue = other.defaultValue;
             packageName = other.packageName;
             id = other.id;
+            defaultSystemSet = other.defaultSystemSet;
+            tag = other.tag;
         }
 
-        public Setting(String name, String value, String packageName) {
-            init(name, value, packageName, String.valueOf(mNextId++));
+        public Setting(String name, String value, boolean makeDefault, String packageName,
+                String tag) {
+            this.name = name;
+            update(value, makeDefault, packageName, tag);
         }
 
-        public Setting(String name, String value, String packageName, String id) {
+        public Setting(String name, String value, String defaultValue,
+                String packageName, String tag, boolean fromSystem, String id) {
             mNextId = Math.max(mNextId, Long.parseLong(id) + 1);
-            init(name, value, packageName, id);
+            if (NULL_VALUE.equals(value)) {
+                value = null;
+            }
+            init(name, value, tag, defaultValue, packageName, fromSystem, id);
         }
 
-        private void init(String name, String value, String packageName, String id) {
+        private void init(String name, String value, String tag, String defaultValue,
+                String packageName, boolean fromSystem, String id) {
             this.name = name;
             this.value = value;
+            this.tag = tag;
+            this.defaultValue = defaultValue;
             this.packageName = packageName;
             this.id = id;
+            this.defaultSystemSet = fromSystem;
         }
 
         public String getName() {
             return name;
         }
 
-        public int getkey() {
+        public int getKey() {
             return mKey;
         }
 
@@ -702,10 +813,22 @@
             return value;
         }
 
+        public String getTag() {
+            return tag;
+        }
+
+        public String getDefaultValue() {
+            return defaultValue;
+        }
+
         public String getPackageName() {
             return packageName;
         }
 
+        public boolean isDefaultSystemSet() {
+            return defaultSystemSet;
+        }
+
         public String getId() {
             return id;
         }
@@ -714,18 +837,62 @@
             return false;
         }
 
-        public boolean update(String value, String packageName) {
-            if (Objects.equal(value, this.value)) {
+        /** @return whether the value changed */
+        public boolean reset(String packageName) {
+            return update(this.defaultValue, false, packageName, null);
+        }
+
+        public boolean update(String value, boolean setDefault, String packageName, String tag) {
+            if (NULL_VALUE.equals(value)) {
+                value = null;
+            }
+
+            final boolean callerSystem = !isNull() && isSystemPackage(mContext, packageName);
+            // Settings set by the system are always defaults.
+            if (callerSystem) {
+                setDefault = true;
+            }
+
+            String defaultValue = this.defaultValue;
+            boolean defaultSystemSet = this.defaultSystemSet;
+            if (setDefault) {
+                if (!Objects.equal(value, this.defaultValue)
+                        && (!defaultSystemSet || callerSystem)) {
+                    defaultValue = value;
+                    // Default null means no default, so the tag is irrelevant
+                    // since it is used to reset a settings subset their defaults.
+                    // Also it is irrelevant if the system set the canonical default.
+                    if (defaultValue == null) {
+                        tag = null;
+                        defaultSystemSet = false;
+                    }
+                }
+                if (!defaultSystemSet && value != null) {
+                    if (callerSystem) {
+                        defaultSystemSet = true;
+                    }
+                }
+            }
+
+            // Is something gonna change?
+            if (Objects.equal(value, this.value)
+                    && Objects.equal(defaultValue, this.defaultValue)
+                    && Objects.equal(packageName, this.packageName)
+                    && Objects.equal(tag, this.tag)
+                    && defaultSystemSet == this.defaultSystemSet) {
                 return false;
             }
-            this.value = value;
-            this.packageName = packageName;
-            this.id = String.valueOf(mNextId++);
+
+            init(name, value, tag, defaultValue, packageName, defaultSystemSet,
+                    String.valueOf(mNextId++));
             return true;
         }
 
         public String toString() {
-            return "Setting{name=" + value + " from " + packageName + "}";
+            return "Setting{name=" + name + " value=" + value
+                    + (defaultValue != null ? " default=" + defaultValue : "")
+                    + " packageName=" + packageName + " tag=" + tag
+                    + " defaultSystemSet=" + defaultSystemSet + "}";
         }
     }
 
@@ -782,4 +949,98 @@
         }
         return sb.toString();
     }
+
+    public static boolean isSystemPackage(Context context, String packageName) {
+        synchronized (sLock) {
+            if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
+                return true;
+            }
+
+            // Shell and Root are not considered a part of the system
+            if (SHELL_PACKAGE_NAME.equals(packageName)
+                    || ROOT_PACKAGE_NAME.equals(packageName)) {
+                return false;
+            }
+
+            // Native services running as a special UID get a pass
+            final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+            if (callingAppId < FIRST_APPLICATION_UID) {
+                sSystemUids.put(callingAppId, callingAppId);
+                return true;
+            }
+
+            // While some callers may have permissions to manipulate cross user
+            // settings or some settings are stored in the parent of a managed
+            // profile for the purpose of determining whether the other end is a
+            // system component we need to use the user id of the caller for
+            // pulling information about the caller from the package manager.
+            final int callingUserId = UserHandle.getCallingUserId();
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                final int uid;
+                try {
+                    uid = context.getPackageManager().getPackageUidAsUser(packageName, 0,
+                            callingUserId);
+                } catch (PackageManager.NameNotFoundException e) {
+                    return false;
+                }
+
+                // If the system or a special system UID (like telephony), done.
+                if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
+                    sSystemUids.put(uid, uid);
+                    return true;
+                }
+
+                // If already known system component, done.
+                if (sSystemUids.indexOfKey(uid) >= 0) {
+                    return true;
+                }
+
+                // If SetupWizard, done.
+                PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                        PackageManagerInternal.class);
+                if (packageName.equals(packageManagerInternal.getSetupWizardPackageName())) {
+                    sSystemUids.put(uid, uid);
+                    return true;
+                }
+
+                // If a persistent system app, done.
+                PackageInfo packageInfo;
+                try {
+                    packageInfo = context.getPackageManager().getPackageInfoAsUser(
+                            packageName, PackageManager.GET_SIGNATURES, callingUserId);
+                    if ((packageInfo.applicationInfo.flags
+                            & ApplicationInfo.FLAG_PERSISTENT) != 0
+                            && (packageInfo.applicationInfo.flags
+                            & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        sSystemUids.put(uid, uid);
+                        return true;
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                    return false;
+                }
+
+                // Last check if system signed.
+                if (sSystemSignature == null) {
+                    try {
+                        sSystemSignature = context.getPackageManager().getPackageInfoAsUser(
+                                SYSTEM_PACKAGE_NAME, PackageManager.GET_SIGNATURES,
+                                UserHandle.USER_SYSTEM).signatures[0];
+                    } catch (PackageManager.NameNotFoundException e) {
+                        /* impossible */
+                        return false;
+                    }
+                }
+                if (sSystemSignature.equals(packageInfo.signatures[0])) {
+                    sSystemUids.put(uid, uid);
+                    return true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            return false;
+        }
+    }
 }
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index ef863e7..918410e 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -2,11 +2,15 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := tests
+
 # Note we statically link SettingsState to do some unit tests.  It's not accessible otherwise
 # because this test is not an instrumentation test. (because the target runs in the system process.)
 LOCAL_SRC_FILES := $(call all-subdir-java-files) \
     ../src/com/android/providers/settings/SettingsState.java
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
 LOCAL_PACKAGE_NAME := SettingsProviderTest
 
 LOCAL_MODULE_TAGS := tests
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 7a86b5f..71e0b15 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -29,7 +29,8 @@
     </application>
 
     <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
+        android:name="android.support.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.providers.setting.test"
         android:label="Settings Provider Tests" />
+
 </manifest>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
index 8e56f47..0454b51 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -25,14 +25,21 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import libcore.io.Streams;
+import org.junit.runner.RunWith;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
 
 /**
  * Base class for the SettingContentProvider tests.
  */
-abstract class BaseSettingsProviderTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+abstract class BaseSettingsProviderTest {
     protected static final int SETTING_TYPE_GLOBAL = 1;
     protected static final int SETTING_TYPE_SECURE = 2;
     protected static final int SETTING_TYPE_SYSTEM = 3;
@@ -48,23 +55,7 @@
             Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
     };
 
-    protected int mSecondaryUserId = UserHandle.USER_SYSTEM;
-
-    @Override
-    public void setContext(Context context) {
-        super.setContext(context);
-
-        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        List<UserInfo> users = userManager.getUsers();
-        final int userCount = users.size();
-        for (int i = 0; i < userCount; i++) {
-            UserInfo user = users.get(i);
-            if (!user.isPrimary() && !user.isManagedProfile()) {
-                mSecondaryUserId = user.id;
-                break;
-            }
-        }
-    }
+    private int mSecondaryUserId = Integer.MIN_VALUE;
 
     protected void setStringViaFrontEndApiSetting(int type, String name, String value, int userId) {
         ContentResolver contentResolver = getContext().getContentResolver();
@@ -176,6 +167,163 @@
         return null;
     }
 
+    protected static void resetSettingsViaShell(int type, int resetMode) throws IOException {
+        final String modeString;
+        switch (resetMode) {
+            case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: {
+                modeString = "untrusted_defaults";
+            } break;
+
+            case Settings.RESET_MODE_UNTRUSTED_CHANGES: {
+                modeString = "untrusted_clear";
+            } break;
+
+            case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
+                modeString = "trusted_defaults";
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid reset mode: " + resetMode);
+            }
+        }
+
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                executeShellCommand("settings reset global " + modeString);
+            } break;
+
+            case SETTING_TYPE_SECURE: {
+                executeShellCommand("settings reset secure " + modeString);
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected static void resetToDefaultsViaShell(int type, String packageName) throws IOException {
+        resetToDefaultsViaShell(type, packageName, null);
+    }
+
+    protected static void resetToDefaultsViaShell(int type, String packageName, String token)
+            throws IOException {
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                executeShellCommand("settings reset global " + packageName + " " + token);
+            } break;
+
+            case SETTING_TYPE_SECURE: {
+                executeShellCommand("settings reset secure " + packageName + " " + token);
+            } break;
+
+            case SETTING_TYPE_SYSTEM: {
+                executeShellCommand("settings reset system " + packageName + " " + token);
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected String getSetting(int type, String name) {
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                return Settings.Global.getString(getContext().getContentResolver(), name);
+            }
+
+            case SETTING_TYPE_SECURE: {
+                return Settings.Secure.getString(getContext().getContentResolver(), name);
+            }
+
+            case SETTING_TYPE_SYSTEM: {
+                return Settings.System.getString(getContext().getContentResolver(), name);
+            }
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected void putSetting(int type, String name, String value) {
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                Settings.Global.putString(getContext().getContentResolver(), name, value);
+            } break;
+
+            case SETTING_TYPE_SECURE: {
+                Settings.Secure.putString(getContext().getContentResolver(), name, value);
+            } break;
+
+            case SETTING_TYPE_SYSTEM: {
+                Settings.System.putString(getContext().getContentResolver(), name, value);
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected static void setSettingViaShell(int type, String name, String value,
+            boolean makeDefault) throws IOException {
+        setSettingViaShell(type, name, value, null, makeDefault);
+    }
+
+    protected static void setSettingViaShell(int type, String name, String value,
+            String token, boolean makeDefault) throws IOException {
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                executeShellCommand("settings put global " + name + " "
+                        + value + (token != null ? " " + token : "")
+                        + (makeDefault ? " default" : ""));
+
+            } break;
+
+            case SETTING_TYPE_SECURE: {
+                executeShellCommand("settings put secure " + name + " "
+                        + value + (token != null ? " " + token : "")
+                        + (makeDefault ? " default" : ""));
+            } break;
+
+            case SETTING_TYPE_SYSTEM: {
+                executeShellCommand("settings put system " + name + " "
+                        + value + (token != null ? " " + token : "")
+                        + (makeDefault ? " default" : ""));
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    protected int getSecondaryUserId() {
+        if (mSecondaryUserId == Integer.MIN_VALUE) {
+            UserManager userManager = (UserManager) getContext()
+                    .getSystemService(Context.USER_SERVICE);
+            List<UserInfo> users = userManager.getUsers();
+            final int userCount = users.size();
+            for (int i = 0; i < userCount; i++) {
+                UserInfo user = users.get(i);
+                if (!user.isPrimary() && !user.isManagedProfile()) {
+                    mSecondaryUserId = user.id;
+                    return mSecondaryUserId;
+                }
+            }
+        }
+        if (mSecondaryUserId == Integer.MIN_VALUE) {
+            mSecondaryUserId =  UserHandle.USER_SYSTEM;
+        }
+        return mSecondaryUserId;
+    }
+
     protected static Uri getBaseUriForType(int type) {
         switch (type) {
             case SETTING_TYPE_GLOBAL: {
@@ -195,4 +343,10 @@
             }
         }
     }
+
+    protected static void executeShellCommand(String command) throws IOException {
+        InputStream is = new FileInputStream(InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().executeShellCommand(command).getFileDescriptor());
+        Streams.readFully(is);
+    }
 }
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
index a09d5fe..d34b9ed 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
@@ -16,9 +16,13 @@
 
 package com.android.providers.settings;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Log;
+import org.junit.Test;
 
 /**
 * Performance tests for the SettingContentProvider.
@@ -32,6 +36,7 @@
 
     private static final long MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS = 20;
 
+    @Test
     public void testSetAndGetPerformanceForGlobalViaFrontEndApi() throws Exception {
         // Start with a clean slate.
         insertStringViaProviderApi(SETTING_TYPE_GLOBAL,
@@ -76,6 +81,7 @@
                 < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
     }
 
+    @Test
     public void testSetAndGetPerformanceForGlobalViaProviderApi() throws Exception {
         // Start with a clean slate.
         deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index 8ca1b46..e2a8fba 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -16,6 +16,11 @@
 
 package com.android.providers.settings;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.fail;
+
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.ContentObserver;
@@ -27,6 +32,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
+import org.junit.Test;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -46,57 +52,70 @@
 
     private final Object mLock = new Object();
 
+    @Test
     public void testSetAndGetGlobalViaFrontEndApiForSystemUser() throws Exception {
         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
     }
 
+    @Test
     public void testSetAndGetGlobalViaFrontEndApiForNonSystemUser() throws Exception {
-        if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
+        final int secondaryUserId = getSecondaryUserId();
+        if (secondaryUserId == UserHandle.USER_SYSTEM) {
             Log.w(LOG_TAG, "No secondary user. Skipping "
                     + "testSetAndGetGlobalViaFrontEndApiForNonSystemUser");
             return;
         }
-        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, secondaryUserId);
     }
 
+    @Test
     public void testSetAndGetSecureViaFrontEndApiForSystemUser() throws Exception {
         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_SYSTEM);
     }
 
+    @Test
     public void testSetAndGetSecureViaFrontEndApiForNonSystemUser() throws Exception {
-        if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
+        final int secondaryUserId = getSecondaryUserId();
+        if (secondaryUserId == UserHandle.USER_SYSTEM) {
             Log.w(LOG_TAG, "No secondary user. Skipping "
                     + "testSetAndGetSecureViaFrontEndApiForNonSystemUser");
             return;
         }
-        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, secondaryUserId);
     }
 
+    @Test
     public void testSetAndGetSystemViaFrontEndApiForSystemUser() throws Exception {
         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_SYSTEM);
     }
 
+    @Test
     public void testSetAndGetSystemViaFrontEndApiForNonSystemUser() throws Exception {
-        if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
+        final int secondaryUserId = getSecondaryUserId();
+        if (secondaryUserId == UserHandle.USER_SYSTEM) {
             Log.w(LOG_TAG, "No secondary user. Skipping "
                     + "testSetAndGetSystemViaFrontEndApiForNonSystemUser");
             return;
         }
-        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, secondaryUserId);
     }
 
+    @Test
     public void testSetAndGetGlobalViaProviderApi() throws Exception {
         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
     }
 
+    @Test
     public void testSetAndGetSecureViaProviderApi() throws Exception {
         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
     }
 
+    @Test
     public void testSetAndGetSystemViaProviderApi() throws Exception {
         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
     }
 
+    @Test
     public void testSelectAllGlobalViaProviderApi() throws Exception {
         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
@@ -108,6 +127,7 @@
         }
     }
 
+    @Test
     public void testSelectAllSecureViaProviderApi() throws Exception {
         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
@@ -119,6 +139,7 @@
         }
     }
 
+    @Test
     public void testSelectAllSystemViaProviderApi() throws Exception {
         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
@@ -130,30 +151,37 @@
         }
     }
 
+    @Test
     public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
     }
 
+    @Test
     public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
     }
 
+    @Test
     public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
     }
 
+    @Test
     public void testBulkInsertGlobalViaProviderApi() throws Exception {
         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
     }
 
+    @Test
     public void testBulkInsertSystemViaProviderApi() throws Exception {
         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
     }
 
+    @Test
     public void testBulkInsertSecureViaProviderApi() throws Exception {
         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
     }
 
+    @Test
     public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
         int insertedCount = 0;
         try {
@@ -164,6 +192,8 @@
             }
             fail("Adding app specific settings must be bound.");
         } catch (Exception e) {
+            // expected
+        } finally {
             for (; insertedCount >= 0; insertedCount--) {
                 Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
                 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
@@ -172,18 +202,22 @@
         }
     }
 
+    @Test
     public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
     }
 
+    @Test
     public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
     }
 
+    @Test
     public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
     }
 
+    @Test
     public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception {
         // Make sure we have a clean slate.
         deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
@@ -206,6 +240,228 @@
         }
     }
 
+    @Test
+    public void testResetModePackageDefaultsGlobal() throws Exception {
+        testResetModePackageDefaultsCommon(SETTING_TYPE_GLOBAL);
+    }
+
+    @Test
+    public void testResetModePackageDefaultsSecure() throws Exception {
+        testResetModePackageDefaultsCommon(SETTING_TYPE_SECURE);
+    }
+
+    private void testResetModePackageDefaultsCommon(int type) throws Exception {
+        // Make sure we have a clean slate.
+        setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
+        try {
+            // Set a value but don't make it the default
+            setSettingViaShell(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, false);
+
+            // Reset the changes made by the "shell/root" package
+            resetToDefaultsViaShell(type, "shell");
+            resetToDefaultsViaShell(type, "root");
+
+            // Make sure the old APIs don't set defaults
+            assertNull(getSetting(type, FAKE_SETTING_NAME));
+
+            // Set a value and make it the default
+            setSettingViaShell(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, true);
+            // Change the setting from the default
+            setSettingViaShell(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE_2, false);
+
+            // Reset the changes made by this package
+            resetToDefaultsViaShell(type, "shell");
+            resetToDefaultsViaShell(type, "root");
+
+            // Make sure the old APIs don't set defaults
+            assertEquals(FAKE_SETTING_VALUE, getSetting(type, FAKE_SETTING_NAME));
+        } finally {
+            // Make sure we have a clean slate.
+            setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
+        }
+    }
+
+    @Test
+    public void testResetModePackageDefaultsWithTokensGlobal() throws Exception {
+        testResetModePackageDefaultsWithTokensCommon(SETTING_TYPE_GLOBAL);
+    }
+
+    @Test
+    public void testResetModePackageDefaultsWithTokensSecure() throws Exception {
+        testResetModePackageDefaultsWithTokensCommon(SETTING_TYPE_SECURE);
+    }
+
+    private void testResetModePackageDefaultsWithTokensCommon(int type) throws Exception {
+        // Make sure we have a clean slate.
+        setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
+        setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        try {
+            // Set a default value
+            setSettingViaShell(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, true);
+            // Change the default and associate a token
+            setSettingViaShell(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE_2, "TOKEN1", false);
+
+            // Set a default value
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE, "TOKEN2", true);
+            // Change the default and associate a token
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE_2, "TOKEN2", false);
+
+            // Reset settings associated with TOKEN1
+            resetToDefaultsViaShell(type, "shell", "TOKEN1");
+            resetToDefaultsViaShell(type, "root", "TOKEN1");
+
+            // Make sure TOKEN1 settings are reset
+            assertEquals(FAKE_SETTING_VALUE, getSetting(type,
+                    FAKE_SETTING_NAME));
+
+            // Make sure TOKEN2 settings are not reset
+            assertEquals(FAKE_SETTING_VALUE_2, getSetting(type,
+                    FAKE_SETTING_NAME_1));
+
+            // Reset settings associated with TOKEN2
+            resetToDefaultsViaShell(type, "shell", "TOKEN2");
+            resetToDefaultsViaShell(type, "root", "TOKEN2");
+
+            // Make sure TOKEN2 settings are reset
+            assertEquals(FAKE_SETTING_VALUE, getSetting(type,
+                    FAKE_SETTING_NAME_1));
+        } finally {
+            // Make sure we have a clean slate.
+            setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
+            setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        }
+    }
+
+    @Test
+    public void testResetModeUntrustedDefaultsGlobal() throws Exception {
+        testResetModeUntrustedDefaultsCommon(SETTING_TYPE_GLOBAL);
+    }
+
+    @Test
+    public void testResetModeUntrustedDefaultsSecure() throws Exception {
+        testResetModeUntrustedDefaultsCommon(SETTING_TYPE_SECURE);
+    }
+
+    private void testResetModeUntrustedDefaultsCommon(int type) throws Exception {
+        // Make sure we have a clean slate.
+        putSetting(type, FAKE_SETTING_NAME, null);
+        setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        try {
+            // Set a default setting as a trusted component
+            putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE);
+            // Change the setting as a trusted component
+            putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE_2);
+
+            // Set a default setting as an untrusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE, true);
+            // Change the setting as an untrusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE_2, false);
+
+            // Reset the untrusted changes to defaults
+            resetSettingsViaShell(type,
+                    Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+
+            // Check whether only the untrusted changes set to defaults
+            assertEquals(FAKE_SETTING_VALUE_2, getSetting(type, FAKE_SETTING_NAME));
+            assertEquals(FAKE_SETTING_VALUE, getSetting(type, FAKE_SETTING_NAME_1));
+        } finally {
+            // Make sure we have a clean slate.
+            putSetting(type, FAKE_SETTING_NAME, null);
+            setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        }
+    }
+
+    @Test
+    public void testResetModeUntrustedClearGlobal() throws Exception {
+        testResetModeUntrustedClearCommon(SETTING_TYPE_GLOBAL);
+    }
+
+    @Test
+    public void testResetModeUntrustedClearSecure() throws Exception {
+        testResetModeUntrustedClearCommon(SETTING_TYPE_SECURE);
+    }
+
+    private void testResetModeUntrustedClearCommon(int type) throws Exception {
+        // Make sure we have a clean slate.
+        putSetting(type, FAKE_SETTING_NAME, null);
+        setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        try {
+            // Set a default setting as a trusted component
+            putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE);
+            // Change the setting as a trusted component
+            putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE_2);
+
+            // Set a default setting as an untrusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE, true);
+            // Change the setting as an untrusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE_2, false);
+
+            // Clear the untrusted changes
+            resetSettingsViaShell(type,
+                    Settings.RESET_MODE_UNTRUSTED_CHANGES);
+
+            // Check whether only the untrusted changes set to defaults
+            assertEquals(FAKE_SETTING_VALUE_2, getSetting(type, FAKE_SETTING_NAME));
+            assertNull(getSetting(type, FAKE_SETTING_NAME_1));
+        } finally {
+            // Make sure we have a clean slate.
+            putSetting(type, FAKE_SETTING_NAME, null);
+            setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        }
+    }
+
+    @Test
+    public void testResetModeTrustedDefaultsGlobal() throws Exception {
+        testResetModeTrustedDefaultsCommon(SETTING_TYPE_GLOBAL);
+    }
+
+    @Test
+    public void testResetModeTrustedDefaultsSecure() throws Exception {
+        testResetModeTrustedDefaultsCommon(SETTING_TYPE_SECURE);
+    }
+
+    private void testResetModeTrustedDefaultsCommon(int type) throws Exception {
+        // Make sure we have a clean slate.
+        putSetting(type, FAKE_SETTING_NAME, null);
+        setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        try {
+            // Set a default setting as a trusted component
+            putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE);
+            // Change the setting as a trusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE_2, false);
+
+            // Set a default setting as an untrusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE, true);
+            // Change the setting as an untrusted component
+            setSettingViaShell(type, FAKE_SETTING_NAME_1,
+                    FAKE_SETTING_VALUE_2, false);
+
+            // Reset to trusted defaults
+            resetSettingsViaShell(type,
+                    Settings.RESET_MODE_TRUSTED_DEFAULTS);
+
+            // Check whether snapped to trusted defaults
+            assertEquals(FAKE_SETTING_VALUE, getSetting(type, FAKE_SETTING_NAME));
+            assertNull(getSetting(type, FAKE_SETTING_NAME_1));
+        } finally {
+            // Make sure we have a clean slate.
+            putSetting(type, FAKE_SETTING_NAME, null);
+            setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
+        }
+    }
+
     private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
         // Make sure we have a clean slate.
         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
@@ -341,22 +597,16 @@
 
     private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
             final String name, final String value, final int userId) throws Exception {
-        setSettingAndAssertSuccessfulChange(new Runnable() {
-            @Override
-            public void run() {
-                setStringViaFrontEndApiSetting(type, name, value, userId);
-            }
+        setSettingAndAssertSuccessfulChange(() -> {
+            setStringViaFrontEndApiSetting(type, name, value, userId);
         }, type, name, value, userId);
     }
 
     private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
             final String name, final String value, final boolean withTableRowUri)
             throws Exception {
-        setSettingAndAssertSuccessfulChange(new Runnable() {
-            @Override
-            public void run() {
-                insertStringViaProviderApi(type, name, value, withTableRowUri);
-            }
+        setSettingAndAssertSuccessfulChange(() -> {
+            insertStringViaProviderApi(type, name, value, withTableRowUri);
         }, type, name, value, UserHandle.USER_SYSTEM);
     }
 
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 9964467..3f68554 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -99,10 +99,10 @@
         checkWriteSingleSetting(serializer, CRAZY_STRING, null);
         SettingsState.writeSingleSetting(
                 SettingsState.SETTINGS_VERSION_NEW_ENCODING,
-                serializer, null, "k", "v", "package");
+                serializer, null, "k", "v", null, "package", null, false);
         SettingsState.writeSingleSetting(
                 SettingsState.SETTINGS_VERSION_NEW_ENCODING,
-                serializer, "1", "k", "v", null);
+                serializer, "1", "k", "v", null, null, null, false);
     }
 
     private void checkWriteSingleSetting(XmlSerializer serializer, String key, String value)
@@ -115,7 +115,7 @@
         // Make sure the XML serializer won't crash.
         SettingsState.writeSingleSetting(
                 SettingsState.SETTINGS_VERSION_NEW_ENCODING,
-                serializer, "1", key, value, "package");
+                serializer, "1", key, value, null, "package", null, false);
     }
 
     /**
@@ -126,19 +126,19 @@
         file.delete();
         final Object lock = new Object();
 
-        final SettingsState ssWriter = new SettingsState(lock, file, 1,
+        final SettingsState ssWriter = new SettingsState(getContext(), lock, file, 1,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING);
 
-        ssWriter.insertSettingLocked("k1", "\u0000", "package");
-        ssWriter.insertSettingLocked("k2", "abc", "p2");
-        ssWriter.insertSettingLocked("k3", null, "p2");
-        ssWriter.insertSettingLocked("k4", CRAZY_STRING, "p3");
+        ssWriter.insertSettingLocked("k1", "\u0000", null, false, "package");
+        ssWriter.insertSettingLocked("k2", "abc", null, false, "p2");
+        ssWriter.insertSettingLocked("k3", null, null, false, "p2");
+        ssWriter.insertSettingLocked("k4", CRAZY_STRING, null, false, "p3");
         synchronized (lock) {
             ssWriter.persistSyncLocked();
         }
 
-        final SettingsState ssReader = new SettingsState(lock, file, 1,
+        final SettingsState ssReader = new SettingsState(getContext(), lock, file, 1,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         synchronized (lock) {
             assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue());
@@ -165,7 +165,7 @@
                 "</settings>");
         os.close();
 
-        final SettingsState ss = new SettingsState(lock, file, 1,
+        final SettingsState ss = new SettingsState(getContext(), lock, file, 1,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
         synchronized (lock) {
             SettingsState.Setting s;