From 1f567385ff6f6b565559e94f5928629bf02b7129 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Fri, 13 Feb 2015 14:18:39 -0500 Subject: [PATCH] Add ConnectivityManager.getActiveNetwork(). Rework NetID allocation in ConnectivityService so registerNetworkAgent() can return the allocated NetID. Bug: 19416463 Change-Id: I68e395552cf27422c80b4dfae5db5d56a0d68f5d --- .../java/android/net/ConnectivityManager.java | 35 ++++++++++-- .../android/net/IConnectivityManager.aidl | 3 +- core/java/android/net/NetworkAgent.java | 6 +- .../android/server/ConnectivityService.java | 57 +++++++++++++++---- .../server/connectivity/NetworkAgentInfo.java | 9 ++- 5 files changed, 91 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 826786b0bf..99e368d5e4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -601,6 +601,27 @@ public class ConnectivityManager { } } + /** + * Returns a {@link Network} object corresponding to the currently active + * default data network. In the event that the current active default data + * network disconnects, the returned {@code Network} object will no longer + * be usable. This will return {@code null} when there is no default + * network. + * + * @return a {@link Network} object for the current default network or + * {@code null} if no default network is currently active + * + *

This method requires the caller to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + */ + public Network getActiveNetwork() { + try { + return mService.getActiveNetwork(); + } catch (RemoteException e) { + return null; + } + } + /** * Returns details about the currently active default data network * for a given uid. This is for internal use only to avoid spying @@ -1927,12 +1948,18 @@ public class ConnectivityManager { } catch (RemoteException e) { } } - /** {@hide} */ - public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + /** + * @hide + * Register a NetworkAgent with ConnectivityService. + * @return NetID corresponding to NetworkAgent. + */ + public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkMisc misc) { try { - mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc); - } catch (RemoteException e) { } + return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc); + } catch (RemoteException e) { + return NETID_UNSET; + } } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 31e60e7ce5..171c7d414d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -42,6 +42,7 @@ import com.android.internal.net.VpnProfile; /** {@hide} */ interface IConnectivityManager { + Network getActiveNetwork(); NetworkInfo getActiveNetworkInfo(); NetworkInfo getActiveNetworkInfoForUid(int uid); NetworkInfo getNetworkInfo(int networkType); @@ -132,7 +133,7 @@ interface IConnectivityManager void unregisterNetworkFactory(in Messenger messenger); - void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkMisc misc); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 74d4ac23e0..ddaa808d9b 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -42,6 +42,10 @@ import java.util.concurrent.atomic.AtomicBoolean; * @hide */ public abstract class NetworkAgent extends Handler { + // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown + // an exception. + public final int netId; + private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; @@ -142,7 +146,7 @@ public abstract class NetworkAgent extends Handler { if (VDBG) log("Registering NetworkAgent"); ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); - cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), + netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 3103592c2d..ee44b0990c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.getNetworkTypeName; @@ -89,6 +90,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.Xml; @@ -691,16 +693,15 @@ public class ConnectivityService extends IConnectivityManager.Stub return mNextNetworkRequestId++; } - private void assignNextNetId(NetworkAgentInfo nai) { + private int reserveNetId() { synchronized (mNetworkForNetId) { for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) { int netId = mNextNetId; if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID; // Make sure NetID unused. http://b/16815182 - if (mNetworkForNetId.get(netId) == null) { - nai.network = new Network(netId); - mNetworkForNetId.put(netId, nai); - return; + if (!mNetIdInUse.get(netId)) { + mNetIdInUse.put(netId, true); + return netId; } } } @@ -859,6 +860,28 @@ public class ConnectivityService extends IConnectivityManager.Stub return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid); } + @Override + public Network getActiveNetwork() { + enforceAccessPermission(); + final int uid = Binder.getCallingUid(); + final int user = UserHandle.getUserId(uid); + int vpnNetId = NETID_UNSET; + synchronized (mVpns) { + final Vpn vpn = mVpns.get(user); + if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId(); + } + NetworkAgentInfo nai; + if (vpnNetId != NETID_UNSET) { + synchronized (mNetworkForNetId) { + nai = mNetworkForNetId.get(vpnNetId); + } + if (nai != null) return nai.network; + } + nai = getDefaultNetwork(); + if (nai != null && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) nai = null; + return nai != null ? nai.network : null; + } + /** * Find the first Provisioning network. * @@ -1942,6 +1965,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai != null) { synchronized (mNetworkForNetId) { mNetworkForNetId.remove(nai.network.netId); + mNetIdInUse.delete(nai.network.netId); } // Just in case. mLegacyTypeTracker.remove(nai); @@ -1985,6 +2009,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mLegacyTypeTracker.remove(nai); synchronized (mNetworkForNetId) { mNetworkForNetId.remove(nai.network.netId); + mNetIdInUse.delete(nai.network.netId); } // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. @@ -3369,14 +3394,23 @@ public class ConnectivityService extends IConnectivityManager.Stub * and the are the highest scored network available. * the are keyed off the Requests requestId. */ + // TODO: Yikes, this is accessed on multiple threads: add synchronization. private final SparseArray mNetworkForRequestId = new SparseArray(); + // NOTE: Accessed on multiple threads, must be synchronized on itself. + @GuardedBy("mNetworkForNetId") private final SparseArray mNetworkForNetId = new SparseArray(); + // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId. + // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so + // there may not be a strict 1:1 correlation between the two. + @GuardedBy("mNetworkForNetId") + private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray(); // NetworkAgentInfo keyed off its connecting messenger // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays + // NOTE: Only should be accessed on ConnectivityServiceThread, except dump(). private final HashMap mNetworkAgentInfos = new HashMap(); @@ -3391,7 +3425,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return nai == getDefaultNetwork(); } - public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) { enforceConnectivityInternalPermission(); @@ -3399,20 +3433,23 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network // satisfies mDefaultRequest. NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), - new NetworkInfo(networkInfo), new LinkProperties(linkProperties), - new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler, - new NetworkMisc(networkMisc), mDefaultRequest); + new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties( + linkProperties), new NetworkCapabilities(networkCapabilities), currentScore, + mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest); synchronized (this) { nai.networkMonitor.systemReady = mSystemReady; } if (DBG) log("registerNetworkAgent " + nai); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); + return nai.network.netId; } private void handleRegisterNetworkAgent(NetworkAgentInfo na) { if (VDBG) log("Got NetworkAgent Messenger"); mNetworkAgentInfos.put(na.messenger, na); - assignNextNetId(na); + synchronized (mNetworkForNetId) { + mNetworkForNetId.put(na.network.netId, na); + } na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); NetworkInfo networkInfo = na.networkInfo; na.networkInfo = null; diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index f3e0bbc573..2d1f939eb8 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -40,7 +40,10 @@ import java.util.ArrayList; */ public class NetworkAgentInfo { public NetworkInfo networkInfo; - public Network network; + // This Network object should always be used if possible, so as to encourage reuse of the + // enclosed socket factory and connection pool. Avoid creating other Network objects. + // This Network object is always valid. + public final Network network; public LinkProperties linkProperties; public NetworkCapabilities networkCapabilities; public final NetworkMonitor networkMonitor; @@ -83,12 +86,12 @@ public class NetworkAgentInfo { // Used by ConnectivityService to keep track of 464xlat. public Nat464Xlat clatd; - public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, NetworkInfo info, + public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, NetworkMisc misc, NetworkRequest defaultRequest) { this.messenger = messenger; asyncChannel = ac; - network = null; + network = net; networkInfo = info; linkProperties = lp; networkCapabilities = nc;