Introduce an overlay for actively preferring bad wifi.

This correctly updates when the mcc/mnc change.

Test: MultinetworkPolicyTrackerTest
Change-Id: I11c7ea7074a15975fb68d39eb3c728778d84a516
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 93265e5..cb209e8 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -783,7 +783,8 @@
     final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
 
     private final DnsManager mDnsManager;
-    private final NetworkRanker mNetworkRanker;
+    @VisibleForTesting
+    final NetworkRanker mNetworkRanker;
 
     private boolean mSystemReady;
     private Intent mInitialBroadcast;
@@ -1417,7 +1418,6 @@
                 new RequestInfoPerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID - 1);
 
         mMetricsLog = logger;
-        mNetworkRanker = new NetworkRanker();
         final NetworkRequest defaultInternetRequest = createDefaultRequest();
         mDefaultRequest = new NetworkRequestInfo(
                 Process.myUid(), defaultInternetRequest, null,
@@ -1538,6 +1538,9 @@
 
         mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
                 mContext, mHandler, () -> updateAvoidBadWifi());
+        mNetworkRanker =
+                new NetworkRanker(new NetworkRanker.Configuration(activelyPreferBadWifi()));
+
         mMultinetworkPolicyTracker.start();
 
         mDnsManager = new DnsManager(mContext, mDnsResolver);
@@ -5050,6 +5053,10 @@
         return mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
 
+    private boolean activelyPreferBadWifi() {
+        return mMultinetworkPolicyTracker.getActivelyPreferBadWifi();
+    }
+
     /**
      * Return whether the device should maintain continuous, working connectivity by switching away
      * from WiFi networks having no connectivity.
@@ -5073,6 +5080,7 @@
         for (final NetworkOfferInfo noi : offersToUpdate) {
             updateOfferScore(noi.offer);
         }
+        mNetworkRanker.setConfiguration(new NetworkRanker.Configuration(activelyPreferBadWifi()));
         rematchAllNetworksAndRequests();
     }
 
@@ -5088,6 +5096,7 @@
         pw.println("Bad Wi-Fi avoidance: " + avoidBadWifi());
         pw.increaseIndent();
         pw.println("Config restrict:   " + configRestrict);
+        pw.println("Actively prefer:   " + activelyPreferBadWifi());
 
         final String value = mMultinetworkPolicyTracker.getAvoidBadWifiSetting();
         String description;
diff --git a/service/src/com/android/server/connectivity/NetworkRanker.java b/service/src/com/android/server/connectivity/NetworkRanker.java
index f2c6aa1..d56e171 100644
--- a/service/src/com/android/server/connectivity/NetworkRanker.java
+++ b/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -38,19 +38,42 @@
 import android.annotation.Nullable;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.util.MultinetworkPolicyTracker;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Predicate;
 
 /**
  * A class that knows how to find the best network matching a request out of a list of networks.
  */
 public class NetworkRanker {
+    /**
+     * Home for all configurations of NetworkRanker
+     */
+    public static final class Configuration {
+        private final boolean mActivelyPreferBadWifi;
+
+        public Configuration(final boolean activelyPreferBadWifi) {
+            this.mActivelyPreferBadWifi = activelyPreferBadWifi;
+        }
+
+        /**
+         * @see MultinetworkPolicyTracker#getActivelyPreferBadWifi()
+         */
+        // TODO : implement the behavior.
+        public boolean activelyPreferBadWifi() {
+            return mActivelyPreferBadWifi;
+        }
+    }
+    @NonNull private volatile Configuration mConf;
+
     // Historically the legacy ints have been 0~100 in principle (though the highest score in
     // AOSP has always been 90). This is relied on by VPNs that send a legacy score of 101.
     public static final int LEGACY_INT_MAX = 100;
@@ -65,7 +88,22 @@
         NetworkCapabilities getCapsNoCopy();
     }
 
-    public NetworkRanker() { }
+    public NetworkRanker(@NonNull final Configuration conf) {
+        // Because mConf is volatile, the only way it could be seen null would be an access to it
+        // on some other thread during this constructor. But this is not possible because mConf is
+        // private and `this` doesn't escape this constructor.
+        setConfiguration(conf);
+    }
+
+    public void setConfiguration(@NonNull final Configuration conf) {
+        mConf = Objects.requireNonNull(conf);
+    }
+
+    // There shouldn't be a use case outside of testing
+    @VisibleForTesting
+    public Configuration getConfiguration() {
+        return mConf;
+    }
 
     /**
      * Find the best network satisfying this request among the list of passed networks.