diff options
author | Mingguang Xu <mingguangxu@google.com> | 2019-10-21 17:27:36 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-10-21 17:27:36 +0000 |
commit | 276542d5b033a9d96c9075293f38de1f2137671e (patch) | |
tree | 244b8bf82340e98ffbb79c0ee699b9cb99b9aac1 | |
parent | f6185e0b31a8258a762b31dd9839a4d731db8946 (diff) | |
parent | 6283731362b946cdcb25a1c039f366c66d49f8bc (diff) |
Merge "Wifi usability: Data stall detection based on link layer stats"
8 files changed, 436 insertions, 80 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 1bc08ea6c..91cb38991 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -717,6 +717,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, @@ -4509,11 +4514,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 f7e12efd8..2eeda1e5f 100644 --- a/service/java/com/android/server/wifi/DeviceConfigFacade.java +++ b/service/java/com/android/server/wifi/DeviceConfigFacade.java @@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit; */ public class DeviceConfigFacade { private Context mContext; + private final WifiMetrics mWifiMetrics; private static final String NAMESPACE = "wifi"; @@ -37,15 +38,32 @@ public class DeviceConfigFacade { @VisibleForTesting protected static final int DEFAULT_ABNORMAL_CONNECTION_DURATION_MS = (int) TimeUnit.SECONDS.toMillis(30); + // 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 Kbps + public static final int DEFAULT_DATA_STALL_TX_TPUT_THR_KBPS = 2000; + // Default threshold of Rx throughput below which to trigger a data stall measured in Kbps + public static final int DEFAULT_DATA_STALL_RX_TPUT_THR_KBPS = 2000; + // 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; private boolean mDefaultMacRandomizationAggressiveModeSsidWhitelistEnabled; // Cached values of fields updated via updateDeviceConfigFlags() private boolean mIsAbnormalConnectionBugreportEnabled; private int mAbnormalConnectionDurationMs; private boolean mIsAggressiveMacRandomizationSsidWhitelistEnabled; + private int mDataStallDurationMs; + private int mDataStallTxTputThrKbps; + private int mDataStallRxTputThrKbps; + private int mDataStallTxPerThr; + private int mDataStallCcaLevelThr; - public DeviceConfigFacade(Context context, Handler handler) { + public DeviceConfigFacade(Context context, Handler handler, WifiMetrics wifiMetrics) { mContext = context; + mWifiMetrics = wifiMetrics; mDefaultMacRandomizationAggressiveModeSsidWhitelistEnabled = mContext.getResources() .getBoolean(R.bool.config_wifi_aggressive_randomization_ssid_whitelist_enabled); @@ -67,6 +85,22 @@ public class DeviceConfigFacade { mIsAggressiveMacRandomizationSsidWhitelistEnabled = DeviceConfig.getBoolean(NAMESPACE, "aggressive_randomization_ssid_whitelist_enabled", mDefaultMacRandomizationAggressiveModeSsidWhitelistEnabled); + + mDataStallDurationMs = DeviceConfig.getInt(NAMESPACE, + "data_stall_duration_ms", DEFAULT_DATA_STALL_DURATION_MS); + mDataStallTxTputThrKbps = DeviceConfig.getInt(NAMESPACE, + "data_stall_tx_tput_thr_kbps", DEFAULT_DATA_STALL_TX_TPUT_THR_KBPS); + mDataStallRxTputThrKbps = DeviceConfig.getInt(NAMESPACE, + "data_stall_rx_tput_thr_kbps", DEFAULT_DATA_STALL_RX_TPUT_THR_KBPS); + mDataStallTxPerThr = DeviceConfig.getInt(NAMESPACE, + "data_stall_tx_per_thr", DEFAULT_DATA_STALL_TX_PER_THR); + mDataStallCcaLevelThr = DeviceConfig.getInt(NAMESPACE, + "data_stall_cca_level_thr", DEFAULT_DATA_STALL_CCA_LEVEL_THR); + mWifiMetrics.setDataStallDurationMs(mDataStallDurationMs); + mWifiMetrics.setDataStallTxTputThrKbps(mDataStallTxTputThrKbps); + mWifiMetrics.setDataStallRxTputThrKbps(mDataStallRxTputThrKbps); + mWifiMetrics.setDataStallTxPerThr(mDataStallTxPerThr); + mWifiMetrics.setDataStallCcaLevelThr(mDataStallCcaLevelThr); } /** @@ -89,4 +123,39 @@ public class DeviceConfigFacade { public boolean isAggressiveMacRandomizationSsidWhitelistEnabled() { return mIsAggressiveMacRandomizationSsidWhitelistEnabled; } + + /** + * Gets the duration of evaluating Wifi condition to trigger a data stall. + */ + public int getDataStallDurationMs() { + return mDataStallDurationMs; + } + + /** + * Gets the threshold of Tx throughput below which to trigger a data stall. + */ + public int getDataStallTxTputThrKbps() { + return mDataStallTxTputThrKbps; + } + + /** + * Gets the threshold of Rx throughput below which to trigger a data stall. + */ + public int getDataStallRxTputThrKbps() { + return mDataStallRxTputThrKbps; + } + + /** + * Gets the threshold of Tx packet error rate above which to trigger a data stall. + */ + public int getDataStallTxPerThr() { + return mDataStallTxPerThr; + } + + /** + * Gets the threshold of CCA level above which to trigger a data stall. + */ + public int getDataStallCcaLevelThr() { + return mDataStallCcaLevelThr; + } } diff --git a/service/java/com/android/server/wifi/WifiDataStall.java b/service/java/com/android/server/wifi/WifiDataStall.java index 1054c2ef1..e32c87c9e 100644 --- a/service/java/com/android/server/wifi/WifiDataStall.java +++ b/service/java/com/android/server/wifi/WifiDataStall.java @@ -17,6 +17,7 @@ package com.android.server.wifi; import android.content.Context; +import android.net.wifi.WifiInfo; import android.provider.Settings; import com.android.server.wifi.nano.WifiMetricsProto.WifiIsUnusableEvent; @@ -33,18 +34,36 @@ 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 int mMinTxBad; private int mMinTxSuccessWithoutRx; + 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, Clock clock) { mContext = context; + mDeviceConfigFacade = deviceConfigFacade; mFacade = facade; mWifiMetrics = wifiMetrics; + mClock = clock; loadSettings(); } @@ -65,9 +84,11 @@ public class WifiDataStall { * 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; @@ -104,24 +125,117 @@ 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) { + long txTputKbps = (long) txLinkSpeed * 1000 * (100 - txPer) * (100 - ccaLevel); + isTxTputLow = + txTputKbps < mDeviceConfigFacade.getDataStallTxTputThrKbps() * 100 * 100; + } + if (rxLinkSpeed > 0) { + long rxTputKbps = (long) rxLinkSpeed * 1000 * (100 - ccaLevel); + isRxTputLow = rxTputKbps < mDeviceConfigFacade.getDataStallRxTputThrKbps() * 100; + } + + boolean dataStallTx = isTxTputLow + || ccaLevel >= mDeviceConfigFacade.getDataStallCcaLevelThr() + || txPer >= mDeviceConfigFacade.getDataStallTxPerThr(); + boolean dataStallRx = isRxTputLow + || ccaLevel >= mDeviceConfigFacade.getDataStallCcaLevelThr(); + + // 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 (mDeviceConfigFacade.getDataStallDurationMs() == 0) { + mDataStallStartTimeMs = -1; + int result = calculateUsabilityEventType(mDataStallTx, mDataStallRx); + mDataStallRx = false; + mDataStallTx = false; + return result; + } + } else { + long elapsedTime = mClock.getElapsedSinceBootMillis() - mDataStallStartTimeMs; + if (elapsedTime >= mDeviceConfigFacade.getDataStallDurationMs()) { + 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; + } } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index a352ba181..19bdf2eca 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -197,13 +197,13 @@ public class WifiInjector { new HandlerThread("PasspointProvisionerHandlerThread"); mPasspointProvisionerHandlerThread.start(); mCarrierNetworkConfig = new CarrierNetworkConfig(mContext, wifiHandler, mFrameworkFacade); - mDeviceConfigFacade = new DeviceConfigFacade(mContext, wifiHandler); WifiAwareMetrics awareMetrics = new WifiAwareMetrics(mClock); RttMetrics rttMetrics = new RttMetrics(mClock); mWifiP2pMetrics = new WifiP2pMetrics(mClock); mDppMetrics = new DppMetrics(); mWifiMetrics = new WifiMetrics(mContext, mFrameworkFacade, mClock, wifiLooper, awareMetrics, rttMetrics, new WifiPowerMetrics(), mWifiP2pMetrics, mDppMetrics); + mDeviceConfigFacade = new DeviceConfigFacade(mContext, wifiHandler, mWifiMetrics); // Modules interacting with Native. mWifiMonitor = new WifiMonitor(this); mHalDeviceManager = new HalDeviceManager(mClock, wifiHandler); @@ -297,7 +297,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, mClock); mWifiMetrics.setWifiDataStall(mWifiDataStall); mLinkProbeManager = new LinkProbeManager(mClock, mWifiNative, mWifiMetrics, mFrameworkFacade, wifiHandler, mContext); diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 109129016..e178e727b 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -2755,6 +2755,16 @@ public class WifiMetrics { + mExperimentValues.wifiDataStallMinTxSuccessWithoutRx); pw.println("mExperimentValues.linkSpeedCountsLoggingEnabled=" + mExperimentValues.linkSpeedCountsLoggingEnabled); + pw.println("mExperimentValues.dataStallDurationMs=" + + mExperimentValues.dataStallDurationMs); + pw.println("mExperimentValues.dataStallTxTputThrKbps=" + + mExperimentValues.dataStallTxTputThrKbps); + pw.println("mExperimentValues.dataStallRxTputThrKbps=" + + mExperimentValues.dataStallRxTputThrKbps); + pw.println("mExperimentValues.dataStallTxPerThr=" + + mExperimentValues.dataStallTxPerThr); + pw.println("mExperimentValues.dataStallCcaLevelThr=" + + mExperimentValues.dataStallCcaLevelThr); pw.println("WifiIsUnusableEventList: "); for (WifiIsUnusableWithTime event : mWifiIsUnusableList) { pw.println(event); @@ -5099,4 +5109,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 setDataStallTxTputThrKbps(int txTputThr) { + synchronized (mLock) { + mExperimentValues.dataStallTxTputThrKbps = txTputThr; + } + } + + /** + * Sets the threshold of Rx throughput below which to trigger a data stall + */ + public void setDataStallRxTputThrKbps(int rxTputThr) { + synchronized (mLock) { + mExperimentValues.dataStallRxTputThrKbps = 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 18d685958..7671076c0 100644 --- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java @@ -3274,7 +3274,7 @@ public class ClientModeImplTest extends WifiBaseTest { 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); } @@ -3290,7 +3290,7 @@ public class ClientModeImplTest extends WifiBaseTest { 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(); @@ -3298,11 +3298,16 @@ public class ClientModeImplTest extends WifiBaseTest { 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/DeviceConfigFacadeTest.java b/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java index f605aa79c..1c04b7439 100644 --- a/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java +++ b/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java @@ -49,6 +49,7 @@ import org.mockito.MockitoSession; @SmallTest public class DeviceConfigFacadeTest extends WifiBaseTest { @Mock Context mContext; + @Mock WifiMetrics mWifiMetrics; final ArgumentCaptor<OnPropertiesChangedListener> mOnPropertiesChangedListenerCaptor = ArgumentCaptor.forClass(OnPropertiesChangedListener.class); @@ -88,7 +89,8 @@ public class DeviceConfigFacadeTest extends WifiBaseTest { } }); - mDeviceConfigFacade = new DeviceConfigFacade(mContext, new Handler(mLooper.getLooper())); + mDeviceConfigFacade = new DeviceConfigFacade(mContext, new Handler(mLooper.getLooper()), + mWifiMetrics); verify(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(), mOnPropertiesChangedListenerCaptor.capture())); } @@ -113,6 +115,16 @@ public class DeviceConfigFacadeTest extends WifiBaseTest { mDeviceConfigFacade.getAbnormalConnectionDurationMs()); assertEquals(false, mDeviceConfigFacade.isAggressiveMacRandomizationSsidWhitelistEnabled()); + assertEquals(DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS, + mDeviceConfigFacade.getDataStallDurationMs()); + assertEquals(DeviceConfigFacade.DEFAULT_DATA_STALL_TX_TPUT_THR_KBPS, + mDeviceConfigFacade.getDataStallTxTputThrKbps()); + assertEquals(DeviceConfigFacade.DEFAULT_DATA_STALL_RX_TPUT_THR_KBPS, + mDeviceConfigFacade.getDataStallRxTputThrKbps()); + assertEquals(DeviceConfigFacade.DEFAULT_DATA_STALL_TX_PER_THR, + mDeviceConfigFacade.getDataStallTxPerThr()); + assertEquals(DeviceConfigFacade.DEFAULT_DATA_STALL_CCA_LEVEL_THR, + mDeviceConfigFacade.getDataStallCcaLevelThr()); // Simulate updating the fields when(DeviceConfig.getBoolean(anyString(), eq("abnormal_connection_bugreport_enabled"), @@ -122,11 +134,26 @@ public class DeviceConfigFacadeTest extends WifiBaseTest { when(DeviceConfig.getBoolean(anyString(), eq("aggressive_randomization_ssid_whitelist_enabled"), anyBoolean())).thenReturn(true); + when(DeviceConfig.getInt(anyString(), eq("data_stall_duration_ms"), + anyInt())).thenReturn(0); + when(DeviceConfig.getInt(anyString(), eq("data_stall_tx_tput_thr_kbps"), + anyInt())).thenReturn(1000); + when(DeviceConfig.getInt(anyString(), eq("data_stall_rx_tput_thr_kbps"), + anyInt())).thenReturn(1500); + when(DeviceConfig.getInt(anyString(), eq("data_stall_tx_per_thr"), + anyInt())).thenReturn(95); + when(DeviceConfig.getInt(anyString(), eq("data_stall_cca_level_thr"), + anyInt())).thenReturn(80); mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); // Verifying fields are updated to the new values assertEquals(true, mDeviceConfigFacade.isAbnormalConnectionBugreportEnabled()); assertEquals(100, mDeviceConfigFacade.getAbnormalConnectionDurationMs()); assertEquals(true, mDeviceConfigFacade.isAggressiveMacRandomizationSsidWhitelistEnabled()); + assertEquals(0, mDeviceConfigFacade.getDataStallDurationMs()); + assertEquals(1000, mDeviceConfigFacade.getDataStallTxTputThrKbps()); + assertEquals(1500, mDeviceConfigFacade.getDataStallRxTputThrKbps()); + assertEquals(95, mDeviceConfigFacade.getDataStallTxPerThr()); + assertEquals(80, mDeviceConfigFacade.getDataStallCcaLevelThr()); } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java b/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java index 09c683a3a..898409f1a 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiDataStallTest.java @@ -20,11 +20,11 @@ import static org.junit.Assert.assertEquals; 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.provider.Settings; import androidx.test.filters.SmallTest; @@ -46,6 +46,9 @@ public class WifiDataStallTest extends WifiBaseTest { @Mock FrameworkFacade mFacade; @Mock WifiMetrics mWifiMetrics; WifiDataStall mWifiDataStall; + @Mock Clock mClock; + @Mock DeviceConfigFacade mDeviceConfigFacade; + @Mock WifiInfo mWifiInfo; private final WifiLinkLayerStats mOldLlStats = new WifiLinkLayerStats(); private final WifiLinkLayerStats mNewLlStats = new WifiLinkLayerStats(); @@ -64,17 +67,32 @@ public class WifiDataStallTest extends WifiBaseTest { 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.getDataStallTxTputThrKbps()).thenReturn( + DeviceConfigFacade.DEFAULT_DATA_STALL_TX_TPUT_THR_KBPS); + when(mDeviceConfigFacade.getDataStallRxTputThrKbps()).thenReturn( + DeviceConfigFacade.DEFAULT_DATA_STALL_RX_TPUT_THR_KBPS); + 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, + 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 @@ -98,23 +116,73 @@ public class WifiDataStallTest extends WifiBaseTest { */ @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 if tx tput is above the threshold + */ + @Test + public void verifyNoDataStallTxFailureWhenTxTputIsHigh() throws Exception { + when(mWifiInfo.getLinkSpeed()).thenReturn(867); + when(mClock.getElapsedSinceBootMillis()).thenReturn(10L); + mNewLlStats.retries_be = mOldLlStats.retries_be; + + assertEquals(WifiIsUnusableEvent.TYPE_UNKNOWN, + mWifiDataStall.checkForDataStall(mOldLlStats, mNewLlStats, mWifiInfo)); + verifyUpdateWifiIsUnusableLinkLayerStats(); + 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 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 +192,57 @@ public class WifiDataStallTest extends WifiBaseTest { */ @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); - - mNewLlStats.lostmpdu_be = mOldLlStats.lostmpdu_be + WifiDataStall.MIN_TX_BAD_DEFAULT; + public void verifyDataStallDurationDeviceConfigChange() throws Exception { + when(mClock.getElapsedSinceBootMillis()).thenReturn(10L); + when(mDeviceConfigFacade.getDataStallDurationMs()).thenReturn( + DeviceConfigFacade.DEFAULT_DATA_STALL_DURATION_MS + 1); 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); 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 +251,7 @@ public class WifiDataStallTest extends WifiBaseTest { @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()); @@ -200,7 +267,7 @@ public class WifiDataStallTest extends WifiBaseTest { 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 +279,7 @@ public class WifiDataStallTest extends WifiBaseTest { 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()); |