Properly compute default and system set flag on an upgrade

We added the notions of a default value and whether this default is set
by the system for a setting which is needed for experiments since in
case a bad value is pushed we should be able to incrementally rollback
to a stable state. If a system component sets a setting value this
automatically becomes the default. System components are the platform
package, the special UIDs (telephony, etc), apps singed with the
platform cert, system installed persistent apps, and SUW.

In N we did not have the notion of a default and during an upgrade need
to adjust the default and whether this default is set by the system.
This migration runs as the system UID and was incorrectly computing that
the package that changed the settings last was a part of the system and
setting the current value as its default set by the system. This
resulted in taking more storage space as we also count the default which
led the package which changed the setting to go over the quota and that
throws. If the first caller into the settings provider is the system
main
thread (almost certain) we end up throwing an exception on the system
main thread - crashing the system server.

Test: flash N, install an app abusing sys settings, update to O

bug:64718888

Change-Id: I24f36ed46bb97e03f72d04ecd9e7ca53da7588c4
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 146b349..e3534f5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2892,7 +2892,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 147;
+            private static final int SETTINGS_VERSION = 148;
 
             private final int mUserId;
 
@@ -3341,22 +3341,11 @@
                 }
 
                 if (currentVersion == 141) {
-                    // Version 142: We added the notion of a default and whether the system set
-                    // the setting. This is used for resetting the internal state and we need
-                    // to make sure this value is updated for the existing settings, otherwise
-                    // we would delete system set settings while they should stay unmodified.
-                    SettingsState globalSettings = getGlobalSettingsLocked();
-                    ensureLegacyDefaultValueAndSystemSetUpdatedLocked(globalSettings);
-                    globalSettings.persistSyncLocked();
-
-                    SettingsState secureSettings = getSecureSettingsLocked(mUserId);
-                    ensureLegacyDefaultValueAndSystemSetUpdatedLocked(secureSettings);
-                    secureSettings.persistSyncLocked();
-
-                    SettingsState systemSettings = getSystemSettingsLocked(mUserId);
-                    ensureLegacyDefaultValueAndSystemSetUpdatedLocked(systemSettings);
-                    systemSettings.persistSyncLocked();
-
+                    // This implementation was incorrectly setting the current value of
+                    // settings changed by non-system packages as the default which default
+                    // is set by the system. We add a new upgrade step at the end to properly
+                    // handle this case which would also fix incorrect changes made by the
+                    // old implementation of this step.
                     currentVersion = 142;
                 }
 
@@ -3403,24 +3392,51 @@
                 }
 
                 if (currentVersion == 145) {
-                    // Version 146: Set the default value for WIFI_WAKEUP_AVAILABLE.
+                    // Version 146: In step 142 we had a bug where incorrectly
+                    // some settings were considered system set and as a result
+                    // made the default and marked as the default being set by
+                    // the system. Here reevaluate the default and default system
+                    // set flags. This would both fix corruption by the old impl
+                    // of step 142 and also properly handle devices which never
+                    // run 142.
                     if (userId == UserHandle.USER_SYSTEM) {
-                        final SettingsState globalSettings = getGlobalSettingsLocked();
-                        final Setting currentSetting = globalSettings.getSettingLocked(
-                                Settings.Global.WIFI_WAKEUP_AVAILABLE);
-                        final int defaultValue = getContext().getResources().getInteger(
-                                com.android.internal.R.integer.config_wifi_wakeup_available);
-                        globalSettings.insertSettingLocked(
-                                Settings.Global.WIFI_WAKEUP_AVAILABLE,
-                                String.valueOf(defaultValue),
-                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                        SettingsState globalSettings = getGlobalSettingsLocked();
+                        ensureLegacyDefaultValueAndSystemSetUpdatedLocked(globalSettings, userId);
+                        globalSettings.persistSyncLocked();
                     }
 
+                    SettingsState secureSettings = getSecureSettingsLocked(mUserId);
+                    ensureLegacyDefaultValueAndSystemSetUpdatedLocked(secureSettings, userId);
+                    secureSettings.persistSyncLocked();
+
+                    SettingsState systemSettings = getSystemSettingsLocked(mUserId);
+                    ensureLegacyDefaultValueAndSystemSetUpdatedLocked(systemSettings, userId);
+                    systemSettings.persistSyncLocked();
+
                     currentVersion = 146;
                 }
 
                 if (currentVersion == 146) {
-                    // Version 146: Set the default value for DEFAULT_RESTRICT_BACKGROUND_DATA.
+                    // Version 147: Set the default value for WIFI_WAKEUP_AVAILABLE.
+                    if (userId == UserHandle.USER_SYSTEM) {
+                        final SettingsState globalSettings = getGlobalSettingsLocked();
+                        final Setting currentSetting = globalSettings.getSettingLocked(
+                                Settings.Global.WIFI_WAKEUP_AVAILABLE);
+                        if (currentSetting.getValue() == null) {
+                            final int defaultValue = getContext().getResources().getInteger(
+                                    com.android.internal.R.integer.config_wifi_wakeup_available);
+                            globalSettings.insertSettingLocked(
+                                    Settings.Global.WIFI_WAKEUP_AVAILABLE,
+                                    String.valueOf(defaultValue),
+                                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
+                    }
+
+                    currentVersion = 147;
+                }
+
+                if (currentVersion == 147) {
+                    // Version 148: Set the default value for DEFAULT_RESTRICT_BACKGROUND_DATA.
                     if (userId == UserHandle.USER_SYSTEM) {
                         final SettingsState globalSettings = getGlobalSettingsLocked();
                         final Setting currentSetting = globalSettings.getSettingLocked(
@@ -3433,7 +3449,7 @@
                                     null, true, SettingsState.SYSTEM_PACKAGE_NAME);
                         }
                     }
-                    currentVersion = 147;
+                    currentVersion = 148;
                 }
 
                 // vXXX: Add new settings above this point.
@@ -3454,19 +3470,46 @@
             }
         }
 
-        private void ensureLegacyDefaultValueAndSystemSetUpdatedLocked(SettingsState settings) {
+        private void ensureLegacyDefaultValueAndSystemSetUpdatedLocked(SettingsState settings,
+                int userId) {
             List<String> names = settings.getSettingNamesLocked();
             final int nameCount = names.size();
             for (int i = 0; i < nameCount; i++) {
                 String name = names.get(i);
                 Setting setting = settings.getSettingLocked(name);
-                if (setting.getDefaultValue() == null) {
-                    boolean systemSet = SettingsState.isSystemPackage(getContext(),
-                            setting.getPackageName());
+
+                // In the upgrade case we pretend the call is made from the app
+                // that made the last change to the setting to properly determine
+                // whether the call has been made by a system component.
+                int callingUid = -1;
+                try {
+                    callingUid = mPackageManager.getPackageUid(setting.getPackageName(), 0, userId);
+                } catch (RemoteException e) {
+                    /* ignore - handled below */
+                }
+                if (callingUid < 0) {
+                    Slog.e(LOG_TAG, "Unknown package: " + setting.getPackageName());
+                    continue;
+                }
+                try {
+                    final boolean systemSet = SettingsState.isSystemPackage(getContext(),
+                            setting.getPackageName(), callingUid);
                     if (systemSet) {
                         settings.insertSettingLocked(name, setting.getValue(),
                                 setting.getTag(), true, setting.getPackageName());
+                    } else if (setting.getDefaultValue() != null && setting.isDefaultFromSystem()) {
+                        // We had a bug where changes by non-system packages were marked
+                        // as system made and as a result set as the default. Therefore, if
+                        // the package changed the setting last is not a system one but the
+                        // setting is marked as its default coming from the system we clear
+                        // the default and clear the system set flag.
+                        settings.resetSettingDefaultValueLocked(name);
                     }
+                } catch (IllegalStateException e) {
+                    // If the package goes over its quota during the upgrade, don't
+                    // crash but just log the error as the system does the upgrade.
+                    Slog.e(LOG_TAG, "Error upgrading setting: " + setting.getName(), e);
+
                 }
             }
         }