Add restore of Settings keys to
SettingsBackupAgent.RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS

Now that we have validators in place for all settings that are
backed up.

Also, add a setting to override restoreAnyVersion, which can be
modified by Phenotype.

Bug: 64988620
Bug: 72162887
Test: manual (P->P - master without changes to master with changes)
Test: manual (Q->P = API29 -> API28)
Test: a lot of other scenarios covered by our end-to-end tests
Test: a GTS test with both settings that don't have validators
      and have values that wouldn't pass validation will be added
      in vendor/xts
Change-Id: Ifaf94306984b5204c79648d48fd4056ad403196e
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b2cc18b..347e563 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11175,6 +11175,15 @@
                 "location_global_kill_switch";
 
         /**
+         * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
+         * and restoring to lower version of platform API will be skipped.
+         *
+         * @hide
+         */
+        public static final String OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION =
+                "override_settings_provider_restore_any_version";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ec3a6ce..406f6d7 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -426,7 +426,8 @@
                     Settings.Global.ZEN_MODE,
                     Settings.Global.ZEN_MODE_CONFIG_ETAG,
                     Settings.Global.ZEN_MODE_RINGER_LEVEL,
-                    Settings.Global.ZRAM_ENABLED);
+                    Settings.Global.ZRAM_ENABLED,
+                    Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION);
 
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index c7ba4d6..dd89df1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -35,6 +35,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.SettingsValidators.Validator;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.BackupUtils;
@@ -155,6 +156,9 @@
             new ArraySet<String>(Arrays.asList(new String[] {
                 KEY_NETWORK_POLICIES,
                 KEY_WIFI_NEW_CONFIG,
+                KEY_SYSTEM,
+                KEY_SECURE,
+                KEY_GLOBAL,
             }));
 
     private SettingsHelper mSettingsHelper;
@@ -223,6 +227,15 @@
             Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode
                     + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT);
         }
+
+        boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(),
+                Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1;
+        if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) {
+            Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API"
+                    + Build.VERSION.SDK_INT + " due to settings flag override.");
+            return;
+        }
+
         // versionCode of com.android.providers.settings corresponds to SDK_INT
         mRestoredFromSdkInt = appVersionCode;
 
@@ -571,15 +584,19 @@
         // Figure out the white list and redirects to the global table.  We restore anything
         // in either the backup whitelist or the legacy-restore whitelist for this table.
         final String[] whitelist;
+        Map<String, Validator> validators = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
             whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
                     Settings.Secure.LEGACY_RESTORE_SETTINGS);
+            validators = Settings.Secure.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
             whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
                     Settings.System.LEGACY_RESTORE_SETTINGS);
+            validators = Settings.System.VALIDATORS;
         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
             whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
                     Settings.Global.LEGACY_RESTORE_SETTINGS);
+            validators = Settings.Global.VALIDATORS;
         } else {
             throw new IllegalArgumentException("Unknown URI: " + contentUri);
         }
@@ -627,6 +644,13 @@
                 continue;
             }
 
+            // only restore the settings that have valid values
+            if (!isValidSettingValue(key, value, validators)) {
+                Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass"
+                        + " validation, value: " + value);
+                continue;
+            }
+
             final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
                     ? Settings.Global.CONTENT_URI
                     : contentUri;
@@ -639,6 +663,15 @@
         }
     }
 
+    private boolean isValidSettingValue(String key, String value,
+            Map<String, Validator> validators) {
+        if (key == null || validators == null) {
+            return false;
+        }
+        Validator validator = validators.get(key);
+        return (validator != null) && validator.validate(value);
+    }
+
     private final String[] concat(String[] first, @Nullable String[] second) {
         if (second == null || second.length == 0) {
             return first;