Add validators for all Settings.Global settings that are backed up

And extend the unit test to fail if new ones are added without
a validator. Also fail to boot in that case.

Ref: go/android-p-backed-up-settings
Test: atest frameworks/base/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
Bug: 64988620
Change-Id: Ibd4a2bad0c6a1f2a9e1beec1a4ec8e6972fd86a4
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b685aef..ce06367 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,10 +16,12 @@
 
 package android.provider;
 
+import static android.provider.SettingsValidators.ANY_STRING_VALIDATOR;
 import static android.provider.SettingsValidators.BOOLEAN_VALIDATOR;
 import static android.provider.SettingsValidators.COMPONENT_NAME_VALIDATOR;
 import static android.provider.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
 import static android.provider.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.SettingsValidators.PACKAGE_NAME_VALIDATOR;
 import static android.provider.SettingsValidators.URI_VALIDATOR;
 
 import android.Manifest;
@@ -4279,6 +4281,8 @@
         @Deprecated
         public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
 
+        private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
          */
@@ -4356,6 +4360,8 @@
         @Deprecated
         public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
 
+        private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
          */
@@ -4385,6 +4391,9 @@
         public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                 Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
 
+       private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
+               BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use
          * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead
@@ -5162,6 +5171,8 @@
         @Deprecated
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
+        private static final Validator BUGREPORT_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead
          */
@@ -5224,6 +5235,8 @@
         @Deprecated
         public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
 
+        private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
          */
@@ -5651,6 +5664,8 @@
         @Deprecated
         public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
 
+        private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
          */
@@ -6118,6 +6133,9 @@
         public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                 Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
 
+       private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
+               BOOLEAN_VALIDATOR;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY}
          * instead.
@@ -7834,6 +7852,8 @@
          */
         public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled";
 
+        private static final Validator CHARGING_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * Whether we keep the device on while the device is plugged in.
          * Supported values are:
@@ -7878,6 +7898,8 @@
          */
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
+        private static final Validator BUGREPORT_IN_POWER_MENU_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * Whether ADB is enabled.
          */
@@ -7901,6 +7923,8 @@
          */
         public static final String BLUETOOTH_ON = "bluetooth_on";
 
+        private static final Validator BLUETOOTH_ON_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * CDMA Cell Broadcast SMS
          *                            0 = CDMA Cell Broadcast SMS disabled
@@ -8519,6 +8543,8 @@
         */
        public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
 
+       private static final Validator USB_MASS_STORAGE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
        /**
         * If this setting is set (to anything), then all references
         * to Gmail on the device must change to Google Mail.
@@ -8655,6 +8681,9 @@
        public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
                "wifi_networks_available_notification_on";
 
+       private static final Validator WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR =
+               BOOLEAN_VALIDATOR;
+
        /**
         * {@hide}
         */
@@ -8717,6 +8746,8 @@
          */
         public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
 
+        private static final Validator SOFT_AP_TIMEOUT_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * Value to specify if Wi-Fi Wakeup feature is enabled.
          *
@@ -8726,6 +8757,8 @@
         @SystemApi
         public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
 
+        private static final Validator WIFI_WAKEUP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * Value to specify if Wi-Fi Wakeup is available.
          *
@@ -8772,6 +8805,9 @@
         public static final String NETWORK_RECOMMENDATIONS_ENABLED =
                 "network_recommendations_enabled";
 
+        private static final Validator NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR =
+                new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "1"});
+
         /**
          * Which package name to use for network recommendations. If null, network recommendations
          * will neither be requested nor accepted.
@@ -8795,6 +8831,13 @@
         @TestApi
         public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
 
+        private static final Validator USE_OPEN_WIFI_PACKAGE_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                return (value == null) || PACKAGE_NAME_VALIDATOR.validate(value);
+            }
+        };
+
         /**
          * The number of milliseconds the {@link com.android.server.NetworkScoreService}
          * will give a recommendation request to complete before returning a default response.
@@ -8874,6 +8917,9 @@
        public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
                "wifi_watchdog_poor_network_test_enabled";
 
+       private static final Validator WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED_VALIDATOR =
+               ANY_STRING_VALIDATOR;
+
        /**
         * Setting to turn on suspend optimizations at screen off on Wi-Fi. Enabled by default and
         * needs to be set to 0 to disable it.
@@ -9409,11 +9455,16 @@
          * @hide
          */
         public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+
+        private static final Validator PRIVATE_DNS_MODE_VALIDATOR = ANY_STRING_VALIDATOR;
+
         /**
          * @hide
          */
         public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
 
+        private static final Validator PRIVATE_DNS_SPECIFIER_VALIDATOR = ANY_STRING_VALIDATOR;
+
         /** {@hide} */
         public static final String
                 BLUETOOTH_HEADSET_PRIORITY_PREFIX = "bluetooth_headset_priority_";
@@ -9987,6 +10038,9 @@
          */
         public static final String EMERGENCY_TONE = "emergency_tone";
 
+        private static final Validator EMERGENCY_TONE_VALIDATOR =
+                new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
+
         /**
          * CDMA only settings
          * Whether the auto retry is enabled. The value is
@@ -9995,6 +10049,8 @@
          */
         public static final String CALL_AUTO_RETRY = "call_auto_retry";
 
+        private static final Validator CALL_AUTO_RETRY_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * A setting that can be read whether the emergency affordance is currently needed.
          * The value is a boolean (1 or 0).
@@ -10064,6 +10120,9 @@
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
 
+        private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 99);
+
          /**
          * If not 0, the activity manager will aggressively finish activities and
          * processes as soon as they are no longer needed.  If 0, the normal
@@ -10079,6 +10138,8 @@
          */
         public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
 
+        private static final Validator DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
         /**
          * The surround sound formats AC3, DTS or IEC61937 are
          * available for use if they are detected.
@@ -10125,6 +10186,9 @@
          */
         public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
 
+        private static final Validator ENCODED_SURROUND_OUTPUT_VALIDATOR =
+                new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"});
+
         /**
          * Persisted safe headphone volume management state by AudioService
          * @hide
@@ -10665,6 +10729,41 @@
         };
 
         /**
+         * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator,
+         * otherwise they won't be restored.
+         *
+         * @hide
+         */
+        public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+        static {
+            VALIDATORS.put(BUGREPORT_IN_POWER_MENU, BUGREPORT_IN_POWER_MENU_VALIDATOR);
+            VALIDATORS.put(STAY_ON_WHILE_PLUGGED_IN, STAY_ON_WHILE_PLUGGED_IN_VALIDATOR);
+            VALIDATORS.put(AUTO_TIME, AUTO_TIME_VALIDATOR);
+            VALIDATORS.put(AUTO_TIME_ZONE, AUTO_TIME_ZONE_VALIDATOR);
+            VALIDATORS.put(POWER_SOUNDS_ENABLED, POWER_SOUNDS_ENABLED_VALIDATOR);
+            VALIDATORS.put(DOCK_SOUNDS_ENABLED, DOCK_SOUNDS_ENABLED_VALIDATOR);
+            VALIDATORS.put(CHARGING_SOUNDS_ENABLED, CHARGING_SOUNDS_ENABLED_VALIDATOR);
+            VALIDATORS.put(USB_MASS_STORAGE_ENABLED, USB_MASS_STORAGE_ENABLED_VALIDATOR);
+            VALIDATORS.put(NETWORK_RECOMMENDATIONS_ENABLED,
+                    NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR);
+            VALIDATORS.put(WIFI_WAKEUP_ENABLED, WIFI_WAKEUP_ENABLED_VALIDATOR);
+            VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                    WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
+            VALIDATORS.put(USE_OPEN_WIFI_PACKAGE, USE_OPEN_WIFI_PACKAGE_VALIDATOR);
+            VALIDATORS.put(WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+                    WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED_VALIDATOR);
+            VALIDATORS.put(EMERGENCY_TONE, EMERGENCY_TONE_VALIDATOR);
+            VALIDATORS.put(CALL_AUTO_RETRY, CALL_AUTO_RETRY_VALIDATOR);
+            VALIDATORS.put(DOCK_AUDIO_MEDIA_ENABLED, DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR);
+            VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
+            VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
+            VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR);
+            VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR);
+            VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR);
+            VALIDATORS.put(SOFT_AP_TIMEOUT_ENABLED, SOFT_AP_TIMEOUT_ENABLED_VALIDATOR);
+        }
+
+        /**
          * Global settings that shouldn't be persisted.
          *
          * @hide
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
index af82452..22ef3b6 100644
--- a/core/java/android/provider/SettingsValidators.java
+++ b/core/java/android/provider/SettingsValidators.java
@@ -32,6 +32,13 @@
     public static final Validator BOOLEAN_VALIDATOR =
             new DiscreteValueValidator(new String[] {"0", "1"});
 
+    public static final Validator ANY_STRING_VALIDATOR = new Validator() {
+        @Override
+        public boolean validate(String value) {
+            return true;
+        }
+    };
+
     public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
         @Override
         public boolean validate(String value) {
@@ -62,6 +69,38 @@
         }
     };
 
+    public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
+        @Override
+        public boolean validate(String value) {
+            return value != null && isStringPackageName(value);
+        }
+
+        private boolean isStringPackageName(String value) {
+            // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers,
+            // and underscores ('_'). However, individual package name parts may only
+            // start with letters.
+            // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package)
+            String[] subparts = value.split(".");
+            boolean isValidPackageName = true;
+            for (String subpart : subparts) {
+                isValidPackageName |= isSubpartValidForPackageName(subpart);
+                if (!isValidPackageName) break;
+            }
+            return isValidPackageName;
+        }
+
+        private boolean isSubpartValidForPackageName(String subpart) {
+            if (subpart.length() == 0) return false;
+            boolean isValidSubpart = Character.isLetter(subpart.charAt(0));
+            for (int i = 1; i < subpart.length(); i++) {
+                isValidSubpart |= (Character.isLetterOrDigit(subpart.charAt(i))
+                                || (subpart.charAt(i) == '_'));
+                if (!isValidSubpart) break;
+            }
+            return isValidSubpart;
+        }
+    };
+
     public static final Validator LENIENT_IP_ADDRESS_VALIDATOR = new Validator() {
         private static final int MAX_IPV6_LENGTH = 45;
 
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index 6b613dd..00732b0 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -19,12 +19,15 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
+import android.provider.SettingsValidators.Validator;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Map;
+
 /** Tests that ensure all backed up settings have non-null validators. */
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -33,18 +36,34 @@
 
     @Test
     public void ensureAllBackedUpSystemSettingsHaveValidators() {
+        String offenders = getOffenders(Settings.System.SETTINGS_TO_BACKUP,
+                Settings.System.VALIDATORS);
+
+        failIfOffendersPresent(offenders, "Settings.System");
+    }
+
+    @Test
+    public void ensureAllBackedUpGlobalSettingsHaveValidators() {
+        String offenders = getOffenders(Settings.Global.SETTINGS_TO_BACKUP,
+                Settings.Global.VALIDATORS);
+
+        failIfOffendersPresent(offenders, "Settings.Global");
+    }
+
+    private void failIfOffendersPresent(String offenders, String settingsType) {
+        if (offenders.length() > 0) {
+            fail("All " + settingsType + " settings that are backed up have to have a non-null"
+                    + " validator, but those don't: " + offenders);
+        }
+    }
+
+    private String getOffenders(String[] settingsToBackup, Map<String, Validator> validators) {
         StringBuilder offenders = new StringBuilder();
-        for (String setting : Settings.System.SETTINGS_TO_BACKUP) {
-            if (Settings.System.VALIDATORS.get(setting) == null) {
+        for (String setting : settingsToBackup) {
+            if (validators.get(setting) == null) {
                 offenders.append(setting).append(" ");
             }
         }
-
-        // if there're any offenders fail the test and report them
-        String offendersStr = offenders.toString();
-        if (offendersStr.length() > 0) {
-            fail("All Settings.System settings that are backed up have to have a non-null"
-                    + " validator, but those don't: " + offendersStr);
-        }
+        return offenders.toString();
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 01e0d52..9ee205f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -301,6 +301,7 @@
 
         // fail to boot if there're any backed up settings that don't have a non-null validator
         ensureAllBackedUpSystemSettingsHaveValidators();
+        ensureAllBackedUpGlobalSettingsHaveValidators();
 
         synchronized (mLock) {
             mUserManager = UserManager.get(getContext());
@@ -320,18 +321,35 @@
     }
 
     private void ensureAllBackedUpSystemSettingsHaveValidators() {
+        String offenders = getOffenders(Settings.System.SETTINGS_TO_BACKUP,
+                Settings.System.VALIDATORS);
+
+        failToBootIfOffendersPresent(offenders, "Settings.System");
+    }
+
+    private void ensureAllBackedUpGlobalSettingsHaveValidators() {
+        String offenders = getOffenders(Settings.Global.SETTINGS_TO_BACKUP,
+                Settings.Global.VALIDATORS);
+
+        failToBootIfOffendersPresent(offenders, "Settings.Global");
+    }
+
+    private void failToBootIfOffendersPresent(String offenders, String settingsType) {
+        if (offenders.length() > 0) {
+            throw new RuntimeException("All " + settingsType + " settings that are backed up"
+                    + " have to have a non-null validator, but those don't: " + offenders);
+        }
+    }
+
+    private String getOffenders(String[] settingsToBackup, Map<String,
+            SettingsValidators.Validator> validators) {
         StringBuilder offenders = new StringBuilder();
-        for (String setting : Settings.System.SETTINGS_TO_BACKUP) {
-            if (Settings.System.VALIDATORS.get(setting) == null) {
+        for (String setting : settingsToBackup) {
+            if (validators.get(setting) == null) {
                 offenders.append(setting).append(" ");
             }
         }
-
-        String offendersStr = offenders.toString();
-        if (offendersStr.length() > 0) {
-            throw new RuntimeException("All Settings.System settings that are backed up must"
-                    + " have a non-null validator, but those don't: " + offendersStr);
-        }
+        return offenders.toString();
     }
 
     @Override