Merge "Reap unvalidated networks that have no chance of becoming highest scoring." into lmp-mr1-dev

This commit is contained in:
Paul Jensen
2014-12-06 01:23:54 +00:00
committed by Android (Google) Code Review
2 changed files with 104 additions and 35 deletions

View File

@@ -170,6 +170,7 @@ import java.util.Collection;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@@ -272,6 +273,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int ENABLED = 1; private static final int ENABLED = 1;
private static final int DISABLED = 0; private static final int DISABLED = 0;
// Arguments to rematchNetworkAndRequests()
private enum NascentState {
// Indicates a network was just validated for the first time. If the network is found to
// be unwanted (i.e. not satisfy any NetworkRequests) it is torn down.
JUST_VALIDATED,
// Indicates a network was not validated for the first time immediately prior to this call.
NOT_JUST_VALIDATED
};
private enum ReapUnvalidatedNetworks {
// Tear down unvalidated networks that have no chance (i.e. even if validated) of becoming
// the highest scoring network satisfying a NetworkRequest. This should be passed when it's
// known that there may be unvalidated networks that could potentially be reaped, and when
// all networks have been rematched against all NetworkRequests.
REAP,
// Don't reap unvalidated networks. This should be passed when it's known that there are
// no unvalidated networks that could potentially be reaped, and when some networks have
// not yet been rematched against all NetworkRequests.
DONT_REAP
};
/** /**
* used internally to change our mobile data enabled flag * used internally to change our mobile data enabled flag
*/ */
@@ -2014,12 +2035,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
if (valid) { if (valid) {
if (DBG) log("Validated " + nai.name()); if (DBG) log("Validated " + nai.name());
final boolean previouslyValidated = nai.validated; if (!nai.validated) {
final int previousScore = nai.getCurrentScore(); nai.validated = true;
nai.validated = true; rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
rematchNetworkAndRequests(nai, !previouslyValidated); ReapUnvalidatedNetworks.REAP);
// If score has changed, rebroadcast to NetworkFactories. b/17726566 // If score has changed, rebroadcast to NetworkFactories. b/17726566
if (nai.getCurrentScore() != previousScore) {
sendUpdatedScoreToFactories(nai); sendUpdatedScoreToFactories(nai);
} }
} }
@@ -2238,7 +2258,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
for (NetworkAgentInfo networkToActivate : toActivate) { for (NetworkAgentInfo networkToActivate : toActivate) {
unlinger(networkToActivate); unlinger(networkToActivate);
rematchNetworkAndRequests(networkToActivate, false); rematchNetworkAndRequests(networkToActivate, NascentState.NOT_JUST_VALIDATED,
ReapUnvalidatedNetworks.DONT_REAP);
} }
} }
} }
@@ -3964,15 +3985,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
// satisfied by newNetwork, and reassigns to newNetwork // satisfied by newNetwork, and reassigns to newNetwork
// any such requests for which newNetwork is the best. // any such requests for which newNetwork is the best.
// //
// - Lingers any Networks that as a result are no longer // - Lingers any validated Networks that as a result are no longer
// needed. A network is needed if it is the best network for // needed. A network is needed if it is the best network for
// one or more NetworkRequests, or if it is a VPN. // one or more NetworkRequests, or if it is a VPN.
// //
// - Tears down newNetwork if it just became validated // - Tears down newNetwork if it just became validated
// (i.e. nascent==true) but turns out to be unneeded. // (i.e. nascent==JUST_VALIDATED) but turns out to be unneeded.
// Does not tear down newNetwork if it is unvalidated, //
// because future validation may improve newNetwork's // - If reapUnvalidatedNetworks==REAP, tears down unvalidated
// score enough that it is needed. // networks that have no chance (i.e. even if validated)
// of becoming the highest scoring network.
// //
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy, // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy. // it does not remove NetworkRequests that other Networks could better satisfy.
@@ -3980,16 +4002,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
// This function should be used when possible instead of {@code rematchAllNetworksAndRequests} // This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
// as it performs better by a factor of the number of Networks. // as it performs better by a factor of the number of Networks.
// //
// @param newNetwork is the network to be matched against NetworkRequests.
// @param nascent indicates if newNetwork just became validated, in which case it should be // @param nascent indicates if newNetwork just became validated, in which case it should be
// torn down if unneeded. If nascent is false, no action is taken if newNetwork // torn down if unneeded.
// is found to be unneeded by this call. Presumably, in this case, either: // @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
// - newNetwork is unvalidated (and left alive), or // performed to tear down unvalidated networks that have no chance (i.e. even if
// - the NetworkRequests keeping newNetwork alive have been transitioned to // validated) of becoming the highest scoring network.
// another higher scoring network by another call to rematchNetworkAndRequests() private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, NascentState nascent,
// and this other call also lingered newNetwork. ReapUnvalidatedNetworks reapUnvalidatedNetworks) {
private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, boolean nascent) {
if (!newNetwork.created) return; if (!newNetwork.created) return;
if (nascent && !newNetwork.validated) loge("ERROR: nascent network not validated."); if (nascent == NascentState.JUST_VALIDATED && !newNetwork.validated) {
loge("ERROR: nascent network not validated.");
}
boolean keep = newNetwork.isVPN(); boolean keep = newNetwork.isVPN();
boolean isNewDefault = false; boolean isNewDefault = false;
if (DBG) log("rematching " + newNetwork.name()); if (DBG) log("rematching " + newNetwork.name());
@@ -4136,17 +4160,44 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (newNetwork.isVPN()) { if (newNetwork.isVPN()) {
mLegacyTypeTracker.add(TYPE_VPN, newNetwork); mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
} }
} else if (nascent) { } else if (nascent == NascentState.JUST_VALIDATED) {
// Only tear down newly validated networks here. Leave unvalidated to either become // Only tear down newly validated networks here. Leave unvalidated to either become
// validated (and get evaluated against peers, one losing here) or // validated (and get evaluated against peers, one losing here), or get reaped (see
// NetworkMonitor reports a bad network and we tear it down then. // reapUnvalidatedNetworks) if they have no chance of becoming the highest scoring
// Networks that have been up for a while and are validated should be torn down via // network. Networks that have been up for a while and are validated should be torn
// the lingering process so communication on that network is given time to wrap up. // down via the lingering process so communication on that network is given time to
// TODO: Could teardown unvalidated networks when their NetworkCapabilities // wrap up.
// satisfy no NetworkRequests.
if (DBG) log("Validated network turns out to be unwanted. Tear it down."); if (DBG) log("Validated network turns out to be unwanted. Tear it down.");
teardownUnneededNetwork(newNetwork); teardownUnneededNetwork(newNetwork);
} }
if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
if (!nai.created || nai.validated || nai.isVPN()) continue;
boolean reap = true;
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
// If this Network is already the highest scoring Network for a request, or if
// there is hope for it to become one if it validated, then don't reap it.
if (nri.isRequest && nai.satisfies(nri.request) &&
(nai.networkRequests.get(nri.request.requestId) != 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 satsifying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
nai.getCurrentScoreAsValidated())) {
reap = false;
break;
}
}
if (reap) {
if (DBG) log("Reaping " + nai.name());
teardownUnneededNetwork(nai);
}
}
}
} }
// Attempt to rematch all Networks with NetworkRequests. This may result in Networks // Attempt to rematch all Networks with NetworkRequests. This may result in Networks
@@ -4167,10 +4218,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
// can only add more NetworkRequests satisfied by "changed", and this is exactly what // can only add more NetworkRequests satisfied by "changed", and this is exactly what
// rematchNetworkAndRequests() handles. // rematchNetworkAndRequests() handles.
if (changed != null && oldScore < changed.getCurrentScore()) { if (changed != null && oldScore < changed.getCurrentScore()) {
rematchNetworkAndRequests(changed, false); rematchNetworkAndRequests(changed, NascentState.NOT_JUST_VALIDATED,
ReapUnvalidatedNetworks.REAP);
} else { } else {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { for (Iterator i = mNetworkAgentInfos.values().iterator(); i.hasNext(); ) {
rematchNetworkAndRequests(nai, false); rematchNetworkAndRequests((NetworkAgentInfo)i.next(),
NascentState.NOT_JUST_VALIDATED,
// Only reap the last time through the loop. Reaping before all rematching
// is complete could incorrectly teardown a network that hasn't yet been
// rematched.
i.hasNext() ? ReapUnvalidatedNetworks.DONT_REAP
: ReapUnvalidatedNetworks.REAP);
} }
} }
} }
@@ -4252,7 +4310,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// TODO: support proxy per network. // TODO: support proxy per network.
} }
// Consider network even though it is not yet validated. // Consider network even though it is not yet validated.
rematchNetworkAndRequests(networkAgent, false); rematchNetworkAndRequests(networkAgent, NascentState.NOT_JUST_VALIDATED,
ReapUnvalidatedNetworks.REAP);
} else if (state == NetworkInfo.State.DISCONNECTED || } else if (state == NetworkInfo.State.DISCONNECTED ||
state == NetworkInfo.State.SUSPENDED) { state == NetworkInfo.State.SUSPENDED) {
networkAgent.asyncChannel.disconnect(); networkAgent.asyncChannel.disconnect();

View File

@@ -106,9 +106,7 @@ public class NetworkAgentInfo {
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN); return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
} }
// Get the current score for this Network. This may be modified from what the private int getCurrentScore(boolean pretendValidated) {
// NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScore() {
// TODO: We may want to refactor this into a NetworkScore class that takes a base score from // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
// the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
// score. The NetworkScore class would provide a nice place to centralize score constants // score. The NetworkScore class would provide a nice place to centralize score constants
@@ -116,7 +114,7 @@ public class NetworkAgentInfo {
int score = currentScore; int score = currentScore;
if (!validated) score -= UNVALIDATED_SCORE_PENALTY; if (!validated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
if (score < 0) score = 0; if (score < 0) score = 0;
if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE; if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;
@@ -124,6 +122,18 @@ public class NetworkAgentInfo {
return score; return score;
} }
// Get the current score for this Network. This may be modified from what the
// NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScore() {
return getCurrentScore(false);
}
// Get the current score for this Network as if it was validated. This may be modified from
// what the NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScoreAsValidated() {
return getCurrentScore(true);
}
public void setCurrentScore(int newScore) { public void setCurrentScore(int newScore) {
currentScore = newScore; currentScore = newScore;
} }