From 79bd2e2841d1f98e00f8f6edc15ad81d31e9bddf Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 28 Nov 2014 11:21:30 +0900 Subject: [PATCH] Make StatusBar display all default networks. The basic principle is: if an app's traffic could possibly go over a network without the app using the multinetwork APIs (hence "by default"), then the status bar should show that network's connectivity. In the normal case, app traffic only goes over the system's default network connection, so that's the only network returned. With a VPN in force, some app traffic may go into the VPN, and thus over whatever underlying networks the VPN specifies, while other app traffic may go over the system default network (e.g.: a split-tunnel VPN, or an app disallowed by the VPN), so the set of networks returned includes the VPN's underlying networks and the system default. Specifically: 1. Add a NETWORK_CAPABILITY_VALIDATED bit to NetworkCapabilities. 2. Add a hidden API to retrieve the NetworkCapabilities of all default networks for a given macro-user. 3. Modify the status bar code that used getActiveNetworkInfo to determine which network was active, and make it consider all validated networks instead. 4. Because the set of active networks depends on which VPN app the user is running, make the status bar re-evaluate the networking situation when the active user changes. Bug: 17460017 Change-Id: Ie4965f35fb5936b088e6060ee06e362c22297ab2 --- .../java/android/net/ConnectivityManager.java | 13 ++++ .../android/net/IConnectivityManager.aidl | 1 + .../java/android/net/NetworkCapabilities.java | 9 ++- .../android/server/ConnectivityService.java | 72 ++++++++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index ff1a4414eb..4215f207ea 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -720,6 +720,19 @@ public class ConnectivityManager { } } + /** + * Returns an array of of {@link NetworkCapabilities} objects, representing + * the Networks that applications run by the given user will use by default. + * @hide + */ + public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { + try { + return mService.getDefaultNetworkCapabilitiesForUser(userId); + } catch (RemoteException e) { + return null; + } + } + /** * Returns details about the Provisioning or currently active default data network. When * connected, this network is the default route for outgoing connections. diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 79f920e0c2..802121093a 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -49,6 +49,7 @@ interface IConnectivityManager NetworkInfo[] getAllNetworkInfo(); Network getNetworkForType(int networkType); Network[] getAllNetworks(); + NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId); NetworkInfo getProvisioningOrActiveNetworkInfo(); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index ce7ad65fef..a7f9c5bcc0 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -154,9 +154,16 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_NOT_VPN = 15; + /** + * Indicates that connectivity on this network was successfully validated. For example, for a + * network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully + * detected. + * @hide + */ + public static final int NET_CAPABILITY_VALIDATED = 16; private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VPN; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_VALIDATED; /** * Adds the given capability to this {@code NetworkCapability} instance. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5eec0b7692..c5af085d87 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1065,6 +1065,72 @@ public class ConnectivityService extends IConnectivityManager.Stub return result.toArray(new Network[result.size()]); } + private NetworkCapabilities getNetworkCapabilitiesAndValidation(NetworkAgentInfo nai) { + if (nai != null) { + synchronized (nai) { + if (nai.created) { + NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities); + if (nai.validated) { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + } else { + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + } + return nc; + } + } + } + return null; + } + + @Override + public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { + // The basic principle is: if an app's traffic could possibly go over a + // network, without the app doing anything multinetwork-specific, + // (hence, by "default"), then include that network's capabilities in + // the array. + // + // In the normal case, app traffic only goes over the system's default + // network connection, so that's the only network returned. + // + // With a VPN in force, some app traffic may go into the VPN, and thus + // over whatever underlying networks the VPN specifies, while other app + // traffic may go over the system default network (e.g.: a split-tunnel + // VPN, or an app disallowed by the VPN), so the set of networks + // returned includes the VPN's underlying networks and the system + // default. + enforceAccessPermission(); + + HashMap result = new HashMap(); + + NetworkAgentInfo nai = getDefaultNetwork(); + NetworkCapabilities nc = getNetworkCapabilitiesAndValidation(getDefaultNetwork()); + if (nc != null) { + result.put(nai.network, nc); + } + + if (!mLockdownEnabled) { + synchronized (mVpns) { + Vpn vpn = mVpns.get(userId); + if (vpn != null) { + Network[] networks = vpn.getUnderlyingNetworks(); + if (networks != null) { + for (Network network : networks) { + nai = getNetworkAgentInfoForNetwork(network); + nc = getNetworkCapabilitiesAndValidation(nai); + if (nc != null) { + result.put(nai.network, nc); + } + } + } + } + } + } + + NetworkCapabilities[] out = new NetworkCapabilities[result.size()]; + out = result.values().toArray(out); + return out; + } + @Override public boolean isNetworkSupported(int networkType) { enforceAccessPermission(); @@ -3544,8 +3610,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated. private final NetworkRequest mDefaultRequest; + private NetworkAgentInfo getDefaultNetwork() { + return mNetworkForRequestId.get(mDefaultRequest.requestId); + } + private boolean isDefaultNetwork(NetworkAgentInfo nai) { - return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai; + return nai == getDefaultNetwork(); } public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,