summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRemi NGUYEN VAN <reminv@google.com>2020-05-01 00:52:20 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-05-01 00:52:20 +0000
commitc370cb0a230d75c24b378426e9762891b5a66c81 (patch)
treee16279851d4dc19ca3f18ab5d7039f447884e14e
parentdf1fcffeb6eb6db78a07edaaf1f8c3b60ac50d0f (diff)
parent9d5175317630e14c2f76de6d6f273609a46a4b76 (diff)
Merge "Add test configuration values for probe URLs" into rvc-dev am: 9d51753176
Change-Id: Ie66ca15fcd73f83ba3336d51f3ec8700ebaf59ac
-rwxr-xr-xsrc/android/net/util/NetworkStackUtils.java31
-rwxr-xr-xsrc/com/android/server/connectivity/NetworkMonitor.java42
-rw-r--r--tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java94
3 files changed, 167 insertions, 0 deletions
diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java
index 6fd6043..be4c2e4 100755
--- a/src/android/net/util/NetworkStackUtils.java
+++ b/src/android/net/util/NetworkStackUtils.java
@@ -93,6 +93,37 @@ public class NetworkStackUtils {
public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
/**
+ * A test URL used to override configuration settings and overlays for the network validation
+ * HTTPS URL, when set in {@link android.provider.DeviceConfig} configuration.
+ *
+ * <p>This URL will be ignored if the host is not "localhost" (it can only be used to test with
+ * a local test server), and must not be set in production scenarios (as enforced by CTS tests).
+ *
+ * <p>{@link #TEST_URL_EXPIRATION_TIME} must also be set to use this setting.
+ */
+ public static final String TEST_CAPTIVE_PORTAL_HTTPS_URL = "test_captive_portal_https_url";
+
+ /**
+ * A test URL used to override configuration settings and overlays for the network validation
+ * HTTP URL, when set in {@link android.provider.DeviceConfig} configuration.
+ *
+ * <p>This URL will be ignored if the host is not "localhost" (it can only be used to test with
+ * a local test server), and must not be set in production scenarios (as enforced by CTS tests).
+ *
+ * <p>{@link #TEST_URL_EXPIRATION_TIME} must also be set to use this setting.
+ */
+ public static final String TEST_CAPTIVE_PORTAL_HTTP_URL = "test_captive_portal_http_url";
+
+ /**
+ * Expiration time of the test URL, in ms, relative to {@link System#currentTimeMillis()}.
+ *
+ * <p>After this expiration time, test URLs will be ignored. They will also be ignored if
+ * the expiration time is more than 10 minutes in the future, to avoid misconfiguration
+ * following test runs.
+ */
+ public static final String TEST_URL_EXPIRATION_TIME = "test_url_expiration_time";
+
+ /**
* The URL used for fallback HTTP captive portal detection when previous HTTP
* and HTTPS captive portal detection attemps did not return a conclusive answer.
*/
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index b6387ab..4c3c4bd 100755
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -71,6 +71,9 @@ import static android.net.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTPS_UR
import static android.net.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTP_URLS;
import static android.net.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK;
import static android.net.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION;
+import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL;
+import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL;
+import static android.net.util.NetworkStackUtils.TEST_URL_EXPIRATION_TIME;
import static android.net.util.NetworkStackUtils.isEmpty;
import static android.net.util.NetworkStackUtils.isIPv6ULA;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -119,6 +122,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellIdentityNr;
@@ -219,6 +223,7 @@ public class NetworkMonitor extends StateMachine {
private static final int SOCKET_TIMEOUT_MS = 10000;
private static final int PROBE_TIMEOUT_MS = 3000;
+ private static final long TEST_URL_EXPIRATION_MS = TimeUnit.MINUTES.toMillis(10);
private static final int UNSET_MCC_OR_MNC = -1;
@@ -1598,12 +1603,47 @@ public class NetworkMonitor extends StateMachine {
return getContextByMccMnc(Integer.parseInt(mcc), UNSET_MCC_OR_MNC);
}
+ @Nullable
+ private String getTestUrl(@NonNull String key) {
+ final String strExpiration = mDependencies.getDeviceConfigProperty(NAMESPACE_CONNECTIVITY,
+ TEST_URL_EXPIRATION_TIME, null);
+ if (strExpiration == null) return null;
+
+ final long expTime;
+ try {
+ expTime = Long.parseUnsignedLong(strExpiration);
+ } catch (NumberFormatException e) {
+ loge("Invalid test URL expiration time format", e);
+ return null;
+ }
+
+ final long now = System.currentTimeMillis();
+ if (expTime < now || (expTime - now) > TEST_URL_EXPIRATION_MS) return null;
+
+ return mDependencies.getDeviceConfigProperty(NAMESPACE_CONNECTIVITY,
+ key, null /* defaultValue */);
+ }
+
private String getCaptivePortalServerHttpsUrl() {
+ final String testUrl = getTestUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL);
+ if (isValidTestUrl(testUrl)) return testUrl;
final Context targetContext = getCustomizedContextOrDefault();
return getSettingFromResource(targetContext, R.string.config_captive_portal_https_url,
R.string.default_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL);
}
+ private static boolean isValidTestUrl(@Nullable String url) {
+ if (TextUtils.isEmpty(url)) return false;
+
+ try {
+ // Only accept test URLs on localhost
+ return Uri.parse(url).getHost().equals("localhost");
+ } catch (Throwable e) {
+ Log.wtf(TAG, "Error parsing test URL", e);
+ return false;
+ }
+ }
+
private int getDnsProbeTimeout() {
return getIntSetting(mContext, R.integer.config_captive_portal_dns_probe_timeout,
CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
@@ -1678,6 +1718,8 @@ public class NetworkMonitor extends StateMachine {
* on one URL that can be used, while NetworkMonitor may implement more complex logic.
*/
public String getCaptivePortalServerHttpUrl() {
+ final String testUrl = getTestUrl(TEST_CAPTIVE_PORTAL_HTTP_URL);
+ if (isValidTestUrl(testUrl)) return testUrl;
final Context targetContext = getCustomizedContextOrDefault();
return getSettingFromResource(targetContext, R.string.config_captive_portal_http_url,
R.string.default_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL);
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index 145c89c..7cf130e 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -40,6 +40,10 @@ import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_U
import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
import static android.net.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK;
import static android.net.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION;
+import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL;
+import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL;
+import static android.net.util.NetworkStackUtils.TEST_URL_EXPIRATION_TIME;
+import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
import static com.android.networkstack.util.DnsUtils.PRIVATE_DNS_PROBE_HOST_SUFFIX;
import static com.android.server.connectivity.NetworkMonitor.extractCharset;
@@ -172,6 +176,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLHandshakeException;
@@ -203,6 +208,7 @@ public class NetworkMonitorTest {
private @Mock HttpURLConnection mOtherHttpsConnection2;
private @Mock HttpURLConnection mFallbackConnection;
private @Mock HttpURLConnection mOtherFallbackConnection;
+ private @Mock HttpURLConnection mTestOverriddenUrlConnection;
private @Mock HttpURLConnection mCapportApiConnection;
private @Mock Random mRandom;
private @Mock NetworkMonitor.Dependencies mDependencies;
@@ -231,6 +237,8 @@ public class NetworkMonitorTest {
private static final String TEST_HTTPS_OTHER_URL2 = "https://other2.google.com/gen_204";
private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
+ private static final String TEST_INVALID_OVERRIDE_URL = "https://override.example.com/test";
+ private static final String TEST_OVERRIDE_URL = "http://localhost:12345/test";
private static final String TEST_CAPPORT_API_URL = "https://capport.example.com/api";
private static final String TEST_LOGIN_URL = "https://testportal.example.com/login";
private static final String TEST_VENUE_INFO_URL = "https://venue.example.com/info";
@@ -462,6 +470,9 @@ public class NetworkMonitorTest {
return mFallbackConnection;
case TEST_OTHER_FALLBACK_URL:
return mOtherFallbackConnection;
+ case TEST_OVERRIDE_URL:
+ case TEST_INVALID_OVERRIDE_URL:
+ return mTestOverriddenUrlConnection;
case TEST_CAPPORT_API_URL:
return mCapportApiConnection;
default:
@@ -1189,6 +1200,84 @@ public class NetworkMonitorTest {
}
@Test
+ public void testIsCaptivePortal_OverriddenHttpsUrlValid() throws Exception {
+ setDeviceConfig(TEST_URL_EXPIRATION_TIME,
+ String.valueOf(currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)));
+ setDeviceConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL, TEST_OVERRIDE_URL);
+ setStatus(mTestOverriddenUrlConnection, 204);
+ setStatus(mHttpConnection, 204);
+
+ runValidatedNetworkTest();
+ verify(mHttpsConnection, never()).getResponseCode();
+ verify(mTestOverriddenUrlConnection).getResponseCode();
+ }
+
+ @Test
+ public void testIsCaptivePortal_OverriddenHttpUrlPortal() throws Exception {
+ setDeviceConfig(TEST_URL_EXPIRATION_TIME,
+ String.valueOf(currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)));
+ setDeviceConfig(TEST_CAPTIVE_PORTAL_HTTP_URL, TEST_OVERRIDE_URL);
+ setStatus(mHttpsConnection, 500);
+ setPortal302(mTestOverriddenUrlConnection);
+
+ runPortalNetworkTest();
+ verify(mHttpConnection, never()).getResponseCode();
+ verify(mTestOverriddenUrlConnection).getResponseCode();
+ }
+
+ @Test
+ public void testIsCaptivePortal_InvalidHttpOverrideUrl() throws Exception {
+ setDeviceConfig(TEST_URL_EXPIRATION_TIME,
+ String.valueOf(currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)));
+ setDeviceConfig(TEST_CAPTIVE_PORTAL_HTTP_URL, TEST_INVALID_OVERRIDE_URL);
+ setStatus(mHttpsConnection, 500);
+ setPortal302(mHttpConnection);
+
+ runPortalNetworkTest();
+ verify(mTestOverriddenUrlConnection, never()).getResponseCode();
+ verify(mHttpConnection).getResponseCode();
+ }
+
+ @Test
+ public void testIsCaptivePortal_InvalidHttpsOverrideUrl() throws Exception {
+ setDeviceConfig(TEST_URL_EXPIRATION_TIME,
+ String.valueOf(currentTimeMillis() + TimeUnit.MINUTES.toMillis(9)));
+ setDeviceConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL, TEST_INVALID_OVERRIDE_URL);
+ setStatus(mHttpsConnection, 204);
+ setStatus(mHttpConnection, 204);
+
+ runValidatedNetworkTest();
+ verify(mTestOverriddenUrlConnection, never()).getResponseCode();
+ verify(mHttpsConnection).getResponseCode();
+ }
+
+ @Test
+ public void testIsCaptivePortal_ExpiredHttpsOverrideUrl() throws Exception {
+ setDeviceConfig(TEST_URL_EXPIRATION_TIME,
+ String.valueOf(currentTimeMillis() - TimeUnit.MINUTES.toMillis(1)));
+ setDeviceConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL, TEST_OVERRIDE_URL);
+ setStatus(mHttpsConnection, 204);
+ setStatus(mHttpConnection, 204);
+
+ runValidatedNetworkTest();
+ verify(mTestOverriddenUrlConnection, never()).getResponseCode();
+ verify(mHttpsConnection).getResponseCode();
+ }
+
+ @Test
+ public void testIsCaptivePortal_TestHttpUrlExpirationTooLarge() throws Exception {
+ setDeviceConfig(TEST_URL_EXPIRATION_TIME,
+ String.valueOf(currentTimeMillis() + TimeUnit.MINUTES.toMillis(20)));
+ setDeviceConfig(TEST_CAPTIVE_PORTAL_HTTP_URL, TEST_OVERRIDE_URL);
+ setStatus(mHttpsConnection, 500);
+ setPortal302(mHttpConnection);
+
+ runPortalNetworkTest();
+ verify(mTestOverriddenUrlConnection, never()).getResponseCode();
+ verify(mHttpConnection).getResponseCode();
+ }
+
+ @Test
public void testIsDataStall_EvaluationDisabled() {
setDataStallEvaluationType(0);
WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
@@ -1985,6 +2074,11 @@ public class NetworkMonitorTest {
eq(DISMISS_PORTAL_IN_VALIDATED_NETWORK), anyBoolean())).thenReturn(enabled);
}
+ private void setDeviceConfig(String key, String value) {
+ doReturn(value).when(mDependencies).getDeviceConfigProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(key), any() /* defaultValue */);
+ }
+
private NetworkMonitor runPortalNetworkTest() throws RemoteException {
final NetworkMonitor nm = runNetworkTest(VALIDATION_RESULT_PORTAL,
0 /* probesSucceeded */, TEST_LOGIN_URL);