Merge "Injecting data stall event to statsd"
This commit is contained in:
@@ -28,6 +28,7 @@ java_library {
|
||||
static_libs: [
|
||||
"netd_aidl_interface-java",
|
||||
"networkstack-aidl-interfaces-java",
|
||||
"datastallprotosnano",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -43,4 +44,4 @@ android_app {
|
||||
jarjar_rules: "jarjar-rules-shared.txt",
|
||||
manifest: "AndroidManifest.xml",
|
||||
required: ["NetworkStackPermissionStub"],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.metrics;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.util.NetworkStackUtils;
|
||||
import android.net.wifi.WifiInfo;
|
||||
|
||||
import com.android.internal.util.HexDump;
|
||||
import com.android.server.connectivity.nano.CellularData;
|
||||
import com.android.server.connectivity.nano.DataStallEventProto;
|
||||
import com.android.server.connectivity.nano.DnsEvent;
|
||||
import com.android.server.connectivity.nano.WifiData;
|
||||
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class to record the stats of detection level information for data stall.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class DataStallDetectionStats {
|
||||
private static final int UNKNOWN_SIGNAL_STRENGTH = -1;
|
||||
@NonNull
|
||||
final byte[] mCellularInfo;
|
||||
@NonNull
|
||||
final byte[] mWifiInfo;
|
||||
@NonNull
|
||||
final byte[] mDns;
|
||||
final int mEvaluationType;
|
||||
final int mNetworkType;
|
||||
|
||||
public DataStallDetectionStats(@Nullable byte[] cell, @Nullable byte[] wifi,
|
||||
@NonNull int[] returnCode, @NonNull long[] dnsTime, int evalType, int netType) {
|
||||
mCellularInfo = emptyCellDataIfNull(cell);
|
||||
mWifiInfo = emptyWifiInfoIfNull(wifi);
|
||||
|
||||
DnsEvent dns = new DnsEvent();
|
||||
dns.dnsReturnCode = returnCode;
|
||||
dns.dnsTime = dnsTime;
|
||||
mDns = MessageNano.toByteArray(dns);
|
||||
mEvaluationType = evalType;
|
||||
mNetworkType = netType;
|
||||
}
|
||||
|
||||
private byte[] emptyCellDataIfNull(@Nullable byte[] cell) {
|
||||
if (cell != null) return cell;
|
||||
|
||||
CellularData data = new CellularData();
|
||||
data.ratType = DataStallEventProto.RADIO_TECHNOLOGY_UNKNOWN;
|
||||
data.networkMccmnc = "";
|
||||
data.simMccmnc = "";
|
||||
data.signalStrength = UNKNOWN_SIGNAL_STRENGTH;
|
||||
return MessageNano.toByteArray(data);
|
||||
}
|
||||
|
||||
private byte[] emptyWifiInfoIfNull(@Nullable byte[] wifi) {
|
||||
if (wifi != null) return wifi;
|
||||
|
||||
WifiData data = new WifiData();
|
||||
data.wifiBand = DataStallEventProto.AP_BAND_UNKNOWN;
|
||||
data.signalStrength = UNKNOWN_SIGNAL_STRENGTH;
|
||||
return MessageNano.toByteArray(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("type: ").append(mNetworkType)
|
||||
.append(", evaluation type: ")
|
||||
.append(mEvaluationType)
|
||||
.append(", wifi info: ")
|
||||
.append(HexDump.toHexString(mWifiInfo))
|
||||
.append(", cell info: ")
|
||||
.append(HexDump.toHexString(mCellularInfo))
|
||||
.append(", dns: ")
|
||||
.append(HexDump.toHexString(mDns));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to create an instance of {@Link DataStallDetectionStats}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class Builder {
|
||||
@Nullable
|
||||
private byte[] mCellularInfo;
|
||||
@Nullable
|
||||
private byte[] mWifiInfo;
|
||||
@NonNull
|
||||
private final List<Integer> mDnsReturnCode = new ArrayList<Integer>();
|
||||
@NonNull
|
||||
private final List<Long> mDnsTimeStamp = new ArrayList<Long>();
|
||||
private int mEvaluationType;
|
||||
private int mNetworkType;
|
||||
|
||||
/**
|
||||
* Add a dns event into Builder.
|
||||
*
|
||||
* @param code the return code of the dns event.
|
||||
* @param timeMs the elapsedRealtime in ms that the the dns event was received from netd.
|
||||
* @return {@code this} {@link Builder} instance.
|
||||
*/
|
||||
public Builder addDnsEvent(int code, long timeMs) {
|
||||
mDnsReturnCode.add(code);
|
||||
mDnsTimeStamp.add(timeMs);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dns evaluation type into Builder.
|
||||
*
|
||||
* @param type the return code of the dns event.
|
||||
* @return {@code this} {@link Builder} instance.
|
||||
*/
|
||||
public Builder setEvaluationType(int type) {
|
||||
mEvaluationType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the network type into Builder.
|
||||
*
|
||||
* @param type the network type of the logged network.
|
||||
* @return {@code this} {@link Builder} instance.
|
||||
*/
|
||||
public Builder setNetworkType(int type) {
|
||||
mNetworkType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the wifi data into Builder.
|
||||
*
|
||||
* @param info a {@link WifiInfo} of the connected wifi network.
|
||||
* @return {@code this} {@link Builder} instance.
|
||||
*/
|
||||
public Builder setWiFiData(@Nullable final WifiInfo info) {
|
||||
WifiData data = new WifiData();
|
||||
data.wifiBand = getWifiBand(info);
|
||||
data.signalStrength = (info != null) ? info.getRssi() : UNKNOWN_SIGNAL_STRENGTH;
|
||||
mWifiInfo = MessageNano.toByteArray(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static int getWifiBand(@Nullable final WifiInfo info) {
|
||||
if (info != null) {
|
||||
int freq = info.getFrequency();
|
||||
// Refer to ScanResult.is5GHz() and ScanResult.is24GHz().
|
||||
if (freq > 4900 && freq < 5900) {
|
||||
return DataStallEventProto.AP_BAND_5GHZ;
|
||||
} else if (freq > 2400 && freq < 2500) {
|
||||
return DataStallEventProto.AP_BAND_2GHZ;
|
||||
}
|
||||
}
|
||||
return DataStallEventProto.AP_BAND_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cellular data into Builder.
|
||||
*
|
||||
* @param radioType the radio technology of the logged cellular network.
|
||||
* @param roaming a boolean indicates if logged cellular network is roaming or not.
|
||||
* @param networkMccmnc the mccmnc of the camped network.
|
||||
* @param simMccmnc the mccmnc of the sim.
|
||||
* @return {@code this} {@link Builder} instance.
|
||||
*/
|
||||
public Builder setCellData(int radioType, boolean roaming,
|
||||
@NonNull String networkMccmnc, @NonNull String simMccmnc, int ss) {
|
||||
CellularData data = new CellularData();
|
||||
data.ratType = radioType;
|
||||
data.isRoaming = roaming;
|
||||
data.networkMccmnc = networkMccmnc;
|
||||
data.simMccmnc = simMccmnc;
|
||||
data.signalStrength = ss;
|
||||
mCellularInfo = MessageNano.toByteArray(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@Link DataStallDetectionStats}.
|
||||
*/
|
||||
public DataStallDetectionStats build() {
|
||||
return new DataStallDetectionStats(mCellularInfo, mWifiInfo,
|
||||
NetworkStackUtils.convertToIntArray(mDnsReturnCode),
|
||||
NetworkStackUtils.convertToLongArray(mDnsTimeStamp),
|
||||
mEvaluationType, mNetworkType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.metrics;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.captiveportal.CaptivePortalProbeResult;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.HexDump;
|
||||
import com.android.server.connectivity.nano.DataStallEventProto;
|
||||
|
||||
/**
|
||||
* Collection of utilities for data stall metrics.
|
||||
*
|
||||
* To see if the logs are properly sent to statsd, execute following command.
|
||||
*
|
||||
* $ adb shell cmd stats print-logs
|
||||
* $ adb logcat | grep statsd OR $ adb logcat -b stats
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class DataStallStatsUtils {
|
||||
private static final String TAG = DataStallStatsUtils.class.getSimpleName();
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static int probeResultToEnum(@Nullable final CaptivePortalProbeResult result) {
|
||||
if (result == null) return DataStallEventProto.INVALID;
|
||||
|
||||
// TODO: Add partial connectivity support.
|
||||
if (result.isSuccessful()) {
|
||||
return DataStallEventProto.VALID;
|
||||
} else if (result.isPortal()) {
|
||||
return DataStallEventProto.PORTAL;
|
||||
} else {
|
||||
return DataStallEventProto.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the metric to {@link StatsLog}.
|
||||
*/
|
||||
public static void write(@NonNull final DataStallDetectionStats stats,
|
||||
@NonNull final CaptivePortalProbeResult result) {
|
||||
int validationResult = probeResultToEnum(result);
|
||||
if (DBG) {
|
||||
Log.d(TAG, "write: " + stats + " with result: " + validationResult
|
||||
+ ", dns: " + HexDump.toHexString(stats.mDns));
|
||||
}
|
||||
// TODO(b/124613085): Send to Statsd once the public StatsLog API is ready.
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package android.net.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Collection of utilities for the network stack.
|
||||
@@ -40,4 +43,26 @@ public class NetworkStackUtils {
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int array from the given Integer list.
|
||||
*/
|
||||
public static int[] convertToIntArray(@NonNull List<Integer> list) {
|
||||
int[] array = new int[list.size()];
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
array[i] = list.get(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long array from the given long list.
|
||||
*/
|
||||
public static long[] convertToLongArray(@NonNull List<Long> list) {
|
||||
long[] array = new long[list.size()];
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
array[i] = list.get(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
|
||||
import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
|
||||
import static android.net.util.NetworkStackUtils.isEmpty;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -50,6 +51,8 @@ import android.net.TrafficStats;
|
||||
import android.net.Uri;
|
||||
import android.net.captiveportal.CaptivePortalProbeResult;
|
||||
import android.net.captiveportal.CaptivePortalProbeSpec;
|
||||
import android.net.metrics.DataStallDetectionStats;
|
||||
import android.net.metrics.DataStallStatsUtils;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
import android.net.metrics.NetworkEvent;
|
||||
import android.net.metrics.ValidationProbeEvent;
|
||||
@@ -66,8 +69,10 @@ import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.AccessNetworkConstants;
|
||||
import android.telephony.CellSignalStrength;
|
||||
import android.telephony.NetworkRegistrationState;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.SignalStrength;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@@ -126,6 +131,9 @@ public class NetworkMonitor extends StateMachine {
|
||||
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);
|
||||
// Reevaluate it as intending to increase the number. Larger log size may cause statsd
|
||||
// log buffer bust and have stats log lost.
|
||||
private static final int DEFAULT_DNS_LOG_SIZE = 20;
|
||||
|
||||
enum EvaluationResult {
|
||||
VALIDATED(true),
|
||||
@@ -244,6 +252,7 @@ public class NetworkMonitor extends StateMachine {
|
||||
private final ConnectivityManager mCm;
|
||||
private final IpConnectivityLog mMetricsLog;
|
||||
private final Dependencies mDependencies;
|
||||
private final DataStallStatsUtils mDetectionStatsUtils;
|
||||
|
||||
// Configuration values for captive portal detection probes.
|
||||
private final String mCaptivePortalUserAgent;
|
||||
@@ -302,17 +311,19 @@ public class NetworkMonitor extends StateMachine {
|
||||
private final int mDataStallEvaluationType;
|
||||
private final DnsStallDetector mDnsStallDetector;
|
||||
private long mLastProbeTime;
|
||||
// Set to true if data stall is suspected and reset to false after metrics are sent to statsd.
|
||||
private boolean mCollectDataStallMetrics = false;
|
||||
|
||||
public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
|
||||
SharedLog validationLog) {
|
||||
this(context, cb, network, new IpConnectivityLog(), validationLog,
|
||||
Dependencies.DEFAULT);
|
||||
Dependencies.DEFAULT, new DataStallStatsUtils());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
|
||||
IpConnectivityLog logger, SharedLog validationLogs,
|
||||
Dependencies deps) {
|
||||
Dependencies deps, DataStallStatsUtils detectionStatsUtils) {
|
||||
// Add suffix indicating which NetworkMonitor we're talking about.
|
||||
super(TAG + "/" + network.toString());
|
||||
|
||||
@@ -325,6 +336,7 @@ public class NetworkMonitor extends StateMachine {
|
||||
mValidationLogs = validationLogs;
|
||||
mCallback = cb;
|
||||
mDependencies = deps;
|
||||
mDetectionStatsUtils = detectionStatsUtils;
|
||||
mNonPrivateDnsBypassNetwork = network;
|
||||
mNetwork = deps.getPrivateDnsBypassNetwork(network);
|
||||
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
@@ -656,6 +668,7 @@ public class NetworkMonitor extends StateMachine {
|
||||
case EVENT_DNS_NOTIFICATION:
|
||||
mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
|
||||
if (isDataStall()) {
|
||||
mCollectDataStallMetrics = true;
|
||||
validationLog("Suspecting data stall, reevaluate");
|
||||
transitionTo(mEvaluatingState);
|
||||
}
|
||||
@@ -667,6 +680,65 @@ public class NetworkMonitor extends StateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDataStallStats(@NonNull final CaptivePortalProbeResult result) {
|
||||
/*
|
||||
* Collect data stall detection level information for each transport type. Collect type
|
||||
* specific information for cellular and wifi only currently. Generate
|
||||
* DataStallDetectionStats for each transport type. E.g., if a network supports both
|
||||
* TRANSPORT_WIFI and TRANSPORT_VPN, two DataStallDetectionStats will be generated.
|
||||
*/
|
||||
final int[] transports = mNetworkCapabilities.getTransportTypes();
|
||||
|
||||
for (int i = 0; i < transports.length; i++) {
|
||||
DataStallStatsUtils.write(buildDataStallDetectionStats(transports[i]), result);
|
||||
}
|
||||
mCollectDataStallMetrics = false;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected DataStallDetectionStats buildDataStallDetectionStats(int transport) {
|
||||
final DataStallDetectionStats.Builder stats = new DataStallDetectionStats.Builder();
|
||||
if (VDBG_STALL) log("collectDataStallMetrics: type=" + transport);
|
||||
stats.setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
|
||||
stats.setNetworkType(transport);
|
||||
switch (transport) {
|
||||
case NetworkCapabilities.TRANSPORT_WIFI:
|
||||
// TODO: Update it if status query in dual wifi is supported.
|
||||
final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
|
||||
stats.setWiFiData(wifiInfo);
|
||||
break;
|
||||
case NetworkCapabilities.TRANSPORT_CELLULAR:
|
||||
final boolean isRoaming = !mNetworkCapabilities.hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
|
||||
final SignalStrength ss = mTelephonyManager.getSignalStrength();
|
||||
// TODO(b/120452078): Support multi-sim.
|
||||
stats.setCellData(
|
||||
mTelephonyManager.getDataNetworkType(),
|
||||
isRoaming,
|
||||
mTelephonyManager.getNetworkOperator(),
|
||||
mTelephonyManager.getSimOperator(),
|
||||
(ss != null)
|
||||
? ss.getLevel() : CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
|
||||
break;
|
||||
default:
|
||||
// No transport type specific information for the other types.
|
||||
break;
|
||||
}
|
||||
addDnsEvents(stats);
|
||||
|
||||
return stats.build();
|
||||
}
|
||||
|
||||
private void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
|
||||
final int size = mDnsStallDetector.mResultIndices.size();
|
||||
for (int i = 1; i <= DEFAULT_DNS_LOG_SIZE && i <= size; i++) {
|
||||
final int index = mDnsStallDetector.mResultIndices.indexOf(size - i);
|
||||
stats.addDnsEvent(mDnsStallDetector.mDnsEvents[index].mReturnCode,
|
||||
mDnsStallDetector.mDnsEvents[index].mTimeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Being in the MaybeNotifyState State indicates the user may have been notified that sign-in
|
||||
// is required. This State takes care to clear the notification upon exit from the State.
|
||||
private class MaybeNotifyState extends State {
|
||||
@@ -972,6 +1044,11 @@ public class NetworkMonitor extends StateMachine {
|
||||
final CaptivePortalProbeResult probeResult =
|
||||
(CaptivePortalProbeResult) message.obj;
|
||||
mLastProbeTime = SystemClock.elapsedRealtime();
|
||||
|
||||
if (mCollectDataStallMetrics) {
|
||||
writeDataStallStats(probeResult);
|
||||
}
|
||||
|
||||
if (probeResult.isSuccessful()) {
|
||||
// Transit EvaluatingPrivateDnsState to get to Validated
|
||||
// state (even if no Private DNS validation required).
|
||||
@@ -1617,7 +1694,6 @@ public class NetworkMonitor extends StateMachine {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected class DnsStallDetector {
|
||||
private static final int DEFAULT_DNS_LOG_SIZE = 50;
|
||||
private int mConsecutiveTimeoutCount = 0;
|
||||
private int mSize;
|
||||
final DnsResult[] mDnsEvents;
|
||||
|
||||
@@ -30,6 +30,7 @@ import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.anyObject;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
@@ -48,6 +49,7 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.captiveportal.CaptivePortalProbeResult;
|
||||
import android.net.metrics.DataStallStatsUtils;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.wifi.WifiManager;
|
||||
@@ -98,6 +100,7 @@ public class NetworkMonitorTest {
|
||||
private @Mock NetworkMonitor.Dependencies mDependencies;
|
||||
private @Mock INetworkMonitorCallbacks mCallbacks;
|
||||
private @Spy Network mNetwork = new Network(TEST_NETID);
|
||||
private @Mock DataStallStatsUtils mDataStallStatsUtils;
|
||||
|
||||
private static final int TEST_NETID = 4242;
|
||||
|
||||
@@ -186,9 +189,9 @@ public class NetworkMonitorTest {
|
||||
private long mProbeTime = 0;
|
||||
|
||||
WrappedNetworkMonitor(Context context, Network network, IpConnectivityLog logger,
|
||||
Dependencies deps) {
|
||||
Dependencies deps, DataStallStatsUtils statsUtils) {
|
||||
super(context, mCallbacks, network, logger,
|
||||
new SharedLog("test_nm"), deps);
|
||||
new SharedLog("test_nm"), deps, statsUtils);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,7 +206,7 @@ public class NetworkMonitorTest {
|
||||
|
||||
private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
|
||||
final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
|
||||
mContext, mNetwork, mLogger, mDependencies);
|
||||
mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
|
||||
when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
|
||||
nm.start();
|
||||
waitForIdle(nm.getHandler());
|
||||
@@ -212,7 +215,7 @@ public class NetworkMonitorTest {
|
||||
|
||||
private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
|
||||
final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
|
||||
mContext, mNetwork, mLogger, mDependencies);
|
||||
mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
|
||||
when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES);
|
||||
nm.start();
|
||||
waitForIdle(nm.getHandler());
|
||||
@@ -222,7 +225,7 @@ public class NetworkMonitorTest {
|
||||
private NetworkMonitor makeMonitor() {
|
||||
final NetworkMonitor nm = new NetworkMonitor(
|
||||
mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
|
||||
mDependencies);
|
||||
mDependencies, mDataStallStatsUtils);
|
||||
nm.start();
|
||||
waitForIdle(nm.getHandler());
|
||||
return nm;
|
||||
@@ -505,6 +508,23 @@ public class NetworkMonitorTest {
|
||||
.notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
|
||||
WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
|
||||
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
|
||||
makeDnsTimeoutEvent(wrappedMonitor, 5);
|
||||
assertTrue(wrappedMonitor.isDataStall());
|
||||
verify(mDataStallStatsUtils, times(1)).write(eq(anyObject()), eq(anyObject()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
|
||||
WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
|
||||
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
|
||||
makeDnsTimeoutEvent(wrappedMonitor, 3);
|
||||
assertFalse(wrappedMonitor.isDataStall());
|
||||
verify(mDataStallStatsUtils, times(0)).write(eq(anyObject()), eq(anyObject()));
|
||||
}
|
||||
private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
|
||||
|
||||
Reference in New Issue
Block a user