Implement ConnectivityManager.reportBadNetwork() to trigger network validation.

Network traffic used to perform the network validation is billed to the UID of
the caller of reportBadNetwork.  This change does not change the actions taken
upon validation failing or succeeding:  NetworkMonitor will show the sign-in
notification if a captive portal is found.  NetworkMonitor will inform
ConnectivityService if a network tests functional.  NetworkMonitor will not
take action if a network lacks any connectivity.
Also, remove an unused Thread that was confusing bandwidth billing.

bug:17326268
Change-Id: I7fea23480af54211004a0a1c535a71c2793f21bb
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ad8f446..109c2ee 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -793,14 +793,28 @@
     }
 
     /**
-     * Check if UID should be blocked from using the network represented by the
-     * given {@link NetworkStateTracker}.
+     * Check if UID should be blocked from using the network represented by the given networkType.
+     * @deprecated Uses mLegacyTypeTracker; cannot deal with multiple Networks of the same type.
      */
     private boolean isNetworkBlocked(int networkType, int uid) {
+        return isNetworkWithLinkPropertiesBlocked(getLinkPropertiesForType(networkType), uid);
+    }
+
+    /**
+     * Check if UID should be blocked from using the network represented by the given
+     * NetworkAgentInfo.
+     */
+    private boolean isNetworkBlocked(NetworkAgentInfo nai, int uid) {
+        return isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid);
+    }
+
+    /**
+     * Check if UID should be blocked from using the network with the given LinkProperties.
+     */
+    private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid) {
         final boolean networkCostly;
         final int uidRules;
 
-        LinkProperties lp = getLinkPropertiesForType(networkType);
         final String iface = (lp == null ? "" : lp.getInterfaceName());
         synchronized (mRulesLock) {
             networkCostly = mMeteredIfaces.contains(iface);
@@ -819,12 +833,16 @@
      * Return a filtered {@link NetworkInfo}, potentially marked
      * {@link DetailedState#BLOCKED} based on
      * {@link #isNetworkBlocked}.
+     * @deprecated Uses mLegacyTypeTracker; cannot deal with multiple Networks of the same type.
      */
     private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
         NetworkInfo info = getNetworkInfoForType(networkType);
         return getFilteredNetworkInfo(info, networkType, uid);
     }
 
+    /*
+     * @deprecated Uses mLegacyTypeTracker; cannot deal with multiple Networks of the same type.
+     */
     private NetworkInfo getFilteredNetworkInfo(NetworkInfo info, int networkType, int uid) {
         if (isNetworkBlocked(networkType, uid)) {
             // network is blocked; clone and override state
@@ -839,6 +857,21 @@
         return info;
     }
 
+    private NetworkInfo getFilteredNetworkInfo(NetworkAgentInfo nai, int uid) {
+        NetworkInfo info = nai.networkInfo;
+        if (isNetworkBlocked(nai, uid)) {
+            // network is blocked; clone and override state
+            info = new NetworkInfo(info);
+            info.setDetailedState(DetailedState.BLOCKED, null, null);
+            if (VDBG) log("returning Blocked NetworkInfo");
+        }
+        if (mLockdownTracker != null) {
+            info = mLockdownTracker.augmentNetworkInfo(info);
+            if (VDBG) log("returning Locked NetworkInfo");
+        }
+        return info;
+    }
+
     /**
      * Return NetworkInfo for the active (i.e., connected) network interface.
      * It is assumed that at most one network is active at a time. If more
@@ -946,7 +979,7 @@
         synchronized (nai) {
             if (nai.networkInfo == null) return null;
 
-            return getFilteredNetworkInfo(nai.networkInfo, nai.networkInfo.getType(), uid);
+            return getFilteredNetworkInfo(nai, uid);
         }
     }
 
@@ -1304,6 +1337,12 @@
 //        }
     }
 
+    private void enforceInternetPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.INTERNET,
+                "ConnectivityService");
+    }
+
     private void enforceAccessPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -2443,7 +2482,22 @@
     }
 
     public void reportBadNetwork(Network network) {
-        //TODO
+        enforceAccessPermission();
+        enforceInternetPermission();
+
+        if (network == null) return;
+
+        final int uid = Binder.getCallingUid();
+        NetworkAgentInfo nai = null;
+        synchronized (mNetworkForNetId) {
+            nai = mNetworkForNetId.get(network.netId);
+        }
+        if (nai == null) return;
+        synchronized (nai) {
+            if (isNetworkBlocked(nai, uid)) return;
+
+            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
+        }
     }
 
     public ProxyInfo getProxy() {
@@ -4423,6 +4477,8 @@
             loge("Unknown NetworkAgentInfo in handleConnectionValidated");
             return;
         }
+        if (newNetwork.validated) return;
+        newNetwork.validated = true;
         boolean keep = newNetwork.isVPN();
         boolean isNewDefault = false;
         if (DBG) log("handleConnectionValidated for "+newNetwork.name());