Merge changes from topic "NS-A44_lingerstate" am: 34587c19ce
Change-Id: Ibec8f280ad0b256d3d9b065a541063fc63d5a356
This commit is contained in:
@@ -155,7 +155,6 @@ import android.security.Credentials;
|
|||||||
import android.security.KeyStore;
|
import android.security.KeyStore;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.LocalLog;
|
import android.util.LocalLog;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -195,6 +194,7 @@ import com.android.server.connectivity.NetworkAgentInfo;
|
|||||||
import com.android.server.connectivity.NetworkDiagnostics;
|
import com.android.server.connectivity.NetworkDiagnostics;
|
||||||
import com.android.server.connectivity.NetworkNotificationManager;
|
import com.android.server.connectivity.NetworkNotificationManager;
|
||||||
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
|
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
|
||||||
|
import com.android.server.connectivity.NetworkRanker;
|
||||||
import com.android.server.connectivity.PermissionMonitor;
|
import com.android.server.connectivity.PermissionMonitor;
|
||||||
import com.android.server.connectivity.ProxyTracker;
|
import com.android.server.connectivity.ProxyTracker;
|
||||||
import com.android.server.connectivity.Vpn;
|
import com.android.server.connectivity.Vpn;
|
||||||
@@ -231,6 +231,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
|
import java.util.StringJoiner;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@@ -579,6 +580,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
|
final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
|
||||||
|
|
||||||
private final DnsManager mDnsManager;
|
private final DnsManager mDnsManager;
|
||||||
|
private final NetworkRanker mNetworkRanker;
|
||||||
|
|
||||||
private boolean mSystemReady;
|
private boolean mSystemReady;
|
||||||
private Intent mInitialBroadcast;
|
private Intent mInitialBroadcast;
|
||||||
@@ -727,9 +729,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
|
private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
|
||||||
boolean isDefaultNetwork) {
|
boolean isDefaultNetwork) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
log("Sending " + state +
|
log("Sending " + state
|
||||||
" broadcast for type " + type + " " + nai.name() +
|
+ " broadcast for type " + type + " " + nai.toShortString()
|
||||||
" isDefaultNetwork=" + isDefaultNetwork);
|
+ " isDefaultNetwork=" + isDefaultNetwork);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,14 +811,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String naiToString(NetworkAgentInfo nai) {
|
|
||||||
String name = nai.name();
|
|
||||||
String state = (nai.networkInfo != null) ?
|
|
||||||
nai.networkInfo.getState() + "/" + nai.networkInfo.getDetailedState() :
|
|
||||||
"???/???";
|
|
||||||
return name + " " + state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dump(IndentingPrintWriter pw) {
|
public void dump(IndentingPrintWriter pw) {
|
||||||
pw.println("mLegacyTypeTracker:");
|
pw.println("mLegacyTypeTracker:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
@@ -831,7 +825,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
for (int type = 0; type < mTypeLists.length; type++) {
|
for (int type = 0; type < mTypeLists.length; type++) {
|
||||||
if (mTypeLists[type] == null || mTypeLists[type].isEmpty()) continue;
|
if (mTypeLists[type] == null || mTypeLists[type].isEmpty()) continue;
|
||||||
for (NetworkAgentInfo nai : mTypeLists[type]) {
|
for (NetworkAgentInfo nai : mTypeLists[type]) {
|
||||||
pw.println(type + " " + naiToString(nai));
|
pw.println(type + " " + nai.toShortString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -966,6 +960,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
mMetricsLog = logger;
|
mMetricsLog = logger;
|
||||||
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
|
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
|
||||||
|
mNetworkRanker = new NetworkRanker();
|
||||||
NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
|
NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
|
||||||
mNetworkRequests.put(mDefaultRequest, defaultNRI);
|
mNetworkRequests.put(mDefaultRequest, defaultNRI);
|
||||||
mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
|
mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
|
||||||
@@ -2786,7 +2781,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
nai.everCaptivePortalDetected |= visible;
|
nai.everCaptivePortalDetected |= visible;
|
||||||
if (nai.lastCaptivePortalDetected &&
|
if (nai.lastCaptivePortalDetected &&
|
||||||
Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
|
Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
|
||||||
if (DBG) log("Avoiding captive portal network: " + nai.name());
|
if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
|
||||||
nai.asyncChannel.sendMessage(
|
nai.asyncChannel.sendMessage(
|
||||||
NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
|
NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
|
||||||
teardownUnneededNetwork(nai);
|
teardownUnneededNetwork(nai);
|
||||||
@@ -2845,7 +2840,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
||||||
? " with redirect to " + redirectUrl
|
? " with redirect to " + redirectUrl
|
||||||
: "";
|
: "";
|
||||||
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
||||||
}
|
}
|
||||||
if (valid != nai.lastValidated) {
|
if (valid != nai.lastValidated) {
|
||||||
if (wasDefault) {
|
if (wasDefault) {
|
||||||
@@ -3126,13 +3121,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// one lingered request, start lingering.
|
// one lingered request, start lingering.
|
||||||
nai.updateLingerTimer();
|
nai.updateLingerTimer();
|
||||||
if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
|
if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
|
||||||
if (DBG) log("Unlingering " + nai.name());
|
if (DBG) log("Unlingering " + nai.toShortString());
|
||||||
nai.unlinger();
|
nai.unlinger();
|
||||||
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
|
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
|
||||||
} else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
|
} else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
final int lingerTime = (int) (nai.getLingerExpiry() - now);
|
final int lingerTime = (int) (nai.getLingerExpiry() - now);
|
||||||
log("Lingering " + nai.name() + " for " + lingerTime + "ms");
|
log("Lingering " + nai.toShortString() + " for " + lingerTime + "ms");
|
||||||
}
|
}
|
||||||
nai.linger();
|
nai.linger();
|
||||||
logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
|
logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
|
||||||
@@ -3196,7 +3191,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
|
private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
|
||||||
ensureRunningOnConnectivityServiceThread();
|
ensureRunningOnConnectivityServiceThread();
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
|
log(nai.toShortString() + " disconnected, was satisfying " + nai.numNetworkRequests());
|
||||||
}
|
}
|
||||||
// Clear all notifications of this network.
|
// Clear all notifications of this network.
|
||||||
mNotifier.clearNotification(nai.network.netId);
|
mNotifier.clearNotification(nai.network.netId);
|
||||||
@@ -3254,7 +3249,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mDefaultNetworkNai = null;
|
mDefaultNetworkNai = null;
|
||||||
updateDataActivityTracking(null /* newNetwork */, nai);
|
updateDataActivityTracking(null /* newNetwork */, nai);
|
||||||
notifyLockdownVpn(nai);
|
notifyLockdownVpn(nai);
|
||||||
ensureNetworkTransitionWakelock(nai.name());
|
ensureNetworkTransitionWakelock(nai.toShortString());
|
||||||
}
|
}
|
||||||
mLegacyTypeTracker.remove(nai, wasDefault);
|
mLegacyTypeTracker.remove(nai, wasDefault);
|
||||||
if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
|
if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
|
||||||
@@ -3477,8 +3472,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
|
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
|
||||||
nai.removeRequest(nri.request.requestId);
|
nai.removeRequest(nri.request.requestId);
|
||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
log(" Removing from current network " + nai.name() +
|
log(" Removing from current network " + nai.toShortString()
|
||||||
", leaving " + nai.numNetworkRequests() + " requests.");
|
+ ", leaving " + nai.numNetworkRequests() + " requests.");
|
||||||
}
|
}
|
||||||
// If there are still lingered requests on this network, don't tear it down,
|
// If there are still lingered requests on this network, don't tear it down,
|
||||||
// but resume lingering instead.
|
// but resume lingering instead.
|
||||||
@@ -3487,7 +3482,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
notifyNetworkLosing(nai, now);
|
notifyNetworkLosing(nai, now);
|
||||||
}
|
}
|
||||||
if (unneeded(nai, UnneededFor.TEARDOWN)) {
|
if (unneeded(nai, UnneededFor.TEARDOWN)) {
|
||||||
if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
|
if (DBG) log("no live requests for " + nai.toShortString() + "; disconnecting");
|
||||||
teardownUnneededNetwork(nai);
|
teardownUnneededNetwork(nai);
|
||||||
} else {
|
} else {
|
||||||
wasKept = true;
|
wasKept = true;
|
||||||
@@ -3822,7 +3817,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
for (NetworkAgentInfo nai : networksSortedById()) {
|
for (NetworkAgentInfo nai : networksSortedById()) {
|
||||||
if (nai.avoidUnvalidated) {
|
if (nai.avoidUnvalidated) {
|
||||||
pw.println(nai.name());
|
pw.println(nai.toShortString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
@@ -3934,7 +3929,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
|
private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
|
||||||
NetworkCapabilities nc = nai.networkCapabilities;
|
NetworkCapabilities nc = nai.networkCapabilities;
|
||||||
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
|
if (DBG) log("handleNetworkUnvalidated " + nai.toShortString() + " cap=" + nc);
|
||||||
|
|
||||||
if (!nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
if (!nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||||
return;
|
return;
|
||||||
@@ -5348,7 +5343,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
detail = reason;
|
detail = reason;
|
||||||
}
|
}
|
||||||
log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s",
|
log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s",
|
||||||
detail, Arrays.toString(thresholdsArray.toArray()), nai.name()));
|
detail, Arrays.toString(thresholdsArray.toArray()), nai.toShortString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
nai.asyncChannel.sendMessage(
|
nai.asyncChannel.sendMessage(
|
||||||
@@ -6272,9 +6267,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// newLp is already a defensive copy.
|
// newLp is already a defensive copy.
|
||||||
newLp.ensureDirectlyConnectedRoutes();
|
newLp.ensureDirectlyConnectedRoutes();
|
||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
log("Update of LinkProperties for " + nai.name() +
|
log("Update of LinkProperties for " + nai.toShortString()
|
||||||
"; created=" + nai.created +
|
+ "; created=" + nai.created
|
||||||
"; everConnected=" + nai.everConnected);
|
+ "; everConnected=" + nai.everConnected);
|
||||||
}
|
}
|
||||||
updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties));
|
updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties));
|
||||||
}
|
}
|
||||||
@@ -6444,7 +6439,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
loge("Unknown NetworkAgentInfo in handleLingerComplete");
|
loge("Unknown NetworkAgentInfo in handleLingerComplete");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DBG) log("handleLingerComplete for " + oldNetwork.name());
|
if (DBG) log("handleLingerComplete for " + oldNetwork.toShortString());
|
||||||
|
|
||||||
// If we get here it means that the last linger timeout for this network expired. So there
|
// If we get here it means that the last linger timeout for this network expired. So there
|
||||||
// must be no other active linger timers, and we must stop lingering.
|
// must be no other active linger timers, and we must stop lingering.
|
||||||
@@ -6517,18 +6512,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An accumulator class to gather the list of changes that result from a rematch.
|
// An accumulator class to gather the list of changes that result from a rematch.
|
||||||
// TODO : enrich to represent an entire set of changes to apply.
|
|
||||||
private static class NetworkReassignment {
|
private static class NetworkReassignment {
|
||||||
static class NetworkBgStatePair {
|
|
||||||
@NonNull final NetworkAgentInfo mNetwork;
|
|
||||||
final boolean mOldBackground;
|
|
||||||
NetworkBgStatePair(@NonNull final NetworkAgentInfo network,
|
|
||||||
final boolean oldBackground) {
|
|
||||||
mNetwork = network;
|
|
||||||
mOldBackground = oldBackground;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class RequestReassignment {
|
static class RequestReassignment {
|
||||||
@NonNull public final NetworkRequestInfo mRequest;
|
@NonNull public final NetworkRequestInfo mRequest;
|
||||||
@Nullable public final NetworkAgentInfo mOldNetwork;
|
@Nullable public final NetworkAgentInfo mOldNetwork;
|
||||||
@@ -6540,44 +6524,34 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mOldNetwork = oldNetwork;
|
mOldNetwork = oldNetwork;
|
||||||
mNewNetwork = newNetwork;
|
mNewNetwork = newNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return mRequest.request.requestId + " : "
|
||||||
|
+ (null != mOldNetwork ? mOldNetwork.network.netId : "null")
|
||||||
|
+ " → " + (null != mNewNetwork ? mNewNetwork.network.netId : "null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>();
|
@NonNull private final ArrayList<RequestReassignment> mReassignments = new ArrayList<>();
|
||||||
@NonNull private final Map<NetworkRequestInfo, RequestReassignment> mReassignments =
|
|
||||||
new ArrayMap<>();
|
|
||||||
|
|
||||||
@NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() {
|
|
||||||
return mRematchedNetworks;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull Iterable<RequestReassignment> getRequestReassignments() {
|
@NonNull Iterable<RequestReassignment> getRequestReassignments() {
|
||||||
return mReassignments.values();
|
return mReassignments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
|
void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
|
||||||
final RequestReassignment oldChange = mReassignments.get(reassignment.mRequest);
|
if (!Build.IS_USER) {
|
||||||
if (null == oldChange) {
|
// The code is never supposed to add two reassignments of the same request. Make
|
||||||
mReassignments.put(reassignment.mRequest, reassignment);
|
// sure this stays true, but without imposing this expensive check on all
|
||||||
return;
|
// reassignments on all user devices.
|
||||||
|
for (final RequestReassignment existing : mReassignments) {
|
||||||
|
if (existing.mRequest.equals(reassignment.mRequest)) {
|
||||||
|
throw new IllegalStateException("Trying to reassign ["
|
||||||
|
+ reassignment + "] but already have ["
|
||||||
|
+ existing + "]");
|
||||||
}
|
}
|
||||||
if (oldChange.mNewNetwork != reassignment.mOldNetwork) {
|
|
||||||
throw new IllegalArgumentException("Reassignment <" + reassignment.mRequest + "> ["
|
|
||||||
+ reassignment.mOldNetwork + " -> " + reassignment.mNewNetwork
|
|
||||||
+ "] conflicts with ["
|
|
||||||
+ oldChange.mOldNetwork + " -> " + oldChange.mNewNetwork + "]");
|
|
||||||
}
|
}
|
||||||
// There was already a note to reassign this request from a network A to a network B,
|
|
||||||
// and a reassignment is added from network B to some other network C. The following
|
|
||||||
// synthesizes the merged reassignment that goes A -> C. An interesting (but not
|
|
||||||
// special) case to think about is when B is null, which can happen when the rematch
|
|
||||||
// loop notices the current satisfier doesn't satisfy the request any more, but
|
|
||||||
// hasn't yet encountered another network that could.
|
|
||||||
mReassignments.put(reassignment.mRequest, new RequestReassignment(reassignment.mRequest,
|
|
||||||
oldChange.mOldNetwork, reassignment.mNewNetwork));
|
|
||||||
}
|
}
|
||||||
|
mReassignments.add(reassignment);
|
||||||
void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
|
|
||||||
mRematchedNetworks.add(network);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will return null if this reassignment does not change the network assigned to
|
// Will return null if this reassignment does not change the network assigned to
|
||||||
@@ -6589,98 +6563,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
final StringJoiner sj = new StringJoiner(", " /* delimiter */,
|
||||||
|
"NetReassign [" /* prefix */, "]" /* suffix */);
|
||||||
|
if (mReassignments.isEmpty()) return sj.add("no changes").toString();
|
||||||
|
for (final RequestReassignment rr : getRequestReassignments()) {
|
||||||
|
sj.add(rr.toString());
|
||||||
|
}
|
||||||
|
return sj.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : remove this when it's useless
|
public String debugString() {
|
||||||
@NonNull private NetworkReassignment computeInitialReassignment() {
|
final StringBuilder sb = new StringBuilder();
|
||||||
final NetworkReassignment change = new NetworkReassignment();
|
sb.append("NetworkReassignment :");
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
if (mReassignments.isEmpty()) return sb.append(" no changes").toString();
|
||||||
change.addRequestReassignment(new NetworkReassignment.RequestReassignment(nri,
|
for (final RequestReassignment rr : getRequestReassignments()) {
|
||||||
nri.mSatisfier, nri.mSatisfier));
|
sb.append("\n ").append(rr);
|
||||||
}
|
}
|
||||||
return change;
|
return sb.append("\n").toString();
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
|
|
||||||
@NonNull final NetworkReassignment changes,
|
|
||||||
@NonNull final NetworkAgentInfo newNetwork) {
|
|
||||||
final int score = newNetwork.getCurrentScore();
|
|
||||||
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>();
|
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
|
||||||
// Process requests in the first pass and listens in the second pass. This allows us to
|
|
||||||
// change a network's capabilities depending on which requests it has. This is only
|
|
||||||
// correct if the change in capabilities doesn't affect whether the network satisfies
|
|
||||||
// requests or not, and doesn't affect the network's score.
|
|
||||||
if (nri.request.isListen()) continue;
|
|
||||||
|
|
||||||
// The reassignment has been seeded with the initial assignment, therefore
|
|
||||||
// getReassignment can't be null and mNewNetwork is only null if there was no
|
|
||||||
// satisfier in the first place or there was an explicit reassignment to null.
|
|
||||||
final NetworkAgentInfo currentNetwork = changes.getReassignment(nri).mNewNetwork;
|
|
||||||
final boolean satisfies = newNetwork.satisfies(nri.request);
|
|
||||||
if (newNetwork == currentNetwork && satisfies) continue;
|
|
||||||
|
|
||||||
// check if it satisfies the NetworkCapabilities
|
|
||||||
if (VDBG) log(" checking if request is satisfied: " + nri.request);
|
|
||||||
if (satisfies) {
|
|
||||||
// next check if it's better than any current network we're using for
|
|
||||||
// this request
|
|
||||||
if (VDBG || DDBG) {
|
|
||||||
log("currentScore = "
|
|
||||||
+ (currentNetwork != null ? currentNetwork.getCurrentScore() : 0)
|
|
||||||
+ ", newScore = " + score);
|
|
||||||
}
|
|
||||||
if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
|
|
||||||
reassignedRequests.put(nri, newNetwork);
|
|
||||||
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
|
|
||||||
nri, currentNetwork, newNetwork));
|
|
||||||
}
|
|
||||||
} else if (newNetwork == currentNetwork) {
|
|
||||||
reassignedRequests.put(nri, null);
|
|
||||||
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
|
|
||||||
nri, currentNetwork, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reassignedRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles a network appearing or improving its score.
|
|
||||||
//
|
|
||||||
// - Evaluates all current NetworkRequests that can be
|
|
||||||
// satisfied by newNetwork, and reassigns to newNetwork
|
|
||||||
// any such requests for which newNetwork is the best.
|
|
||||||
//
|
|
||||||
// - Writes into the passed reassignment object all changes that should be done for
|
|
||||||
// rematching this network with all requests, to be applied later.
|
|
||||||
//
|
|
||||||
// TODO : stop writing to the passed reassignment. This is temporarily more useful, but
|
|
||||||
// it's unidiomatic Java and it's hard to read.
|
|
||||||
//
|
|
||||||
// @param changes a currently-building list of changes to write to
|
|
||||||
// @param newNetwork is the network to be matched against NetworkRequests.
|
|
||||||
// @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
|
|
||||||
private void rematchNetworkAndRequests(@NonNull final NetworkReassignment changes,
|
|
||||||
@NonNull final NetworkAgentInfo newNetwork, final long now) {
|
|
||||||
ensureRunningOnConnectivityServiceThread();
|
|
||||||
if (!newNetwork.everConnected) return;
|
|
||||||
|
|
||||||
changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
|
|
||||||
newNetwork.isBackgroundNetwork()));
|
|
||||||
|
|
||||||
if (VDBG || DDBG) log("rematching " + newNetwork.name());
|
|
||||||
|
|
||||||
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
|
|
||||||
computeRequestReassignmentForNetwork(changes, newNetwork);
|
|
||||||
|
|
||||||
// Find and migrate to this Network any NetworkRequests for
|
|
||||||
// which this network is now the best.
|
|
||||||
for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
|
|
||||||
reassignedRequests.entrySet()) {
|
|
||||||
final NetworkRequestInfo nri = entry.getKey();
|
|
||||||
final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
|
|
||||||
final NetworkAgentInfo newSatisfier = entry.getValue();
|
|
||||||
updateSatisfiersForRematchRequest(nri, previousSatisfier, newSatisfier, now);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6689,10 +6590,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
@Nullable final NetworkAgentInfo newSatisfier,
|
@Nullable final NetworkAgentInfo newSatisfier,
|
||||||
final long now) {
|
final long now) {
|
||||||
if (newSatisfier != null) {
|
if (newSatisfier != null) {
|
||||||
if (VDBG) log("rematch for " + newSatisfier.name());
|
if (VDBG) log("rematch for " + newSatisfier.toShortString());
|
||||||
if (previousSatisfier != null) {
|
if (previousSatisfier != null) {
|
||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
log(" accepting network in place of " + previousSatisfier.name());
|
log(" accepting network in place of " + previousSatisfier.toShortString());
|
||||||
}
|
}
|
||||||
previousSatisfier.removeRequest(nri.request.requestId);
|
previousSatisfier.removeRequest(nri.request.requestId);
|
||||||
previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
|
previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
|
||||||
@@ -6701,11 +6602,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
newSatisfier.unlingerRequest(nri.request);
|
newSatisfier.unlingerRequest(nri.request);
|
||||||
if (!newSatisfier.addRequest(nri.request)) {
|
if (!newSatisfier.addRequest(nri.request)) {
|
||||||
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
|
Slog.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
|
||||||
|
+ nri.request);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
log("Network " + previousSatisfier.name() + " stopped satisfying"
|
log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
|
||||||
+ " request " + nri.request.requestId);
|
+ " request " + nri.request.requestId);
|
||||||
}
|
}
|
||||||
previousSatisfier.removeRequest(nri.request.requestId);
|
previousSatisfier.removeRequest(nri.request.requestId);
|
||||||
@@ -6713,30 +6615,67 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
nri.mSatisfier = newSatisfier;
|
nri.mSatisfier = newSatisfier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private NetworkReassignment computeNetworkReassignment() {
|
||||||
|
ensureRunningOnConnectivityServiceThread();
|
||||||
|
final NetworkReassignment changes = new NetworkReassignment();
|
||||||
|
|
||||||
|
// Gather the list of all relevant agents and sort them by score.
|
||||||
|
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
|
||||||
|
for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
|
||||||
|
if (!nai.everConnected) continue;
|
||||||
|
nais.add(nai);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
|
if (nri.request.isListen()) continue;
|
||||||
|
final NetworkAgentInfo bestNetwork = mNetworkRanker.getBestNetwork(nri.request, nais);
|
||||||
|
if (bestNetwork != nri.mSatisfier) {
|
||||||
|
// bestNetwork may be null if no network can satisfy this request.
|
||||||
|
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
|
||||||
|
nri, nri.mSatisfier, bestNetwork));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
|
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
|
||||||
* being disconnected.
|
* being disconnected.
|
||||||
*/
|
*/
|
||||||
private void rematchAllNetworksAndRequests() {
|
private void rematchAllNetworksAndRequests() {
|
||||||
// TODO: This may be slow, and should be optimized. Unfortunately at this moment the
|
// TODO: This may be slow, and should be optimized.
|
||||||
// processing is network-major instead of request-major (the code iterates through all
|
|
||||||
// networks, then for each it iterates for all requests), which is a problem for re-scoring
|
|
||||||
// requests. Once the code has switched to a request-major iteration style, this can
|
|
||||||
// be optimized to only do the processing needed.
|
|
||||||
final long now = SystemClock.elapsedRealtime();
|
final long now = SystemClock.elapsedRealtime();
|
||||||
final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
|
final NetworkReassignment changes = computeNetworkReassignment();
|
||||||
|
if (VDBG || DDBG) {
|
||||||
final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
|
log(changes.debugString());
|
||||||
new NetworkAgentInfo[mNetworkAgentInfos.size()]);
|
} else if (DBG) {
|
||||||
// Rematch higher scoring networks first to prevent requests first matching a lower
|
log(changes.toString()); // Shorter form, only one line of log
|
||||||
// scoring network and then a higher scoring network, which could produce multiple
|
}
|
||||||
// callbacks.
|
applyNetworkReassignment(changes, now);
|
||||||
Arrays.sort(nais);
|
|
||||||
final NetworkReassignment changes = computeInitialReassignment();
|
|
||||||
for (final NetworkAgentInfo nai : nais) {
|
|
||||||
rematchNetworkAndRequests(changes, nai, now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
|
||||||
|
final long now) {
|
||||||
|
final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos.values();
|
||||||
|
|
||||||
|
// Since most of the time there are only 0 or 1 background networks, it would probably
|
||||||
|
// be more efficient to just use an ArrayList here. TODO : measure performance
|
||||||
|
final ArraySet<NetworkAgentInfo> oldBgNetworks = new ArraySet<>();
|
||||||
|
for (final NetworkAgentInfo nai : nais) {
|
||||||
|
if (nai.isBackgroundNetwork()) oldBgNetworks.add(nai);
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, update the lists of satisfied requests in the network agents. This is necessary
|
||||||
|
// because some code later depends on this state to be correct, most prominently computing
|
||||||
|
// the linger status.
|
||||||
|
for (final NetworkReassignment.RequestReassignment event :
|
||||||
|
changes.getRequestReassignments()) {
|
||||||
|
updateSatisfiersForRematchRequest(event.mRequest, event.mOldNetwork,
|
||||||
|
event.mNewNetwork, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
|
||||||
final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
|
final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
|
||||||
final NetworkReassignment.RequestReassignment reassignment =
|
final NetworkReassignment.RequestReassignment reassignment =
|
||||||
changes.getReassignment(defaultRequestInfo);
|
changes.getReassignment(defaultRequestInfo);
|
||||||
@@ -6761,8 +6700,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// before LegacyTypeTracker sends legacy broadcasts
|
// before LegacyTypeTracker sends legacy broadcasts
|
||||||
for (final NetworkReassignment.RequestReassignment event :
|
for (final NetworkReassignment.RequestReassignment event :
|
||||||
changes.getRequestReassignments()) {
|
changes.getRequestReassignments()) {
|
||||||
if (event.mOldNetwork == event.mNewNetwork) continue;
|
|
||||||
|
|
||||||
// Tell NetworkProviders about the new score, so they can stop
|
// Tell NetworkProviders about the new score, so they can stop
|
||||||
// trying to connect if they know they cannot match it.
|
// trying to connect if they know they cannot match it.
|
||||||
// TODO - this could get expensive if there are a lot of outstanding requests for this
|
// TODO - this could get expensive if there are a lot of outstanding requests for this
|
||||||
@@ -6777,17 +6714,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) {
|
// Update the linger state before processing listen callbacks, because the background
|
||||||
// Process listen requests and update capabilities if the background state has
|
// computation depends on whether the network is lingering. Don't send the LOSING callbacks
|
||||||
// changed for this network. For consistency with previous behavior, send onLost
|
// just yet though, because they have to be sent after the listens are processed to keep
|
||||||
// callbacks before onAvailable.
|
// backward compatibility.
|
||||||
processNewlyLostListenRequests(event.mNetwork);
|
|
||||||
if (event.mOldBackground != event.mNetwork.isBackgroundNetwork()) {
|
|
||||||
applyBackgroundChangeForRematch(event.mNetwork);
|
|
||||||
}
|
|
||||||
processNewlySatisfiedListenRequests(event.mNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ArrayList<NetworkAgentInfo> lingeredNetworks = new ArrayList<>();
|
final ArrayList<NetworkAgentInfo> lingeredNetworks = new ArrayList<>();
|
||||||
for (final NetworkAgentInfo nai : nais) {
|
for (final NetworkAgentInfo nai : nais) {
|
||||||
// Rematching may have altered the linger state of some networks, so update all linger
|
// Rematching may have altered the linger state of some networks, so update all linger
|
||||||
@@ -6800,6 +6730,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (final NetworkAgentInfo nai : nais) {
|
||||||
|
if (!nai.everConnected) continue;
|
||||||
|
final boolean oldBackground = oldBgNetworks.contains(nai);
|
||||||
|
// Process listen requests and update capabilities if the background state has
|
||||||
|
// changed for this network. For consistency with previous behavior, send onLost
|
||||||
|
// callbacks before onAvailable.
|
||||||
|
processNewlyLostListenRequests(nai);
|
||||||
|
if (oldBackground != nai.isBackgroundNetwork()) {
|
||||||
|
applyBackgroundChangeForRematch(nai);
|
||||||
|
}
|
||||||
|
processNewlySatisfiedListenRequests(nai);
|
||||||
|
}
|
||||||
|
|
||||||
for (final NetworkAgentInfo nai : lingeredNetworks) {
|
for (final NetworkAgentInfo nai : lingeredNetworks) {
|
||||||
notifyNetworkLosing(nai, now);
|
notifyNetworkLosing(nai, now);
|
||||||
}
|
}
|
||||||
@@ -6821,7 +6764,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
notifyNetworkLosing(nai, now);
|
notifyNetworkLosing(nai, now);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (DBG) log("Reaping " + nai.name());
|
if (DBG) log("Reaping " + nai.toShortString());
|
||||||
teardownUnneededNetwork(nai);
|
teardownUnneededNetwork(nai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6849,7 +6792,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
|
private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
|
||||||
@Nullable final NetworkAgentInfo oldDefaultNetwork,
|
@Nullable final NetworkAgentInfo oldDefaultNetwork,
|
||||||
@Nullable final NetworkAgentInfo newDefaultNetwork,
|
@Nullable final NetworkAgentInfo newDefaultNetwork,
|
||||||
@NonNull final NetworkAgentInfo[] nais) {
|
@NonNull final Collection<NetworkAgentInfo> nais) {
|
||||||
if (oldDefaultNetwork != newDefaultNetwork) {
|
if (oldDefaultNetwork != newDefaultNetwork) {
|
||||||
// Maintain the illusion : since the legacy API only understands one network at a time,
|
// Maintain the illusion : since the legacy API only understands one network at a time,
|
||||||
// if the default network changed, apps should see a disconnected broadcast for the
|
// if the default network changed, apps should see a disconnected broadcast for the
|
||||||
@@ -6888,9 +6831,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// they may get old info. Reverse this after the old startUsing api is removed.
|
// they may get old info. Reverse this after the old startUsing api is removed.
|
||||||
// This is on top of the multiple intent sequencing referenced in the todo above.
|
// This is on top of the multiple intent sequencing referenced in the todo above.
|
||||||
for (NetworkAgentInfo nai : nais) {
|
for (NetworkAgentInfo nai : nais) {
|
||||||
|
if (nai.everConnected) {
|
||||||
addNetworkToLegacyTypeTracker(nai);
|
addNetworkToLegacyTypeTracker(nai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
|
private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
|
||||||
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
for (int i = 0; i < nai.numNetworkRequests(); i++) {
|
||||||
@@ -6969,8 +6914,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
notifyLockdownVpn(networkAgent);
|
notifyLockdownVpn(networkAgent);
|
||||||
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
|
log(networkAgent.toShortString() + " EVENT_NETWORK_INFO_CHANGED, going from "
|
||||||
oldInfo.getState() + " to " + state);
|
+ oldInfo.getState() + " to " + state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!networkAgent.created
|
if (!networkAgent.created
|
||||||
@@ -6988,7 +6933,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
networkAgent.everConnected = true;
|
networkAgent.everConnected = true;
|
||||||
|
|
||||||
if (networkAgent.linkProperties == null) {
|
if (networkAgent.linkProperties == null) {
|
||||||
Slog.wtf(TAG, networkAgent.name() + " connected with null LinkProperties");
|
Slog.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkCapabilities need to be set before sending the private DNS config to
|
// NetworkCapabilities need to be set before sending the private DNS config to
|
||||||
@@ -7048,7 +6993,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
|
private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
|
||||||
if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + ns);
|
if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + ns);
|
||||||
nai.setNetworkScore(ns);
|
nai.setNetworkScore(ns);
|
||||||
rematchAllNetworksAndRequests();
|
rematchAllNetworksAndRequests();
|
||||||
sendUpdatedScoreToFactories(nai);
|
sendUpdatedScoreToFactories(nai);
|
||||||
@@ -7194,14 +7139,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType, int arg1) {
|
protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType, int arg1) {
|
||||||
if (VDBG || DDBG) {
|
if (VDBG || DDBG) {
|
||||||
String notification = ConnectivityManager.getCallbackName(notifyType);
|
String notification = ConnectivityManager.getCallbackName(notifyType);
|
||||||
log("notifyType " + notification + " for " + networkAgent.name());
|
log("notifyType " + notification + " for " + networkAgent.toShortString());
|
||||||
}
|
}
|
||||||
for (int i = 0; i < networkAgent.numNetworkRequests(); i++) {
|
for (int i = 0; i < networkAgent.numNetworkRequests(); i++) {
|
||||||
NetworkRequest nr = networkAgent.requestAt(i);
|
NetworkRequest nr = networkAgent.requestAt(i);
|
||||||
NetworkRequestInfo nri = mNetworkRequests.get(nr);
|
NetworkRequestInfo nri = mNetworkRequests.get(nr);
|
||||||
if (VDBG) log(" sending notification for " + nr);
|
if (VDBG) log(" sending notification for " + nr);
|
||||||
// TODO: if we're in the middle of a rematch, can we send a CAP_CHANGED callback for
|
|
||||||
// a network that no longer satisfies the listen?
|
|
||||||
if (nri.mPendingIntent == null) {
|
if (nri.mPendingIntent == null) {
|
||||||
callCallbackForRequest(nri, networkAgent, notifyType, arg1);
|
callCallbackForRequest(nri, networkAgent, notifyType, arg1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ public class KeepaliveTracker {
|
|||||||
mSlot = slot;
|
mSlot = slot;
|
||||||
int error = isValid();
|
int error = isValid();
|
||||||
if (error == SUCCESS) {
|
if (error == SUCCESS) {
|
||||||
Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
|
Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.toShortString());
|
||||||
switch (mType) {
|
switch (mType) {
|
||||||
case TYPE_NATT:
|
case TYPE_NATT:
|
||||||
mNai.asyncChannel.sendMessage(
|
mNai.asyncChannel.sendMessage(
|
||||||
@@ -365,7 +365,8 @@ public class KeepaliveTracker {
|
|||||||
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
|
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name() + ": " + reason);
|
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.toShortString()
|
||||||
|
+ ": " + reason);
|
||||||
switch (mStartedState) {
|
switch (mStartedState) {
|
||||||
case NOT_STARTED:
|
case NOT_STARTED:
|
||||||
// Remove the reference of the keepalive that meet error before starting,
|
// Remove the reference of the keepalive that meet error before starting,
|
||||||
@@ -476,7 +477,7 @@ public class KeepaliveTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
|
public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
|
||||||
String networkName = (nai == null) ? "(null)" : nai.name();
|
final String networkName = NetworkAgentInfo.toShortString(nai);
|
||||||
HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
|
HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
|
||||||
if (networkKeepalives == null) {
|
if (networkKeepalives == null) {
|
||||||
Log.e(TAG, "Attempt to stop keepalive on nonexistent network " + networkName);
|
Log.e(TAG, "Attempt to stop keepalive on nonexistent network " + networkName);
|
||||||
@@ -493,7 +494,7 @@ public class KeepaliveTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupStoppedKeepalive(NetworkAgentInfo nai, int slot) {
|
private void cleanupStoppedKeepalive(NetworkAgentInfo nai, int slot) {
|
||||||
String networkName = (nai == null) ? "(null)" : nai.name();
|
final String networkName = NetworkAgentInfo.toShortString(nai);
|
||||||
HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
|
HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
|
||||||
if (networkKeepalives == null) {
|
if (networkKeepalives == null) {
|
||||||
Log.e(TAG, "Attempt to remove keepalive on nonexistent network " + networkName);
|
Log.e(TAG, "Attempt to remove keepalive on nonexistent network " + networkName);
|
||||||
@@ -540,7 +541,7 @@ public class KeepaliveTracker {
|
|||||||
} catch(NullPointerException e) {}
|
} catch(NullPointerException e) {}
|
||||||
if (ki == null) {
|
if (ki == null) {
|
||||||
Log.e(TAG, "Event " + message.what + "," + slot + "," + reason
|
Log.e(TAG, "Event " + message.what + "," + slot + "," + reason
|
||||||
+ " for unknown keepalive " + slot + " on " + nai.name());
|
+ " for unknown keepalive " + slot + " on " + nai.toShortString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +563,7 @@ public class KeepaliveTracker {
|
|||||||
if (KeepaliveInfo.STARTING == ki.mStartedState) {
|
if (KeepaliveInfo.STARTING == ki.mStartedState) {
|
||||||
if (SUCCESS == reason) {
|
if (SUCCESS == reason) {
|
||||||
// Keepalive successfully started.
|
// Keepalive successfully started.
|
||||||
Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
|
Log.d(TAG, "Started keepalive " + slot + " on " + nai.toShortString());
|
||||||
ki.mStartedState = KeepaliveInfo.STARTED;
|
ki.mStartedState = KeepaliveInfo.STARTED;
|
||||||
try {
|
try {
|
||||||
ki.mCallback.onStarted(slot);
|
ki.mCallback.onStarted(slot);
|
||||||
@@ -570,14 +571,14 @@ public class KeepaliveTracker {
|
|||||||
Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
|
Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.name()
|
Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.toShortString()
|
||||||
+ ": " + reason);
|
+ ": " + reason);
|
||||||
// The message indicated some error trying to start: do call handleStopKeepalive.
|
// The message indicated some error trying to start: do call handleStopKeepalive.
|
||||||
handleStopKeepalive(nai, slot, reason);
|
handleStopKeepalive(nai, slot, reason);
|
||||||
}
|
}
|
||||||
} else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
|
} else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
|
||||||
// The message indicated result of stopping : clean up keepalive slots.
|
// The message indicated result of stopping : clean up keepalive slots.
|
||||||
Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name()
|
Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.toShortString()
|
||||||
+ " stopped: " + reason);
|
+ " stopped: " + reason);
|
||||||
ki.mStartedState = KeepaliveInfo.NOT_STARTED;
|
ki.mStartedState = KeepaliveInfo.NOT_STARTED;
|
||||||
cleanupStoppedKeepalive(nai, slot);
|
cleanupStoppedKeepalive(nai, slot);
|
||||||
@@ -733,7 +734,7 @@ public class KeepaliveTracker {
|
|||||||
pw.println("Socket keepalives:");
|
pw.println("Socket keepalives:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
for (NetworkAgentInfo nai : mKeepalives.keySet()) {
|
for (NetworkAgentInfo nai : mKeepalives.keySet()) {
|
||||||
pw.println(nai.name());
|
pw.println(nai.toShortString());
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
for (int slot : mKeepalives.get(nai).keySet()) {
|
for (int slot : mKeepalives.get(nai).keySet()) {
|
||||||
KeepaliveInfo ki = mKeepalives.get(nai).get(slot);
|
KeepaliveInfo ki = mKeepalives.get(nai).get(slot);
|
||||||
|
|||||||
@@ -200,8 +200,9 @@ public class LingerMonitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.d(TAG, "Notifying switch from=" + fromNai.name() + " to=" + toNai.name() +
|
Log.d(TAG, "Notifying switch from=" + fromNai.toShortString()
|
||||||
" type=" + sNotifyTypeNames.get(notifyType, "unknown(" + notifyType + ")"));
|
+ " to=" + toNai.toShortString()
|
||||||
|
+ " type=" + sNotifyTypeNames.get(notifyType, "unknown(" + notifyType + ")"));
|
||||||
}
|
}
|
||||||
|
|
||||||
mNotifications.put(fromNai.network.netId, toNai.network.netId);
|
mNotifications.put(fromNai.network.netId, toNai.network.netId);
|
||||||
@@ -222,10 +223,10 @@ public class LingerMonitor {
|
|||||||
public void noteLingerDefaultNetwork(@NonNull final NetworkAgentInfo fromNai,
|
public void noteLingerDefaultNetwork(@NonNull final NetworkAgentInfo fromNai,
|
||||||
@Nullable final NetworkAgentInfo toNai) {
|
@Nullable final NetworkAgentInfo toNai) {
|
||||||
if (VDBG) {
|
if (VDBG) {
|
||||||
Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.name() +
|
Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.toShortString()
|
||||||
" everValidated=" + fromNai.everValidated +
|
+ " everValidated=" + fromNai.everValidated
|
||||||
" lastValidated=" + fromNai.lastValidated +
|
+ " lastValidated=" + fromNai.lastValidated
|
||||||
" to=" + toNai.name());
|
+ " to=" + toNai.toShortString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are currently notifying the user because the device switched to fromNai, now that
|
// If we are currently notifying the user because the device switched to fromNai, now that
|
||||||
@@ -270,7 +271,8 @@ public class LingerMonitor {
|
|||||||
// TODO: should we do this?
|
// TODO: should we do this?
|
||||||
if (everNotified(fromNai)) {
|
if (everNotified(fromNai)) {
|
||||||
if (VDBG) {
|
if (VDBG) {
|
||||||
Log.d(TAG, "Not notifying handover from " + fromNai.name() + ", already notified");
|
Log.d(TAG, "Not notifying handover from " + fromNai.toShortString()
|
||||||
|
+ ", already notified");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
|
|||||||
try {
|
try {
|
||||||
mNMService.registerObserver(this);
|
mNMService.registerObserver(this);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Can't register interface observer for clat on " + mNetwork.name());
|
Slog.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity;
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.transportNamesOf;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.IDnsResolver;
|
import android.net.IDnsResolver;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
@@ -372,7 +375,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
// Should only happen if the requestId wraps. If that happens lots of other things will
|
// Should only happen if the requestId wraps. If that happens lots of other things will
|
||||||
// be broken as well.
|
// be broken as well.
|
||||||
Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
|
Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
|
||||||
networkRequest, existing, name()));
|
networkRequest, existing, toShortString()));
|
||||||
updateRequestCounts(REMOVE, existing);
|
updateRequestCounts(REMOVE, existing);
|
||||||
}
|
}
|
||||||
mNetworkRequests.put(networkRequest.requestId, networkRequest);
|
mNetworkRequests.put(networkRequest.requestId, networkRequest);
|
||||||
@@ -542,11 +545,11 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
// Cannot happen. Once a request is lingering on a particular network, we cannot
|
// Cannot happen. Once a request is lingering on a particular network, we cannot
|
||||||
// re-linger it unless that network becomes the best for that request again, in which
|
// re-linger it unless that network becomes the best for that request again, in which
|
||||||
// case we should have unlingered it.
|
// case we should have unlingered it.
|
||||||
Log.wtf(TAG, this.name() + ": request " + request.requestId + " already lingered");
|
Log.wtf(TAG, toShortString() + ": request " + request.requestId + " already lingered");
|
||||||
}
|
}
|
||||||
final long expiryMs = now + duration;
|
final long expiryMs = now + duration;
|
||||||
LingerTimer timer = new LingerTimer(request, expiryMs);
|
LingerTimer timer = new LingerTimer(request, expiryMs);
|
||||||
if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + this.name());
|
if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString());
|
||||||
mLingerTimers.add(timer);
|
mLingerTimers.add(timer);
|
||||||
mLingerTimerForRequest.put(request.requestId, timer);
|
mLingerTimerForRequest.put(request.requestId, timer);
|
||||||
}
|
}
|
||||||
@@ -558,7 +561,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
public boolean unlingerRequest(NetworkRequest request) {
|
public boolean unlingerRequest(NetworkRequest request) {
|
||||||
LingerTimer timer = mLingerTimerForRequest.get(request.requestId);
|
LingerTimer timer = mLingerTimerForRequest.get(request.requestId);
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + this.name());
|
if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString());
|
||||||
mLingerTimers.remove(timer);
|
mLingerTimers.remove(timer);
|
||||||
mLingerTimerForRequest.remove(request.requestId);
|
mLingerTimerForRequest.remove(request.requestId);
|
||||||
return true;
|
return true;
|
||||||
@@ -645,9 +648,16 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String name() {
|
/**
|
||||||
return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" +
|
* Show a short string representing a Network.
|
||||||
networkInfo.getSubtypeName() + ") - " + Objects.toString(network) + "]";
|
*
|
||||||
|
* This is often not enough for debugging purposes for anything complex, but the full form
|
||||||
|
* is very long and hard to read, so this is useful when there isn't a lot of ambiguity.
|
||||||
|
* This represents the network with something like "[100 WIFI|VPN]" or "[108 MOBILE]".
|
||||||
|
*/
|
||||||
|
public String toShortString() {
|
||||||
|
return "[" + network.netId + " "
|
||||||
|
+ transportNamesOf(networkCapabilities.getTransportTypes()) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enables sorting in descending order of score.
|
// Enables sorting in descending order of score.
|
||||||
@@ -655,4 +665,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
public int compareTo(NetworkAgentInfo other) {
|
public int compareTo(NetworkAgentInfo other) {
|
||||||
return other.getCurrentScore() - getCurrentScore();
|
return other.getCurrentScore() - getCurrentScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null-guarding version of NetworkAgentInfo#toShortString()
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String toShortString(@Nullable final NetworkAgentInfo nai) {
|
||||||
|
return null != nai ? nai.toShortString() : "[null]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.net.NetworkRequest;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that knows how to find the best network matching a request out of a list of networks.
|
||||||
|
*/
|
||||||
|
public class NetworkRanker {
|
||||||
|
public NetworkRanker() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the best network satisfying this request among the list of passed networks.
|
||||||
|
*/
|
||||||
|
// Almost equivalent to Collections.max(nais), but allows returning null if no network
|
||||||
|
// satisfies the request.
|
||||||
|
@Nullable
|
||||||
|
public NetworkAgentInfo getBestNetwork(@NonNull final NetworkRequest request,
|
||||||
|
@NonNull final Collection<NetworkAgentInfo> nais) {
|
||||||
|
NetworkAgentInfo bestNetwork = null;
|
||||||
|
int bestScore = Integer.MIN_VALUE;
|
||||||
|
for (final NetworkAgentInfo nai : nais) {
|
||||||
|
if (!nai.satisfies(request)) continue;
|
||||||
|
if (nai.getCurrentScore() > bestScore) {
|
||||||
|
bestNetwork = nai;
|
||||||
|
bestScore = nai.getCurrentScore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestNetwork;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.connectivity
|
||||||
|
|
||||||
|
import android.net.NetworkRequest
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetBestNetwork() {
|
||||||
|
val scores = listOf(20, 50, 90, 60, 23, 68)
|
||||||
|
val nais = scores.map { makeNai(true, it) }
|
||||||
|
val bestNetwork = nais[2] // The one with the top score
|
||||||
|
val someRequest = mock(NetworkRequest::class.java)
|
||||||
|
assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIgnoreNonSatisfying() {
|
||||||
|
val nais = listOf(makeNai(true, 20), makeNai(true, 50), makeNai(false, 90),
|
||||||
|
makeNai(false, 60), makeNai(true, 23), makeNai(false, 68))
|
||||||
|
val bestNetwork = nais[1] // Top score that's satisfying
|
||||||
|
val someRequest = mock(NetworkRequest::class.java)
|
||||||
|
assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoMatch() {
|
||||||
|
val nais = listOf(makeNai(false, 20), makeNai(false, 50), makeNai(false, 90))
|
||||||
|
val someRequest = mock(NetworkRequest::class.java)
|
||||||
|
assertNull(ranker.getBestNetwork(someRequest, nais))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEmpty() {
|
||||||
|
val someRequest = mock(NetworkRequest::class.java)
|
||||||
|
assertNull(ranker.getBestNetwork(someRequest, emptyList()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the ranker is "stable" (as in stable sort), that is, it always returns the FIRST
|
||||||
|
// network satisfying the request if multiple of them have the same score.
|
||||||
|
@Test
|
||||||
|
fun testStable() {
|
||||||
|
val nais1 = listOf(makeNai(true, 30), makeNai(true, 30), makeNai(true, 30),
|
||||||
|
makeNai(true, 30), makeNai(true, 30), makeNai(true, 30))
|
||||||
|
val someRequest = mock(NetworkRequest::class.java)
|
||||||
|
assertEquals(nais1[0], ranker.getBestNetwork(someRequest, nais1))
|
||||||
|
|
||||||
|
val nais2 = listOf(makeNai(true, 30), makeNai(true, 50), makeNai(true, 20),
|
||||||
|
makeNai(true, 50), makeNai(true, 50), makeNai(true, 40))
|
||||||
|
assertEquals(nais2[1], ranker.getBestNetwork(someRequest, nais2))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user