Merge changes from topics "enable-policy-ranking", "sendNetworkScore"
* changes: Adjust a test for policy scoring Enable policy ranking Add CTS to verify NetworkAgent#setLingerDuration Allow network providers to set the linger duration. Fix nascent timer never get removed [NS13] Remove the last usage of the legacy int Add documentation Use filter from CollectionUtils. Fix a bug where updates of offers won't find existing offers [NS12] Address comments on NS09 [NS11] Fix yieldToBadWifi over the policy scoring Add doc for NetworkScore#getLegacyInt Expose sendNetworkScore that takes a NetworkScore
This commit is contained in:
@@ -232,12 +232,14 @@ package android.net {
|
||||
method @NonNull public android.net.Network register();
|
||||
method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
|
||||
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
|
||||
method public final void sendNetworkScore(@NonNull android.net.NetworkScore);
|
||||
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
|
||||
method public final void sendQosCallbackError(int, int);
|
||||
method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
|
||||
method public final void sendQosSessionLost(int, int, int);
|
||||
method public final void sendSocketKeepaliveEvent(int, int);
|
||||
method @Deprecated public void setLegacySubtype(int, @NonNull String);
|
||||
method public void setLingerDuration(@NonNull java.time.Duration);
|
||||
method public void setTeardownDelayMillis(@IntRange(from=0, to=0x1388) int);
|
||||
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
|
||||
method public void unregister();
|
||||
|
||||
@@ -42,4 +42,5 @@ oneway interface INetworkAgentRegistry {
|
||||
void sendQosSessionLost(int qosCallbackId, in QosSession session);
|
||||
void sendQosCallbackError(int qosCallbackId, int exceptionType);
|
||||
void sendTeardownDelayMs(int teardownDelayMs);
|
||||
void sendLingerDuration(int durationMs);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.TestApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
@@ -106,6 +107,9 @@ public abstract class NetworkAgent {
|
||||
private final String LOG_TAG;
|
||||
private static final boolean DBG = true;
|
||||
private static final boolean VDBG = false;
|
||||
/** @hide */
|
||||
@TestApi
|
||||
public static final int MIN_LINGER_TIMER_MS = 2000;
|
||||
private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>();
|
||||
private volatile long mLastBwRefreshTime = 0;
|
||||
private static final long BW_REFRESH_MIN_WIN_MS = 500;
|
||||
@@ -391,6 +395,15 @@ public abstract class NetworkAgent {
|
||||
*/
|
||||
public static final int CMD_NETWORK_DESTROYED = BASE + 23;
|
||||
|
||||
/**
|
||||
* Sent by the NetworkAgent to ConnectivityService to set the linger duration for this network
|
||||
* agent.
|
||||
* arg1 = the linger duration, represents by {@link Duration}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int EVENT_LINGER_DURATION_CHANGED = BASE + 24;
|
||||
|
||||
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
|
||||
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
|
||||
config.legacyTypeName, config.legacySubTypeName);
|
||||
@@ -956,7 +969,6 @@ public abstract class NetworkAgent {
|
||||
* Must be called by the agent to update the score of this network.
|
||||
*
|
||||
* @param score the new score.
|
||||
* @hide TODO : unhide when impl is complete
|
||||
*/
|
||||
public final void sendNetworkScore(@NonNull NetworkScore score) {
|
||||
Objects.requireNonNull(score);
|
||||
@@ -1288,6 +1300,22 @@ public abstract class NetworkAgent {
|
||||
queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the linger duration for this network agent.
|
||||
* @param duration the delay between the moment the network becomes unneeded and the
|
||||
* moment the network is disconnected or moved into the background.
|
||||
* Note that If this duration has greater than millisecond precision, then
|
||||
* the internal implementation will drop any excess precision.
|
||||
*/
|
||||
public void setLingerDuration(@NonNull final Duration duration) {
|
||||
Objects.requireNonNull(duration);
|
||||
final long durationMs = duration.toMillis();
|
||||
if (durationMs < MIN_LINGER_TIMER_MS || durationMs > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Duration must be within ["
|
||||
+ MIN_LINGER_TIMER_MS + "," + Integer.MAX_VALUE + "]ms");
|
||||
}
|
||||
queueOrSendMessage(ra -> ra.sendLingerDuration((int) durationMs));
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected void log(final String s) {
|
||||
|
||||
@@ -167,7 +167,15 @@ public class NetworkProvider {
|
||||
ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
/**
|
||||
* A callback for parties registering a NetworkOffer.
|
||||
*
|
||||
* This is used with {@link ConnectivityManager#offerNetwork}. When offering a network,
|
||||
* the system will use this callback to inform the caller that a network corresponding to
|
||||
* this offer is needed or unneeded.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public interface NetworkOfferCallback {
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,14 @@ public final class NetworkScore implements Parcelable {
|
||||
})
|
||||
public @interface KeepConnectedReason { }
|
||||
|
||||
/**
|
||||
* Do not keep this network connected if there is no outstanding request for it.
|
||||
*/
|
||||
public static final int KEEP_CONNECTED_NONE = 0;
|
||||
/**
|
||||
* Keep this network connected even if there is no outstanding request for it, because it
|
||||
* is being considered for handover.
|
||||
*/
|
||||
public static final int KEEP_CONNECTED_FOR_HANDOVER = 1;
|
||||
|
||||
// Agent-managed policies
|
||||
@@ -93,6 +100,10 @@ public final class NetworkScore implements Parcelable {
|
||||
mKeepConnectedReason = in.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy int score embedded in this NetworkScore.
|
||||
* @see Builder#setLegacyInt(int)
|
||||
*/
|
||||
public int getLegacyInt() {
|
||||
return mLegacyInt;
|
||||
}
|
||||
@@ -212,7 +223,9 @@ public final class NetworkScore implements Parcelable {
|
||||
/**
|
||||
* Sets the legacy int for this score.
|
||||
*
|
||||
* Do not rely on this. It will be gone by the time S is released.
|
||||
* This will be used for measurements and logs, but will no longer be used for ranking
|
||||
* networks against each other. Callers that existed before Android S should send what
|
||||
* they used to send as the int score.
|
||||
*
|
||||
* @param score the legacy int
|
||||
* @return this
|
||||
|
||||
@@ -1400,8 +1400,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
new NetworkInfo(TYPE_NONE, 0, "", ""),
|
||||
new LinkProperties(), new NetworkCapabilities(),
|
||||
new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
|
||||
new NetworkAgentConfig(), this, null, null, 0, INVALID_UID, mQosCallbackTracker,
|
||||
mDeps);
|
||||
new NetworkAgentConfig(), this, null, null, 0, INVALID_UID,
|
||||
mLingerDelayMs, mQosCallbackTracker, mDeps);
|
||||
}
|
||||
|
||||
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
|
||||
@@ -3234,6 +3234,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
} else {
|
||||
logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetworkAgent.EVENT_LINGER_DURATION_CHANGED: {
|
||||
nai.setLingerDuration((int) arg.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4038,17 +4043,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
// multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request
|
||||
// is important so as to not evaluate lower priority requests further in
|
||||
// nri.mRequests.
|
||||
final boolean isNetworkNeeded = candidate.isSatisfyingRequest(req.requestId)
|
||||
// Note that this catches two important cases:
|
||||
// 1. Unvalidated cellular will not be reaped when unvalidated WiFi
|
||||
// is currently satisfying the request. This is desirable when
|
||||
// cellular ends up validating but WiFi does not.
|
||||
// 2. Unvalidated WiFi will not be reaped when validated cellular
|
||||
// is currently satisfying the request. This is desirable when
|
||||
// WiFi ends up validating and out scoring cellular.
|
||||
|| nri.getSatisfier().getCurrentScore()
|
||||
< candidate.getCurrentScoreAsValidated();
|
||||
return isNetworkNeeded;
|
||||
final NetworkAgentInfo champion = req.equals(nri.getActiveRequest())
|
||||
? nri.getSatisfier() : null;
|
||||
// Note that this catches two important cases:
|
||||
// 1. Unvalidated cellular will not be reaped when unvalidated WiFi
|
||||
// is currently satisfying the request. This is desirable when
|
||||
// cellular ends up validating but WiFi does not.
|
||||
// 2. Unvalidated WiFi will not be reaped when validated cellular
|
||||
// is currently satisfying the request. This is desirable when
|
||||
// WiFi ends up validating and out scoring cellular.
|
||||
return mNetworkRanker.mightBeat(req, champion, candidate.getValidatedScoreable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4305,7 +4309,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();
|
||||
}
|
||||
|
||||
@@ -4373,6 +4377,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
if (!nai.avoidUnvalidated) {
|
||||
nai.avoidUnvalidated = true;
|
||||
nai.updateScoreForNetworkAgentUpdate();
|
||||
rematchAllNetworksAndRequests();
|
||||
}
|
||||
}
|
||||
@@ -4480,7 +4485,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
|
||||
private void updateAvoidBadWifi() {
|
||||
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
||||
nai.updateScoreForNetworkAgentConfigUpdate();
|
||||
nai.updateScoreForNetworkAgentUpdate();
|
||||
}
|
||||
rematchAllNetworksAndRequests();
|
||||
}
|
||||
@@ -6597,7 +6602,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
|
||||
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
|
||||
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
|
||||
this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker, mDeps);
|
||||
this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
|
||||
mQosCallbackTracker, mDeps);
|
||||
|
||||
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
|
||||
processCapabilitiesFromAgent(nai, nc);
|
||||
@@ -6697,7 +6703,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
@NonNull final INetworkOfferCallback callback) {
|
||||
ensureRunningOnConnectivityServiceThread();
|
||||
for (final NetworkOfferInfo noi : mNetworkOffers) {
|
||||
if (noi.offer.callback.equals(callback)) return noi;
|
||||
if (noi.offer.callback.asBinder().equals(callback.asBinder())) return noi;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -7255,6 +7261,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
|
||||
@@ -7840,7 +7847,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
log(" accepting network in place of " + previousSatisfier.toShortString());
|
||||
}
|
||||
previousSatisfier.removeRequest(previousRequest.requestId);
|
||||
previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs);
|
||||
previousSatisfier.lingerRequest(previousRequest.requestId, now);
|
||||
} else {
|
||||
if (VDBG || DDBG) log(" accepting network in place of null");
|
||||
}
|
||||
@@ -7850,6 +7857,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
// all networks except in the case of an underlying network for a VCN.
|
||||
if (newSatisfier.isNascent()) {
|
||||
newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE);
|
||||
newSatisfier.unsetInactive();
|
||||
}
|
||||
|
||||
// if newSatisfier is not null, then newRequest may not be null.
|
||||
@@ -7885,7 +7893,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
@NonNull final Collection<NetworkRequestInfo> networkRequests) {
|
||||
final NetworkReassignment changes = new NetworkReassignment();
|
||||
|
||||
// Gather the list of all relevant agents and sort them by score.
|
||||
// Gather the list of all relevant agents.
|
||||
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
|
||||
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
|
||||
if (!nai.everConnected) {
|
||||
@@ -8354,6 +8362,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
// But it will be removed as soon as the network satisfies a request for the first time.
|
||||
networkAgent.lingerRequest(NetworkRequest.REQUEST_ID_NONE,
|
||||
SystemClock.elapsedRealtime(), mNascentDelayMs);
|
||||
networkAgent.setInactive();
|
||||
|
||||
// Consider network even though it is not yet validated.
|
||||
rematchAllNetworksAndRequests();
|
||||
|
||||
@@ -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)
|
||||
@@ -239,6 +258,14 @@ public class FullScore {
|
||||
keepConnectedReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this score but validated.
|
||||
*/
|
||||
public FullScore asValidated() {
|
||||
return new FullScore(mLegacyInt, mPolicies | (1L << POLICY_IS_VALIDATED),
|
||||
mKeepConnectedReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* For backward compatibility, get the legacy int.
|
||||
* This will be removed before S is published.
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.android.internal.util.WakeupMessage;
|
||||
import com.android.server.ConnectivityService;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -281,6 +282,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
*/
|
||||
public static final int ARG_AGENT_SUCCESS = 1;
|
||||
|
||||
// How long this network should linger for.
|
||||
private int mLingerDurationMs;
|
||||
|
||||
// All inactivity timers for this network, sorted by expiry time. A timer is added whenever
|
||||
// a request is moved to a network with a better score, regardless of whether the network is or
|
||||
// was lingering or not. An inactivity timer is also added when a network connects
|
||||
@@ -349,7 +353,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
@NonNull NetworkScore score, Context context,
|
||||
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
|
||||
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
|
||||
QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) {
|
||||
int lingerDurationMs, QosCallbackTracker qosCallbackTracker,
|
||||
ConnectivityService.Dependencies deps) {
|
||||
Objects.requireNonNull(net);
|
||||
Objects.requireNonNull(info);
|
||||
Objects.requireNonNull(lp);
|
||||
@@ -370,6 +375,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
mHandler = handler;
|
||||
this.factorySerialNumber = factorySerialNumber;
|
||||
this.creatorUid = creatorUid;
|
||||
mLingerDurationMs = lingerDurationMs;
|
||||
mQosCallbackTracker = qosCallbackTracker;
|
||||
}
|
||||
|
||||
@@ -685,6 +691,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
|
||||
teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLingerDuration(final int durationMs) {
|
||||
mHandler.obtainMessage(NetworkAgent.EVENT_LINGER_DURATION_CHANGED,
|
||||
new Pair<>(NetworkAgentInfo.this, durationMs)).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -707,7 +719,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 +906,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 +932,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 +940,33 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Scoreable identical to this NAI, but validated.
|
||||
*
|
||||
* This is useful to probe what scoring would be if this network validated, to know
|
||||
* whether to provisionally keep a network that may or may not validate.
|
||||
*
|
||||
* @return a Scoreable identical to this NAI, but validated.
|
||||
*/
|
||||
public NetworkRanker.Scoreable getValidatedScoreable() {
|
||||
return new NetworkRanker.Scoreable() {
|
||||
@Override public FullScore getScore() {
|
||||
return mScore.asValidated();
|
||||
}
|
||||
|
||||
@Override public NetworkCapabilities getCapsNoCopy() {
|
||||
return networkCapabilities;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -948,13 +986,14 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
|
||||
/**
|
||||
* Sets the specified requestId to linger on this network for the specified time. Called by
|
||||
* ConnectivityService when the request is moved to another network with a higher score, or
|
||||
* ConnectivityService when any request is moved to another network with a higher score, or
|
||||
* when a network is newly created.
|
||||
*
|
||||
* @param requestId The requestId of the request that no longer need to be served by this
|
||||
* network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
|
||||
* {@code LingerTimer} for a newly created network.
|
||||
* {@code InactivityTimer} for a newly created network.
|
||||
*/
|
||||
// TODO: Consider creating a dedicated function for nascent network, e.g. start/stopNascent.
|
||||
public void lingerRequest(int requestId, long now, long duration) {
|
||||
if (mInactivityTimerForRequest.get(requestId) != null) {
|
||||
// Cannot happen. Once a request is lingering on a particular network, we cannot
|
||||
@@ -969,6 +1008,19 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
mInactivityTimerForRequest.put(requestId, timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified requestId to linger on this network for the timeout set when
|
||||
* initializing or modified by {@link #setLingerDuration(int)}. Called by
|
||||
* ConnectivityService when any request is moved to another network with a higher score.
|
||||
*
|
||||
* @param requestId The requestId of the request that no longer need to be served by this
|
||||
* network.
|
||||
* @param now current system timestamp obtained by {@code SystemClock.elapsedRealtime}.
|
||||
*/
|
||||
public void lingerRequest(int requestId, long now) {
|
||||
lingerRequest(requestId, now, mLingerDurationMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel lingering. Called by ConnectivityService when a request is added to this network.
|
||||
* Returns true if the given requestId was lingering on this network, false otherwise.
|
||||
@@ -1006,6 +1058,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
}
|
||||
|
||||
if (newExpiry > 0) {
|
||||
// If the newExpiry timestamp is in the past, the wakeup message will fire immediately.
|
||||
mInactivityMessage = new WakeupMessage(
|
||||
mContext, mHandler,
|
||||
"NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
|
||||
@@ -1035,8 +1088,33 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRa
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the network is just connected and about to be torn down because of not
|
||||
* satisfying any request.
|
||||
* Set the linger duration for this NAI.
|
||||
* @param durationMs The new linger duration, in milliseconds.
|
||||
*/
|
||||
public void setLingerDuration(final int durationMs) {
|
||||
final long diff = durationMs - mLingerDurationMs;
|
||||
final ArrayList<InactivityTimer> newTimers = new ArrayList<>();
|
||||
for (final InactivityTimer timer : mInactivityTimers) {
|
||||
if (timer.requestId == NetworkRequest.REQUEST_ID_NONE) {
|
||||
// Don't touch nascent timer, re-add as is.
|
||||
newTimers.add(timer);
|
||||
} else {
|
||||
newTimers.add(new InactivityTimer(timer.requestId, timer.expiryMs + diff));
|
||||
}
|
||||
}
|
||||
mInactivityTimers.clear();
|
||||
mInactivityTimers.addAll(newTimers);
|
||||
updateInactivityTimer();
|
||||
mLingerDurationMs = durationMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the network satisfies no request, but is still being kept up
|
||||
* because it has just connected less than
|
||||
* {@code ConnectivityService#DEFAULT_NASCENT_DELAY_MS}ms ago and is thus still considered
|
||||
* nascent. Note that nascent mechanism uses inactivity timer which isn't
|
||||
* associated with a request. Thus, use {@link NetworkRequest#REQUEST_ID_NONE} to identify it.
|
||||
*
|
||||
*/
|
||||
public boolean isNascent() {
|
||||
return mInactive && mInactivityTimers.size() == 1
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ public class NetworkOffer implements NetworkRanker.Scoreable {
|
||||
* @param previousOffer the previous offer
|
||||
*/
|
||||
public void migrateFrom(@NonNull final NetworkOffer previousOffer) {
|
||||
if (!callback.equals(previousOffer.callback)) {
|
||||
if (!callback.asBinder().equals(previousOffer.callback.asBinder())) {
|
||||
throw new IllegalArgumentException("Can only migrate from a previous version of"
|
||||
+ " the same offer");
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ 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 static com.android.net.module.util.CollectionUtils.filter;
|
||||
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,25 +60,13 @@ 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;
|
||||
private static final boolean USE_POLICY_RANKING = true;
|
||||
|
||||
public NetworkRanker() { }
|
||||
|
||||
// TODO : move to module utils CollectionUtils.
|
||||
@NonNull private static <T> ArrayList<T> filter(@NonNull final Collection<T> source,
|
||||
@NonNull final Predicate<T> test) {
|
||||
final ArrayList<T> matches = new ArrayList<>();
|
||||
for (final T e : source) {
|
||||
if (test.test(e)) {
|
||||
matches.add(e);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the best network satisfying this request among the list of passed networks.
|
||||
*/
|
||||
@@ -158,11 +148,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 +197,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) {
|
||||
@@ -243,16 +234,17 @@ public class NetworkRanker {
|
||||
NetworkAgentInfo bestNetwork = null;
|
||||
int bestScore = Integer.MIN_VALUE;
|
||||
for (final NetworkAgentInfo nai : nais) {
|
||||
if (nai.getCurrentScore() > bestScore) {
|
||||
final int naiScore = nai.getCurrentScore();
|
||||
if (naiScore > bestScore) {
|
||||
bestNetwork = nai;
|
||||
bestScore = nai.getCurrentScore();
|
||||
bestScore = naiScore;
|
||||
}
|
||||
}
|
||||
return bestNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an offer has a chance to beat a champion network for a request.
|
||||
* Returns whether a {@link Scoreable} has a chance to beat a champion network for a request.
|
||||
*
|
||||
* Offers are sent by network providers when they think they might be able to make a network
|
||||
* with the characteristics contained in the offer. If the offer has no chance to beat
|
||||
@@ -266,15 +258,15 @@ public class NetworkRanker {
|
||||
*
|
||||
* @param request The request to evaluate against.
|
||||
* @param champion The currently best network for this request.
|
||||
* @param offer The offer.
|
||||
* @param contestant The offer.
|
||||
* @return Whether the offer stands a chance to beat the champion.
|
||||
*/
|
||||
public boolean mightBeat(@NonNull final NetworkRequest request,
|
||||
@Nullable final NetworkAgentInfo champion,
|
||||
@NonNull final NetworkOffer offer) {
|
||||
@NonNull final Scoreable contestant) {
|
||||
// If this network can't even satisfy the request then it can't beat anything, not
|
||||
// even an absence of network. It can't satisfy it anyway.
|
||||
if (!request.canBeSatisfiedBy(offer.caps)) return false;
|
||||
if (!request.canBeSatisfiedBy(contestant.getCapsNoCopy())) return false;
|
||||
// If there is no satisfying network, then this network can beat, because some network
|
||||
// is always better than no network.
|
||||
if (null == champion) return true;
|
||||
@@ -283,25 +275,24 @@ public class NetworkRanker {
|
||||
// Otherwise rank them.
|
||||
final ArrayList<Scoreable> candidates = new ArrayList<>();
|
||||
candidates.add(champion);
|
||||
candidates.add(offer);
|
||||
return offer == getBestNetworkByPolicy(candidates, champion);
|
||||
candidates.add(contestant);
|
||||
return contestant == getBestNetworkByPolicy(candidates, champion);
|
||||
} else {
|
||||
return mightBeatByLegacyInt(request, champion.getScore(), offer);
|
||||
return mightBeatByLegacyInt(champion.getScore(), contestant);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an offer might beat a champion according to the legacy int.
|
||||
* Returns whether a contestant might beat a champion according to the legacy int.
|
||||
*/
|
||||
public boolean mightBeatByLegacyInt(@NonNull final NetworkRequest request,
|
||||
@Nullable final FullScore championScore,
|
||||
@NonNull final NetworkOffer offer) {
|
||||
private boolean mightBeatByLegacyInt(@Nullable final FullScore championScore,
|
||||
@NonNull final Scoreable contestant) {
|
||||
final int offerIntScore;
|
||||
if (offer.caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
|
||||
if (contestant.getCapsNoCopy().hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
|
||||
// If the offer might have Internet access, then it might validate.
|
||||
offerIntScore = offer.score.getLegacyIntAsValidated();
|
||||
offerIntScore = contestant.getScore().getLegacyIntAsValidated();
|
||||
} else {
|
||||
offerIntScore = offer.score.getLegacyInt();
|
||||
offerIntScore = contestant.getScore().getLegacyInt();
|
||||
}
|
||||
return championScore.getLegacyInt() < offerIntScore;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import android.os.Build
|
||||
import android.os.HandlerThread
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.os.SystemClock
|
||||
import android.util.DebugUtils.valueToString
|
||||
import androidx.test.InstrumentationRegistry
|
||||
import com.android.modules.utils.build.SdkLevel
|
||||
@@ -76,6 +77,7 @@ import com.android.testutils.CompatUtil
|
||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||
import com.android.testutils.DevSdkIgnoreRunner
|
||||
import com.android.testutils.RecorderCallback.CallbackEntry.Available
|
||||
import com.android.testutils.RecorderCallback.CallbackEntry.Losing
|
||||
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
|
||||
import com.android.testutils.TestableNetworkCallback
|
||||
import org.junit.After
|
||||
@@ -114,6 +116,7 @@ private const val NO_CALLBACK_TIMEOUT = 200L
|
||||
// requests filed by the test and should never match normal internet requests. 70 is the default
|
||||
// score of Ethernet networks, it's as good a value as any other.
|
||||
private const val TEST_NETWORK_SCORE = 70
|
||||
private const val WORSE_NETWORK_SCORE = 65
|
||||
private const val BETTER_NETWORK_SCORE = 75
|
||||
private const val FAKE_NET_ID = 1098
|
||||
private val instrumentation: Instrumentation
|
||||
@@ -543,16 +546,23 @@ class NetworkAgentTest {
|
||||
// Connect the first Network
|
||||
createConnectedNetworkAgent(name = name1).let { (agent1, _) ->
|
||||
callback.expectAvailableThenValidatedCallbacks(agent1.network)
|
||||
// Upgrade agent1 to a better score so that there is no ambiguity when
|
||||
// agent2 connects that agent1 is still better
|
||||
agent1.sendNetworkScore(BETTER_NETWORK_SCORE - 1)
|
||||
// If using the int ranking, agent1 must be upgraded to a better score so that there is
|
||||
// no ambiguity when agent2 connects that agent1 is still better. If using policy
|
||||
// ranking, this is not necessary.
|
||||
agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(BETTER_NETWORK_SCORE)
|
||||
.build())
|
||||
// Connect the second agent
|
||||
createConnectedNetworkAgent(name = name2).let { (agent2, _) ->
|
||||
agent2.markConnected()
|
||||
// The callback should not see anything yet
|
||||
// The callback should not see anything yet. With int ranking, agent1 was upgraded
|
||||
// to a stronger score beforehand. With policy ranking, agent1 is preferred by
|
||||
// virtue of already satisfying the request.
|
||||
callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
|
||||
// Now update the score and expect the callback now prefers agent2
|
||||
agent2.sendNetworkScore(BETTER_NETWORK_SCORE)
|
||||
// Now downgrade the score and expect the callback now prefers agent2
|
||||
agent1.sendNetworkScore(NetworkScore.Builder()
|
||||
.setLegacyInt(WORSE_NETWORK_SCORE)
|
||||
.setExiting(true)
|
||||
.build())
|
||||
callback.expectCallback<Available>(agent2.network)
|
||||
}
|
||||
}
|
||||
@@ -768,4 +778,71 @@ class NetworkAgentTest {
|
||||
|
||||
// tearDown() will unregister the requests and agents
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||
fun testSetLingerDuration() {
|
||||
// This test will create two networks and check that the one with the stronger
|
||||
// score wins out for a request that matches them both. And the weaker agent will
|
||||
// be disconnected after customized linger duration.
|
||||
|
||||
// Connect the first Network
|
||||
val name1 = UUID.randomUUID().toString()
|
||||
val name2 = UUID.randomUUID().toString()
|
||||
val (agent1, callback) = createConnectedNetworkAgent(name = name1)
|
||||
callback.expectAvailableThenValidatedCallbacks(agent1.network!!)
|
||||
// Downgrade agent1 to a worse score so that there is no ambiguity when
|
||||
// agent2 connects.
|
||||
agent1.sendNetworkScore(NetworkScore.Builder().setLegacyInt(WORSE_NETWORK_SCORE)
|
||||
.setExiting(true).build())
|
||||
|
||||
// Verify invalid linger duration cannot be set.
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
agent1.setLingerDuration(Duration.ofMillis(-1))
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> { agent1.setLingerDuration(Duration.ZERO) }
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
agent1.setLingerDuration(Duration.ofMillis(Integer.MIN_VALUE.toLong()))
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
agent1.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong() + 1))
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
agent1.setLingerDuration(Duration.ofMillis(
|
||||
NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - 1))
|
||||
}
|
||||
// Verify valid linger timer can be set, but it should not take effect since the network
|
||||
// is still needed.
|
||||
agent1.setLingerDuration(Duration.ofMillis(Integer.MAX_VALUE.toLong()))
|
||||
callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
|
||||
// Set to the value we want to verify the functionality.
|
||||
agent1.setLingerDuration(Duration.ofMillis(NetworkAgent.MIN_LINGER_TIMER_MS.toLong()))
|
||||
// Make a listener which can observe agent1 lost later.
|
||||
val callbackWeaker = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
|
||||
registerNetworkCallback(NetworkRequest.Builder()
|
||||
.clearCapabilities()
|
||||
.addTransportType(TRANSPORT_TEST)
|
||||
.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(name1))
|
||||
.build(), callbackWeaker)
|
||||
callbackWeaker.expectAvailableCallbacks(agent1.network!!)
|
||||
|
||||
// Connect the second agent with a score better than agent1. Verify the callback for
|
||||
// agent1 sees the linger expiry while the callback for both sees the winner.
|
||||
// Record linger start timestamp prior to send score to prevent possible race, the actual
|
||||
// timestamp should be slightly late than this since the service handles update
|
||||
// network score asynchronously.
|
||||
val lingerStart = SystemClock.elapsedRealtime()
|
||||
val agent2 = createNetworkAgent(name = name2)
|
||||
agent2.register()
|
||||
agent2.markConnected()
|
||||
callback.expectAvailableCallbacks(agent2.network!!)
|
||||
callbackWeaker.expectCallback<Losing>(agent1.network!!)
|
||||
val expectedRemainingLingerDuration = lingerStart +
|
||||
NetworkAgent.MIN_LINGER_TIMER_MS.toLong() - SystemClock.elapsedRealtime()
|
||||
// If the available callback is too late. The remaining duration will be reduced.
|
||||
assertTrue(expectedRemainingLingerDuration > 0,
|
||||
"expected remaining linger duration is $expectedRemainingLingerDuration")
|
||||
callbackWeaker.assertNoCallback(expectedRemainingLingerDuration)
|
||||
callbackWeaker.expectCallback<Lost>(agent1.network!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2683,25 +2683,6 @@ public class ConnectivityServiceTest {
|
||||
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
// Bring up wifi with a score of 70.
|
||||
// Cell is lingered because it would not satisfy any request, even if it validated.
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
||||
mWiFiNetworkAgent.adjustScore(50);
|
||||
mWiFiNetworkAgent.connect(false); // Score: 70
|
||||
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||
callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
|
||||
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
// Tear down wifi.
|
||||
mWiFiNetworkAgent.disconnect();
|
||||
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
|
||||
defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
|
||||
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
|
||||
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
|
||||
// it's arguably correct to linger it, since it was the default network before it validated.
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
||||
@@ -3017,11 +2998,11 @@ public class ConnectivityServiceTest {
|
||||
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
|
||||
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
// BUG: the network will no longer linger, even though it's validated and outscored.
|
||||
// TODO: fix this.
|
||||
mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
|
||||
mEthernetNetworkAgent.connect(true);
|
||||
callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
|
||||
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
|
||||
callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
|
||||
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
|
||||
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
callback.assertNoCallback();
|
||||
|
||||
@@ -4580,9 +4561,8 @@ public class ConnectivityServiceTest {
|
||||
expectNoRequestChanged(testFactory);
|
||||
testFactory.assertRequestCountEquals(0);
|
||||
assertFalse(testFactory.getMyStartRequested());
|
||||
// ... and cell data to be torn down after nascent network timeout.
|
||||
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
|
||||
mService.mNascentDelayMs + TEST_CALLBACK_TIMEOUT_MS);
|
||||
// ... and cell data to be torn down immediately since it is no longer nascent.
|
||||
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
|
||||
waitForIdle();
|
||||
assertLength(1, mCm.getAllNetworks());
|
||||
} finally {
|
||||
@@ -9846,7 +9826,8 @@ public class ConnectivityServiceTest {
|
||||
return new NetworkAgentInfo(null, new Network(NET_ID), networkInfo, new LinkProperties(),
|
||||
nc, new NetworkScore.Builder().setLegacyInt(0).build(),
|
||||
mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
|
||||
INVALID_UID, mQosCallbackTracker, new ConnectivityService.Dependencies());
|
||||
INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
|
||||
new ConnectivityService.Dependencies());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -11887,6 +11868,11 @@ public class ConnectivityServiceTest {
|
||||
internetFactory.expectRequestRemove();
|
||||
internetFactory.assertRequestCountEquals(0);
|
||||
|
||||
// Create a request that holds the upcoming wifi network.
|
||||
final TestNetworkCallback wifiCallback = new TestNetworkCallback();
|
||||
mCm.requestNetwork(new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(),
|
||||
wifiCallback);
|
||||
|
||||
// Now WiFi connects and it's unmetered, but it's weaker than cell.
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
|
||||
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
|
||||
@@ -11895,7 +11881,7 @@ public class ConnectivityServiceTest {
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
|
||||
// The OEM_PAID preference prefers an unmetered network to an OEM_PAID network, so
|
||||
// the oemPaidFactory can't beat this no matter how high its score.
|
||||
// the oemPaidFactory can't beat wifi no matter how high its score.
|
||||
oemPaidFactory.expectRequestRemove();
|
||||
expectNoRequestChanged(internetFactory);
|
||||
|
||||
@@ -11906,6 +11892,7 @@ public class ConnectivityServiceTest {
|
||||
// unmetered network, so the oemPaidNetworkFactory still can't beat this.
|
||||
expectNoRequestChanged(oemPaidFactory);
|
||||
internetFactory.expectRequestAdd();
|
||||
mCm.unregisterNetworkCallback(wifiCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -71,6 +71,8 @@ public class LingerMonitorTest {
|
||||
static final int LOW_DAILY_LIMIT = 2;
|
||||
static final int HIGH_DAILY_LIMIT = 1000;
|
||||
|
||||
private static final int TEST_LINGER_DELAY_MS = 400;
|
||||
|
||||
LingerMonitor mMonitor;
|
||||
|
||||
@Mock ConnectivityService mConnService;
|
||||
@@ -366,7 +368,7 @@ public class LingerMonitorTest {
|
||||
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
|
||||
new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
|
||||
mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
|
||||
mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
|
||||
mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS,
|
||||
mQosCallbackTracker, new ConnectivityService.Dependencies());
|
||||
nai.everValidated = true;
|
||||
return nai;
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.android.server.connectivity
|
||||
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkRequest
|
||||
import android.net.NetworkScore.KEEP_CONNECTED_NONE
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import org.junit.Test
|
||||
@@ -32,10 +34,14 @@ import kotlin.test.assertNull
|
||||
class NetworkRankerTest {
|
||||
private val ranker = NetworkRanker()
|
||||
|
||||
private fun makeNai(satisfy: Boolean, score: Int) = mock(NetworkAgentInfo::class.java).also {
|
||||
doReturn(satisfy).`when`(it).satisfies(any())
|
||||
doReturn(score).`when`(it).currentScore
|
||||
}
|
||||
private fun makeNai(satisfy: Boolean, legacyScore: Int) =
|
||||
mock(NetworkAgentInfo::class.java).also {
|
||||
doReturn(satisfy).`when`(it).satisfies(any())
|
||||
val fs = FullScore(legacyScore, 0 /* policies */, KEEP_CONNECTED_NONE)
|
||||
doReturn(fs).`when`(it).getScore()
|
||||
val nc = NetworkCapabilities.Builder().build()
|
||||
doReturn(nc).`when`(it).getCapsNoCopy()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetBestNetwork() {
|
||||
|
||||
Reference in New Issue
Block a user