Merge changes I40f73526,Ia08900c5 into nyc-mr1-dev

* changes:
  Add a background NetworkRequest type for mobile data always on.
  Rematch requests first and listens second.
This commit is contained in:
Lorenzo Colitti
2016-09-12 13:30:19 +00:00
committed by Android (Google) Code Review
3 changed files with 210 additions and 57 deletions

View File

@@ -49,7 +49,7 @@ public class NetworkRequest implements Parcelable {
public final int legacyType; public final int legacyType;
/** /**
* A NetworkRequest as used by the system can be one of three types: * A NetworkRequest as used by the system can be one of the following types:
* *
* - LISTEN, for which the framework will issue callbacks about any * - LISTEN, for which the framework will issue callbacks about any
* and all networks that match the specified NetworkCapabilities, * and all networks that match the specified NetworkCapabilities,
@@ -64,7 +64,20 @@ public class NetworkRequest implements Parcelable {
* current network (if any) that matches the capabilities of the * current network (if any) that matches the capabilities of the
* default Internet request (mDefaultRequest), but which cannot cause * default Internet request (mDefaultRequest), but which cannot cause
* the framework to either create or retain the existence of any * the framework to either create or retain the existence of any
* specific network. * specific network. Note that from the point of view of the request
* matching code, TRACK_DEFAULT is identical to REQUEST: its special
* behaviour is not due to different semantics, but to the fact that
* the system will only ever create a TRACK_DEFAULT with capabilities
* that are identical to the default request's capabilities, thus
* causing it to share fate in every way with the default request.
*
* - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
* to retain the NET_CAPABILITY_FOREGROUND capability. A network with
* no foreground requests is in the background. A network that has
* one or more background requests and loses its last foreground
* request to a higher-scoring network will not go into the
* background immediately, but will linger and go into the background
* after the linger timeout.
* *
* - The value NONE is used only by applications. When an application * - The value NONE is used only by applications. When an application
* creates a NetworkRequest, it does not have a type; the type is set * creates a NetworkRequest, it does not have a type; the type is set
@@ -77,7 +90,8 @@ public class NetworkRequest implements Parcelable {
NONE, NONE,
LISTEN, LISTEN,
TRACK_DEFAULT, TRACK_DEFAULT,
REQUEST REQUEST,
BACKGROUND_REQUEST,
}; };
/** /**
@@ -140,7 +154,7 @@ public class NetworkRequest implements Parcelable {
* Add the given capability requirement to this builder. These represent * Add the given capability requirement to this builder. These represent
* the requested network's required capabilities. Note that when searching * the requested network's required capabilities. Note that when searching
* for a network to satisfy a request, all capabilities requested must be * for a network to satisfy a request, all capabilities requested must be
* satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*} * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITY_*}
* definitions. * definitions.
* *
* @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add. * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
@@ -284,7 +298,7 @@ public class NetworkRequest implements Parcelable {
}; };
/** /**
* Returns true iff. the contained NetworkRequest is of type LISTEN. * Returns true iff. this NetworkRequest is of type LISTEN.
* *
* @hide * @hide
*/ */
@@ -298,8 +312,9 @@ public class NetworkRequest implements Parcelable {
* - should be associated with at most one satisfying network * - should be associated with at most one satisfying network
* at a time; * at a time;
* *
* - should cause a network to be kept up if it is the best network * - should cause a network to be kept up, but not necessarily in
* which can satisfy the NetworkRequest. * the foreground, if it is the best network which can satisfy the
* NetworkRequest.
* *
* For full detail of how isRequest() is used for pairing Networks with * For full detail of how isRequest() is used for pairing Networks with
* NetworkRequests read rematchNetworkAndRequests(). * NetworkRequests read rematchNetworkAndRequests().
@@ -307,9 +322,36 @@ public class NetworkRequest implements Parcelable {
* @hide * @hide
*/ */
public boolean isRequest() { public boolean isRequest() {
return isForegroundRequest() || isBackgroundRequest();
}
/**
* Returns true iff. the contained NetworkRequest is one that:
*
* - should be associated with at most one satisfying network
* at a time;
*
* - should cause a network to be kept up and in the foreground if
* it is the best network which can satisfy the NetworkRequest.
*
* For full detail of how isRequest() is used for pairing Networks with
* NetworkRequests read rematchNetworkAndRequests().
*
* @hide
*/
public boolean isForegroundRequest() {
return type == Type.TRACK_DEFAULT || type == Type.REQUEST; return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
} }
/**
* Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST.
*
* @hide
*/
public boolean isBackgroundRequest() {
return type == Type.BACKGROUND_REQUEST;
}
public String toString() { public String toString() {
return "NetworkRequest [ " + type + " id=" + requestId + return "NetworkRequest [ " + type + " id=" + requestId +
(legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +

View File

@@ -262,6 +262,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
DONT_REAP DONT_REAP
}; };
private enum UnneededFor {
LINGER, // Determine whether this network is unneeded and should be lingered.
TEARDOWN, // Determine whether this network is unneeded and should be torn down.
}
/** /**
* used internally to change our mobile data enabled flag * used internally to change our mobile data enabled flag
*/ */
@@ -691,13 +696,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("ConnectivityService starting up"); if (DBG) log("ConnectivityService starting up");
mMetricsLog = logger; mMetricsLog = logger;
mDefaultRequest = createInternetRequestForTransport(-1); mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
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);
mDefaultMobileDataRequest = createInternetRequestForTransport( mDefaultMobileDataRequest = createInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR); NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
mHandlerThread = createHandlerThread(); mHandlerThread = createHandlerThread();
mHandlerThread.start(); mHandlerThread.start();
@@ -848,15 +853,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
} }
private NetworkRequest createInternetRequestForTransport(int transportType) { private NetworkRequest createInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
NetworkCapabilities netCap = new NetworkCapabilities(); NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
if (transportType > -1) { if (transportType > -1) {
netCap.addTransportType(transportType); netCap.addTransportType(transportType);
} }
return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
NetworkRequest.Type.REQUEST);
} }
// Used only for testing. // Used only for testing.
@@ -1970,8 +1975,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
pw.println(nai.toString()); pw.println(nai.toString());
pw.increaseIndent(); pw.increaseIndent();
pw.println(String.format("Requests: %d request/%d total", pw.println(String.format(
nai.numRequestNetworkRequests(), nai.numNetworkRequests())); "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d",
nai.numForegroundNetworkRequests(),
nai.numNetworkRequests() - nai.numRequestNetworkRequests(),
nai.numBackgroundNetworkRequests(),
nai.numNetworkRequests()));
pw.increaseIndent(); pw.increaseIndent();
for (int i = 0; i < nai.numNetworkRequests(); i++) { for (int i = 0; i < nai.numNetworkRequests(); i++) {
pw.println(nai.requestAt(i).toString()); pw.println(nai.requestAt(i).toString());
@@ -2292,15 +2301,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 3. If this network is unneeded (which implies it is not lingering), and there is at least // 3. If this network is unneeded (which implies it is not lingering), and there is at least
// one lingered request, start lingering. // one lingered request, start lingering.
nai.updateLingerTimer(); nai.updateLingerTimer();
if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) { if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
if (DBG) log("Unlingering " + nai.name()); if (DBG) log("Unlingering " + nai.name());
nai.unlinger(); nai.unlinger();
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER); logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
} else if (unneeded(nai) && nai.getLingerExpiry() > 0) { // unneeded() calls isLingering() } else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
int lingerTime = (int) (nai.getLingerExpiry() - now); int lingerTime = (int) (nai.getLingerExpiry() - now);
if (DBG) { if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms");
Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms");
}
nai.linger(); nai.linger();
logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER); logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
@@ -2479,15 +2486,37 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
// Is nai unneeded by all NetworkRequests (and should be disconnected)? // Determines whether the network is the best (or could become the best, if it validated), for
// This is whether it is satisfying any NetworkRequests or were it to become validated, // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends
// would it have a chance of satisfying any NetworkRequests. // on the value of reason:
private boolean unneeded(NetworkAgentInfo nai) { //
if (!nai.everConnected || nai.isVPN() || // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason,
nai.isLingering() || nai.numRequestNetworkRequests() > 0) { // then it should be torn down.
// - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
// then it should be lingered.
private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
final int numRequests;
switch (reason) {
case TEARDOWN:
numRequests = nai.numRequestNetworkRequests();
break;
case LINGER:
numRequests = nai.numForegroundNetworkRequests();
break;
default:
Slog.wtf(TAG, "Invalid reason. Cannot happen.");
return true;
}
if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
return false; return false;
} }
for (NetworkRequestInfo nri : mNetworkRequests.values()) { for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
// Background requests don't affect lingering.
continue;
}
// If this Network is already the highest scoring Network for a request, or if // 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 it is needed. // there is hope for it to become one if it validated, then it is needed.
if (nri.request.isRequest() && nai.satisfies(nri.request) && if (nri.request.isRequest() && nai.satisfies(nri.request) &&
@@ -2583,7 +2612,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 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.
updateLingerState(nai, SystemClock.elapsedRealtime()); updateLingerState(nai, SystemClock.elapsedRealtime());
if (unneeded(nai)) { if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (DBG) log("no live requests for " + nai.name() + "; disconnecting"); if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
teardownUnneededNetwork(nai); teardownUnneededNetwork(nai);
} else { } else {
@@ -4612,7 +4641,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// must be no other active linger timers, and we must stop lingering. // must be no other active linger timers, and we must stop lingering.
oldNetwork.clearLingerState(); oldNetwork.clearLingerState();
if (unneeded(oldNetwork)) { if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
teardownUnneededNetwork(oldNetwork); teardownUnneededNetwork(oldNetwork);
} }
} }
@@ -4631,6 +4660,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
} }
private void processListenRequests(NetworkAgentInfo nai) {
// For consistency with previous behaviour, send onLost callbacks before onAvailable.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
nai.removeRequest(nri.request.requestId);
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
}
}
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkRequest nr = nri.request;
if (!nr.isListen()) continue;
if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
nai.addRequest(nr);
notifyNetworkCallback(nai, nri);
}
}
}
// Handles a network appearing or improving its score. // Handles a network appearing or improving its score.
// //
// - Evaluates all current NetworkRequests that can be // - Evaluates all current NetworkRequests that can be
@@ -4671,6 +4721,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>(); ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
if (VDBG) log(" network has: " + newNetwork.networkCapabilities); if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
for (NetworkRequestInfo nri : mNetworkRequests.values()) { 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;
final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
final boolean satisfies = newNetwork.satisfies(nri.request); final boolean satisfies = newNetwork.satisfies(nri.request);
if (newNetwork == currentNetwork && satisfies) { if (newNetwork == currentNetwork && satisfies) {
@@ -4685,13 +4741,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// check if it satisfies the NetworkCapabilities // check if it satisfies the NetworkCapabilities
if (VDBG) log(" checking if request is satisfied: " + nri.request); if (VDBG) log(" checking if request is satisfied: " + nri.request);
if (satisfies) { if (satisfies) {
if (nri.request.isListen()) {
// This is not a request, it's a callback listener.
// Add it to newNetwork regardless of score.
if (newNetwork.addRequest(nri.request)) addedRequests.add(nri);
continue;
}
// next check if it's better than any current network we're using for // next check if it's better than any current network we're using for
// this request // this request
if (VDBG) { if (VDBG) {
@@ -4748,16 +4797,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkForRequestId.remove(nri.request.requestId); mNetworkForRequestId.remove(nri.request.requestId);
sendUpdatedScoreToFactories(nri.request, 0); sendUpdatedScoreToFactories(nri.request, 0);
} else { } else {
if (nri.request.isRequest()) { Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + newNetwork.name() +
newNetwork.name() + " without updating mNetworkForRequestId or factories!");
" without updating mNetworkForRequestId or factories!");
}
} }
// TODO: technically, sending CALLBACK_LOST here is // TODO: Technically, sending CALLBACK_LOST here is
// incorrect if nri is a request (not a listen) and there // incorrect if there is a replacement network currently
// is a replacement network currently connected that can // connected that can satisfy nri, which is a request
// satisfy it. However, the only capability that can both // (not a listen). However, the only capability that can both
// a) be requested and b) change is NET_CAPABILITY_TRUSTED, // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
// so this code is only incorrect for a network that loses // so this code is only incorrect for a network that loses
// the TRUSTED capability, which is a rare case. // the TRUSTED capability, which is a rare case.
@@ -4782,6 +4829,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
// Second pass: process all listens.
processListenRequests(newNetwork);
// do this after the default net is switched, but // do this after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts // before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri); for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
@@ -4859,7 +4909,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) { if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
if (unneeded(nai)) { if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (nai.getLingerExpiry() > 0) { if (nai.getLingerExpiry() > 0) {
// This network has active linger timers and no requests, but is not // This network has active linger timers and no requests, but is not
// lingering. Linger it. // lingering. Linger it.

View File

@@ -104,14 +104,16 @@ import java.util.TreeSet;
// ----------------------------------------------- // -----------------------------------------------
// If a network has no chance of satisfying any requests (even if it were to become validated // If a network has no chance of satisfying any requests (even if it were to become validated
// and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel. // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been //
// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the // If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that
// highest scoring network for any NetworkRequest, then there will be a 30s pause before // satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any
// ConnectivityService disconnects the NetworkAgent's AsyncChannel. During this pause the // foreground NetworkRequest, then there will be a 30s pause to allow network communication to be
// network is considered "lingering". This pause exists to allow network communication to be // wrapped up rather than abruptly terminated. During this pause the network is said to be
// wrapped up rather than abruptly terminated. During this pause if the network begins satisfying // "lingering". During this pause if the network begins satisfying a foreground NetworkRequest,
// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's // ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and
// AsyncChannel, and the network is no longer considered "lingering". // the network is no longer considered "lingering". After the linger timer expires, if the network
// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public NetworkInfo networkInfo; public NetworkInfo networkInfo;
// This Network object should always be used if possible, so as to encourage reuse of the // This Network object should always be used if possible, so as to encourage reuse of the
@@ -227,11 +229,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// The list of NetworkRequests being satisfied by this Network. // The list of NetworkRequests being satisfied by this Network.
private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
// The list of NetworkRequests that this Network previously satisfied with the highest
// score. A non-empty list indicates that if this Network was validated it is lingered.
// How many of the satisfied requests are actual requests and not listens. // How many of the satisfied requests are actual requests and not listens.
private int mNumRequestNetworkRequests = 0; private int mNumRequestNetworkRequests = 0;
// How many of the satisfied requests are of type BACKGROUND_REQUEST.
private int mNumBackgroundNetworkRequests = 0;
public final Messenger messenger; public final Messenger messenger;
public final AsyncChannel asyncChannel; public final AsyncChannel asyncChannel;
@@ -265,6 +269,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// //
// These functions must only called on ConnectivityService's main thread. // These functions must only called on ConnectivityService's main thread.
private static final boolean ADD = true;
private static final boolean REMOVE = false;
private void updateRequestCounts(boolean add, NetworkRequest request) {
int delta = add ? +1 : -1;
switch (request.type) {
case REQUEST:
case TRACK_DEFAULT:
mNumRequestNetworkRequests += delta;
break;
case BACKGROUND_REQUEST:
mNumRequestNetworkRequests += delta;
mNumBackgroundNetworkRequests += delta;
break;
case LISTEN:
break;
case NONE:
default:
Log.wtf(TAG, "Unhandled request type " + request.type);
break;
}
}
/** /**
* Add {@code networkRequest} to this network as it's satisfied by this network. * Add {@code networkRequest} to this network as it's satisfied by this network.
* @return true if {@code networkRequest} was added or false if {@code networkRequest} was * @return true if {@code networkRequest} was added or false if {@code networkRequest} was
@@ -273,9 +303,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public boolean addRequest(NetworkRequest networkRequest) { public boolean addRequest(NetworkRequest networkRequest) {
NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId);
if (existing == networkRequest) return false; if (existing == networkRequest) return false;
if (existing != null && existing.isRequest()) mNumRequestNetworkRequests--; if (existing != null) {
// Should only happen if the requestId wraps. If that happens lots of other things will
// be broken as well.
Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
networkRequest, existing, name()));
updateRequestCounts(REMOVE, existing);
}
mNetworkRequests.put(networkRequest.requestId, networkRequest); mNetworkRequests.put(networkRequest.requestId, networkRequest);
if (networkRequest.isRequest()) mNumRequestNetworkRequests++; updateRequestCounts(ADD, networkRequest);
return true; return true;
} }
@@ -285,9 +321,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public void removeRequest(int requestId) { public void removeRequest(int requestId) {
NetworkRequest existing = mNetworkRequests.get(requestId); NetworkRequest existing = mNetworkRequests.get(requestId);
if (existing == null) return; if (existing == null) return;
updateRequestCounts(REMOVE, existing);
mNetworkRequests.remove(requestId); mNetworkRequests.remove(requestId);
if (existing.isRequest()) { if (existing.isRequest()) {
mNumRequestNetworkRequests--;
unlingerRequest(existing); unlingerRequest(existing);
} }
} }
@@ -315,6 +351,21 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return mNumRequestNetworkRequests; return mNumRequestNetworkRequests;
} }
/**
* Returns the number of requests currently satisfied by this network of type
* {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}.
*/
public int numBackgroundNetworkRequests() {
return mNumBackgroundNetworkRequests;
}
/**
* Returns the number of foreground requests currently satisfied by this network.
*/
public int numForegroundNetworkRequests() {
return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests;
}
/** /**
* Returns the number of requests of any type currently satisfied by this network. * Returns the number of requests of any type currently satisfied by this network.
*/ */
@@ -322,6 +373,16 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return mNetworkRequests.size(); return mNetworkRequests.size();
} }
/**
* Returns whether the network is a background network. A network is a background network if it
* is satisfying no foreground requests and at least one background request. (If it did not have
* a background request, it would be a speculative network that is only being kept up because
* it might satisfy a request if it validated).
*/
public boolean isBackgroundNetwork() {
return numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
}
// Does this network satisfy request? // Does this network satisfy request?
public boolean satisfies(NetworkRequest request) { public boolean satisfies(NetworkRequest request) {
return created && return created &&