Add serial urls probe logic for NetworkMonitor Change-Id: If83557214e4cd970dff0a7ee553bb52028fb106b
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 659e911..197ed69 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()); @@ -2386,6 +2390,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; @@ -3420,14 +3434,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<>(); @@ -3772,6 +3798,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 4273d95..92120cf 100644 --- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -227,6 +227,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; @@ -321,6 +322,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 = @@ -374,6 +376,7 @@ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED); private FakeDns mFakeDns; + private Semaphore mSerialProbeLock; @GuardedBy("mThreadsToBeCleared") private final ArrayList<Thread> mThreadsToBeCleared = new ArrayList<>(); @@ -475,6 +478,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 @@ -3418,6 +3422,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()); @@ -3524,6 +3558,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) @@ -3621,6 +3667,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,