Loading core/java/android/net/NetworkRequest.java +49 −7 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class NetworkRequest implements Parcelable { 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 * and all networks that match the specified NetworkCapabilities, Loading @@ -64,7 +64,20 @@ public class NetworkRequest implements Parcelable { * current network (if any) that matches the capabilities of the * default Internet request (mDefaultRequest), but which cannot cause * 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 * creates a NetworkRequest, it does not have a type; the type is set Loading @@ -77,7 +90,8 @@ public class NetworkRequest implements Parcelable { NONE, LISTEN, TRACK_DEFAULT, REQUEST REQUEST, BACKGROUND_REQUEST, }; /** Loading Loading @@ -140,7 +154,7 @@ public class NetworkRequest implements Parcelable { * Add the given capability requirement to this builder. These represent * the requested network's required capabilities. Note that when searching * 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. * * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add. Loading Loading @@ -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 */ Loading @@ -298,8 +312,9 @@ public class NetworkRequest implements Parcelable { * - should be associated with at most one satisfying network * at a time; * * - should cause a network to be kept up if it is the best network * which can satisfy the NetworkRequest. * - should cause a network to be kept up, but not necessarily 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(). Loading @@ -307,9 +322,36 @@ public class NetworkRequest implements Parcelable { * @hide */ 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; } /** * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST. * * @hide */ public boolean isBackgroundRequest() { return type == Type.BACKGROUND_REQUEST; } public String toString() { return "NetworkRequest [ " + type + " id=" + requestId + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + Loading services/core/java/com/android/server/ConnectivityService.java +50 −21 Original line number Diff line number Diff line Loading @@ -262,6 +262,11 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 */ Loading Loading @@ -691,13 +696,13 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("ConnectivityService starting up"); mMetricsLog = logger; mDefaultRequest = createInternetRequestForTransport(-1); mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder()); mNetworkRequests.put(mDefaultRequest, defaultNRI); mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI); mDefaultMobileDataRequest = createInternetRequestForTransport( NetworkCapabilities.TRANSPORT_CELLULAR); NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST); mHandlerThread = createHandlerThread(); mHandlerThread.start(); Loading Loading @@ -848,15 +853,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); } private NetworkRequest createInternetRequestForTransport(int transportType) { private NetworkRequest createInternetRequestForTransport( int transportType, NetworkRequest.Type type) { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); if (transportType > -1) { netCap.addTransportType(transportType); } return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type); } // Used only for testing. Loading Loading @@ -1964,8 +1969,12 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { pw.println(nai.toString()); pw.increaseIndent(); pw.println(String.format("Requests: %d request/%d total", nai.numRequestNetworkRequests(), nai.numNetworkRequests())); pw.println(String.format( "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d", nai.numForegroundNetworkRequests(), nai.numNetworkRequests() - nai.numRequestNetworkRequests(), nai.numBackgroundNetworkRequests(), nai.numNetworkRequests())); pw.increaseIndent(); for (int i = 0; i < nai.numNetworkRequests(); i++) { pw.println(nai.requestAt(i).toString()); Loading Loading @@ -2286,15 +2295,13 @@ public class ConnectivityService extends IConnectivityManager.Stub // 3. If this network is unneeded (which implies it is not lingering), and there is at least // one lingered request, start lingering. nai.updateLingerTimer(); if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) { if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) { if (DBG) log("Unlingering " + nai.name()); nai.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); if (DBG) { Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms"); } if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms"); nai.linger(); logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime); Loading Loading @@ -2473,15 +2480,37 @@ public class ConnectivityService extends IConnectivityManager.Stub } } // Is nai unneeded by all NetworkRequests (and should be disconnected)? // This is whether it is satisfying any NetworkRequests or were it to become validated, // would it have a chance of satisfying any NetworkRequests. private boolean unneeded(NetworkAgentInfo nai) { if (!nai.everConnected || nai.isVPN() || nai.isLingering() || nai.numRequestNetworkRequests() > 0) { // Determines whether the network is the best (or could become the best, if it validated), for // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends // on the value of reason: // // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason, // 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; } 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 // there is hope for it to become one if it validated, then it is needed. if (nri.request.isRequest() && nai.satisfies(nri.request) && Loading Loading @@ -2591,7 +2620,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If there are still lingered requests on this network, don't tear it down, // but resume lingering instead. updateLingerState(nai, SystemClock.elapsedRealtime()); if (unneeded(nai)) { if (unneeded(nai, UnneededFor.TEARDOWN)) { if (DBG) log("no live requests for " + nai.name() + "; disconnecting"); teardownUnneededNetwork(nai); } else { Loading Loading @@ -4625,7 +4654,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // must be no other active linger timers, and we must stop lingering. oldNetwork.clearLingerState(); if (unneeded(oldNetwork)) { if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) { teardownUnneededNetwork(oldNetwork); } } Loading Loading @@ -4893,7 +4922,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { if (unneeded(nai)) { if (unneeded(nai, UnneededFor.TEARDOWN)) { if (nai.getLingerExpiry() > 0) { // This network has active linger timers and no requests, but is not // lingering. Linger it. Loading services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +74 −13 Original line number Diff line number Diff line Loading @@ -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 // 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 // highest scoring network for any NetworkRequest, then there will be a 30s pause before // ConnectivityService disconnects the NetworkAgent's AsyncChannel. During this pause the // network is considered "lingering". This pause exists to allow network communication to be // wrapped up rather than abruptly terminated. During this pause if the network begins satisfying // a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's // AsyncChannel, and the network is no longer considered "lingering". // // If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that // satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any // foreground NetworkRequest, then there will be a 30s pause to allow network communication to be // wrapped up rather than abruptly terminated. During this pause the network is said to be // "lingering". During this pause if the network begins satisfying a foreground NetworkRequest, // ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and // 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 NetworkInfo networkInfo; // This Network object should always be used if possible, so as to encourage reuse of the Loading Loading @@ -227,11 +229,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // The list of NetworkRequests being satisfied by this Network. 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. 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 AsyncChannel asyncChannel; Loading Loading @@ -265,6 +269,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // // 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. * @return true if {@code networkRequest} was added or false if {@code networkRequest} was Loading @@ -273,9 +303,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public boolean addRequest(NetworkRequest networkRequest) { NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); 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); if (networkRequest.isRequest()) mNumRequestNetworkRequests++; updateRequestCounts(ADD, networkRequest); return true; } Loading @@ -285,9 +321,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public void removeRequest(int requestId) { NetworkRequest existing = mNetworkRequests.get(requestId); if (existing == null) return; updateRequestCounts(REMOVE, existing); mNetworkRequests.remove(requestId); if (existing.isRequest()) { mNumRequestNetworkRequests--; unlingerRequest(existing); } } Loading Loading @@ -315,6 +351,21 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { 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. */ Loading @@ -322,6 +373,16 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { 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? public boolean satisfies(NetworkRequest request) { return created && Loading Loading
core/java/android/net/NetworkRequest.java +49 −7 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class NetworkRequest implements Parcelable { 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 * and all networks that match the specified NetworkCapabilities, Loading @@ -64,7 +64,20 @@ public class NetworkRequest implements Parcelable { * current network (if any) that matches the capabilities of the * default Internet request (mDefaultRequest), but which cannot cause * 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 * creates a NetworkRequest, it does not have a type; the type is set Loading @@ -77,7 +90,8 @@ public class NetworkRequest implements Parcelable { NONE, LISTEN, TRACK_DEFAULT, REQUEST REQUEST, BACKGROUND_REQUEST, }; /** Loading Loading @@ -140,7 +154,7 @@ public class NetworkRequest implements Parcelable { * Add the given capability requirement to this builder. These represent * the requested network's required capabilities. Note that when searching * 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. * * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add. Loading Loading @@ -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 */ Loading @@ -298,8 +312,9 @@ public class NetworkRequest implements Parcelable { * - should be associated with at most one satisfying network * at a time; * * - should cause a network to be kept up if it is the best network * which can satisfy the NetworkRequest. * - should cause a network to be kept up, but not necessarily 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(). Loading @@ -307,9 +322,36 @@ public class NetworkRequest implements Parcelable { * @hide */ 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; } /** * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST. * * @hide */ public boolean isBackgroundRequest() { return type == Type.BACKGROUND_REQUEST; } public String toString() { return "NetworkRequest [ " + type + " id=" + requestId + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + Loading
services/core/java/com/android/server/ConnectivityService.java +50 −21 Original line number Diff line number Diff line Loading @@ -262,6 +262,11 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 */ Loading Loading @@ -691,13 +696,13 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("ConnectivityService starting up"); mMetricsLog = logger; mDefaultRequest = createInternetRequestForTransport(-1); mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder()); mNetworkRequests.put(mDefaultRequest, defaultNRI); mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI); mDefaultMobileDataRequest = createInternetRequestForTransport( NetworkCapabilities.TRANSPORT_CELLULAR); NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST); mHandlerThread = createHandlerThread(); mHandlerThread.start(); Loading Loading @@ -848,15 +853,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); } private NetworkRequest createInternetRequestForTransport(int transportType) { private NetworkRequest createInternetRequestForTransport( int transportType, NetworkRequest.Type type) { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); if (transportType > -1) { netCap.addTransportType(transportType); } return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type); } // Used only for testing. Loading Loading @@ -1964,8 +1969,12 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { pw.println(nai.toString()); pw.increaseIndent(); pw.println(String.format("Requests: %d request/%d total", nai.numRequestNetworkRequests(), nai.numNetworkRequests())); pw.println(String.format( "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d", nai.numForegroundNetworkRequests(), nai.numNetworkRequests() - nai.numRequestNetworkRequests(), nai.numBackgroundNetworkRequests(), nai.numNetworkRequests())); pw.increaseIndent(); for (int i = 0; i < nai.numNetworkRequests(); i++) { pw.println(nai.requestAt(i).toString()); Loading Loading @@ -2286,15 +2295,13 @@ public class ConnectivityService extends IConnectivityManager.Stub // 3. If this network is unneeded (which implies it is not lingering), and there is at least // one lingered request, start lingering. nai.updateLingerTimer(); if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) { if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) { if (DBG) log("Unlingering " + nai.name()); nai.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); if (DBG) { Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms"); } if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms"); nai.linger(); logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime); Loading Loading @@ -2473,15 +2480,37 @@ public class ConnectivityService extends IConnectivityManager.Stub } } // Is nai unneeded by all NetworkRequests (and should be disconnected)? // This is whether it is satisfying any NetworkRequests or were it to become validated, // would it have a chance of satisfying any NetworkRequests. private boolean unneeded(NetworkAgentInfo nai) { if (!nai.everConnected || nai.isVPN() || nai.isLingering() || nai.numRequestNetworkRequests() > 0) { // Determines whether the network is the best (or could become the best, if it validated), for // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends // on the value of reason: // // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason, // 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; } 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 // there is hope for it to become one if it validated, then it is needed. if (nri.request.isRequest() && nai.satisfies(nri.request) && Loading Loading @@ -2591,7 +2620,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If there are still lingered requests on this network, don't tear it down, // but resume lingering instead. updateLingerState(nai, SystemClock.elapsedRealtime()); if (unneeded(nai)) { if (unneeded(nai, UnneededFor.TEARDOWN)) { if (DBG) log("no live requests for " + nai.name() + "; disconnecting"); teardownUnneededNetwork(nai); } else { Loading Loading @@ -4625,7 +4654,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // must be no other active linger timers, and we must stop lingering. oldNetwork.clearLingerState(); if (unneeded(oldNetwork)) { if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) { teardownUnneededNetwork(oldNetwork); } } Loading Loading @@ -4893,7 +4922,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { if (unneeded(nai)) { if (unneeded(nai, UnneededFor.TEARDOWN)) { if (nai.getLingerExpiry() > 0) { // This network has active linger timers and no requests, but is not // lingering. Linger it. Loading
services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +74 −13 Original line number Diff line number Diff line Loading @@ -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 // 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 // highest scoring network for any NetworkRequest, then there will be a 30s pause before // ConnectivityService disconnects the NetworkAgent's AsyncChannel. During this pause the // network is considered "lingering". This pause exists to allow network communication to be // wrapped up rather than abruptly terminated. During this pause if the network begins satisfying // a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's // AsyncChannel, and the network is no longer considered "lingering". // // If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that // satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any // foreground NetworkRequest, then there will be a 30s pause to allow network communication to be // wrapped up rather than abruptly terminated. During this pause the network is said to be // "lingering". During this pause if the network begins satisfying a foreground NetworkRequest, // ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and // 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 NetworkInfo networkInfo; // This Network object should always be used if possible, so as to encourage reuse of the Loading Loading @@ -227,11 +229,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // The list of NetworkRequests being satisfied by this Network. 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. 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 AsyncChannel asyncChannel; Loading Loading @@ -265,6 +269,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // // 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. * @return true if {@code networkRequest} was added or false if {@code networkRequest} was Loading @@ -273,9 +303,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public boolean addRequest(NetworkRequest networkRequest) { NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); 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); if (networkRequest.isRequest()) mNumRequestNetworkRequests++; updateRequestCounts(ADD, networkRequest); return true; } Loading @@ -285,9 +321,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public void removeRequest(int requestId) { NetworkRequest existing = mNetworkRequests.get(requestId); if (existing == null) return; updateRequestCounts(REMOVE, existing); mNetworkRequests.remove(requestId); if (existing.isRequest()) { mNumRequestNetworkRequests--; unlingerRequest(existing); } } Loading Loading @@ -315,6 +351,21 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { 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. */ Loading @@ -322,6 +373,16 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { 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? public boolean satisfies(NetworkRequest request) { return created && Loading