diff options
6 files changed, 400 insertions, 1 deletions
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java index 1999e78decc4..cb82fbe71f6b 100644 --- a/core/java/android/net/metrics/NetworkEvent.java +++ b/core/java/android/net/metrics/NetworkEvent.java @@ -44,6 +44,8 @@ public final class NetworkEvent implements Parcelable { public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; + public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; + @IntDef(value = { NETWORK_CONNECTED, NETWORK_VALIDATED, @@ -56,6 +58,7 @@ public final class NetworkEvent implements Parcelable { NETWORK_REVALIDATION_SUCCESS, NETWORK_FIRST_VALIDATION_PORTAL_FOUND, NETWORK_REVALIDATION_PORTAL_FOUND, + NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND, }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 258426e34a49..258c9a92fbfc 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10436,6 +10436,41 @@ public final class Settings { public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent"; /** + * The threshold value for the number of consecutive dns timeout events received to be a + * signal of data stall. Set the value to 0 or less than 0 to disable. Note that the value + * should be larger than 0 if the DNS data stall detection is enabled. + * + * @hide + */ + public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = + "data_stall_consecutive_dns_timeout_threshold"; + + /** + * The minimal time interval in milliseconds for data stall reevaluation. + * + * @hide + */ + public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = + "data_stall_min_evaluate_interval"; + + /** + * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting + * a data stall. + * + * @hide + */ + public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = + "data_stall_valid_dns_time_threshold"; + + /** + * Which data stall detection signal to use. Possible values are a union of the powers of 2 + * of DATA_STALL_EVALUATION_TYPE_*. + * + * @hide + */ + public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type"; + + /** * Whether network service discovery is enabled. * * @hide diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 9d3085aa2f88..f2f28937bb50 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -185,6 +185,10 @@ public class SettingsBackupTest { Settings.Global.DATA_ROAMING, Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, + Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, + Settings.Global.DATA_STALL_EVALUATION_TYPE, + Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL, + Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, Settings.Global.DEBUG_APP, Settings.Global.DEBUG_VIEW_ATTRIBUTES, Settings.Global.DEFAULT_DNS_SERVER, diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 564d35a0936d..8a0d9fe93d1c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1667,6 +1667,24 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Error parsing ip address in validation event"); } } + + @Override + public void onDnsEvent(int netId, int eventType, int returnCode, String hostname, + String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { + NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); + // Netd event only allow registrants from system. Each NetworkMonitor thread is under + // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd + // event callback for certain nai. e.g. cellular. Register here to pass to + // NetworkMonitor instead. + // TODO: Move the Dns Event to NetworkMonitor. Use Binder.clearCallingIdentity() in + // registerNetworkAgent to have NetworkMonitor created with system process as design + // expectation. Also, NetdEventListenerService only allow one callback from each + // caller type. Need to re-factor NetdEventListenerService to allow multiple + // NetworkMonitor registrants. + if (nai != null && nai.satisfies(mDefaultRequest)) { + nai.networkMonitor.sendMessage(NetworkMonitor.EVENT_DNS_NOTIFICATION, returnCode); + } + } }; @VisibleForTesting diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index c3e38424e90b..c2f4406c615d 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -72,6 +72,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Protocol; +import com.android.internal.util.RingBufferIndices; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.connectivity.DnsManager.PrivateDnsConfig; @@ -99,7 +100,7 @@ public class NetworkMonitor extends StateMachine { private static final String TAG = NetworkMonitor.class.getSimpleName(); private static final boolean DBG = true; private static final boolean VDBG = false; - + private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG); // Default configuration values for captive portal detection probes. // TODO: append a random length parameter to the default HTTPS url. // TODO: randomize browser version ids in the default User-Agent String. @@ -116,6 +117,15 @@ public class NetworkMonitor extends StateMachine { private static final int SOCKET_TIMEOUT_MS = 10000; private static final int PROBE_TIMEOUT_MS = 3000; + // Default configuration values for data stall detection. + private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5; + private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000; + private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000; + + private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; + private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = + (1 << DATA_STALL_EVALUATION_TYPE_DNS); + static enum EvaluationResult { VALIDATED(true), CAPTIVE_PORTAL(false); @@ -233,6 +243,12 @@ public class NetworkMonitor extends StateMachine { */ public static final int CMD_PROBE_COMPLETE = BASE + 16; + /** + * ConnectivityService notifies NetworkMonitor of DNS query responses event. + * arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query. + */ + public static final int EVENT_DNS_NOTIFICATION = BASE + 17; + // Start mReevaluateDelayMs at this value and double. private static final int INITIAL_REEVALUATE_DELAY_MS = 1000; private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000; @@ -314,6 +330,12 @@ public class NetworkMonitor extends StateMachine { private int mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS; private int mEvaluateAttempts = 0; private volatile int mProbeToken = 0; + private final int mConsecutiveDnsTimeoutThreshold; + private final int mDataStallMinEvaluateTime; + private final int mDataStallValidDnsTimeThreshold; + private final int mDataStallEvaluationType; + private final DnsStallDetector mDnsStallDetector; + private long mLastProbeTime; public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) { @@ -359,6 +381,12 @@ public class NetworkMonitor extends StateMachine { mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls(); mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs(); mRandom = deps.getRandom(); + // TODO: Evaluate to move data stall configuration to a specific class. + mConsecutiveDnsTimeoutThreshold = getConsecutiveDnsTimeoutThreshold(); + mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold); + mDataStallMinEvaluateTime = getDataStallMinEvaluateTime(); + mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold(); + mDataStallEvaluationType = getDataStallEvalutionType(); start(); } @@ -507,6 +535,9 @@ public class NetworkMonitor extends StateMachine { sendMessage(CMD_EVALUATE_PRIVATE_DNS); break; } + case EVENT_DNS_NOTIFICATION: + mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1); + break; default: break; } @@ -537,6 +568,13 @@ public class NetworkMonitor extends StateMachine { case CMD_EVALUATE_PRIVATE_DNS: transitionTo(mEvaluatingPrivateDnsState); break; + case EVENT_DNS_NOTIFICATION: + mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1); + if (isDataStall()) { + validationLog("Suspecting data stall, reevaluate"); + transitionTo(mEvaluatingState); + } + break; default: return NOT_HANDLED; } @@ -856,6 +894,7 @@ public class NetworkMonitor extends StateMachine { final CaptivePortalProbeResult probeResult = (CaptivePortalProbeResult) message.obj; + mLastProbeTime = SystemClock.elapsedRealtime(); if (probeResult.isSuccessful()) { // Transit EvaluatingPrivateDnsState to get to Validated // state (even if no Private DNS validation required). @@ -883,6 +922,7 @@ public class NetworkMonitor extends StateMachine { // Leave the event to EvaluatingState. Defer this message will result in reset // of mReevaluateDelayMs and mEvaluateAttempts. case CMD_NETWORK_DISCONNECTED: + case EVENT_DNS_NOTIFICATION: return NOT_HANDLED; default: // TODO: Some events may able to handle in this state, instead of deferring to @@ -947,6 +987,29 @@ public class NetworkMonitor extends StateMachine { Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL); } + private int getConsecutiveDnsTimeoutThreshold() { + return mDependencies.getSetting(mContext, + Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD, + DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD); + } + + private int getDataStallMinEvaluateTime() { + return mDependencies.getSetting(mContext, + Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL, + DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS); + } + + private int getDataStallValidDnsTimeThreshold() { + return mDependencies.getSetting(mContext, + Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD, + DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS); + } + + private int getDataStallEvalutionType() { + return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE, + DEFAULT_DATA_STALL_EVALUATION_TYPES); + } + // Static for direct access by ConnectivityService public static String getCaptivePortalServerHttpUrl(Context context) { return getCaptivePortalServerHttpUrl(Dependencies.DEFAULT, context); @@ -1462,4 +1525,127 @@ public class NetworkMonitor extends StateMachine { public static final Dependencies DEFAULT = new Dependencies(); } + + /** + * Methods in this class perform no locking because all accesses are performed on the state + * machine's thread. Need to consider the thread safety if it ever could be accessed outside the + * state machine. + */ + @VisibleForTesting + protected class DnsStallDetector { + private static final int DEFAULT_DNS_LOG_SIZE = 50; + private int mConsecutiveTimeoutCount = 0; + private int mSize; + final DnsResult[] mDnsEvents; + final RingBufferIndices mResultIndices; + + DnsStallDetector(int size) { + mSize = Math.max(DEFAULT_DNS_LOG_SIZE, size); + mDnsEvents = new DnsResult[mSize]; + mResultIndices = new RingBufferIndices(mSize); + } + + @VisibleForTesting + protected void accumulateConsecutiveDnsTimeoutCount(int code) { + final DnsResult result = new DnsResult(code); + mDnsEvents[mResultIndices.add()] = result; + if (result.isTimeout()) { + mConsecutiveTimeoutCount++; + } else { + // Keep the event in mDnsEvents without clearing it so that there are logs to do the + // simulation and analysis. + mConsecutiveTimeoutCount = 0; + } + } + + private boolean isDataStallSuspected(int timeoutCountThreshold, int validTime) { + if (timeoutCountThreshold <= 0) { + Log.wtf(TAG, "Timeout count threshold should be larger than 0."); + return false; + } + + // Check if the consecutive timeout count reach the threshold or not. + if (mConsecutiveTimeoutCount < timeoutCountThreshold) { + return false; + } + + // Check if the target dns event index is valid or not. + final int firstConsecutiveTimeoutIndex = + mResultIndices.indexOf(mResultIndices.size() - timeoutCountThreshold); + + // If the dns timeout events happened long time ago, the events are meaningless for + // data stall evaluation. Thus, check if the first consecutive timeout dns event + // considered in the evaluation happened in defined threshold time. + final long now = SystemClock.elapsedRealtime(); + final long firstTimeoutTime = now - mDnsEvents[firstConsecutiveTimeoutIndex].mTimeStamp; + return (firstTimeoutTime < validTime); + } + + int getConsecutiveTimeoutCount() { + return mConsecutiveTimeoutCount; + } + } + + private static class DnsResult { + // TODO: Need to move the DNS return code definition to a specific class once unify DNS + // response code is done. + private static final int RETURN_CODE_DNS_TIMEOUT = 255; + + private final long mTimeStamp; + private final int mReturnCode; + + DnsResult(int code) { + mTimeStamp = SystemClock.elapsedRealtime(); + mReturnCode = code; + } + + private boolean isTimeout() { + return mReturnCode == RETURN_CODE_DNS_TIMEOUT; + } + } + + + @VisibleForTesting + protected DnsStallDetector getDnsStallDetector() { + return mDnsStallDetector; + } + + private boolean dataStallEvaluateTypeEnabled(int type) { + return (mDataStallEvaluationType & (1 << type)) != 0; + } + + @VisibleForTesting + protected long getLastProbeTime() { + return mLastProbeTime; + } + + @VisibleForTesting + protected boolean isDataStall() { + boolean result = false; + // Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the + // possible traffic cost in metered network. + if (mNetworkAgentInfo.networkCapabilities.isMetered() + && (SystemClock.elapsedRealtime() - getLastProbeTime() + < mDataStallMinEvaluateTime)) { + return false; + } + + // Check dns signal. Suspect it may be a data stall if both : + // 1. The number of consecutive DNS query timeouts > mConsecutiveDnsTimeoutThreshold. + // 2. Those consecutive DNS queries happened in the last mValidDataStallDnsTimeThreshold ms. + if (dataStallEvaluateTypeEnabled(DATA_STALL_EVALUATION_TYPE_DNS)) { + if (mDnsStallDetector.isDataStallSuspected(mConsecutiveDnsTimeoutThreshold, + mDataStallValidDnsTimeThreshold)) { + result = true; + logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND); + } + } + + if (VDBG_STALL) { + log("isDataStall: result=" + result + ", consecutive dns timeout count=" + + mDnsStallDetector.getConsecutiveTimeoutCount()); + } + + return result; + } } diff --git a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java index b399b0d51577..6e07b26e883a 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java @@ -40,6 +40,7 @@ import android.net.captiveportal.CaptivePortalProbeResult; import android.net.metrics.IpConnectivityLog; import android.net.wifi.WifiManager; import android.os.Handler; +import android.os.SystemClock; import android.provider.Settings; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -70,6 +71,7 @@ public class NetworkMonitorTest { private @Mock Handler mHandler; private @Mock IpConnectivityLog mLogger; private @Mock NetworkAgentInfo mAgent; + private @Mock NetworkAgentInfo mNotMeteredAgent; private @Mock NetworkInfo mNetworkInfo; private @Mock NetworkRequest mRequest; private @Mock TelephonyManager mTelephony; @@ -87,6 +89,10 @@ public class NetworkMonitorTest { 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 int DATA_STALL_EVALUATION_TYPE_DNS = 1; + private static final int RETURN_CODE_DNS_SUCCESS = 0; + private static final int RETURN_CODE_DNS_TIMEOUT = 255; + @Before public void setUp() throws IOException { MockitoAnnotations.initMocks(this); @@ -95,6 +101,12 @@ public class NetworkMonitorTest { .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); mAgent.networkInfo = mNetworkInfo; + mNotMeteredAgent.linkProperties = new LinkProperties(); + mNotMeteredAgent.networkCapabilities = new NetworkCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + mNotMeteredAgent.networkInfo = mNetworkInfo; + when(mAgent.network()).thenReturn(mNetwork); when(mDependencies.getNetwork(any())).thenReturn(mNetwork); when(mDependencies.getRandom()).thenReturn(mRandom); @@ -138,6 +150,40 @@ public class NetworkMonitorTest { when(mNetwork.getAllByName(any())).thenReturn(new InetAddress[] { InetAddress.parseNumericAddress("192.168.0.0") }); + + setMinDataStallEvaluateInterval(500); + setDataStallEvaluationType(1 << DATA_STALL_EVALUATION_TYPE_DNS); + setValidDataStallDnsTimeThreshold(500); + setConsecutiveDnsTimeoutThreshold(5); + } + + private class WrappedNetworkMonitor extends NetworkMonitor { + private long mProbeTime = 0; + + WrappedNetworkMonitor(Context context, Handler handler, + NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest, + IpConnectivityLog logger, Dependencies deps) { + super(context, handler, networkAgentInfo, defaultRequest, logger, deps); + } + + @Override + protected long getLastProbeTime() { + return mProbeTime; + } + + protected void setLastProbeTime(long time) { + mProbeTime = time; + } + } + + WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() { + return new WrappedNetworkMonitor( + mContext, mHandler, mAgent, mRequest, mLogger, mDependencies); + } + + WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() { + return new WrappedNetworkMonitor( + mContext, mHandler, mNotMeteredAgent, mRequest, mLogger, mDependencies); } NetworkMonitor makeMonitor() { @@ -272,6 +318,113 @@ public class NetworkMonitorTest { assertPortal(makeMonitor().isCaptivePortal()); } + @Test + public void testIsDataStall_EvaluationDisabled() { + setDataStallEvaluationType(0); + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + assertFalse(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() { + WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertTrue(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsOnMeteredNetwork() { + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + assertFalse(wrappedMonitor.isDataStall()); + + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertTrue(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() { + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + makeDnsTimeoutEvent(wrappedMonitor, 3); + assertFalse(wrappedMonitor.isDataStall()); + // Reset consecutive timeout counts. + makeDnsSuccessEvent(wrappedMonitor, 1); + makeDnsTimeoutEvent(wrappedMonitor, 2); + assertFalse(wrappedMonitor.isDataStall()); + + makeDnsTimeoutEvent(wrappedMonitor, 3); + assertTrue(wrappedMonitor.isDataStall()); + + // Set the value to larger than the default dns log size. + setConsecutiveDnsTimeoutThreshold(51); + wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + makeDnsTimeoutEvent(wrappedMonitor, 50); + assertFalse(wrappedMonitor.isDataStall()); + + makeDnsTimeoutEvent(wrappedMonitor, 1); + assertTrue(wrappedMonitor.isDataStall()); + } + + @Test + public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() { + // Test dns events happened in valid dns time threshold. + WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertFalse(wrappedMonitor.isDataStall()); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + assertTrue(wrappedMonitor.isDataStall()); + + // Test dns events happened before valid dns time threshold. + setValidDataStallDnsTimeThreshold(0); + wrappedMonitor = makeMeteredWrappedNetworkMonitor(); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100); + makeDnsTimeoutEvent(wrappedMonitor, 5); + assertFalse(wrappedMonitor.isDataStall()); + wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000); + assertFalse(wrappedMonitor.isDataStall()); + } + + private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) { + for (int i = 0; i < count; i++) { + wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount( + RETURN_CODE_DNS_TIMEOUT); + } + } + + private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) { + for (int i = 0; i < count; i++) { + wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount( + RETURN_CODE_DNS_SUCCESS); + } + } + + private void setDataStallEvaluationType(int type) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type); + } + + private void setMinDataStallEvaluateInterval(int time) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time); + } + + private void setValidDataStallDnsTimeThreshold(int time) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time); + } + + private void setConsecutiveDnsTimeoutThreshold(int num) { + when(mDependencies.getSetting(any(), + eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())) + .thenReturn(num); + } + private void setFallbackUrl(String url) { when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url); |