[NS10] Fix a bug where registerIgnoringScore is broken

Fixes: 184028345
Test: ConnectivityServiceTest
Merged-In: I3c2563d4ae4e3715d0c6270344ba8f7ef067872f
Merged-In: Ib5cd2c27a2bd0f53b500e8edbe48126fbf58f34d
Change-Id: Ib5cd2c27a2bd0f53b500e8edbe48126fbf58f34d
  (cherry-picked from ag/14034625)
diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java
index 6e38e2d..a8a83fc 100644
--- a/service/src/com/android/server/connectivity/FullScore.java
+++ b/service/src/com/android/server/connectivity/FullScore.java
@@ -86,9 +86,14 @@
     /** @hide */
     public static final int POLICY_IS_UNMETERED = 59;
 
+    // This network is invincible. This is useful for offers until there is an API to listen
+    // to requests.
+    /** @hide */
+    public static final int POLICY_IS_INVINCIBLE = 58;
+
     // To help iterate when printing
     @VisibleForTesting
-    static final int MIN_CS_MANAGED_POLICY = POLICY_IS_UNMETERED;
+    static final int MIN_CS_MANAGED_POLICY = POLICY_IS_INVINCIBLE;
     @VisibleForTesting
     static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;
 
@@ -109,6 +114,7 @@
             case POLICY_YIELD_TO_BAD_WIFI: return "YIELD_TO_BAD_WIFI";
             case POLICY_TRANSPORT_PRIMARY: return "TRANSPORT_PRIMARY";
             case POLICY_EXITING: return "EXITING";
+            case POLICY_IS_INVINCIBLE: return "INVINCIBLE";
         }
         throw new IllegalArgumentException("Unknown policy : " + policy);
     }
@@ -147,7 +153,8 @@
                 caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                 config.explicitlySelected,
                 config.acceptUnvalidated,
-                yieldToBadWiFi);
+                yieldToBadWiFi,
+                false /* invincible */); // only prospective scores can be invincible
     }
 
     /**
@@ -178,8 +185,12 @@
         final boolean acceptUnvalidated = false;
         // Don't assume clinging to bad wifi
         final boolean yieldToBadWiFi = false;
+        // A prospective score is invincible if the legacy int in the filter is over the maximum
+        // score.
+        final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
         return withPolicies(score.getLegacyInt(), score.getPolicies(), KEEP_CONNECTED_NONE,
-                mayValidate, vpn, unmetered, everUserSelected, acceptUnvalidated, yieldToBadWiFi);
+                mayValidate, vpn, unmetered, everUserSelected, acceptUnvalidated, yieldToBadWiFi,
+                invincible);
     }
 
     /**
@@ -200,7 +211,8 @@
                 caps.hasCapability(NET_CAPABILITY_NOT_METERED),
                 config.explicitlySelected,
                 config.acceptUnvalidated,
-                yieldToBadWifi);
+                yieldToBadWifi,
+                false /* invincible */); // only prospective scores can be invincible
     }
 
     // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
@@ -214,14 +226,16 @@
             final boolean isUnmetered,
             final boolean everUserSelected,
             final boolean acceptUnvalidated,
-            final boolean yieldToBadWiFi) {
+            final boolean yieldToBadWiFi,
+            final boolean invincible) {
         return new FullScore(legacyInt, (externalPolicies & EXTERNAL_POLICIES_MASK)
                 | (isValidated       ? 1L << POLICY_IS_VALIDATED : 0)
                 | (isVpn             ? 1L << POLICY_IS_VPN : 0)
                 | (isUnmetered       ? 1L << POLICY_IS_UNMETERED : 0)
                 | (everUserSelected  ? 1L << POLICY_EVER_USER_SELECTED : 0)
                 | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)
-                | (yieldToBadWiFi    ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0),
+                | (yieldToBadWiFi    ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0)
+                | (invincible        ? 1L << POLICY_IS_INVINCIBLE : 0),
                 keepConnectedReason);
     }
 
diff --git a/service/src/com/android/server/connectivity/NetworkRanker.java b/service/src/com/android/server/connectivity/NetworkRanker.java
index 698744a..3aaff59 100644
--- a/service/src/com/android/server/connectivity/NetworkRanker.java
+++ b/service/src/com/android/server/connectivity/NetworkRanker.java
@@ -26,6 +26,7 @@
 
 import static com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED;
 import static com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED;
+import static com.android.server.connectivity.FullScore.POLICY_IS_INVINCIBLE;
 import static com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED;
 import static com.android.server.connectivity.FullScore.POLICY_IS_VPN;
 
@@ -46,6 +47,10 @@
  * A class that knows how to find the best network matching a request out of a list of networks.
  */
 public class NetworkRanker {
+    // 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;
+
     /**
      * A class that can be scored against other scoreables.
      */
@@ -72,7 +77,6 @@
         return matches;
     }
 
-
     /**
      * Find the best network satisfying this request among the list of passed networks.
      */
@@ -134,6 +138,12 @@
         // 4. if none remain, the criterion did not help discriminate so keep them all. As an
         //    optimization, skip creating a new array and go on to the next criterion.
 
+        // If a network is invincible, use it.
+        partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_INVINCIBLE),
+                accepted, rejected);
+        if (accepted.size() == 1) return accepted.get(0);
+        if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
+
         // If there is a connected VPN, use it.
         partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_VPN),
                 accepted, rejected);
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index a42adbd..072d304 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -3205,7 +3205,6 @@
         // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
     }
 
-    @Ignore("Refactoring in progress b/184028345")
     @Test
     public void testRegisterIgnoringScore() throws Exception {
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);