Rewrite startUsingNetworkFeature for new API
bug:14993207
Change-Id: I041a80faa07bf3094af13a6c606f3b15aa03f789
(cherry picked from commit 09fe5e618b09965183cf53fba87c39025a19e8d1)
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2f2aba3..24844ba 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -40,6 +40,7 @@
import android.util.Log;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.Protocol;
import java.net.InetAddress;
@@ -807,11 +808,34 @@
* @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
*/
public int startUsingNetworkFeature(int networkType, String feature) {
- try {
- return mService.startUsingNetworkFeature(networkType, feature,
- new Binder());
- } catch (RemoteException e) {
- return -1;
+ NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature);
+ if (netCap == null) {
+ Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " +
+ feature);
+ return PhoneConstants.APN_REQUEST_FAILED;
+ }
+
+ NetworkRequest request = null;
+ synchronized (sLegacyRequests) {
+ LegacyRequest l = sLegacyRequests.get(netCap);
+ if (l != null) {
+ Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest);
+ renewRequestLocked(l);
+ if (l.currentNetwork != null) {
+ return PhoneConstants.APN_ALREADY_ACTIVE;
+ } else {
+ return PhoneConstants.APN_REQUEST_STARTED;
+ }
+ }
+
+ request = requestNetworkForFeatureLocked(netCap);
+ }
+ if (request != null) {
+ Log.d(TAG, "starting startUsingNeworkFeature for request " + request);
+ return PhoneConstants.APN_REQUEST_STARTED;
+ } else {
+ Log.d(TAG, " request Failed");
+ return PhoneConstants.APN_REQUEST_FAILED;
}
}
@@ -831,11 +855,169 @@
* @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
*/
public int stopUsingNetworkFeature(int networkType, String feature) {
- try {
- return mService.stopUsingNetworkFeature(networkType, feature);
- } catch (RemoteException e) {
+ NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature);
+ if (netCap == null) {
+ Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " +
+ feature);
return -1;
}
+
+ NetworkRequest request = removeRequestForFeature(netCap);
+ if (request != null) {
+ Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature);
+ releaseNetworkRequest(request);
+ }
+ return 1;
+ }
+
+ private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
+ if (networkType == TYPE_MOBILE) {
+ int cap = -1;
+ if ("enableMMS".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_MMS;
+ } else if ("enableSUPL".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_SUPL;
+ } else if ("enableDUN".equals(feature) || "enableDUNAlways".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_DUN;
+ } else if ("enableHIPRI".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_INTERNET;
+ } else if ("enableFOTA".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_FOTA;
+ } else if ("enableIMS".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_IMS;
+ } else if ("enableCBS".equals(feature)) {
+ cap = NetworkCapabilities.NET_CAPABILITY_CBS;
+ } else {
+ return null;
+ }
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ netCap.addNetworkCapability(cap);
+ return netCap;
+ } else if (networkType == TYPE_WIFI) {
+ if ("p2p".equals(feature)) {
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+ return netCap;
+ }
+ }
+ return null;
+ }
+
+ private int networkTypeForNetworkCapabilities(NetworkCapabilities netCap) {
+ if (netCap == null) return TYPE_NONE;
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
+ return TYPE_MOBILE_CBS;
+ }
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+ return TYPE_MOBILE_IMS;
+ }
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
+ return TYPE_MOBILE_FOTA;
+ }
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
+ return TYPE_MOBILE_DUN;
+ }
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
+ return TYPE_MOBILE_SUPL;
+ }
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+ return TYPE_MOBILE_MMS;
+ }
+ if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ return TYPE_MOBILE_HIPRI;
+ }
+ return TYPE_NONE;
+ }
+
+ private static class LegacyRequest {
+ NetworkCapabilities networkCapabilities;
+ NetworkRequest networkRequest;
+ int expireSequenceNumber;
+ Network currentNetwork;
+ int delay = -1;
+ NetworkCallbackListener networkCallbackListener = new NetworkCallbackListener() {
+ @Override
+ public void onAvailable(NetworkRequest request, Network network) {
+ currentNetwork = network;
+ Log.d(TAG, "startUsingNetworkFeature got Network:" + network);
+ network.bindProcessForHostResolution();
+ }
+ @Override
+ public void onLost(NetworkRequest request, Network network) {
+ if (network.equals(currentNetwork)) {
+ currentNetwork = null;
+ network.unbindProcessForHostResolution();
+ }
+ Log.d(TAG, "startUsingNetworkFeature lost Network:" + network);
+ }
+ };
+ }
+
+ private HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
+ new HashMap<NetworkCapabilities, LegacyRequest>();
+
+ private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) {
+ synchronized (sLegacyRequests) {
+ LegacyRequest l = sLegacyRequests.get(netCap);
+ if (l != null) return l.networkRequest;
+ }
+ return null;
+ }
+
+ private void renewRequestLocked(LegacyRequest l) {
+ l.expireSequenceNumber++;
+ Log.d(TAG, "renewing request to seqNum " + l.expireSequenceNumber);
+ sendExpireMsgForFeature(l.networkCapabilities, l.expireSequenceNumber, l.delay);
+ }
+
+ private void expireRequest(NetworkCapabilities netCap, int sequenceNum) {
+ int ourSeqNum = -1;
+ synchronized (sLegacyRequests) {
+ LegacyRequest l = sLegacyRequests.get(netCap);
+ if (l == null) return;
+ ourSeqNum = l.expireSequenceNumber;
+ if (l.expireSequenceNumber == sequenceNum) {
+ releaseNetworkRequest(l.networkRequest);
+ sLegacyRequests.remove(netCap);
+ }
+ }
+ Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum);
+ }
+
+ private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) {
+ int delay = -1;
+ int type = networkTypeForNetworkCapabilities(netCap);
+ try {
+ delay = mService.getRestoreDefaultNetworkDelay(type);
+ } catch (RemoteException e) {}
+ LegacyRequest l = new LegacyRequest();
+ l.networkCapabilities = netCap;
+ l.delay = delay;
+ l.expireSequenceNumber = 0;
+ l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0,
+ REQUEST, true);
+ if (l.networkRequest == null) return null;
+ sLegacyRequests.put(netCap, l);
+ sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay);
+ return l.networkRequest;
+ }
+
+ private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) {
+ if (delay >= 0) {
+ Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay);
+ Message msg = sCallbackHandler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
+ sCallbackHandler.sendMessageDelayed(msg, delay);
+ }
+ }
+
+ private NetworkRequest removeRequestForFeature(NetworkCapabilities netCap) {
+ synchronized (sLegacyRequests) {
+ LegacyRequest l = sLegacyRequests.remove(netCap);
+ if (l == null) return null;
+ return l.networkRequest;
+ }
}
/**
@@ -1782,8 +1964,10 @@
public static final int CALLBACK_RELEASED = BASE + 8;
/** @hide */
public static final int CALLBACK_EXIT = BASE + 9;
+ /** @hide obj = NetworkCapabilities, arg1 = seq number */
+ private static final int EXPIRE_LEGACY_REQUEST = BASE + 10;
- private static class CallbackHandler extends Handler {
+ private class CallbackHandler extends Handler {
private final HashMap<NetworkRequest, NetworkCallbackListener>mCallbackMap;
private final AtomicInteger mRefCount;
private static final String TAG = "ConnectivityManager.CallbackHandler";
@@ -1903,6 +2087,10 @@
getLooper().quit();
break;
}
+ case EXPIRE_LEGACY_REQUEST: {
+ expireRequest((NetworkCapabilities)message.obj, message.arg1);
+ break;
+ }
}
}
@@ -1954,8 +2142,9 @@
private final static int LISTEN = 1;
private final static int REQUEST = 2;
- private NetworkRequest somethingForNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener, int timeoutSec, int action) {
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
+ NetworkCallbackListener networkCallbackListener, int timeoutSec, int action,
+ boolean legacy) {
NetworkRequest networkRequest = null;
if (networkCallbackListener == null) {
throw new IllegalArgumentException("null NetworkCallbackListener");
@@ -1968,7 +2157,7 @@
new Binder());
} else {
networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
- timeoutSec, new Binder());
+ timeoutSec, new Binder(), legacy);
}
if (networkRequest != null) {
synchronized(sNetworkCallbackListener) {
@@ -1998,7 +2187,7 @@
*/
public NetworkRequest requestNetwork(NetworkCapabilities need,
NetworkCallbackListener networkCallbackListener) {
- return somethingForNetwork(need, networkCallbackListener, 0, REQUEST);
+ return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, false);
}
/**
@@ -2021,7 +2210,7 @@
*/
public NetworkRequest requestNetwork(NetworkCapabilities need,
NetworkCallbackListener networkCallbackListener, int timeoutSec) {
- return somethingForNetwork(need, networkCallbackListener, timeoutSec, REQUEST);
+ return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, false);
}
/**
@@ -2099,7 +2288,7 @@
*/
public NetworkRequest listenForNetwork(NetworkCapabilities need,
NetworkCallbackListener networkCallbackListener) {
- return somethingForNetwork(need, networkCallbackListener, 0, LISTEN);
+ return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, false);
}
/**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index baec36a..b67ae88 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -158,7 +158,7 @@
in NetworkCapabilities nc, int score);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, int timeoutSec, in IBinder binder);
+ in Messenger messenger, int timeoutSec, in IBinder binder, boolean legacy);
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation);
@@ -170,4 +170,6 @@
in PendingIntent operation);
void releaseNetworkRequest(in NetworkRequest networkRequest);
+
+ int getRestoreDefaultNetworkDelay(int networkType);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d7a19ad..1c0b7b6 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2843,7 +2843,8 @@
}
}
- private int getRestoreDefaultNetworkDelay(int networkType) {
+ @Override
+ public int getRestoreDefaultNetworkDelay(int networkType) {
String restoreDefaultNetworkDelayStr = SystemProperties.get(
NETWORK_RESTORE_DELAY_PROP_NAME);
if(restoreDefaultNetworkDelayStr != null &&
@@ -3137,6 +3138,14 @@
} catch (Exception e) {
loge("Exception removing network: " + e);
}
+ // TODO - if we move the logic to the network agent (have them disconnect
+ // because they lost all their requests or because their score isn't good)
+ // then they would disconnect organically, report their new state and then
+ // disconnect the channel.
+ if (nai.networkInfo.isConnected()) {
+ nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
+ null, null);
+ }
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
mNetworkAgentInfos.remove(msg.replyTo);
@@ -3203,7 +3212,7 @@
}
if (bestNetwork != null) {
if (VDBG) log("using " + bestNetwork.name());
- bestNetwork.networkRequests.put(nri.request.requestId, nri.request);
+ bestNetwork.addRequest(nri.request);
notifyNetworkCallback(bestNetwork, nri);
score = bestNetwork.currentScore;
}
@@ -3211,7 +3220,8 @@
if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) {
if (DBG) log("sending new NetworkRequest to factories");
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
+ nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score,
+ 0, nri.request);
}
}
}
@@ -5279,7 +5289,7 @@
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, int timeoutSec, IBinder binder) {
+ Messenger messenger, int timeoutSec, IBinder binder, boolean legacy) {
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
== false) {
enforceConnectivityInternalPermission();
@@ -5291,7 +5301,7 @@
throw new IllegalArgumentException("Bad timeout specified");
}
NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
- networkCapabilities), false, nextNetworkRequestId());
+ networkCapabilities), legacy, nextNetworkRequestId());
if (DBG) log("requestNetwork for " + networkRequest);
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
NetworkRequestInfo.REQUEST);
@@ -5392,7 +5402,7 @@
NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(),
new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler);
-
+ if (VDBG) log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
}
@@ -5439,7 +5449,7 @@
mClat.stopClat();
}
// If the link requires clat to be running, then start the daemon now.
- if (newLp != null && na.networkInfo.isConnected()) {
+ if (na.networkInfo.isConnected()) {
mClat.startClat(na);
} else {
mClat.stopClat();
@@ -5658,7 +5668,7 @@
if (VDBG) log(" accepting network in place of null");
}
mNetworkForRequestId.put(nri.request.requestId, newNetwork);
- newNetwork.networkRequests.put(nri.request.requestId, nri.request);
+ newNetwork.addRequest(nri.request);
keep = true;
// TODO - this could get expensive if we have alot of requests for this
// network. Think about if there is a way to reduce this. Push
@@ -5810,15 +5820,13 @@
protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name());
- boolean needsBroadcasts = false;
for (int i = 0; i < networkAgent.networkRequests.size(); i++) {
NetworkRequest nr = networkAgent.networkRequests.valueAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
if (VDBG) log(" sending notification for " + nr);
- if (nr.needsBroadcasts) needsBroadcasts = true;
callCallbackForRequest(nri, networkAgent, notifyType);
}
- if (needsBroadcasts) {
+ if (networkAgent.needsBroadcasts) {
if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) {
sendConnectedBroadcastDelayed(networkAgent.networkInfo,
getConnectivityChangeDelay());
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8102591..e9f9683 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -45,6 +45,17 @@
public int currentScore;
public final NetworkMonitor networkMonitor;
+ /**
+ * Indicates we need to send CONNECTIVITY_ACTION broadcasts for this network.
+ * For example the built-in default network request and any requsts coming from
+ * the deprecated startUsingNetworkFeature API will have this set. Networks
+ * responding to the new requestNetwork API will rely on point to point callbacks.
+ *
+ * Gets set if any legacy requests get affiliated with this network and
+ * stays set for life so we send disconnected bcasts to match the connected,
+ * even if the legacy request has moved on.
+ */
+ public boolean needsBroadcasts = false;
// The list of NetworkRequests being satisfied by this Network.
public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
@@ -66,6 +77,12 @@
networkMonitor = new NetworkMonitor(context, handler, this);
}
+ public void addRequest(NetworkRequest networkRequest) {
+ if (networkRequest.needsBroadcasts) needsBroadcasts = true;
+
+ networkRequests.put(networkRequest.requestId, networkRequest);
+ }
+
public String toString() {
return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" +
network + "} lp{" +