Make getNetworkInfo() take into account VPN underlying networks.

If a user is subject to a VPN, getActiveNetworkInfo() will return
the VPN's underlying network (e.g., TYPE_WIFI), so that apps that
call getActiveNetworkInfo to answer questions like "is the device
connected to wifi?" will continue to work. Make getNetworkInfo
do this as well: if the query is for a network type that is
underlying the current user's VPN, then return that network.

Bug: 19196545
Change-Id: Ic5a651735b927c758594a26d26a03fbd704b52e6
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 944f1c0..551a5dc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -832,6 +832,19 @@
         }
     };
 
+    private Network[] getVpnUnderlyingNetworks(int uid) {
+        if (!mLockdownEnabled) {
+            int user = UserHandle.getUserId(uid);
+            synchronized (mVpns) {
+                Vpn vpn = mVpns.get(user);
+                if (vpn != null && vpn.appliesToUid(uid)) {
+                    return vpn.getUnderlyingNetworks();
+                }
+            }
+        }
+        return null;
+    }
+
     private NetworkState getUnfilteredActiveNetworkState(int uid) {
         NetworkInfo info = null;
         LinkProperties lp = null;
@@ -841,25 +854,17 @@
 
         NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId);
 
-        if (!mLockdownEnabled) {
-            int user = UserHandle.getUserId(uid);
-            synchronized (mVpns) {
-                Vpn vpn = mVpns.get(user);
-                if (vpn != null && vpn.appliesToUid(uid)) {
-                    // getUnderlyingNetworks() returns:
-                    // null => the VPN didn't specify anything, so we use the default.
-                    // empty array => the VPN explicitly said "no default network".
-                    // non-empty array => the VPN specified one or more default networks; we use the
-                    //                    first one.
-                    Network[] networks = vpn.getUnderlyingNetworks();
-                    if (networks != null) {
-                        if (networks.length > 0) {
-                            nai = getNetworkAgentInfoForNetwork(networks[0]);
-                        } else {
-                            nai = null;
-                        }
-                    }
-                }
+        final Network[] networks = getVpnUnderlyingNetworks(uid);
+        if (networks != null) {
+            // getUnderlyingNetworks() returns:
+            // null => there was no VPN, or the VPN didn't specify anything, so we use the default.
+            // empty array => the VPN explicitly said "no default network".
+            // non-empty array => the VPN specified one or more default networks; we use the
+            //                    first one.
+            if (networks.length > 0) {
+                nai = getNetworkAgentInfoForNetwork(networks[0]);
+            } else {
+                nai = null;
             }
         }
 
@@ -990,6 +995,15 @@
     public NetworkInfo getNetworkInfo(int networkType) {
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
+        if (getVpnUnderlyingNetworks(uid) != null) {
+            // A VPN is active, so we may need to return one of its underlying networks. This
+            // information is not available in LegacyTypeTracker, so we have to get it from
+            // getUnfilteredActiveNetworkState.
+            NetworkState state = getUnfilteredActiveNetworkState(uid);
+            if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
+                return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+            }
+        }
         NetworkState state = getFilteredNetworkState(networkType, uid);
         return state.networkInfo;
     }