diff options
author | 2021-03-31 11:42:19 +0000 | |
---|---|---|
committer | 2021-03-31 11:42:19 +0000 | |
commit | 59634a7fc7a8b0984ab040c87fb47318fa1589df (patch) | |
tree | 94ab53fd1a354f436125ac8b64c81f41f58a006f | |
parent | a154af88818bbe2540dba779ab9f72ce9ad25a0f (diff) | |
parent | 8f98eb9c08f71d4b1bd727a0686dadc261b4cb00 (diff) |
Merge changes Id7ee1bd3,I5ea44a94 into sc-dev
* changes:
[NS08] Expose public NetworkScore API
[NS07] Add the rest of the scoring policy
6 files changed, 227 insertions, 38 deletions
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt index 6c3b6201180c..2cae99fbb326 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -341,6 +341,8 @@ package android.net { method public int describeContents(); method public int getKeepConnectedReason(); method public int getLegacyInt(); + method public boolean isExiting(); + method public boolean isTransportPrimary(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR; field public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // 0x1 @@ -350,8 +352,10 @@ package android.net { public static final class NetworkScore.Builder { ctor public NetworkScore.Builder(); method @NonNull public android.net.NetworkScore build(); + method @NonNull public android.net.NetworkScore.Builder setExiting(boolean); method @NonNull public android.net.NetworkScore.Builder setKeepConnectedReason(int); method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int); + method @NonNull public android.net.NetworkScore.Builder setTransportPrimary(boolean); } public final class OemNetworkPreferences implements android.os.Parcelable { diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java index 9786b09e3508..1c235f470157 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkScore.java +++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java @@ -52,11 +52,27 @@ public final class NetworkScore implements Parcelable { public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // Agent-managed policies - // TODO : add them here, starting from 1 + // This network should lose to a wifi that has ever been validated + // NOTE : temporarily this policy is managed by ConnectivityService, because of legacy. The + // legacy design has this bit global to the system and tacked on WiFi which means it will affect + // networks from carriers who don't want it and non-carrier networks, which is bad for users. + // The S design has this on mobile networks only, so this can be fixed eventually ; as CS + // doesn't know what carriers need this bit, the initial S implementation will continue to + // affect other carriers but will at least leave non-mobile networks alone. Eventually Telephony + // should set this on networks from carriers that require it. /** @hide */ - public static final int MIN_AGENT_MANAGED_POLICY = 0; + public static final int POLICY_YIELD_TO_BAD_WIFI = 1; + // This network is primary for this transport. /** @hide */ - public static final int MAX_AGENT_MANAGED_POLICY = -1; + public static final int POLICY_TRANSPORT_PRIMARY = 2; + // This network is exiting : it will likely disconnect in a few seconds. + /** @hide */ + public static final int POLICY_EXITING = 3; + + /** @hide */ + public static final int MIN_AGENT_MANAGED_POLICY = POLICY_YIELD_TO_BAD_WIFI; + /** @hide */ + public static final int MAX_AGENT_MANAGED_POLICY = POLICY_EXITING; // Bitmask of all the policies applied to this score. private final long mPolicies; @@ -98,6 +114,60 @@ public final class NetworkScore implements Parcelable { return 0 != (mPolicies & (1L << policy)); } + /** + * To the exclusive usage of FullScore + * @hide + */ + public long getPolicies() { + return mPolicies; + } + + /** + * Whether this network should yield to a previously validated wifi gone bad. + * + * If this policy is set, other things being equal, the device will prefer a previously + * validated WiFi even if this network is validated and the WiFi is not. + * If this policy is not set, the device prefers the validated network. + * + * @hide + */ + // TODO : Unhide this for telephony and have telephony call it on the relevant carriers. + // In the mean time this is handled by Connectivity in a backward-compatible manner. + public boolean shouldYieldToBadWifi() { + return hasPolicy(POLICY_YIELD_TO_BAD_WIFI); + } + + /** + * Whether this network is primary for this transport. + * + * When multiple networks of the same transport are active, the device prefers the ones that + * are primary. This is meant in particular for DS-DA devices with a user setting to choose the + * default SIM card, or for WiFi STA+STA and make-before-break cases. + * + * @hide + */ + @SystemApi + public boolean isTransportPrimary() { + return hasPolicy(POLICY_TRANSPORT_PRIMARY); + } + + /** + * Whether this network is exiting. + * + * If this policy is set, the device will expect this network to disconnect within seconds. + * It will try to migrate to some other network if any is available, policy permitting, to + * avoid service disruption. + * This is useful in particular when a good cellular network is available and WiFi is getting + * weak and risks disconnecting soon. The WiFi network should be marked as exiting so that + * the device will prefer the reliable mobile network over this soon-to-be-lost WiFi. + * + * @hide + */ + @SystemApi + public boolean isExiting() { + return hasPolicy(POLICY_EXITING); + } + @Override public String toString() { return "Score(" + mLegacyInt + ")"; @@ -137,6 +207,7 @@ public final class NetworkScore implements Parcelable { private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE; private int mLegacyInt = INVALID_LEGACY_INT; private int mKeepConnectedReason = KEEP_CONNECTED_NONE; + private int mPolicies = 0; /** * Sets the legacy int for this score. @@ -152,6 +223,75 @@ public final class NetworkScore implements Parcelable { return this; } + + /** + * Set for a network that should never be preferred to a wifi that has ever been validated + * + * If this policy is set, other things being equal, the device will prefer a previously + * validated WiFi even if this network is validated and the WiFi is not. + * If this policy is not set, the device prefers the validated network. + * + * @return this builder + * @hide + */ + // TODO : Unhide this for telephony and have telephony call it on the relevant carriers. + // In the mean time this is handled by Connectivity in a backward-compatible manner. + @NonNull + public Builder setShouldYieldToBadWifi(final boolean val) { + if (val) { + mPolicies |= (1L << POLICY_YIELD_TO_BAD_WIFI); + } else { + mPolicies &= ~(1L << POLICY_YIELD_TO_BAD_WIFI); + } + return this; + } + + /** + * Set for a network that is primary for this transport. + * + * When multiple networks of the same transport are active, the device prefers the ones that + * are primary. This is meant in particular for DS-DA devices with a user setting to choose + * the default SIM card, or for WiFi STA+STA and make-before-break cases. + * + * @return this builder + * @hide + */ + @SystemApi + @NonNull + public Builder setTransportPrimary(final boolean val) { + if (val) { + mPolicies |= (1L << POLICY_TRANSPORT_PRIMARY); + } else { + mPolicies &= ~(1L << POLICY_TRANSPORT_PRIMARY); + } + return this; + } + + /** + * Set for a network that will likely disconnect in a few seconds. + * + * If this policy is set, the device will expect this network to disconnect within seconds. + * It will try to migrate to some other network if any is available, policy permitting, to + * avoid service disruption. + * This is useful in particular when a good cellular network is available and WiFi is + * getting weak and risks disconnecting soon. The WiFi network should be marked as exiting + * so that the device will prefer the reliable mobile network over this soon-to-be-lost + * WiFi. + * + * @return this builder + * @hide + */ + @SystemApi + @NonNull + public Builder setExiting(final boolean val) { + if (val) { + mPolicies |= (1L << POLICY_EXITING); + } else { + mPolicies &= ~(1L << POLICY_EXITING); + } + return this; + } + /** * Set the keep-connected reason. * @@ -169,7 +309,7 @@ public final class NetworkScore implements Parcelable { */ @NonNull public NetworkScore build() { - return new NetworkScore(mLegacyInt, POLICY_NONE, mKeepConnectedReason); + return new NetworkScore(mLegacyInt, mPolicies, mKeepConnectedReason); } } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f3e6428bc318..6708fc380e08 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1329,7 +1329,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker( - mContext, mHandler, () -> rematchForAvoidBadWifiUpdate()); + mContext, mHandler, () -> updateAvoidBadWifi()); mMultinetworkPolicyTracker.start(); mDnsManager = new DnsManager(mContext, mDnsResolver); @@ -4389,8 +4389,10 @@ public class ConnectivityService extends IConnectivityManager.Stub return avoidBadWifi(); } - // TODO : this function is now useless. - private void rematchForAvoidBadWifiUpdate() { + private void updateAvoidBadWifi() { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { + nai.updateScoreForNetworkAgentConfigUpdate(); + } rematchAllNetworksAndRequests(); } diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java index 375d005a0bcd..117253f9c75d 100644 --- a/services/core/java/com/android/server/connectivity/FullScore.java +++ b/services/core/java/com/android/server/connectivity/FullScore.java @@ -17,9 +17,13 @@ package com.android.server.connectivity; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkScore.KEEP_CONNECTED_NONE; +import static android.net.NetworkScore.POLICY_EXITING; +import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY; +import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI; import android.annotation.IntDef; import android.annotation.NonNull; @@ -52,7 +56,8 @@ public class FullScore { POLICY_IS_VALIDATED, POLICY_IS_VPN, POLICY_EVER_USER_SELECTED, - POLICY_ACCEPT_UNVALIDATED + POLICY_ACCEPT_UNVALIDATED, + POLICY_IS_UNMETERED }) public @interface Policy { } @@ -77,12 +82,22 @@ public class FullScore { /** @hide */ public static final int POLICY_ACCEPT_UNVALIDATED = 60; + // This network is unmetered. {@see NetworkCapabilities.NET_CAPABILITY_NOT_METERED}. + /** @hide */ + public static final int POLICY_IS_UNMETERED = 59; + // To help iterate when printing @VisibleForTesting - static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED; + static final int MIN_CS_MANAGED_POLICY = POLICY_IS_UNMETERED; @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 + // there are more than 32 bits handled on either side. + private static final int EXTERNAL_POLICIES_MASK = 0x0000FFFF; + @VisibleForTesting static @NonNull String policyNameOf(final int policy) { switch (policy) { @@ -90,6 +105,10 @@ public class FullScore { case POLICY_IS_VPN: return "IS_VPN"; case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED"; case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED"; + case POLICY_IS_UNMETERED: return "IS_UNMETERED"; + case POLICY_YIELD_TO_BAD_WIFI: return "YIELD_TO_BAD_WIFI"; + case POLICY_TRANSPORT_PRIMARY: return "TRANSPORT_PRIMARY"; + case POLICY_EXITING: return "EXITING"; } throw new IllegalArgumentException("Unknown policy : " + policy); } @@ -112,15 +131,23 @@ 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 - * @return an FullScore that is appropriate to use for ranking. + * @param yieldToBadWiFi whether this network yields to a previously validated wifi gone bad + * @return a FullScore that is appropriate to use for ranking. */ + // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the + // telephony factory, so that it depends on the carrier. For now this is handled by + // connectivity for backward compatibility. public static FullScore fromNetworkScore(@NonNull final NetworkScore score, - @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) { - return withPolicies(score.getLegacyInt(), score.getKeepConnectedReason(), + @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config, + 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), config.explicitlySelected, - config.acceptUnvalidated); + config.acceptUnvalidated, + yieldToBadWiFi); } /** @@ -142,12 +169,17 @@ public class FullScore { final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET); // VPN transports are known in advance. final boolean vpn = caps.hasTransport(TRANSPORT_VPN); + // 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; // 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. final boolean acceptUnvalidated = false; - return withPolicies(score.getLegacyInt(), KEEP_CONNECTED_NONE, - mayValidate, vpn, everUserSelected, acceptUnvalidated); + // Don't assume clinging to bad wifi + final boolean yieldToBadWiFi = false; + return withPolicies(score.getLegacyInt(), score.getPolicies(), KEEP_CONNECTED_NONE, + mayValidate, vpn, unmetered, everUserSelected, acceptUnvalidated, yieldToBadWiFi); } /** @@ -157,26 +189,39 @@ public class FullScore { * @param config the NetworkAgentConfig of the network * @return a score with the policies from the arguments reset */ + // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the + // 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) { - return withPolicies(mLegacyInt, mKeepConnectedReason, + @NonNull final NetworkAgentConfig config, final boolean avoidBadWiFi) { + return withPolicies(mLegacyInt, mPolicies, mKeepConnectedReason, caps.hasCapability(NET_CAPABILITY_VALIDATED), caps.hasTransport(TRANSPORT_VPN), + caps.hasCapability(NET_CAPABILITY_NOT_METERED), config.explicitlySelected, - config.acceptUnvalidated); + config.acceptUnvalidated, + avoidBadWiFi); } + // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the + // telephony factory, so that it depends on the carrier. For now this is handled by + // connectivity for backward compatibility. private static FullScore withPolicies(@NonNull final int legacyInt, + final long externalPolicies, @KeepConnectedReason final int keepConnectedReason, final boolean isValidated, final boolean isVpn, + final boolean isUnmetered, final boolean everUserSelected, - final boolean acceptUnvalidated) { - return new FullScore(legacyInt, - (isValidated ? 1L << POLICY_IS_VALIDATED : 0) + final boolean acceptUnvalidated, + final boolean yieldToBadWiFi) { + 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), + | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0) + | (yieldToBadWiFi ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0), keepConnectedReason); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index d16a2de57b09..3902573fa241 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -17,6 +17,7 @@ package com.android.server.connectivity; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.transportNamesOf; import android.annotation.NonNull; @@ -362,9 +363,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { linkProperties = lp; networkCapabilities = nc; networkAgentConfig = config; - setScore(score); // uses members networkCapabilities and networkAgentConfig - clatd = new Nat464Xlat(this, netd, dnsResolver, deps); mConnService = connService; + setScore(score); // uses members connService, networkCapabilities and networkAgentConfig + clatd = new Nat464Xlat(this, netd, dnsResolver, deps); mContext = context; mHandler = handler; this.factorySerialNumber = factorySerialNumber; @@ -706,7 +707,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { @NonNull final NetworkCapabilities nc) { final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; - mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig); + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi()); final NetworkMonitorManager nm = mNetworkMonitor; if (nm != null) { nm.notifyNetworkCapabilitiesChanged(nc); @@ -714,6 +715,11 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { return oldNc; } + private boolean yieldToBadWiFi() { + // Only cellular networks yield to bad wifi + return networkCapabilities.hasTransport(TRANSPORT_CELLULAR) && !mConnService.avoidBadWifi(); + } + public ConnectivityService connService() { return mConnService; } @@ -884,15 +890,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { return isVPN(); } - // Return true on devices configured to ignore score penalty for wifi networks - // that become unvalidated (b/31075769). - private boolean ignoreWifiUnvalidationPenalty() { - boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && - networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated; - return isWifi && !avoidBadWifi && everValidated; - } - public FullScore getScore() { return mScore; } @@ -913,7 +910,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { * Mix-in the ConnectivityService-managed bits in the score. */ public void setScore(final NetworkScore score) { - mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig); + mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig, + yieldToBadWiFi()); } /** @@ -922,7 +920,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { * Call this after updating the network agent config. */ public void updateScoreForNetworkAgentConfigUpdate() { - mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig); + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, yieldToBadWiFi()); } /** @@ -1085,7 +1083,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { return "NetworkAgentInfo{" + "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{" + networkInfo.toShortString() + "} " - + " Score{" + getCurrentScore() + "} " + + mScore + " " + (isNascent() ? " nascent" : (isLingering() ? " lingering" : "")) + (everValidated ? " everValidated" : "") + (lastValidated ? " lastValidated" : "") diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt index 2864bc7e794a..f0d7d86feb2f 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) + return mixInScore(nc, nac, false /* avoidBadWifi */) } @Test |