diff options
6 files changed, 55 insertions, 26 deletions
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 09687d34bb80..348e40118340 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4229,7 +4229,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // network, we should respect the user's option and don't need to popup the // PARTIAL_CONNECTIVITY notification to user again. nai.networkAgentConfig.acceptPartialConnectivity = accept; - nai.updateScoreForNetworkAgentConfigUpdate(); + nai.updateScoreForNetworkAgentUpdate(); rematchAllNetworksAndRequests(); } @@ -4297,6 +4297,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (!nai.avoidUnvalidated) { nai.avoidUnvalidated = true; + nai.updateScoreForNetworkAgentUpdate(); rematchAllNetworksAndRequests(); } } @@ -4404,7 +4405,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void updateAvoidBadWifi() { for (final NetworkAgentInfo nai : mNetworkAgentInfos) { - nai.updateScoreForNetworkAgentConfigUpdate(); + nai.updateScoreForNetworkAgentUpdate(); } rematchAllNetworksAndRequests(); } @@ -7170,6 +7171,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc); updateUids(nai, prevNc, newNc); + nai.updateScoreForNetworkAgentUpdate(); if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) { // If the requestable capabilities haven't changed, and the score hasn't changed, then diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java index a8a83fc00491..52da56690721 100644 --- a/services/core/java/com/android/server/connectivity/FullScore.java +++ b/services/core/java/com/android/server/connectivity/FullScore.java @@ -91,17 +91,26 @@ public class FullScore { /** @hide */ public static final int POLICY_IS_INVINCIBLE = 58; + // This network has been validated at least once since it was connected, but not explicitly + // avoided in UI. + // TODO : remove setAvoidUnvalidated and instead disconnect the network when the user + // chooses to move away from this network, and remove this flag. + /** @hide */ + public static final int POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD = 57; + // To help iterate when printing @VisibleForTesting - static final int MIN_CS_MANAGED_POLICY = POLICY_IS_INVINCIBLE; + static final int MIN_CS_MANAGED_POLICY = POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD; @VisibleForTesting static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED; // Mask for policies in NetworkScore. This should have all bits managed by NetworkScore set // and all bits managed by FullScore unset. As bits are handled from 0 up in NetworkScore and - // from 63 down in FullScore, cut at the 32rd bit for simplicity, but change this if some day + // from 63 down in FullScore, cut at the 32nd bit for simplicity, but change this if some day // there are more than 32 bits handled on either side. - private static final int EXTERNAL_POLICIES_MASK = 0x0000FFFF; + // YIELD_TO_BAD_WIFI is temporarily handled by ConnectivityService. + private static final long EXTERNAL_POLICIES_MASK = + 0x00000000FFFFFFFFL & ~(1L << POLICY_YIELD_TO_BAD_WIFI); @VisibleForTesting static @NonNull String policyNameOf(final int policy) { @@ -115,6 +124,7 @@ public class FullScore { case POLICY_TRANSPORT_PRIMARY: return "TRANSPORT_PRIMARY"; case POLICY_EXITING: return "EXITING"; case POLICY_IS_INVINCIBLE: return "INVINCIBLE"; + case POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD: return "EVER_VALIDATED"; } throw new IllegalArgumentException("Unknown policy : " + policy); } @@ -137,6 +147,7 @@ public class FullScore { * @param score the score supplied by the agent * @param caps the NetworkCapabilities of the network * @param config the NetworkAgentConfig of the network + * @param everValidated whether this network has ever validated * @param yieldToBadWiFi whether this network yields to a previously validated wifi gone bad * @return a FullScore that is appropriate to use for ranking. */ @@ -145,12 +156,13 @@ public class FullScore { // connectivity for backward compatibility. public static FullScore fromNetworkScore(@NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config, - final boolean yieldToBadWiFi) { + final boolean everValidated, final boolean yieldToBadWiFi) { return withPolicies(score.getLegacyInt(), score.getPolicies(), score.getKeepConnectedReason(), caps.hasCapability(NET_CAPABILITY_VALIDATED), caps.hasTransport(TRANSPORT_VPN), caps.hasCapability(NET_CAPABILITY_NOT_METERED), + everValidated, config.explicitlySelected, config.acceptUnvalidated, yieldToBadWiFi, @@ -179,6 +191,8 @@ public class FullScore { // Prospective scores are always unmetered, because unmetered networks are stronger // than metered networks, and it's not known in advance whether the network is metered. final boolean unmetered = true; + // If the offer may validate, then it should be considered to have validated at some point + final boolean everValidated = mayValidate; // The network hasn't been chosen by the user (yet, at least). final boolean everUserSelected = false; // Don't assume the user will accept unvalidated connectivity. @@ -189,8 +203,8 @@ public class FullScore { // 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, - invincible); + mayValidate, vpn, unmetered, everValidated, everUserSelected, acceptUnvalidated, + yieldToBadWiFi, invincible); } /** @@ -204,11 +218,14 @@ public class FullScore { // telephony factory, so that it depends on the carrier. For now this is handled by // connectivity for backward compatibility. public FullScore mixInScore(@NonNull final NetworkCapabilities caps, - @NonNull final NetworkAgentConfig config, final boolean yieldToBadWifi) { + @NonNull final NetworkAgentConfig config, + final boolean everValidated, + final boolean yieldToBadWifi) { return withPolicies(mLegacyInt, mPolicies, mKeepConnectedReason, caps.hasCapability(NET_CAPABILITY_VALIDATED), caps.hasTransport(TRANSPORT_VPN), caps.hasCapability(NET_CAPABILITY_NOT_METERED), + everValidated, config.explicitlySelected, config.acceptUnvalidated, yieldToBadWifi, @@ -224,6 +241,7 @@ public class FullScore { final boolean isValidated, final boolean isVpn, final boolean isUnmetered, + final boolean everValidated, final boolean everUserSelected, final boolean acceptUnvalidated, final boolean yieldToBadWiFi, @@ -232,6 +250,7 @@ public class FullScore { | (isValidated ? 1L << POLICY_IS_VALIDATED : 0) | (isVpn ? 1L << POLICY_IS_VPN : 0) | (isUnmetered ? 1L << POLICY_IS_UNMETERED : 0) + | (everValidated ? 1L << POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD : 0) | (everUserSelected ? 1L << POLICY_EVER_USER_SELECTED : 0) | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0) | (yieldToBadWiFi ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0) diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 5d793fdda7b0..4d310cbc06bb 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -707,7 +707,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa @NonNull final NetworkCapabilities nc) { final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; - mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi()); + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, everValidatedForYield(), + yieldToBadWiFi()); final NetworkMonitorManager nm = mNetworkMonitor; if (nm != null) { nm.notifyNetworkCapabilitiesChanged(nc); @@ -893,7 +894,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa // Caller must not mutate. This method is called frequently and making a defensive copy // would be too expensive. This is used by NetworkRanker.Scoreable, so it can be compared // against other scoreables. - @Override public NetworkCapabilities getCaps() { + @Override public NetworkCapabilities getCapsNoCopy() { return networkCapabilities; } @@ -919,7 +920,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa */ public void setScore(final NetworkScore score) { mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig, - yieldToBadWiFi()); + everValidatedForYield(), yieldToBadWiFi()); } /** @@ -927,8 +928,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa * * Call this after updating the network agent config. */ - public void updateScoreForNetworkAgentConfigUpdate() { - mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi()); + public void updateScoreForNetworkAgentUpdate() { + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, + everValidatedForYield(), yieldToBadWiFi()); + } + + private boolean everValidatedForYield() { + return everValidated && !avoidUnvalidated; } /** diff --git a/services/core/java/com/android/server/connectivity/NetworkOffer.java b/services/core/java/com/android/server/connectivity/NetworkOffer.java index 5336593b4065..2bad596a590b 100644 --- a/services/core/java/com/android/server/connectivity/NetworkOffer.java +++ b/services/core/java/com/android/server/connectivity/NetworkOffer.java @@ -76,7 +76,7 @@ public class NetworkOffer implements NetworkRanker.Scoreable { /** * Get the capabilities filter of this offer */ - @Override @NonNull public NetworkCapabilities getCaps() { + @Override @NonNull public NetworkCapabilities getCapsNoCopy() { return caps; } diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java index 3aaff59a7484..c123ea75c66c 100644 --- a/services/core/java/com/android/server/connectivity/NetworkRanker.java +++ b/services/core/java/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_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD; 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; @@ -58,7 +59,7 @@ public class NetworkRanker { /** Get score of this scoreable */ FullScore getScore(); /** Get capabilities of this scoreable */ - NetworkCapabilities getCaps(); + NetworkCapabilities getCapsNoCopy(); } private static final boolean USE_POLICY_RANKING = false; @@ -158,11 +159,12 @@ public class NetworkRanker { if (accepted.size() == 1) return accepted.get(0); if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted); - // Yield to bad wifi policy : if any wifi has ever been validated, keep only networks - // that don't yield to such a wifi network. + // Yield to bad wifi policy : if any wifi has ever been validated (even if it's now + // unvalidated), and unless it's been explicitly avoided when bad in UI, then keep only + // networks that don't yield to such a wifi network. final boolean anyWiFiEverValidated = CollectionUtils.any(candidates, - nai -> nai.getScore().hasPolicy(POLICY_EVER_USER_SELECTED) - && nai.getCaps().hasTransport(TRANSPORT_WIFI)); + nai -> nai.getScore().hasPolicy(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD) + && nai.getCapsNoCopy().hasTransport(TRANSPORT_WIFI)); if (anyWiFiEverValidated) { partitionInto(candidates, nai -> !nai.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI), accepted, rejected); @@ -206,18 +208,18 @@ public class NetworkRanker { for (final Scoreable defaultSubNai : accepted) { // Remove all networks without the DEFAULT_SUBSCRIPTION policy and the same transports // as a network that has it. - final int[] transports = defaultSubNai.getCaps().getTransportTypes(); + final int[] transports = defaultSubNai.getCapsNoCopy().getTransportTypes(); candidates.removeIf(nai -> !nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY) - && Arrays.equals(transports, nai.getCaps().getTransportTypes())); + && Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes())); } if (1 == candidates.size()) return candidates.get(0); - // It's guaranteed candidates.size() > 0 because there is at least one with DEFAULT_SUB - // policy and only those without it were removed. + // It's guaranteed candidates.size() > 0 because there is at least one with the + // TRANSPORT_PRIMARY policy and only those without it were removed. // If some of the networks have a better transport than others, keep only the ones with // the best transports. for (final int transport : PREFERRED_TRANSPORTS_ORDER) { - partitionInto(candidates, nai -> nai.getCaps().hasTransport(transport), + partitionInto(candidates, nai -> nai.getCapsNoCopy().hasTransport(transport), accepted, rejected); if (accepted.size() == 1) return accepted.get(0); if (accepted.size() > 0 && rejected.size() > 0) { diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt index f0d7d86feb2f..45b575a4365d 100644 --- a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt +++ b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt @@ -56,7 +56,7 @@ class FullScoreTest { if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN) if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) }.build() - return mixInScore(nc, nac, false /* avoidBadWifi */) + return mixInScore(nc, nac, validated, false /* yieldToBadWifi */) } @Test |