From 7ccd3dfd53d8d45c447398ff137f052865dfd3b3 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Fri, 29 Aug 2014 09:54:01 -0400 Subject: [PATCH] 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 --- .../android/server/ConnectivityService.java | 66 +++++++++++++++++-- .../server/connectivity/NetworkAgentInfo.java | 2 + .../server/connectivity/NetworkMonitor.java | 59 ++++++++--------- 3 files changed, 89 insertions(+), 38 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ad8f446f31c01..109c2eef2cd0c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -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()); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 5a97aee9729c9..bba786dc5d9b0 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -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 networkRequests = new SparseArray(); @@ -68,6 +69,7 @@ public class NetworkAgentInfo { networkMonitor = new NetworkMonitor(context, handler, this); networkMisc = misc; created = false; + validated = false; } public void addRequest(NetworkRequest networkRequest) { diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index cedf5739a60ef..2d8adc1ec4868 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -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; @@ -138,35 +139,29 @@ 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 {