Merge "Don't send the same PendingIntent more than once." into lmp-mr1-dev
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a110964..9c0e486 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -170,6 +170,7 @@
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -276,6 +277,26 @@
private static final int ENABLED = 1;
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
*/
@@ -1551,6 +1572,17 @@
}
final long ident = Binder.clearCallingIdentity();
+ if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+ final IBatteryStats bs = BatteryStatsService.getService();
+ try {
+ NetworkInfo ni = intent.getParcelableExtra(
+ ConnectivityManager.EXTRA_NETWORK_INFO);
+ bs.noteConnectivityChanged(intent.getIntExtra(
+ ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
+ ni != null ? ni.getState().toString() : "?");
+ } catch (RemoteException e) {
+ }
+ }
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
} finally {
@@ -2010,12 +2042,11 @@
boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
if (valid) {
if (DBG) log("Validated " + nai.name());
- final boolean previouslyValidated = nai.validated;
- final int previousScore = nai.getCurrentScore();
- nai.validated = true;
- rematchNetworkAndRequests(nai, !previouslyValidated);
- // If score has changed, rebroadcast to NetworkFactories. b/17726566
- if (nai.getCurrentScore() != previousScore) {
+ if (!nai.validated) {
+ nai.validated = true;
+ rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
+ ReapUnvalidatedNetworks.REAP);
+ // If score has changed, rebroadcast to NetworkFactories. b/17726566
sendUpdatedScoreToFactories(nai);
}
}
@@ -2234,7 +2265,8 @@
}
for (NetworkAgentInfo networkToActivate : toActivate) {
unlinger(networkToActivate);
- rematchNetworkAndRequests(networkToActivate, false);
+ rematchNetworkAndRequests(networkToActivate, NascentState.NOT_JUST_VALIDATED,
+ ReapUnvalidatedNetworks.DONT_REAP);
}
}
}
@@ -3970,15 +4002,16 @@
// satisfied by newNetwork, and reassigns to newNetwork
// 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
// one or more NetworkRequests, or if it is a VPN.
//
// - Tears down newNetwork if it just became validated
- // (i.e. nascent==true) but turns out to be unneeded.
- // Does not tear down newNetwork if it is unvalidated,
- // because future validation may improve newNetwork's
- // score enough that it is needed.
+ // (i.e. nascent==JUST_VALIDATED) but turns out to be unneeded.
+ //
+ // - If reapUnvalidatedNetworks==REAP, tears down unvalidated
+ // 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,
// it does not remove NetworkRequests that other Networks could better satisfy.
@@ -3986,16 +4019,18 @@
// This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
// 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
- // torn down if unneeded. If nascent is false, no action is taken if newNetwork
- // is found to be unneeded by this call. Presumably, in this case, either:
- // - newNetwork is unvalidated (and left alive), or
- // - the NetworkRequests keeping newNetwork alive have been transitioned to
- // another higher scoring network by another call to rematchNetworkAndRequests()
- // and this other call also lingered newNetwork.
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, boolean nascent) {
+ // torn down if unneeded.
+ // @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
+ // performed to tear down unvalidated networks that have no chance (i.e. even if
+ // validated) of becoming the highest scoring network.
+ private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, NascentState nascent,
+ ReapUnvalidatedNetworks reapUnvalidatedNetworks) {
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 isNewDefault = false;
if (DBG) log("rematching " + newNetwork.name());
@@ -4142,17 +4177,44 @@
if (newNetwork.isVPN()) {
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
- // validated (and get evaluated against peers, one losing here) or
- // NetworkMonitor reports a bad network and we tear it down then.
- // Networks that have been up for a while and are validated should be torn down via
- // the lingering process so communication on that network is given time to wrap up.
- // TODO: Could teardown unvalidated networks when their NetworkCapabilities
- // satisfy no NetworkRequests.
+ // validated (and get evaluated against peers, one losing here), or get reaped (see
+ // reapUnvalidatedNetworks) if they have no chance of becoming the highest scoring
+ // network. Networks that have been up for a while and are validated should be torn
+ // down via the lingering process so communication on that network is given time to
+ // wrap up.
if (DBG) log("Validated network turns out to be unwanted. Tear it down.");
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
@@ -4173,10 +4235,17 @@
// can only add more NetworkRequests satisfied by "changed", and this is exactly what
// rematchNetworkAndRequests() handles.
if (changed != null && oldScore < changed.getCurrentScore()) {
- rematchNetworkAndRequests(changed, false);
+ rematchNetworkAndRequests(changed, NascentState.NOT_JUST_VALIDATED,
+ ReapUnvalidatedNetworks.REAP);
} else {
- for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- rematchNetworkAndRequests(nai, false);
+ for (Iterator i = mNetworkAgentInfos.values().iterator(); i.hasNext(); ) {
+ 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);
}
}
}
@@ -4258,7 +4327,8 @@
// TODO: support proxy per network.
}
// 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 ||
state == NetworkInfo.State.SUSPENDED) {
networkAgent.asyncChannel.disconnect();
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 6feeb7c..779a834 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -106,9 +106,7 @@
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
- // 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() {
+ private int getCurrentScore(boolean pretendValidated) {
// 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
// score. The NetworkScore class would provide a nice place to centralize score constants
@@ -116,7 +114,7 @@
int score = currentScore;
- if (!validated) score -= UNVALIDATED_SCORE_PENALTY;
+ if (!validated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
if (score < 0) score = 0;
if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;
@@ -124,6 +122,18 @@
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) {
currentScore = newScore;
}