summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/ClientModeImpl.java28
-rw-r--r--service/java/com/android/server/wifi/DeviceConfigFacade.java51
-rw-r--r--service/java/com/android/server/wifi/WifiDataStall.java176
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java3
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java55
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java11
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java161
7 files changed, 408 insertions, 77 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 8e8361ed4..b80371285 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -765,6 +765,11 @@ public class ClientModeImpl extends StateMachine {
private final WrongPasswordNotifier mWrongPasswordNotifier;
private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
private boolean mConnectedMacRandomzationSupported;
+ // Maximum duration to continue to log Wifi usability stats after a data stall is triggered.
+ @VisibleForTesting
+ public static final long DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS = 30 * 1000;
+ private long mDataStallTriggerTimeMs = -1;
+ private int mLastStatusDataStall = WifiIsUnusableEvent.TYPE_UNKNOWN;
public ClientModeImpl(Context context, FrameworkFacade facade, Looper looper,
UserManager userManager, WifiInjector wifiInjector,
@@ -5109,11 +5114,24 @@ public class ClientModeImpl extends StateMachine {
}
mWifiScoreReport.noteIpCheck();
}
- int statusDataStall =
- mWifiDataStall.checkForDataStall(mLastLinkLayerStats, stats);
- if (statusDataStall != WifiIsUnusableEvent.TYPE_UNKNOWN) {
- mWifiMetrics.addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_BAD,
- convertToUsabilityStatsTriggerType(statusDataStall), -1);
+ int statusDataStall = mWifiDataStall.checkForDataStall(
+ mLastLinkLayerStats, stats, mWifiInfo);
+ if (mDataStallTriggerTimeMs == -1
+ && statusDataStall != WifiIsUnusableEvent.TYPE_UNKNOWN) {
+ mDataStallTriggerTimeMs = mClock.getElapsedSinceBootMillis();
+ mLastStatusDataStall = statusDataStall;
+ }
+ if (mDataStallTriggerTimeMs != -1) {
+ long elapsedTime = mClock.getElapsedSinceBootMillis()
+ - mDataStallTriggerTimeMs;
+ if (elapsedTime >= DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS) {
+ mDataStallTriggerTimeMs = -1;
+ mWifiMetrics.addToWifiUsabilityStatsList(
+ WifiUsabilityStats.LABEL_BAD,
+ convertToUsabilityStatsTriggerType(mLastStatusDataStall),
+ -1);
+ mLastStatusDataStall = WifiIsUnusableEvent.TYPE_UNKNOWN;
+ }
}
mWifiMetrics.incrementWifiLinkLayerUsageStats(stats);
mLastLinkLayerStats = stats;
diff --git a/service/java/com/android/server/wifi/DeviceConfigFacade.java b/service/java/com/android/server/wifi/DeviceConfigFacade.java
index c64cd5259..a9889f424 100644
--- a/service/java/com/android/server/wifi/DeviceConfigFacade.java
+++ b/service/java/com/android/server/wifi/DeviceConfigFacade.java
@@ -28,6 +28,17 @@ public class DeviceConfigFacade {
private static final int DEFAULT_ABNORMAL_CONNECTION_DURATION_MS =
(int) TimeUnit.SECONDS.toMillis(30);
private static final String NAMESPACE = "wifi";
+ // Default duration for evaluating Wifi condition to trigger a data stall
+ // measured in milliseconds
+ public static final int DEFAULT_DATA_STALL_DURATION_MS = 1500;
+ // Default threshold of Tx throughput below which to trigger a data stall measured in Mbps
+ public static final int DEFAULT_DATA_STALL_TX_TPUT_THR_MBPS = 2;
+ // Default threshold of Rx throughput below which to trigger a data stall measured in Mbps
+ public static final int DEFAULT_DATA_STALL_RX_TPUT_THR_MBPS = 2;
+ // Default threshold of Tx packet error rate above which to trigger a data stall in percentage
+ public static final int DEFAULT_DATA_STALL_TX_PER_THR = 90;
+ // Default threshold of CCA level above which to trigger a data stall in percentage
+ public static final int DEFAULT_DATA_STALL_CCA_LEVEL_THR = 100;
/**
* Gets the feature flag for reporting abnormally long connections.
@@ -54,4 +65,44 @@ public class DeviceConfigFacade {
DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor,
onPropertiesChangedListener);
}
+
+ /**
+ * Gets the duration of evaluating Wifi condition to trigger a data stall.
+ */
+ public int getDataStallDurationMs() {
+ return DeviceConfig.getInt(NAMESPACE, "data_stall_duration_ms",
+ DEFAULT_DATA_STALL_DURATION_MS);
+ }
+
+ /**
+ * Gets the threshold of Tx throughput below which to trigger a data stall.
+ */
+ public int getDataStallTxTputThrMbps() {
+ return DeviceConfig.getInt(NAMESPACE, "data_stall_tx_tput_thr_mbps",
+ DEFAULT_DATA_STALL_TX_TPUT_THR_MBPS);
+ }
+
+ /**
+ * Gets the threshold of Rx throughput below which to trigger a data stall.
+ */
+ public int getDataStallRxTputThrMbps() {
+ return DeviceConfig.getInt(NAMESPACE, "data_stall_rx_tput_thr_mbps",
+ DEFAULT_DATA_STALL_RX_TPUT_THR_MBPS);
+ }
+
+ /**
+ * Gets the threshold of Tx packet error rate above which to trigger a data stall.
+ */
+ public int getDataStallTxPerThr() {
+ return DeviceConfig.getInt(NAMESPACE, "data_stall_tx_per_thr",
+ DEFAULT_DATA_STALL_TX_PER_THR);
+ }
+
+ /**
+ * Gets the threshold of CCA level above which to trigger a data stall.
+ */
+ public int getDataStallCcaLevelThr() {
+ return DeviceConfig.getInt(NAMESPACE, "data_stall_cca_level_thr",
+ DEFAULT_DATA_STALL_CCA_LEVEL_THR);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiDataStall.java b/service/java/com/android/server/wifi/WifiDataStall.java
index 1054c2ef1..6eb3b41e5 100644
--- a/service/java/com/android/server/wifi/WifiDataStall.java
+++ b/service/java/com/android/server/wifi/WifiDataStall.java
@@ -17,6 +17,9 @@
package com.android.server.wifi;
import android.content.Context;
+import android.net.wifi.WifiInfo;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import com.android.server.wifi.nano.WifiMetricsProto.WifiIsUnusableEvent;
@@ -33,19 +36,50 @@ public class WifiDataStall {
public static final int MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT = 50;
// Maximum time gap between two WifiLinkLayerStats to trigger a data stall
public static final long MAX_MS_DELTA_FOR_DATA_STALL = 60 * 1000; // 1 minute
+ // Maximum time that a data stall start time stays valid.
+ public static final long VALIDITY_PERIOD_OF_DATA_STALL_START_MS = 30 * 1000; // 0.5 minutes
+ // Default Tx packet error rate when there is no Tx attempt
+ public static final int DEFAULT_TX_PACKET_ERROR_RATE = 20;
+ // Default CCA level when CCA stats are not available
+ public static final int DEFAULT_CCA_LEVEL = 0;
private final Context mContext;
+ private final DeviceConfigFacade mDeviceConfigFacade;
private final FrameworkFacade mFacade;
private final WifiMetrics mWifiMetrics;
+ private Handler mHandler;
private int mMinTxBad;
private int mMinTxSuccessWithoutRx;
+ private int mDataStallDurationMs;
+ private int mDataStallTxTputThrMbps;
+ private int mDataStallRxTputThrMbps;
+ private int mDataStallTxPerThr;
+ private int mDataStallCcaLevelThr;
+ private int mLastFrequency = -1;
+ private String mLastBssid;
+ private long mLastTotalRadioOnFreqTimeMs = -1;
+ private long mLastTotalCcaBusyFreqTimeMs = -1;
+ private long mDataStallStartTimeMs = -1;
+ private Clock mClock;
+ private boolean mDataStallTx = false;
+ private boolean mDataStallRx = false;
- public WifiDataStall(Context context, FrameworkFacade facade, WifiMetrics wifiMetrics) {
+ public WifiDataStall(Context context, FrameworkFacade facade, WifiMetrics wifiMetrics,
+ DeviceConfigFacade deviceConfigFacade, Looper clientModeImplLooper, Clock clock) {
mContext = context;
+ mDeviceConfigFacade = deviceConfigFacade;
mFacade = facade;
+ mHandler = new Handler(clientModeImplLooper);
mWifiMetrics = wifiMetrics;
+ mClock = clock;
loadSettings();
+
+ mDeviceConfigFacade.addOnPropertiesChangedListener(
+ command -> mHandler.post(command),
+ properties -> {
+ updateUsabilityDataCollectionFlags();
+ });
}
/**
@@ -59,15 +93,18 @@ public class WifiDataStall {
MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT);
mWifiMetrics.setWifiDataStallMinTxBad(mMinTxBad);
mWifiMetrics.setWifiDataStallMinRxWithoutTx(mMinTxSuccessWithoutRx);
+ updateUsabilityDataCollectionFlags();
}
/**
* Checks for data stall by looking at tx/rx packet counts
* @param oldStats second most recent WifiLinkLayerStats
* @param newStats most recent WifiLinkLayerStats
+ * @param wifiInfo WifiInfo for current connection
* @return trigger type of WifiIsUnusableEvent
*/
- public int checkForDataStall(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats) {
+ public int checkForDataStall(WifiLinkLayerStats oldStats, WifiLinkLayerStats newStats,
+ WifiInfo wifiInfo) {
if (oldStats == null || newStats == null) {
mWifiMetrics.resetWifiIsUnusableLinkLayerStats();
return WifiIsUnusableEvent.TYPE_UNKNOWN;
@@ -103,25 +140,130 @@ public class WifiDataStall {
mWifiMetrics.updateWifiIsUnusableLinkLayerStats(txSuccessDelta, txRetriesDelta,
txBadDelta, rxSuccessDelta, timeMsDelta);
+
if (timeMsDelta < MAX_MS_DELTA_FOR_DATA_STALL) {
- // There is a data stall if there are too many tx failures
- // or if we are not receiving any packets despite many tx successes
- boolean dataStallBadTx = (txBadDelta >= mMinTxBad);
- boolean dataStallTxSuccessWithoutRx =
- (rxSuccessDelta == 0 && txSuccessDelta >= mMinTxSuccessWithoutRx);
- if (dataStallBadTx && dataStallTxSuccessWithoutRx) {
- mWifiMetrics.logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH);
- return WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH;
- } else if (dataStallBadTx) {
- mWifiMetrics.logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
- return WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX;
- } else if (dataStallTxSuccessWithoutRx) {
- mWifiMetrics.logWifiIsUnusableEvent(
- WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX);
- return WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX;
+ int txLinkSpeed = wifiInfo.getLinkSpeed();
+ int rxLinkSpeed = wifiInfo.getRxLinkSpeedMbps();
+ boolean isSameBssidAndFreq = mLastBssid == null || mLastFrequency == -1
+ || (mLastBssid.equals(wifiInfo.getBSSID())
+ && mLastFrequency == wifiInfo.getFrequency());
+ mLastFrequency = wifiInfo.getFrequency();
+ mLastBssid = wifiInfo.getBSSID();
+
+ int ccaLevel = updateCcaLevel(newStats, wifiInfo, isSameBssidAndFreq);
+ int txPer = updateTxPer(txSuccessDelta, txRetriesDelta, isSameBssidAndFreq);
+
+ boolean isTxTputLow = false;
+ boolean isRxTputLow = false;
+ if (txLinkSpeed > 0) {
+ int txTput = txLinkSpeed * (100 - txPer) * (100 - ccaLevel);
+ isTxTputLow = txTput < mDataStallTxTputThrMbps * 100 * 100;
+ }
+ if (rxLinkSpeed > 0) {
+ int rxTput = rxLinkSpeed * (100 - ccaLevel);
+ isRxTputLow = rxTput < mDataStallRxTputThrMbps * 100;
+ }
+
+ boolean dataStallTx = isTxTputLow || ccaLevel >= mDataStallCcaLevelThr
+ || txPer >= mDataStallTxPerThr;
+ boolean dataStallRx = isRxTputLow || ccaLevel >= mDataStallCcaLevelThr;
+
+ // Data stall event is triggered if there are consecutive Tx and/or Rx data stalls
+ // Reset mDataStallStartTimeMs to -1 if currently there is no Tx or Rx data stall
+ if (dataStallTx || dataStallRx) {
+ mDataStallTx = mDataStallTx || dataStallTx;
+ mDataStallRx = mDataStallRx || dataStallRx;
+ if (mDataStallStartTimeMs == -1) {
+ mDataStallStartTimeMs = mClock.getElapsedSinceBootMillis();
+ if (mDataStallDurationMs == 0) {
+ mDataStallStartTimeMs = -1;
+ int result = calculateUsabilityEventType(mDataStallTx, mDataStallRx);
+ mDataStallRx = false;
+ mDataStallTx = false;
+ return result;
+ }
+ } else {
+ long elapsedTime = mClock.getElapsedSinceBootMillis() - mDataStallStartTimeMs;
+ if (elapsedTime >= mDataStallDurationMs) {
+ mDataStallStartTimeMs = -1;
+ if (elapsedTime <= VALIDITY_PERIOD_OF_DATA_STALL_START_MS) {
+ int result = calculateUsabilityEventType(mDataStallTx, mDataStallRx);
+ mDataStallRx = false;
+ mDataStallTx = false;
+ return result;
+ } else {
+ mDataStallTx = false;
+ mDataStallRx = false;
+ }
+ } else {
+ // No need to do anything.
+ }
+ }
+ } else {
+ mDataStallStartTimeMs = -1;
+ mDataStallTx = false;
+ mDataStallRx = false;
}
}
return WifiIsUnusableEvent.TYPE_UNKNOWN;
}
+
+ private int updateCcaLevel(WifiLinkLayerStats newStats, WifiInfo wifiInfo,
+ boolean isSameBssidAndFreq) {
+ WifiLinkLayerStats.ChannelStats statsMap = newStats.channelStatsMap.get(mLastFrequency);
+ if (statsMap == null || !isSameBssidAndFreq) {
+ return DEFAULT_CCA_LEVEL;
+ }
+ int radioOnTimeDelta = (int) (statsMap.radioOnTimeMs - mLastTotalRadioOnFreqTimeMs);
+ int ccaBusyTimeDelta = (int) (statsMap.ccaBusyTimeMs - mLastTotalCcaBusyFreqTimeMs);
+ mLastTotalRadioOnFreqTimeMs = statsMap.radioOnTimeMs;
+ mLastTotalCcaBusyFreqTimeMs = statsMap.ccaBusyTimeMs;
+
+ boolean isCcaValid = (radioOnTimeDelta > 0) && (ccaBusyTimeDelta >= 0)
+ && (ccaBusyTimeDelta <= radioOnTimeDelta);
+ // Update CCA level only if CCA stats are valid.
+ if (!isCcaValid) {
+ return DEFAULT_CCA_LEVEL;
+ }
+ return (int) (ccaBusyTimeDelta * 100 / radioOnTimeDelta);
+ }
+
+ private int updateTxPer(long txSuccessDelta, long txRetriesDelta, boolean isSameBssidAndFreq) {
+ if (!isSameBssidAndFreq) {
+ return DEFAULT_TX_PACKET_ERROR_RATE;
+ }
+ long txAttempts = txSuccessDelta + txRetriesDelta;
+ if (txAttempts <= 0) {
+ return DEFAULT_TX_PACKET_ERROR_RATE;
+ }
+ return (int) (txRetriesDelta * 100 / txAttempts);
+ }
+
+ private int calculateUsabilityEventType(boolean dataStallTx, boolean dataStallRx) {
+ int result = WifiIsUnusableEvent.TYPE_UNKNOWN;
+ if (dataStallTx && dataStallRx) {
+ result = WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH;
+ } else if (dataStallTx) {
+ result = WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX;
+ } else if (dataStallRx) {
+ result = WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX;
+ }
+ mWifiMetrics.logWifiIsUnusableEvent(result);
+ return result;
+ }
+
+ private void updateUsabilityDataCollectionFlags() {
+ mDataStallDurationMs = mDeviceConfigFacade.getDataStallDurationMs();
+ mDataStallTxTputThrMbps = mDeviceConfigFacade.getDataStallTxTputThrMbps();
+ mDataStallRxTputThrMbps = mDeviceConfigFacade.getDataStallRxTputThrMbps();
+ mDataStallTxPerThr = mDeviceConfigFacade.getDataStallTxPerThr();
+ mDataStallCcaLevelThr = mDeviceConfigFacade.getDataStallCcaLevelThr();
+
+ mWifiMetrics.setDataStallDurationMs(mDataStallDurationMs);
+ mWifiMetrics.setDataStallTxTputThrMbps(mDataStallTxTputThrMbps);
+ mWifiMetrics.setDataStallRxTputThrMbps(mDataStallRxTputThrMbps);
+ mWifiMetrics.setDataStallTxPerThr(mDataStallTxPerThr);
+ mWifiMetrics.setDataStallCcaLevelThr(mDataStallCcaLevelThr);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 3a79e590b..fe9ebea17 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -301,7 +301,8 @@ public class WifiInjector {
mWifiDiagnostics = new WifiDiagnostics(
mContext, this, mWifiNative, mBuildProperties,
new LastMileLogger(this), mClock);
- mWifiDataStall = new WifiDataStall(mContext, mFrameworkFacade, mWifiMetrics);
+ mWifiDataStall = new WifiDataStall(mContext, mFrameworkFacade, mWifiMetrics,
+ mDeviceConfigFacade, clientModeImplLooper, mClock);
mWifiMetrics.setWifiDataStall(mWifiDataStall);
mLinkProbeManager = new LinkProbeManager(mClock, mWifiNative, mWifiMetrics,
mFrameworkFacade, mWifiCoreHandlerThread.getLooper(), mContext);
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index c0b04d34c..1b7e8cdb3 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -2782,6 +2782,16 @@ public class WifiMetrics {
+ mExperimentValues.wifiDataStallMinTxSuccessWithoutRx);
pw.println("mExperimentValues.linkSpeedCountsLoggingEnabled="
+ mExperimentValues.linkSpeedCountsLoggingEnabled);
+ pw.println("mExperimentValues.dataStallDurationMs="
+ + mExperimentValues.dataStallDurationMs);
+ pw.println("mExperimentValues.dataStallTxTputThrMbps="
+ + mExperimentValues.dataStallTxTputThrMbps);
+ pw.println("mExperimentValues.dataStallRxTputThrMbps="
+ + mExperimentValues.dataStallRxTputThrMbps);
+ pw.println("mExperimentValues.dataStallTxPerThr="
+ + mExperimentValues.dataStallTxPerThr);
+ pw.println("mExperimentValues.dataStallCcaLevelThr="
+ + mExperimentValues.dataStallCcaLevelThr);
pw.println("WifiIsUnusableEventList: ");
for (WifiIsUnusableWithTime event : mWifiIsUnusableList) {
pw.println(event);
@@ -5191,4 +5201,49 @@ public class WifiMetrics {
mNumProvisionSuccess++;
}
}
+
+ /**
+ * Sets the duration for evaluating Wifi condition to trigger a data stall
+ */
+ public void setDataStallDurationMs(int duration) {
+ synchronized (mLock) {
+ mExperimentValues.dataStallDurationMs = duration;
+ }
+ }
+
+ /**
+ * Sets the threshold of Tx throughput below which to trigger a data stall
+ */
+ public void setDataStallTxTputThrMbps(int txTputThr) {
+ synchronized (mLock) {
+ mExperimentValues.dataStallTxTputThrMbps = txTputThr;
+ }
+ }
+
+ /**
+ * Sets the threshold of Rx throughput below which to trigger a data stall
+ */
+ public void setDataStallRxTputThrMbps(int rxTputThr) {
+ synchronized (mLock) {
+ mExperimentValues.dataStallRxTputThrMbps = rxTputThr;
+ }
+ }
+
+ /**
+ * Sets the threshold of Tx packet error rate above which to trigger a data stall
+ */
+ public void setDataStallTxPerThr(int txPerThr) {
+ synchronized (mLock) {
+ mExperimentValues.dataStallTxPerThr = txPerThr;
+ }
+ }
+
+ /**
+ * Sets the threshold of CCA level above which to trigger a data stall
+ */
+ public void setDataStallCcaLevelThr(int ccaLevel) {
+ synchronized (mLock) {
+ mExperimentValues.dataStallCcaLevelThr = ccaLevel;
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index a26582c5c..7896a8f0b 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -3340,7 +3340,7 @@ public class ClientModeImplTest {
when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(newLLStats);
mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
mLooper.dispatchAll();
- verify(mWifiDataStall).checkForDataStall(oldLLStats, newLLStats);
+ verify(mWifiDataStall).checkForDataStall(oldLLStats, newLLStats, mCmi.getWifiInfo());
verify(mWifiMetrics).incrementWifiLinkLayerUsageStats(newLLStats);
}
@@ -3356,7 +3356,7 @@ public class ClientModeImplTest {
WifiLinkLayerStats stats = new WifiLinkLayerStats();
when(mWifiNative.getWifiLinkLayerStats(any())).thenReturn(stats);
- when(mWifiDataStall.checkForDataStall(any(), any()))
+ when(mWifiDataStall.checkForDataStall(any(), any(), any()))
.thenReturn(WifiIsUnusableEvent.TYPE_UNKNOWN);
mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
mLooper.dispatchAll();
@@ -3364,11 +3364,16 @@ public class ClientModeImplTest {
verify(mWifiMetrics, never()).addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_BAD,
eq(anyInt()), eq(-1));
- when(mWifiDataStall.checkForDataStall(any(), any()))
+ when(mWifiDataStall.checkForDataStall(any(), any(), any()))
.thenReturn(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
mLooper.dispatchAll();
verify(mWifiMetrics, times(2)).updateWifiUsabilityStatsEntries(any(), eq(stats));
+ when(mClock.getElapsedSinceBootMillis())
+ .thenReturn(10L + ClientModeImpl.DURATION_TO_WAIT_ADD_STATS_AFTER_DATA_STALL_MS);
+ mCmi.sendMessage(ClientModeImpl.CMD_RSSI_POLL, 1);
+ mLooper.dispatchAll();
verify(mWifiMetrics).addToWifiUsabilityStatsList(WifiUsabilityStats.LABEL_BAD,
WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX, -1);
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java b/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java
index a5f6852f8..71b658923 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java
@@ -17,14 +17,17 @@
package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.wifi.WifiInfo;
+import android.os.Looper;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.Settings;
import androidx.test.filters.SmallTest;
@@ -33,6 +36,7 @@ import com.android.server.wifi.nano.WifiMetricsProto.WifiIsUnusableEvent;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -46,9 +50,15 @@ public class WifiDataStallTest {
@Mock FrameworkFacade mFacade;
@Mock WifiMetrics mWifiMetrics;
WifiDataStall mWifiDataStall;
+ @Mock Clock mClock;
+ @Mock DeviceConfigFacade mDeviceConfigFacade;
+ @Mock Looper mClientModeImplLooper;
+ @Mock WifiInfo mWifiInfo;
private final WifiLinkLayerStats mOldLlStats = new WifiLinkLayerStats();
private final WifiLinkLayerStats mNewLlStats = new WifiLinkLayerStats();
+ final ArgumentCaptor<OnPropertiesChangedListener> mOnPropertiesChangedListenerCaptor =
+ ArgumentCaptor.forClass(OnPropertiesChangedListener.class);
/**
* Sets up for unit test
@@ -64,21 +74,38 @@ public class WifiDataStallTest {
Settings.Global.WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX,
WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT))
.thenReturn(WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT);
+ when(mDeviceConfigFacade.getDataStallDurationMs()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ when(mDeviceConfigFacade.getDataStallTxTputThrMbps()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_TX_TPUT_THR_MBPS);
+ when(mDeviceConfigFacade.getDataStallRxTputThrMbps()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_RX_TPUT_THR_MBPS);
+ when(mDeviceConfigFacade.getDataStallTxPerThr()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_TX_PER_THR);
+ when(mDeviceConfigFacade.getDataStallCcaLevelThr()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_CCA_LEVEL_THR);
+ when(mWifiInfo.getLinkSpeed()).thenReturn(100);
+ when(mWifiInfo.getRxLinkSpeedMbps()).thenReturn(100);
+ when(mWifiInfo.getFrequency()).thenReturn(5850);
+ when(mWifiInfo.getBSSID()).thenReturn("5G_WiFi");
- mWifiDataStall = new WifiDataStall(mContext, mFacade, mWifiMetrics);
+ mWifiDataStall = new WifiDataStall(mContext, mFacade, mWifiMetrics, mDeviceConfigFacade,
+ mClientModeImplLooper, mClock);
mOldLlStats.txmpdu_be = 1000;
- mOldLlStats.retries_be = 2000;
+ mOldLlStats.retries_be = 1000;
mOldLlStats.lostmpdu_be = 3000;
mOldLlStats.rxmpdu_be = 4000;
mOldLlStats.timeStampInMs = 10000;
- mNewLlStats.txmpdu_be = mOldLlStats.txmpdu_be;
- mNewLlStats.retries_be = mOldLlStats.retries_be;
+ mNewLlStats.txmpdu_be = 2 * mOldLlStats.txmpdu_be;
+ mNewLlStats.retries_be = 10 * mOldLlStats.retries_be;
mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be;
mNewLlStats.rxmpdu_be = mOldLlStats.rxmpdu_be;
mNewLlStats.timeStampInMs = mOldLlStats.timeStampInMs
+ WifiDataStall.MAX_MS_DELTA_FOR_DATA_STALL - 1;
+ verify(mDeviceConfigFacade).addOnPropertiesChangedListener(any(),
+ mOnPropertiesChangedListenerCaptor.capture());
}
/**
@@ -98,23 +125,53 @@ public class WifiDataStallTest {
*/
@Test
public void verifyDataStallTxFailure() throws Exception {
- mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be + WifiDataStall.MIN_TX_BAD_DEFAULT;
- assertEquals(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
+
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verifyUpdateWifiIsUnusableLinkLayerStats();
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(
+ 10L + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ assertEquals(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verify(mWifiMetrics).logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
}
/**
+ * Verify there is no data stall from tx failures if tx failures are not consecutively bad
+ */
+ @Test
+ public void verifyNoDataStallWhenTxFailureIsNotConsecutive() throws Exception {
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
+
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
+ verifyUpdateWifiIsUnusableLinkLayerStats();
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(
+ 10L + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ mNewLlStats.retries_be = 2 * mOldLlStats.retries_be;
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
+ verify(mWifiMetrics, never()).logWifiIsUnusableEvent(
+ WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
+ }
+
+ /**
* Verify there is data stall from rx failures
*/
@Test
public void verifyDataStallRxFailure() throws Exception {
- mNewLlStats.txmpdu_be =
- mOldLlStats.txmpdu_be + WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT;
- assertEquals(WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ when(mWifiInfo.getRxLinkSpeedMbps()).thenReturn(1);
+ mNewLlStats.retries_be = 2 * mOldLlStats.retries_be;
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
+
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verifyUpdateWifiIsUnusableLinkLayerStats();
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(
+ 10L + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ assertEquals(WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verify(mWifiMetrics).logWifiIsUnusableEvent(
WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX);
}
@@ -124,58 +181,61 @@ public class WifiDataStallTest {
*/
@Test
public void verifyDataStallBothTxRxFailure() throws Exception {
- mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be + WifiDataStall.MIN_TX_BAD_DEFAULT;
- mNewLlStats.txmpdu_be =
- mOldLlStats.txmpdu_be + WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT;
- assertEquals(WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ when(mWifiInfo.getRxLinkSpeedMbps()).thenReturn(1);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
+
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verifyUpdateWifiIsUnusableLinkLayerStats();
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(
+ 10L + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ assertEquals(WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verify(mWifiMetrics).logWifiIsUnusableEvent(WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH);
}
/**
- * Verify that we can change the minimum number of tx failures
- * to trigger data stall from settings
+ * Verify that we can change the duration of evaluating Wifi conditions
+ * to trigger data stall from DeviceConfigFacade
*/
@Test
- public void verifyDataStallTxFailureSettingsChange() throws Exception {
- when(mFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_DATA_STALL_MIN_TX_BAD,
- WifiDataStall.MIN_TX_BAD_DEFAULT))
- .thenReturn(WifiDataStall.MIN_TX_BAD_DEFAULT + 1);
- mWifiDataStall.loadSettings();
- verify(mWifiMetrics).setWifiDataStallMinTxBad(WifiDataStall.MIN_TX_BAD_DEFAULT + 1);
- verify(mWifiMetrics, times(2)).setWifiDataStallMinRxWithoutTx(
- WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT);
+ public void verifyDataStallDurationDeviceConfigChange() throws Exception {
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
+ when(mDeviceConfigFacade.getDataStallDurationMs()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS + 1);
+ mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
- mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be + WifiDataStall.MIN_TX_BAD_DEFAULT;
assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verifyUpdateWifiIsUnusableLinkLayerStats();
- verify(mWifiMetrics, never()).logWifiIsUnusableEvent(anyInt());
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(
+ 10L + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
+ verify(mWifiMetrics, never()).logWifiIsUnusableEvent(
+ WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
}
/**
- * Verify that we can change the minimum number of tx successes when rx success is 0
- * to trigger data stall from settings
+ * Verify that we can change the threshold of Tx packet error rate to trigger a data stall
+ * from DeviceConfigFacade
*/
@Test
- public void verifyDataStallRxFailureSettingsChange() throws Exception {
- when(mFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX,
- WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT))
- .thenReturn(WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT + 1);
- mWifiDataStall.loadSettings();
- verify(mWifiMetrics, times(2)).setWifiDataStallMinTxBad(WifiDataStall.MIN_TX_BAD_DEFAULT);
- verify(mWifiMetrics).setWifiDataStallMinRxWithoutTx(
- WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT + 1);
-
- mNewLlStats.txmpdu_be =
- mOldLlStats.txmpdu_be + WifiDataStall.MIN_TX_SUCCESS_WITHOUT_RX_DEFAULT;
+ public void verifyDataStallTxPerThrDeviceConfigChange() throws Exception {
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(10L);
+ when(mDeviceConfigFacade.getDataStallTxPerThr()).thenReturn(
+ DeviceConfigFacade.DEFAULT_DATA_STALL_TX_PER_THR + 1);
+ mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null);
+
assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verifyUpdateWifiIsUnusableLinkLayerStats();
- verify(mWifiMetrics, never()).logWifiIsUnusableEvent(anyInt());
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(
+ 10L + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS);
+ assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
+ verify(mWifiMetrics, never()).logWifiIsUnusableEvent(
+ WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX);
}
/**
@@ -184,7 +244,7 @@ public class WifiDataStallTest {
@Test
public void verifyNoDataStallWhenNoFail() throws Exception {
assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verify(mWifiMetrics, never()).resetWifiIsUnusableLinkLayerStats();
verifyUpdateWifiIsUnusableLinkLayerStats();
verify(mWifiMetrics, never()).logWifiIsUnusableEvent(anyInt());
@@ -196,11 +256,10 @@ public class WifiDataStallTest {
*/
@Test
public void verifyNoDataStallBigTimeGap() throws Exception {
- mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be + WifiDataStall.MIN_TX_BAD_DEFAULT;
mNewLlStats.timeStampInMs = mOldLlStats.timeStampInMs
+ WifiDataStall.MAX_MS_DELTA_FOR_DATA_STALL + 1;
assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verifyUpdateWifiIsUnusableLinkLayerStats();
verify(mWifiMetrics, never()).logWifiIsUnusableEvent(anyInt());
}
@@ -212,7 +271,7 @@ public class WifiDataStallTest {
public void verifyReset() throws Exception {
mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be - 1;
assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN,
- mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats));
+ mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo));
verify(mWifiMetrics).resetWifiIsUnusableLinkLayerStats();
verify(mWifiMetrics, never()).updateWifiIsUnusableLinkLayerStats(
anyLong(), anyLong(), anyLong(), anyLong(), anyLong());