Merge "Reap unvalidated networks that have no chance of becoming highest scoring." into lmp-mr1-dev
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ff1a441..4215f20 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -721,6 +721,19 @@
     }
 
     /**
+     * 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.
      * You should always check {@link NetworkInfo#isConnected()} before initiating
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 79f920e..8021210 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -49,6 +49,7 @@
     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 ce7ad65..a7f9c5b 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -154,9 +154,16 @@
      */
     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 c691499..97d8c2f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1086,6 +1086,72 @@
         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<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
+
+        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();
@@ -1499,6 +1565,17 @@
             }
 
             final long ident = Binder.clearCallingIdentity();
+            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+                final IBatteryStats bs = BatteryStatsService.getService();
+                try {
+                    NetworkInfo ni = intent.getParcelableExtra(
+                            ConnectivityManager.EXTRA_NETWORK_INFO);
+                    bs.noteConnectivityChanged(intent.getIntExtra(
+                            ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
+                            ni != null ? ni.getState().toString() : "?");
+                } catch (RemoteException e) {
+                }
+            }
             try {
                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
             } finally {
@@ -3565,8 +3642,12 @@
     // 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,