From 8c5842cfafd6a5f501d0d0f27271597fd82857d2 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 24 Aug 2014 22:52:10 -0700 Subject: [PATCH] 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 --- .../android/server/ConnectivityService.java | 72 +++++++++++-------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7655e922ce..78f8dc53f7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2167,41 +2167,53 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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);