OSDN Git Service

Implement ConnectivityManager.reportBadNetwork() to trigger network validation.
authorPaul Jensen <pauljensen@google.com>
Fri, 29 Aug 2014 13:54:01 +0000 (09:54 -0400)
committerPaul Jensen <pauljensen@google.com>
Thu, 4 Sep 2014 16:02:52 +0000 (12:02 -0400)
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

services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
services/core/java/com/android/server/connectivity/NetworkMonitor.java

index ad8f446..109c2ee 100644 (file)
@@ -793,14 +793,28 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     }
 
     /**
-     * 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 @@ public class ConnectivityService extends IConnectivityManager.Stub {
      * 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 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         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 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         synchronized (nai) {
             if (nai.networkInfo == null) return null;
 
-            return getFilteredNetworkInfo(nai.networkInfo, nai.networkInfo.getType(), uid);
+            return getFilteredNetworkInfo(nai, uid);
         }
     }
 
@@ -1304,6 +1337,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
 //        }
     }
 
+    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 class ConnectivityService extends IConnectivityManager.Stub {
     }
 
     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 @@ public class ConnectivityService extends IConnectivityManager.Stub {
             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());
index 5a97aee..bba786d 100644 (file)
@@ -47,6 +47,7 @@ public class NetworkAgentInfo {
     public final NetworkMonitor networkMonitor;
     public final NetworkMisc networkMisc;
     public boolean created;
+    public boolean validated;
 
     // The list of NetworkRequests being satisfied by this Network.
     public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
@@ -68,6 +69,7 @@ public class NetworkAgentInfo {
         networkMonitor = new NetworkMonitor(context, handler, this);
         networkMisc = misc;
         created = false;
+        validated = false;
     }
 
     public void addRequest(NetworkRequest networkRequest) {
index cedf573..2d8adc1 100644 (file)
@@ -26,6 +26,7 @@ import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
+import android.net.TrafficStats;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
@@ -139,34 +140,28 @@ public class NetworkMonitor extends StateMachine {
     private static final int CMD_REEVALUATE = BASE + 6;
 
     /**
-     * Message to self indicating network evaluation is complete.
-     * arg1 = Token to ignore old messages.
-     * arg2 = HTTP response code of network evaluation.
-     */
-    private static final int EVENT_REEVALUATION_COMPLETE = BASE + 7;
-
-    /**
      * Inform NetworkMonitor that the network has disconnected.
      */
-    public static final int CMD_NETWORK_DISCONNECTED = BASE + 8;
+    public static final int CMD_NETWORK_DISCONNECTED = BASE + 7;
 
     /**
      * Force evaluation even if it has succeeded in the past.
+     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
      */
-    public static final int CMD_FORCE_REEVALUATION = BASE + 9;
+    public static final int CMD_FORCE_REEVALUATION = BASE + 8;
 
     /**
      * Message to self indicating captive portal login is complete.
      * arg1 = Token to ignore old messages.
      * arg2 = 1 if we should use this network, 0 otherwise.
      */
-    private static final int CMD_CAPTIVE_PORTAL_LOGGED_IN = BASE + 10;
+    private static final int CMD_CAPTIVE_PORTAL_LOGGED_IN = BASE + 9;
 
     /**
      * Message to self indicating user desires to log into captive portal.
      * arg1 = Token to ignore old messages.
      */
-    private static final int CMD_USER_WANTS_SIGN_IN = BASE + 11;
+    private static final int CMD_USER_WANTS_SIGN_IN = BASE + 10;
 
     /**
      * Request ConnectivityService display provisioning notification.
@@ -174,22 +169,22 @@ public class NetworkMonitor extends StateMachine {
      * arg2    = NetID.
      * obj     = Intent to be launched when notification selected by user, null if !arg1.
      */
-    public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 12;
+    public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 11;
 
     /**
      * Message to self indicating sign-in app bypassed captive portal.
      */
-    private static final int EVENT_APP_BYPASSED_CAPTIVE_PORTAL = BASE + 13;
+    private static final int EVENT_APP_BYPASSED_CAPTIVE_PORTAL = BASE + 12;
 
     /**
      * Message to self indicating no sign-in app responded.
      */
-    private static final int EVENT_NO_APP_RESPONSE = BASE + 14;
+    private static final int EVENT_NO_APP_RESPONSE = BASE + 13;
 
     /**
      * Message to self indicating sign-in app indicates sign-in is not possible.
      */
-    private static final int EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLE = BASE + 15;
+    private static final int EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLE = BASE + 14;
 
     private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
     // Default to 30s linger time-out.
@@ -204,6 +199,8 @@ public class NetworkMonitor extends StateMachine {
     private static final int MAX_RETRIES = 10;
     private final int mReevaluateDelayMs;
     private int mReevaluateToken = 0;
+    private static final int INVALID_UID = -1;
+    private int mUidResponsibleForReeval = INVALID_UID;
 
     private int mCaptivePortalLoggedInToken = 0;
     private int mUserPromptedToken = 0;
@@ -279,6 +276,7 @@ public class NetworkMonitor extends StateMachine {
                     return HANDLED;
                 case CMD_FORCE_REEVALUATION:
                     if (DBG) log("Forcing reevaluation");
+                    mUidResponsibleForReeval = message.arg1;
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 default:
@@ -319,20 +317,14 @@ public class NetworkMonitor extends StateMachine {
     private class EvaluatingState extends State {
         private int mRetries;
 
-        private class EvaluateInternetConnectivity extends Thread {
-            private int mToken;
-            EvaluateInternetConnectivity(int token) {
-                mToken = token;
-            }
-            public void run() {
-                sendMessage(EVENT_REEVALUATION_COMPLETE, mToken, isCaptivePortal());
-            }
-        }
-
         @Override
         public void enter() {
             mRetries = 0;
             sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+            if (mUidResponsibleForReeval != INVALID_UID) {
+                TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
+                mUidResponsibleForReeval = INVALID_UID;
+            }
         }
 
         @Override
@@ -353,14 +345,7 @@ public class NetworkMonitor extends StateMachine {
                         transitionTo(mValidatedState);
                         return HANDLED;
                     }
-                    // Kick off a thread to perform internet connectivity evaluation.
-                    Thread thread = new EvaluateInternetConnectivity(mReevaluateToken);
-                    thread.run();
-                    return HANDLED;
-                case EVENT_REEVALUATION_COMPLETE:
-                    if (message.arg1 != mReevaluateToken)
-                        return HANDLED;
-                    int httpResponseCode = message.arg2;
+                    int httpResponseCode = isCaptivePortal();
                     if (httpResponseCode == 204) {
                         transitionTo(mValidatedState);
                     } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
@@ -372,10 +357,18 @@ public class NetworkMonitor extends StateMachine {
                         sendMessageDelayed(msg, mReevaluateDelayMs);
                     }
                     return HANDLED;
+                case CMD_FORCE_REEVALUATION:
+                    // Ignore duplicate requests.
+                    return HANDLED;
                 default:
                     return NOT_HANDLED;
             }
         }
+
+        @Override
+        public void exit() {
+            TrafficStats.clearThreadStatsUid();
+        }
     }
 
     private class UserPromptedState extends State {