New Settings symbols for captive portal detection
This patch defines new Settings symbols for
- setting the probe urls for captive portal detection.
- setting which User-Agent to use for captive portal detection.
The existing default values for these settings are not changed, i.e:
- HTTP and HTTPS probes urls are unchanged.
- the fallback probe is not used.
- User-Agent is empty by default.
Bug: 29367974
Change-Id: I6e4b3b172e56b8b67fffa4b51f776d68d5851f25
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c9b03cc..3cb46a7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7960,12 +7960,37 @@
/**
* The server used for captive portal detection upon a new conection. A
* 204 response code from the server is used for validation.
+ * TODO: remove this deprecated symbol.
*
* @hide
*/
public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server";
/**
+ * The URL used for HTTPS captive portal detection upon a new connection.
+ * A 204 response code from the server is used for validation.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
+
+ /**
+ * The URL used for HTTP captive portal detection upon a new connection.
+ * A 204 response code from the server is used for validation.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+
+ /**
+ * The URL used for fallback HTTP captive portal detection when previous HTTP
+ * and HTTPS captive portal detection attemps did not return a conclusive answer.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
+
+ /**
* Whether to use HTTPS for network validation. This is enabled by default and the setting
* needs to be set to 0 to disable it. This setting is a misnomer because captive portals
* don't actually use HTTPS, but it's consistent with the other settings.
@@ -7975,6 +8000,14 @@
public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
/**
+ * Which User-Agent string to use in the header of the captive portal detection probes.
+ * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+
+ /**
* Whether network service discovery is enabled.
*
* @hide
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 524c3cc..b7dfd19 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5501,7 +5501,7 @@
@Override
public String getCaptivePortalServerUrl() {
- return NetworkMonitor.getCaptivePortalServerUrl(mContext);
+ return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 01a2cad..13f3174 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -79,11 +79,20 @@
* {@hide}
*/
public class NetworkMonitor extends StateMachine {
- private static final boolean DBG = false;
private static final String TAG = NetworkMonitor.class.getSimpleName();
- private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
+ private static final boolean DBG = false;
+
+ // Default urls for captive portal detection probes
+ private static final String DEFAULT_HTTPS_URL =
+ "https://connectivitycheck.gstatic.com/generate_204";
+ private static final String DEFAULT_HTTP_URL =
+ "http://connectivitycheck.gstatic.com/generate_204";
+ private static final String DEFAULT_FALLBACK_URL = null;
+ private static final String DEFAULT_USER_AGENT = null;
+
private static final int SOCKET_TIMEOUT_MS = 10000;
- private static final int PROBE_TIMEOUT_MS = 3000;
+ private static final int PROBE_TIMEOUT_MS = 3000;
+
public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
"android.net.conn.NETWORK_CONDITIONS_MEASURED";
public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
@@ -596,22 +605,33 @@
}
}
- private static String getCaptivePortalServerUrl(Context context, boolean isHttps) {
- String server = Settings.Global.getString(context.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_SERVER);
- if (server == null) server = DEFAULT_SERVER;
- return (isHttps ? "https" : "http") + "://" + server + "/generate_204";
+ private static String getCaptivePortalServerHttpsUrl(Context context) {
+ return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
}
- public static String getCaptivePortalServerUrl(Context context) {
- return getCaptivePortalServerUrl(context, false);
+ public static String getCaptivePortalServerHttpUrl(Context context) {
+ return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
+ }
+
+ private static String getCaptivePortalFallbackUrl(Context context) {
+ return getSetting(context,
+ Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
+ }
+
+ private static String getCaptivePortalUserAgent(Context context) {
+ return getSetting(context, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
+ }
+
+ private static String getSetting(Context context, String symbol, String defaultValue) {
+ final String value = Settings.Global.getString(context.getContentResolver(), symbol);
+ return value != null ? value : defaultValue;
}
@VisibleForTesting
protected CaptivePortalProbeResult isCaptivePortal() {
if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204);
- URL pacUrl = null, httpUrl = null, httpsUrl = null;
+ URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;
// On networks with a PAC instead of fetching a URL that should result in a 204
// response, we instead simply fetch the PAC script. This is done for a few reasons:
@@ -632,20 +652,17 @@
// results for network validation.
final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
- try {
- pacUrl = new URL(proxyInfo.getPacFileUrl().toString());
- } catch (MalformedURLException e) {
- validationLog("Invalid PAC URL: " + proxyInfo.getPacFileUrl().toString());
+ pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
+ if (pacUrl == null) {
return CaptivePortalProbeResult.FAILED;
}
}
if (pacUrl == null) {
- try {
- httpUrl = new URL(getCaptivePortalServerUrl(mContext, false));
- httpsUrl = new URL(getCaptivePortalServerUrl(mContext, true));
- } catch (MalformedURLException e) {
- validationLog("Bad validation URL: " + getCaptivePortalServerUrl(mContext, false));
+ httpsUrl = makeURL(getCaptivePortalServerHttpsUrl(mContext));
+ httpUrl = makeURL(getCaptivePortalServerHttpUrl(mContext));
+ fallbackUrl = makeURL(getCaptivePortalFallbackUrl(mContext));
+ if (httpUrl == null || httpsUrl == null) {
return CaptivePortalProbeResult.FAILED;
}
}
@@ -691,7 +708,7 @@
if (pacUrl != null) {
result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
} else if (mUseHttps) {
- result = sendParallelHttpProbes(httpsUrl, httpUrl, null);
+ result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
} else {
result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
}
@@ -721,6 +738,10 @@
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
+ final String userAgent = getCaptivePortalUserAgent(mContext);
+ if (userAgent != null) {
+ urlConnection.setRequestProperty("User-Agent", userAgent);
+ }
// Time how long it takes to get a response to our request
long requestTimestamp = SystemClock.elapsedRealtime();
@@ -846,6 +867,17 @@
return httpsProbe.result();
}
+ private URL makeURL(String url) {
+ if (url != null) {
+ try {
+ return new URL(url);
+ } catch (MalformedURLException e) {
+ validationLog("Bad URL: " + url);
+ }
+ }
+ return null;
+ }
+
/**
* @param responseReceived - whether or not we received a valid HTTP response to our request.
* If false, isCaptivePortal and responseTimestampMs are ignored