Merge "Remember to cancel lingering when a network again satsifies a NetworkRequest." into lmp-mr1-dev
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ff1a441..4fe418a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,7 +100,7 @@
 
     /**
      * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any
-     * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
+     * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
      *
      * @hide
      */
@@ -428,18 +428,6 @@
     public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
 
     /**
-     * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in
-     * milliseconds.  This was introduced because IPv6 routes seem to take a
-     * moment to settle - trying network activity before the routes are adjusted
-     * can lead to packets using the wrong interface or having the wrong IP address.
-     * This delay is a bit crude, but in the future hopefully we will have kernel
-     * notifications letting us know when it's safe to use the new network.
-     *
-     * @hide
-     */
-    public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000;
-
-    /**
      * @hide
      */
     public final static int REQUEST_ID_UNSET = 0;
@@ -721,6 +709,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 fe6cb70..0f1ed0a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -797,17 +797,6 @@
         throw new IllegalStateException("No free netIds");
     }
 
-    private int getConnectivityChangeDelay() {
-        final ContentResolver cr = mContext.getContentResolver();
-
-        /** Check system properties for the default value then use secure settings value, if any. */
-        int defaultDelay = SystemProperties.getInt(
-                "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY,
-                ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT);
-        return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY,
-                defaultDelay);
-    }
-
     private boolean teardown(NetworkStateTracker netTracker) {
         if (netTracker.teardown()) {
             netTracker.setTeardownRequested(true);
@@ -1065,6 +1054,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();
@@ -1413,11 +1468,6 @@
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
 
-    private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) {
-        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
-        sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
-    }
-
     private void sendInetConditionBroadcast(NetworkInfo info) {
         sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
     }
@@ -1449,10 +1499,6 @@
         sendStickyBroadcast(makeGeneralIntent(info, bcastType));
     }
 
-    private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) {
-        sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
-    }
-
     private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
         Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
         intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
@@ -1486,19 +1532,6 @@
         }
     }
 
-    private void sendStickyBroadcastDelayed(Intent intent, int delayMs) {
-        if (delayMs <= 0) {
-            sendStickyBroadcast(intent);
-        } else {
-            if (VDBG) {
-                log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action="
-                        + intent.getAction());
-            }
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(
-                    EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs);
-        }
-    }
-
     void systemReady() {
         // start network sampling ..
         Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
@@ -3544,8 +3577,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,
@@ -4231,7 +4268,7 @@
         info.setType(type);
         if (connected) {
             info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo());
-            sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
+            sendConnectedBroadcast(info);
         } else {
             info.setDetailedState(DetailedState.DISCONNECTED, null, info.getExtraInfo());
             Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -4262,10 +4299,9 @@
             final Intent immediateIntent = new Intent(intent);
             immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
             sendStickyBroadcast(immediateIntent);
-            sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
+            sendStickyBroadcast(intent);
             if (newDefaultAgent != null) {
-                sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
-                getConnectivityChangeDelay());
+                sendConnectedBroadcast(newDefaultAgent.networkInfo);
             }
         }
     }