Merge "Add serial urls probe logic for NetworkMonitor" into main
diff --git a/res/values/config.xml b/res/values/config.xml
index 8d6b64e..d9ee36d 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -51,6 +51,8 @@
</string-array>
<string-array name="config_captive_portal_https_urls" translatable="false">
</string-array>
+ <bool name="config_probe_multi_http_https_url_serial">false</bool>
+ <integer name="config_serial_url_probe_gap_time">1000</integer>
<!-- Customized default DNS Servers address. -->
<string-array name="config_default_dns_servers" translatable="false">
diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml
index 0aeaaec..8e8fe08 100644
--- a/res/values/overlayable.xml
+++ b/res/values/overlayable.xml
@@ -42,6 +42,8 @@
<item type="array" name="config_captive_portal_http_urls"/>
<item type="array" name="config_captive_portal_https_urls"/>
<item type="array" name="config_captive_portal_fallback_urls"/>
+ <item type="bool" name="config_probe_multi_http_https_url_serial"/>
+ <item type="integer" name="config_serial_url_probe_gap_time"/>
<item type="bool" name="config_no_sim_card_uses_neighbor_mcc"/>
<!-- Configuration value for DhcpResults -->
<item type="array" name="config_default_dns_servers"/>
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index eaed8e5..3ae8557 100755
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -517,6 +517,8 @@
private final boolean mIsCaptivePortalCheckEnabled;
private boolean mUseHttps;
+ private final boolean mUseSerialProbe;
+ private final int mSerialProbeGapTime;
/**
* The total number of completed validation attempts (network validated or a captive portal was
* detected) for this NetworkMonitor instance.
@@ -679,6 +681,8 @@
&& deps.isFeatureSupported(mContext, FEATURE_DDR_IN_CONNECTIVITY)
&& deps.isFeatureSupported(mContext, FEATURE_DDR_IN_DNSRESOLVER);
mUseHttps = getUseHttpsValidation();
+ mUseSerialProbe = getUseSerialProbeValidation();
+ mSerialProbeGapTime = getSerialProbeGapTime();
mCaptivePortalUserAgent = getCaptivePortalUserAgent();
mCaptivePortalFallbackSpecs =
makeCaptivePortalFallbackProbeSpecs(getCustomizedContextOrDefault());
@@ -2392,6 +2396,16 @@
R.bool.config_force_dns_probe_private_ip_no_internet);
}
+ private boolean getUseSerialProbeValidation() {
+ return mContext.getResources().getBoolean(
+ R.bool.config_probe_multi_http_https_url_serial);
+ }
+
+ private int getSerialProbeGapTime() {
+ return mContext.getResources().getInteger(
+ R.integer.config_serial_url_probe_gap_time);
+ }
+
private boolean getUseHttpsValidation() {
return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
@@ -3426,14 +3440,26 @@
// Probe capport API with the first HTTP probe.
// TODO: Have the capport probe as a different probe for cleanliness.
final URL urlMaybeWithCapport = httpUrls[0];
+ int delayCount=0;
for (final URL url : httpUrls) {
- futures.add(ecs.submit(() -> new HttpProbe(properties, proxy, url,
- url.equals(urlMaybeWithCapport) ? capportApiUrl : null).sendProbe()));
+ final int cnt = delayCount++;
+ futures.add(ecs.submit(() -> {
+ if (mUseSerialProbe && cnt > 0) {
+ mDependencies.sleep(mSerialProbeGapTime * cnt);
+ }
+ return new HttpProbe(properties, proxy, url,
+ url.equals(urlMaybeWithCapport) ? capportApiUrl : null).sendProbe();
+ }));
}
-
+ delayCount=0;
for (final URL url : httpsUrls) {
- futures.add(ecs.submit(() -> new HttpsProbe(properties, proxy, url, capportApiUrl)
- .sendProbe()));
+ final int cnt = delayCount++;
+ futures.add(ecs.submit(() -> {
+ if (mUseSerialProbe && cnt > 0) {
+ mDependencies.sleep(mSerialProbeGapTime * cnt);
+ }
+ return new HttpsProbe(properties, proxy, url, capportApiUrl).sendProbe();
+ }));
}
final ArrayList<CaptivePortalProbeResult> completedProbes = new ArrayList<>();
@@ -3778,6 +3804,13 @@
public void onExecutorServiceCreated(@NonNull ExecutorService ecs) {
}
+ /**
+ * Wait for another round of serial probe
+ */
+ public void sleep(int time) throws InterruptedException {
+ Thread.sleep((long)time);
+ }
+
public static final Dependencies DEFAULT = new Dependencies();
}
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
index 37b157b..e9bd616 100644
--- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -226,6 +226,7 @@
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@@ -320,6 +321,7 @@
private static final int DEFAULT_DNS_TIMEOUT_THRESHOLD = 5;
private static final int HANDLER_TIMEOUT_MS = 1000;
+ private static final int SERIAL_PROBE_GAP_TIME_MS = 500;
private static final int TEST_MIN_STALL_EVALUATE_INTERVAL_MS = 500;
private static final int TEST_MIN_VALID_STALL_DNS_TIME_THRESHOLD_MS = 5000;
private static final int STALL_EXPECTED_LAST_PROBE_TIME_MS =
@@ -373,6 +375,7 @@
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
private FakeDns mFakeDns;
+ private Semaphore mSerialProbeLock;
@GuardedBy("mThreadsToBeCleared")
private final ArrayList<Thread> mThreadsToBeCleared = new ArrayList<>();
@@ -474,6 +477,7 @@
initHttpConnection(mFallbackConnection);
initHttpConnection(mOtherFallbackConnection);
+ mSerialProbeLock = new Semaphore(0);
mFakeDns = new FakeDns(mNetwork, mDnsResolver);
mFakeDns.startMocking();
// Set private dns suffix answer. sendPrivateDnsProbe() in NetworkMonitor send probe with
@@ -3417,6 +3421,36 @@
}
@Test
+ public void testSerialProbesOnFirstValidNetwork() throws Exception {
+ setupResourceForSerialProbes();
+ setStatus(mOtherHttpsConnection1, 204);
+ runSerialProbesNetworkTest(NETWORK_VALIDATION_RESULT_VALID,
+ NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS);
+ verify(mDependencies, timeout(HANDLER_TIMEOUT_MS).times(2)).sleep(anyInt());
+ verify(mCleartextDnsNetwork, timeout(HANDLER_TIMEOUT_MS).times(2)).openConnection(any());
+ }
+
+ @Test
+ public void testSerialProbesOnSecondValidNetwork() throws Exception {
+ setupResourceForSerialProbes();
+ setStatus(mOtherHttpsConnection2, 204);
+ mSerialProbeLock.release(2);
+ runSerialProbesNetworkTest(NETWORK_VALIDATION_RESULT_VALID,
+ NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS);
+ verify(mDependencies, timeout(HANDLER_TIMEOUT_MS).times(2)).sleep(anyInt());
+ verify(mCleartextDnsNetwork, timeout(HANDLER_TIMEOUT_MS).times(4)).openConnection(any());
+ }
+
+ @Test
+ public void testSerialProbesOnInValidNetwork() throws Exception {
+ setupResourceForSerialProbes();
+ mSerialProbeLock.release(2);
+ runSerialProbesNetworkTest(VALIDATION_RESULT_INVALID, 0);
+ verify(mDependencies, timeout(HANDLER_TIMEOUT_MS).times(2)).sleep(anyInt());
+ verify(mCleartextDnsNetwork, timeout(HANDLER_TIMEOUT_MS).times(4)).openConnection(any());
+ }
+
+ @Test
public void testIsCaptivePortal_FromExternalSource() throws Exception {
assumeTrue(CaptivePortalDataShimImpl.isSupported());
assumeTrue(ShimUtils.isAtLeastS());
@@ -3523,6 +3557,18 @@
verify(mCallbacks, never()).showProvisioningNotification(any(), any());
}
+ private void waitForSerialProbes(int time) throws InterruptedException {
+ mSerialProbeLock.tryAcquire(time, TimeUnit.MILLISECONDS);
+ }
+
+ private void setupResourceForSerialProbes() {
+ doReturn(true).when(mResources)
+ .getBoolean(R.bool.config_probe_multi_http_https_url_serial);
+ doReturn(SERIAL_PROBE_GAP_TIME_MS).when(mResources)
+ .getInteger(R.integer.config_serial_url_probe_gap_time);
+ setupResourceForMultipleProbes();
+ }
+
private void setupResourceForMultipleProbes() {
// Configure the resource to send multiple probe.
doReturn(TEST_HTTPS_URLS).when(mResources)
@@ -3620,6 +3666,17 @@
return nm;
}
+ private void runSerialProbesNetworkTest(int testResult, int probesSucceeded) throws Exception {
+ final WrappedNetworkMonitor monitor = makeMonitor(CELL_METERED_CAPABILITIES);
+ notifyNetworkConnected(monitor, TEST_AGENT_CONFIG,
+ TEST_LINK_PROPERTIES, CELL_METERED_CAPABILITIES);
+ doAnswer(invocation -> {
+ waitForSerialProbes(invocation.getArgument(0));
+ return null;
+ }).when(mDependencies).sleep(anyInt());
+ verifyNetworkTested(testResult, probesSucceeded, 1);
+ }
+
private NetworkMonitor runPartialConnectivityNetworkTest(int probesSucceeded)
throws Exception {
final NetworkMonitor nm = runNetworkTest(NETWORK_VALIDATION_RESULT_PARTIAL,