[NS07] Add the rest of the scoring policy

Bug: 167544279
Test: FrameworksNetTests
Merged-In: I3c2563d4ae4e3715d0c6270344ba8f7ef067872f
Merged-In: I5ea44a94ac6f16486274e9091f15a84734db2341
Change-Id: I5ea44a94ac6f16486274e9091f15a84734db2341
  (cherry-picked from ag/13988828)
This commit is contained in:
Chalard Jean
2021-03-19 13:49:56 +09:00
committed by Junyu Lai
parent 947acd4275
commit f3ff362210
5 changed files with 223 additions and 38 deletions

View File

@@ -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
*/
// TODO : @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
*/
// TODO : @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
*/
// TODO : @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
*/
// TODO : @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);
}
}
}

View File

@@ -1383,7 +1383,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);
@@ -4477,8 +4477,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();
}

View File

@@ -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);
}

View File

@@ -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" : "")

View File

@@ -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