diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java index 6e38e2d1ec..a8a83fc004 100644 --- a/service/src/com/android/server/connectivity/FullScore.java +++ b/service/src/com/android/server/connectivity/FullScore.java @@ -86,9 +86,14 @@ public class FullScore { /** @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 @@ public class FullScore { 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 @@ public class FullScore { caps.hasCapability(NET_CAPABILITY_NOT_METERED), config.explicitlySelected, config.acceptUnvalidated, - yieldToBadWiFi); + yieldToBadWiFi, + false /* invincible */); // only prospective scores can be invincible } /** @@ -178,8 +185,12 @@ public class FullScore { 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 @@ public class FullScore { 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 @@ public class FullScore { 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 698744a57a..3aaff59a74 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 android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI; 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 @@ 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 { + // 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 @@ public class NetworkRanker { return matches; } - /** * Find the best network satisfying this request among the list of passed networks. */ @@ -134,6 +138,12 @@ public class NetworkRanker { // 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 7d6f95f825..7ba415b743 100644 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -3205,7 +3205,6 @@ public class ConnectivityServiceTest { // 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);