Remove listen requests properly.
https://googleplex-android-review.googlesource.com/#/c/527772/
correctly stopped adding listen requests to the mNetworkForRequestId
sparse array, but when we remove requests, if it's not getting
serviced by a network, we don't remove it from the network. That
means that when we go to send a notification for that network we have
a request affiliated with the network, but don't have data for the
request and hit this NPE.
If it's not a request, don't do the optimization and remove it only
from the network servicing the request, but instead scan all networks
and remove it from each, if found.
bug:17239054
Change-Id: I49165ed08c224ef20f703469f9ce39df5f21b163
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7655e92..78f8dc5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2167,41 +2167,53 @@
if (DBG) log("releasing NetworkRequest " + request);
nri.unlinkDeathRecipient();
mNetworkRequests.remove(request);
- // tell the network currently servicing this that it's no longer interested
- NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
- if (affectedNetwork != null) {
- mNetworkForRequestId.remove(nri.request.requestId);
- affectedNetwork.networkRequests.remove(nri.request.requestId);
- if (VDBG) {
- log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
- affectedNetwork.networkRequests.size() + " requests.");
- }
- if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {
- mLegacyTypeTracker.remove(nri.request.legacyType, affectedNetwork);
- }
- }
-
if (nri.isRequest) {
+ // Find all networks that are satisfying this request and remove the request
+ // from their request lists.
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.networkRequests.get(nri.request.requestId) != null) {
+ nai.networkRequests.remove(nri.request.requestId);
+ if (VDBG) {
+ log(" Removing from current network " + nai.name() +
+ ", leaving " + nai.networkRequests.size() +
+ " requests.");
+ }
+ // check if has any requests remaining and if not,
+ // disconnect (unless it's a VPN).
+ boolean keep = nai.isVPN();
+ for (int i = 0; i < nai.networkRequests.size() && !keep; i++) {
+ NetworkRequest r = nai.networkRequests.valueAt(i);
+ if (mNetworkRequests.get(r).isRequest) keep = true;
+ }
+ if (!keep) {
+ if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
+ nai.asyncChannel.disconnect();
+ }
+ }
+ }
+
+ // Maintain the illusion. When this request arrived, we might have preteneded
+ // that a network connected to serve it, even though the network was already
+ // connected. Now that this request has gone away, we might have to pretend
+ // that the network disconnected. LegacyTypeTracker will generate that
+ // phatom disconnect for this type.
+ NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+ if (nai != null) {
+ mNetworkForRequestId.remove(nri.request.requestId);
+ if (nri.request.legacyType != TYPE_NONE) {
+ mLegacyTypeTracker.remove(nri.request.legacyType, nai);
+ }
+ }
+
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
nri.request);
}
-
- if (affectedNetwork != null) {
- // check if this network still has live requests - otherwise, tear down
- // TODO - probably push this to the NF/NA
- boolean keep = affectedNetwork.isVPN();
- for (int i = 0; i < affectedNetwork.networkRequests.size() && !keep; i++) {
- NetworkRequest r = affectedNetwork.networkRequests.valueAt(i);
- if (mNetworkRequests.get(r).isRequest) {
- keep = true;
- }
- }
- if (keep == false) {
- if (DBG) log("no live requests for " + affectedNetwork.name() +
- "; disconnecting");
- affectedNetwork.asyncChannel.disconnect();
- }
+ } else {
+ // listens don't have a singular affectedNetwork. Check all networks to see
+ // if this listen request applies and remove it.
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ nai.networkRequests.remove(nri.request.requestId);
}
}
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);