Add ConnectivityManager.getActiveNetwork().

Rework NetID allocation in ConnectivityService so registerNetworkAgent() can
return the allocated NetID.

Bug: 19416463
Change-Id: I68e395552cf27422c80b4dfae5db5d56a0d68f5d
This commit is contained in:
Paul Jensen
2015-02-13 14:18:39 -05:00
parent bf18bedced
commit 31a94f48bf
8 changed files with 99 additions and 20 deletions

View File

@ -16955,6 +16955,7 @@ package android.net {
public class ConnectivityManager {
method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean bindProcessToNetwork(android.net.Network);
method public android.net.Network getActiveNetwork();
method public android.net.NetworkInfo getActiveNetworkInfo();
method public android.net.NetworkInfo[] getAllNetworkInfo();
method public android.net.Network[] getAllNetworks();

View File

@ -18216,6 +18216,7 @@ package android.net {
public class ConnectivityManager {
method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean bindProcessToNetwork(android.net.Network);
method public android.net.Network getActiveNetwork();
method public android.net.NetworkInfo getActiveNetworkInfo();
method public android.net.NetworkInfo[] getAllNetworkInfo();
method public android.net.Network[] getAllNetworks();

View File

@ -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
*
* <p>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;
}
}
/**

View File

@ -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,

View File

@ -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);
}

View File

@ -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<NetworkAgentInfo> mNetworkForRequestId =
new SparseArray<NetworkAgentInfo>();
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
new SparseArray<NetworkAgentInfo>();
// 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<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
new HashMap<Messenger, NetworkAgentInfo>();
@ -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;

View File

@ -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;

View File

@ -17,9 +17,10 @@
package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.os.UserHandle.PER_USER_RANGE;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.os.UserHandle.PER_USER_RANGE;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
@ -339,6 +340,10 @@ public class Vpn {
return mNetworkInfo;
}
public int getNetId() {
return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
}
private LinkProperties makeLinkProperties() {
boolean allowIPv4 = mConfig.allowIPv4;
boolean allowIPv6 = mConfig.allowIPv6;