From e252a740ca6323c5497cab2b1ed277572304c9fc Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 12 Mar 2019 13:08:03 +0800 Subject: [PATCH] Check if network has partial connectivity In some networks, network validation may only get success result for http probe but fail result for https probe. For this kind of network, it may still work at some websites or apps, but user didn't know about that. In order to fix this issue, we will check if network has partial connectivity and notify user to make a choice if they want to use this partial connectivity or not. Bug: 113450764 Test: 1. Build pass. 2. Fake partial connectivity case for testing. 3. atest FrameworksNetTests 4. atest NetworkStackTests Change-Id: I69ed00ac4850904ff708c9fef22e148879a10e92 --- api/system-current.txt | 4 + api/test-current.txt | 3 + .../java/android/net/ConnectivityManager.java | 37 ++++- .../android/net/IConnectivityManager.aidl | 1 + core/java/android/net/INetworkMonitor.aidl | 7 + .../java/android/net/NetworkCapabilities.java | 83 +++++---- core/java/android/net/NetworkMisc.java | 6 + .../CaptivePortalProbeResult.java | 14 ++ .../android/net/metrics/NetworkEvent.java | 3 + core/res/res/values/strings.xml | 7 +- core/res/res/values/symbols.xml | 2 + .../android/server/NetworkStackService.java | 6 + .../server/connectivity/NetworkMonitor.java | 40 ++++- .../connectivity/NetworkMonitorTest.java | 33 ++++ proto/src/system_messages.proto | 2 + .../android/server/ConnectivityService.java | 157 ++++++++++++++++-- .../server/connectivity/NetworkAgentInfo.java | 7 + .../NetworkNotificationManager.java | 18 +- .../android/net/NetworkCapabilitiesTest.java | 20 +++ .../server/ConnectivityServiceTest.java | 113 +++++++++++++ 20 files changed, 510 insertions(+), 53 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 1d6b595bc9661..b89a1da22ca27 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3193,6 +3193,7 @@ package android.net { method public int[] getTransportTypes(); method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities); field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16 + field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18 } public class NetworkKey implements android.os.Parcelable { @@ -3341,10 +3342,12 @@ package android.net.captiveportal { ctor public CaptivePortalProbeResult(int, String, String); ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec); method public boolean isFailed(); + method public boolean isPartialConnectivity(); method public boolean isPortal(); method public boolean isSuccessful(); field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED; field public static final int FAILED_CODE = 599; // 0x257 + field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL; field public static final int PORTAL_CODE = 302; // 0x12e field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS; field public static final int SUCCESS_CODE = 204; // 0xcc @@ -3476,6 +3479,7 @@ package android.net.metrics { field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8 field public static final int NETWORK_LINGER = 5; // 0x5 + field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9 field public static final int NETWORK_UNLINGER = 6; // 0x6 diff --git a/api/test-current.txt b/api/test-current.txt index 055066337da5c..d43b1c4ec275c 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -751,10 +751,12 @@ package android.net.captiveportal { ctor public CaptivePortalProbeResult(int, String, String); ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec); method public boolean isFailed(); + method public boolean isPartialConnectivity(); method public boolean isPortal(); method public boolean isSuccessful(); field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED; field public static final int FAILED_CODE = 599; // 0x257 + field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL; field public static final int PORTAL_CODE = 302; // 0x12e field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS; field public static final int SUCCESS_CODE = 204; // 0xcc @@ -886,6 +888,7 @@ package android.net.metrics { field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8 field public static final int NETWORK_LINGER = 5; // 0x5 + field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9 field public static final int NETWORK_UNLINGER = 6; // 0x6 diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 249357e3633d7..91fefa2f1cb09 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -426,6 +426,16 @@ public class ConnectivityManager { public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.conn.PROMPT_LOST_VALIDATION"; + /** + * Action used to display a dialog that asks the user whether to stay connected to a network + * that has not validated. This intent is used to start the dialog in settings via + * startActivity. + * + * @hide + */ + public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = + "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY"; + /** * Invalid tethering type. * @see #startTethering(int, boolean, OnStartTetheringCallback) @@ -4018,7 +4028,7 @@ public class ConnectivityManager { * * @hide */ - @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { try { mService.setAcceptUnvalidated(network, accept, always); @@ -4027,6 +4037,29 @@ public class ConnectivityManager { } } + /** + * Informs the system whether it should consider the network as validated even if it only has + * partial connectivity. If {@code accept} is true, then the network will be considered as + * validated even if connectivity is only partial. If {@code always} is true, then the choice + * is remembered, so that the next time the user connects to this network, the system will + * switch to it. + * + * @param network The network to accept. + * @param accept Whether to consider the network as validated even if it has partial + * connectivity. + * @param always Whether to remember this choice in the future. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) { + try { + mService.setAcceptPartialConnectivity(network, accept, always); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is * only meaningful if the system is configured not to penalize such networks, e.g., if the @@ -4037,7 +4070,7 @@ public class ConnectivityManager { * * @hide */ - @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAvoidUnvalidated(Network network) { try { mService.setAvoidUnvalidated(network); diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 9fc56b4e3d36b..2df4e75c49a42 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -176,6 +176,7 @@ interface IConnectivityManager void releaseNetworkRequest(in NetworkRequest networkRequest); void setAcceptUnvalidated(in Network network, boolean accept, boolean always); + void setAcceptPartialConnectivity(in Network network, boolean accept, boolean always); void setAvoidUnvalidated(in Network network); void startCaptivePortalApp(in Network network); void startCaptivePortalAppInternal(in Network network, in Bundle appExtras); diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl index c94cdde15aa8c..5d1ab983c5fcd 100644 --- a/core/java/android/net/INetworkMonitor.aidl +++ b/core/java/android/net/INetworkMonitor.aidl @@ -32,9 +32,16 @@ oneway interface INetworkMonitor { // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed). const int NETWORK_TEST_RESULT_INVALID = 1; + // After a network has been tested, this result can be sent with EVENT_NETWORK_TESTED. + // The network may be used as a default internet connection, but it was found to be a partial + // connectivity network which can get the pass result for http probe but get the failed result + // for https probe. + const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2; + void start(); void launchCaptivePortalApp(); void notifyCaptivePortalAppFinished(int response); + void notifyAcceptPartialConnectivity(); void forceReevaluation(int uid); void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config); void notifyDnsResponse(int returnCode); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 0a63e75d1a310..e1cfe991de8da 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -143,7 +143,8 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_NOT_CONGESTED, NET_CAPABILITY_NOT_SUSPENDED, NET_CAPABILITY_OEM_PAID, - NET_CAPABILITY_MCX + NET_CAPABILITY_MCX, + NET_CAPABILITY_PARTIAL_CONNECTIVITY, }) public @interface NetCapability { } @@ -304,8 +305,15 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_MCX = 23; + /** + * Indicates that this network was tested to only provide partial connectivity. + * @hide + */ + @SystemApi + public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_MCX; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_PARTIAL_CONNECTIVITY; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -320,7 +328,8 @@ public final class NetworkCapabilities implements Parcelable { | (1 << NET_CAPABILITY_NOT_ROAMING) | (1 << NET_CAPABILITY_FOREGROUND) | (1 << NET_CAPABILITY_NOT_CONGESTED) - | (1 << NET_CAPABILITY_NOT_SUSPENDED); + | (1 << NET_CAPABILITY_NOT_SUSPENDED) + | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY); /** * Network capabilities that are not allowed in NetworkRequests. This exists because the @@ -374,6 +383,15 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_SUPL) | (1 << NET_CAPABILITY_WIFI_P2P); + /** + * Capabilities that are managed by ConnectivityService. + */ + private static final long CONNECTIVITY_MANAGED_CAPABILITIES = + (1 << NET_CAPABILITY_VALIDATED) + | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) + | (1 << NET_CAPABILITY_FOREGROUND) + | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY); + /** * Adds the given capability to this {@code NetworkCapability} instance. * Multiple capabilities may be applied sequentially. Note that when searching @@ -507,6 +525,14 @@ public final class NetworkCapabilities implements Parcelable { && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0); } + /** + * Check if this NetworkCapabilities has system managed capabilities or not. + * @hide + */ + public boolean hasConnectivityManagedCapability() { + return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0); + } + /** Note this method may result in having the same capability in wanted and unwanted lists. */ private void combineNetCapabilities(NetworkCapabilities nc) { this.mNetworkCapabilities |= nc.mNetworkCapabilities; @@ -1599,31 +1625,32 @@ public final class NetworkCapabilities implements Parcelable { */ public static String capabilityNameOf(@NetCapability int capability) { switch (capability) { - case NET_CAPABILITY_MMS: return "MMS"; - case NET_CAPABILITY_SUPL: return "SUPL"; - case NET_CAPABILITY_DUN: return "DUN"; - case NET_CAPABILITY_FOTA: return "FOTA"; - case NET_CAPABILITY_IMS: return "IMS"; - case NET_CAPABILITY_CBS: return "CBS"; - case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P"; - case NET_CAPABILITY_IA: return "IA"; - case NET_CAPABILITY_RCS: return "RCS"; - case NET_CAPABILITY_XCAP: return "XCAP"; - case NET_CAPABILITY_EIMS: return "EIMS"; - case NET_CAPABILITY_NOT_METERED: return "NOT_METERED"; - case NET_CAPABILITY_INTERNET: return "INTERNET"; - case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED"; - case NET_CAPABILITY_TRUSTED: return "TRUSTED"; - case NET_CAPABILITY_NOT_VPN: return "NOT_VPN"; - case NET_CAPABILITY_VALIDATED: return "VALIDATED"; - case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; - case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING"; - case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; - case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; - case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; - case NET_CAPABILITY_OEM_PAID: return "OEM_PAID"; - case NET_CAPABILITY_MCX: return "MCX"; - default: return Integer.toString(capability); + case NET_CAPABILITY_MMS: return "MMS"; + case NET_CAPABILITY_SUPL: return "SUPL"; + case NET_CAPABILITY_DUN: return "DUN"; + case NET_CAPABILITY_FOTA: return "FOTA"; + case NET_CAPABILITY_IMS: return "IMS"; + case NET_CAPABILITY_CBS: return "CBS"; + case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P"; + case NET_CAPABILITY_IA: return "IA"; + case NET_CAPABILITY_RCS: return "RCS"; + case NET_CAPABILITY_XCAP: return "XCAP"; + case NET_CAPABILITY_EIMS: return "EIMS"; + case NET_CAPABILITY_NOT_METERED: return "NOT_METERED"; + case NET_CAPABILITY_INTERNET: return "INTERNET"; + case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED"; + case NET_CAPABILITY_TRUSTED: return "TRUSTED"; + case NET_CAPABILITY_NOT_VPN: return "NOT_VPN"; + case NET_CAPABILITY_VALIDATED: return "VALIDATED"; + case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL"; + case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING"; + case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; + case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; + case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; + case NET_CAPABILITY_OEM_PAID: return "OEM_PAID"; + case NET_CAPABILITY_MCX: return "MCX"; + case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY"; + default: return Integer.toString(capability); } } diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java index c0487b521b466..6fb239015aee4 100644 --- a/core/java/android/net/NetworkMisc.java +++ b/core/java/android/net/NetworkMisc.java @@ -51,6 +51,12 @@ public class NetworkMisc implements Parcelable { */ public boolean acceptUnvalidated; + /** + * Whether the user explicitly set that this network should be validated even if presence of + * only partial internet connectivity. + */ + public boolean acceptPartialConnectivity; + /** * Set to avoid surfacing the "Sign in to network" notification. * if carrier receivers/apps are registered to handle the carrier-specific provisioning diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java index 7432687e136f6..3930344e5d27b 100644 --- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java +++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java @@ -30,10 +30,20 @@ public final class CaptivePortalProbeResult { public static final int SUCCESS_CODE = 204; public static final int FAILED_CODE = 599; public static final int PORTAL_CODE = 302; + // Set partial connectivity http response code to -1 to prevent conflict with the other http + // response codes. Besides the default http response code of probe result is set as 599 in + // NetworkMonitor#sendParallelHttpProbes(), so response code will be set as -1 only when + // NetworkMonitor detects partial connectivity. + /** + * @hide + */ + public static final int PARTIAL_CODE = -1; public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE); public static final CaptivePortalProbeResult SUCCESS = new CaptivePortalProbeResult(SUCCESS_CODE); + public static final CaptivePortalProbeResult PARTIAL = + new CaptivePortalProbeResult(PARTIAL_CODE); private final int mHttpResponseCode; // HTTP response code returned from Internet probe. public final String redirectUrl; // Redirect destination returned from Internet probe. @@ -69,4 +79,8 @@ public final class CaptivePortalProbeResult { public boolean isFailed() { return !isSuccessful() && !isPortal(); } + + public boolean isPartialConnectivity() { + return mHttpResponseCode == PARTIAL_CODE; + } } diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java index f5b2ff1304949..5128115800217 100644 --- a/core/java/android/net/metrics/NetworkEvent.java +++ b/core/java/android/net/metrics/NetworkEvent.java @@ -50,6 +50,8 @@ public final class NetworkEvent implements IpConnectivityLog.Event { public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; + public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; + /** @hide */ @IntDef(value = { NETWORK_CONNECTED, @@ -64,6 +66,7 @@ public final class NetworkEvent implements IpConnectivityLog.Event { NETWORK_FIRST_VALIDATION_PORTAL_FOUND, NETWORK_REVALIDATION_PORTAL_FOUND, NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND, + NETWORK_PARTIAL_CONNECTIVITY, }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index b412f0fdb9b5f..b4e69adc119ce 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3197,13 +3197,18 @@ %1$s - Wi-Fi has no internet access + %1$s has no internet access Tap for options Connected + + %1$s has limited connectivity + + + Tap to connect anyway