Update the avoid bad wifi settings on the handler thread.

Currently, every call to avoidBadWifi fetches the current value
of the config variable and setting whenever it is called. This
means that the score of an unvalidated wifi network can
unpredictably change at any time, creating a data race.

Instead, persist the value and only update it when something
changes.

Bug: 31075769
Change-Id: I0f4e0e742c91ef77fabc95d3ebb494338396aca5
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 66d23a2..59c8840 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -851,6 +851,15 @@
                 Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
                 LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
         mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
+
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
+            }
+        }, UserHandle.ALL, intentFilter, null, null);
+        updateAvoidBadWifi();
     }
 
     private NetworkRequest createInternetRequestForTransport(int transportType) {
@@ -2719,17 +2728,29 @@
                 PROMPT_UNVALIDATED_DELAY_MS);
     }
 
-    @VisibleForTesting
+    private boolean mAvoidBadWifi;
+
     public boolean avoidBadWifi() {
+        return mAvoidBadWifi;
+    }
+
+    @VisibleForTesting
+    public boolean updateAvoidBadWifi() {
         // There are two modes: either we always automatically avoid unvalidated wifi, or we show a
         // dialog and don't switch to it. The behaviour is controlled by the NETWORK_AVOID_BAD_WIFI
         // setting. If the setting has no value, then the value is taken from the config value,
         // which can be changed via OEM/carrier overlays.
+        //
+        // The only valid values for NETWORK_AVOID_BAD_WIFI are null and unset. Currently, the unit
+        // test uses 0 in order to avoid having to mock out fetching the carrier setting.
         int defaultAvoidBadWifi =
             mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
         int avoid = Settings.Global.getInt(mContext.getContentResolver(),
             Settings.Global.NETWORK_AVOID_BAD_WIFI, defaultAvoidBadWifi);
-        return avoid == 1;
+
+        boolean prev = mAvoidBadWifi;
+        mAvoidBadWifi = (avoid == 1);
+        return mAvoidBadWifi != prev;
     }
 
     private void showValidationNotification(NetworkAgentInfo nai, NotificationType type) {
@@ -2868,7 +2889,9 @@
                     break;
                 }
                 case EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI: {
-                    rematchAllNetworksAndRequests(null, 0);
+                    if (updateAvoidBadWifi()) {
+                        rematchAllNetworksAndRequests(null, 0);
+                    }
                     break;
                 }
                 case EVENT_REQUEST_LINKPROPERTIES: