diff options
9 files changed, 238 insertions, 69 deletions
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 2c01eb8f8..85eeb22fa 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -1583,6 +1583,32 @@ public class ClientModeImpl extends StateMachine { sendMessageAtFrontOfQueue(CMD_SET_OPERATIONAL_MODE); } + private void checkAbnormalConnectionFailureAndTakeBugReport(String ssid) { + if (mWifiInjector.getDeviceConfigFacade() + .isAbnormalConnectionFailureBugreportEnabled()) { + int reasonCode = mWifiScoreCard.detectAbnormalConnectionFailure(ssid); + if (reasonCode != WifiHealthMonitor.REASON_NO_FAILURE) { + String bugTitle = "Wi-Fi BugReport"; + String bugDetail = "Detect abnormal " + + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode]; + takeBugReport(bugTitle, bugDetail); + } + } + } + + private void checkAbnormalDisconnectionAndTakeBugReport() { + if (mWifiInjector.getDeviceConfigFacade() + .isAbnormalDisconnectionBugreportEnabled()) { + int reasonCode = mWifiScoreCard.detectAbnormalDisconnection(); + if (reasonCode != WifiHealthMonitor.REASON_NO_FAILURE) { + String bugTitle = "Wi-Fi BugReport"; + String bugDetail = "Detect abnormal " + + WifiHealthMonitor.FAILURE_REASON_NAME[reasonCode]; + takeBugReport(bugTitle, bugDetail); + } + } + } + /** * Initiates a system-level bugreport, in a non-blocking fashion. */ @@ -2731,6 +2757,7 @@ public class ClientModeImpl extends StateMachine { mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mLastSimBasedConnectionCarrierName = null; + checkAbnormalDisconnectionAndTakeBugReport(); mWifiScoreCard.resetConnectionState(); mWifiDataStall.reset(); updateL2KeyAndGroupHint(); @@ -2901,18 +2928,7 @@ public class ClientModeImpl extends StateMachine { : configuration.networkId; int scanRssi = mWifiConfigManager.findScanRssi(networkId, SCAN_RSSI_VALID_TIME_MS); mWifiScoreCard.noteConnectionFailure(mWifiInfo, scanRssi, ssid, blocklistReason); - boolean isNonWrongPwdAuthFailure = - blocklistReason == BssidBlocklistMonitor.REASON_AUTHENTICATION_FAILURE - || blocklistReason == BssidBlocklistMonitor.REASON_EAP_FAILURE; - boolean isEnterpriseNetwork = configuration != null && configuration.isEnterprise(); - if (isNonWrongPwdAuthFailure && isEnterpriseNetwork && mWifiInjector - .getDeviceConfigFacade().isAbnormalEapAuthFailureBugreportEnabled() - && mWifiScoreCard.detectAbnormalAuthFailure(ssid)) { - String bugTitle = "Wi-Fi BugReport"; - String bugDetail = "Abnormal authentication failure with enterprise network"; - mWifiDiagnostics.takeBugReport(bugTitle, bugDetail); - } - + checkAbnormalConnectionFailureAndTakeBugReport(ssid); boolean isLowRssi = false; int sufficientRssi = getSufficientRssi(networkId, bssid); if (scanRssi != WifiInfo.INVALID_RSSI && sufficientRssi != WifiInfo.INVALID_RSSI) { diff --git a/service/java/com/android/server/wifi/DeviceConfigFacade.java b/service/java/com/android/server/wifi/DeviceConfigFacade.java index 7ea346c80..67cc01ce9 100644 --- a/service/java/com/android/server/wifi/DeviceConfigFacade.java +++ b/service/java/com/android/server/wifi/DeviceConfigFacade.java @@ -67,12 +67,12 @@ public class DeviceConfigFacade { public static final int DEFAULT_RX_PACKET_PER_SECOND_THR = 1; // Default high threshold values for various connection/disconnection cases // All of them are in percent with respect to connection attempts - static final int DEFAULT_CONNECTION_FAILURE_HIGH_THR_PERCENT = 30; - static final int DEFAULT_ASSOC_REJECTION_HIGH_THR_PERCENT = 20; - static final int DEFAULT_ASSOC_TIMEOUT_HIGH_THR_PERCENT = 20; - static final int DEFAULT_AUTH_FAILURE_HIGH_THR_PERCENT = 20; - static final int DEFAULT_SHORT_CONNECTION_NONLOCAL_HIGH_THR_PERCENT = 15; - static final int DEFAULT_DISCONNECTION_NONLOCAL_HIGH_THR_PERCENT = 20; + static final int DEFAULT_CONNECTION_FAILURE_HIGH_THR_PERCENT = 40; + static final int DEFAULT_ASSOC_REJECTION_HIGH_THR_PERCENT = 30; + static final int DEFAULT_ASSOC_TIMEOUT_HIGH_THR_PERCENT = 30; + static final int DEFAULT_AUTH_FAILURE_HIGH_THR_PERCENT = 30; + static final int DEFAULT_SHORT_CONNECTION_NONLOCAL_HIGH_THR_PERCENT = 20; + static final int DEFAULT_DISCONNECTION_NONLOCAL_HIGH_THR_PERCENT = 25; // Default health monitor abnormal count minimum for various cases static final int DEFAULT_CONNECTION_FAILURE_COUNT_MIN = 6; static final int DEFAULT_ASSOC_REJECTION_COUNT_MIN = 3; @@ -90,6 +90,11 @@ public class DeviceConfigFacade { static final int DEFAULT_HEALTH_MONITOR_MIN_RSSI_THR_DBM = -68; // Default minimum number of connection attempts to qualify daily detection static final int DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT = 10; + // Default minimum wait time between two bug report captures + static final int DEFAULT_BUG_REPORT_MIN_WINDOW_MS = 3_600_000; + // Default report-high threshold to take-bug-report threshold ratio. + // It should be larger than 1 since the bar to take bugreport should be higher. + static final int DEFAULT_BUG_REPORT_THRESHOLD_EXTRA_RATIO = 2; // Cached values of fields updated via updateDeviceConfigFlags() private boolean mIsAbnormalConnectionBugreportEnabled; @@ -122,8 +127,11 @@ public class DeviceConfigFacade { private Set<String> mRandomizationFlakySsidHotlist; private Set<String> mAggressiveMacRandomizationSsidAllowlist; private Set<String> mAggressiveMacRandomizationSsidBlocklist; - private boolean mIsAbnormalEapAuthFailureBugreportEnabled; + private boolean mIsAbnormalConnectionFailureBugreportEnabled; + private boolean mIsAbnormalDisconnectionBugreportEnabled; private int mHealthMonitorMinNumConnectionAttempt; + private int mBugReportMinWindowMs; + private int mBugReportThresholdExtraRatio; public DeviceConfigFacade(Context context, Handler handler, WifiMetrics wifiMetrics) { mContext = context; @@ -224,11 +232,19 @@ public class DeviceConfigFacade { mAggressiveMacRandomizationSsidBlocklist = getUnmodifiableSetQuoted("aggressive_randomization_ssid_blocklist"); - mIsAbnormalEapAuthFailureBugreportEnabled = DeviceConfig.getBoolean(NAMESPACE, - "abnormal_eap_auth_failure_bugreport_enabled", false); + mIsAbnormalConnectionFailureBugreportEnabled = DeviceConfig.getBoolean(NAMESPACE, + "abnormal_connection_failure_bugreport_enabled", false); + mIsAbnormalDisconnectionBugreportEnabled = DeviceConfig.getBoolean(NAMESPACE, + "abnormal_disconnection_bugreport_enabled", false); mHealthMonitorMinNumConnectionAttempt = DeviceConfig.getInt(NAMESPACE, "health_monitor_min_num_connection_attempt", DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT); + mBugReportMinWindowMs = DeviceConfig.getInt(NAMESPACE, + "bug_report_min_window_ms", + DEFAULT_BUG_REPORT_MIN_WINDOW_MS); + mBugReportThresholdExtraRatio = DeviceConfig.getInt(NAMESPACE, + "report_bug_report_threshold_extra_ratio", + DEFAULT_BUG_REPORT_THRESHOLD_EXTRA_RATIO); } private Set<String> getUnmodifiableSetQuoted(String key) { @@ -458,12 +474,18 @@ public class DeviceConfigFacade { public Set<String> getAggressiveMacRandomizationSsidBlocklist() { return mAggressiveMacRandomizationSsidBlocklist; } + /** + * Gets the feature flag for reporting abnormal connection failure. + */ + public boolean isAbnormalConnectionFailureBugreportEnabled() { + return mIsAbnormalConnectionFailureBugreportEnabled; + } /** - * Gets the feature flag for reporting abnormal EAP authentication failure. + * Gets the feature flag for reporting abnormal disconnection. */ - public boolean isAbnormalEapAuthFailureBugreportEnabled() { - return mIsAbnormalEapAuthFailureBugreportEnabled; + public boolean isAbnormalDisconnectionBugreportEnabled() { + return mIsAbnormalDisconnectionBugreportEnabled; } /** @@ -472,4 +494,18 @@ public class DeviceConfigFacade { public int getHealthMonitorMinNumConnectionAttempt() { return mHealthMonitorMinNumConnectionAttempt; } + + /** + * Gets minimum wait time between two bug report captures + */ + public int getBugReportMinWindowMs() { + return mBugReportMinWindowMs; + } + + /** + * Gets the extra ratio of threshold to trigger bug report. + */ + public int getBugReportThresholdExtraRatio() { + return mBugReportThresholdExtraRatio; + } } diff --git a/service/java/com/android/server/wifi/WifiDiagnostics.java b/service/java/com/android/server/wifi/WifiDiagnostics.java index 05c4df634..4ac982063 100644 --- a/service/java/com/android/server/wifi/WifiDiagnostics.java +++ b/service/java/com/android/server/wifi/WifiDiagnostics.java @@ -108,7 +108,6 @@ class WifiDiagnostics extends BaseWifiDiagnostics { public static final long MIN_DUMP_TIME_WINDOW_MILLIS = 10 * 60 * 1000; // 10 mins private long mLastBugReportTime; - static final long MIN_BUG_REPORT_TIME_WINDOW_MILLIS = 60 * 60 * 1000; // 60 mins @VisibleForTesting public static final String FIRMWARE_DUMP_SECTION_HEADER = "FW Memory dump"; @@ -302,7 +301,8 @@ class WifiDiagnostics extends BaseWifiDiagnostics { return; } long currentTime = mClock.getWallClockMillis(); - if ((currentTime - mLastBugReportTime) < MIN_BUG_REPORT_TIME_WINDOW_MILLIS + if ((currentTime - mLastBugReportTime) + < mWifiInjector.getDeviceConfigFacade().getBugReportMinWindowMs() && mLastBugReportTime > 0) { return; } diff --git a/service/java/com/android/server/wifi/WifiHealthMonitor.java b/service/java/com/android/server/wifi/WifiHealthMonitor.java index b85fa5fbe..123c576bd 100644 --- a/service/java/com/android/server/wifi/WifiHealthMonitor.java +++ b/service/java/com/android/server/wifi/WifiHealthMonitor.java @@ -524,6 +524,7 @@ public class WifiHealthMonitor { mWifiSystemInfoStats.clearAll(); } + public static final int REASON_NO_FAILURE = -1; public static final int REASON_ASSOC_REJECTION = 0; public static final int REASON_ASSOC_TIMEOUT = 1; public static final int REASON_AUTH_FAILURE = 2; @@ -531,7 +532,16 @@ public class WifiHealthMonitor { public static final int REASON_DISCONNECTION_NONLOCAL = 4; public static final int REASON_SHORT_CONNECTION_NONLOCAL = 5; public static final int NUMBER_FAILURE_REASON_CODE = 6; + public static final String[] FAILURE_REASON_NAME = { + "association rejection failure", + "association timeout failure", + "authentication failure", + "connection failure", + "disconnection", + "short connection" + }; @IntDef(prefix = { "REASON_" }, value = { + REASON_NO_FAILURE, REASON_ASSOC_REJECTION, REASON_ASSOC_TIMEOUT, REASON_AUTH_FAILURE, diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java index 79c9ccb24..61a8435ed 100644 --- a/service/java/com/android/server/wifi/WifiScoreCard.java +++ b/service/java/com/android/server/wifi/WifiScoreCard.java @@ -27,6 +27,7 @@ import static com.android.server.wifi.WifiHealthMonitor.REASON_ASSOC_TIMEOUT; import static com.android.server.wifi.WifiHealthMonitor.REASON_AUTH_FAILURE; import static com.android.server.wifi.WifiHealthMonitor.REASON_CONNECTION_FAILURE; import static com.android.server.wifi.WifiHealthMonitor.REASON_DISCONNECTION_NONLOCAL; +import static com.android.server.wifi.WifiHealthMonitor.REASON_NO_FAILURE; import static com.android.server.wifi.WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL; import android.annotation.IntDef; @@ -104,10 +105,6 @@ public class WifiScoreCard { // disconnection stats collection. private static final int LAST_RSSI_POLL_MAX_INTERVAL_MS = 3_100; - // Minimum number of connection attempts to qualify abnormal auth detection - static final int MIN_NUM_CONNECTION_ATTEMPT_ABNORMAL_AUTH_FAILURE = 5; - static final int FAILURE_PERCENT_THRESHOLD_ABNORMAL_AUTH_FAILURE = 80; - static final int INSUFFICIENT_RECENT_STATS = 0; static final int SUFFICIENT_RECENT_STATS_ONLY = 1; static final int SUFFICIENT_RECENT_PREV_STATS = 2; @@ -258,7 +255,7 @@ public class WifiScoreCard { * Handle network disconnection or shutdown event */ public void resetConnectionState() { - String ssidDisconnected = (mAttemptingSwitch) ? mSsidPrev : mSsidCurr; + String ssidDisconnected = mAttemptingSwitch ? mSsidPrev : mSsidCurr; updatePerNetwork(Event.DISCONNECTION, ssidDisconnected, INVALID_RSSI, LINK_SPEED_UNKNOWN, UNKNOWN_REASON); if (mVerboseLoggingEnabled && mTsConnectionAttemptStart > TS_NONE && !mAttemptingSwitch) { @@ -565,20 +562,90 @@ public class WifiScoreCard { } /** - * Detect abnormal authentication failure at high RSSI with enough connection attempts - * and high failure rate - * @return true if abnormal auth failure is detected, false otherwise + * Detect abnormal disconnection at high RSSI with a high rate */ - public boolean detectAbnormalAuthFailure(String ssid) { + public int detectAbnormalDisconnection() { + String ssid = mAttemptingSwitch ? mSsidPrev : mSsidCurr; PerNetwork perNetwork = lookupNetwork(ssid); NetworkConnectionStats recentStats = perNetwork.getRecentStats(); - logd("detectAbnormalAuthFailure: " + recentStats.toString()); - int numAuthFailure = recentStats.getCount(CNT_AUTHENTICATION_FAILURE); - int numAttempt = recentStats.getCount(CNT_CONNECTION_ATTEMPT); - boolean hasEnoughAttempt = numAttempt >= MIN_NUM_CONNECTION_ATTEMPT_ABNORMAL_AUTH_FAILURE; - boolean isAuthFailureRateHigh = (numAuthFailure * 100) - >= (numAttempt * FAILURE_PERCENT_THRESHOLD_ABNORMAL_AUTH_FAILURE); - return hasEnoughAttempt && isAuthFailureRateHigh; + if (recentStats.getRecentCountCode() == CNT_SHORT_CONNECTION_NONLOCAL) { + return detectAbnormalFailureReason(recentStats, CNT_SHORT_CONNECTION_NONLOCAL, + REASON_SHORT_CONNECTION_NONLOCAL, + mDeviceConfigFacade.getShortConnectionNonlocalHighThrPercent(), + mDeviceConfigFacade.getShortConnectionNonlocalCountMin(), + CNT_DISCONNECTION); + } else if (recentStats.getRecentCountCode() == CNT_DISCONNECTION_NONLOCAL) { + return detectAbnormalFailureReason(recentStats, CNT_DISCONNECTION_NONLOCAL, + REASON_DISCONNECTION_NONLOCAL, + mDeviceConfigFacade.getDisconnectionNonlocalHighThrPercent(), + mDeviceConfigFacade.getDisconnectionNonlocalCountMin(), + CNT_DISCONNECTION); + } else { + return REASON_NO_FAILURE; + } + } + + /** + * Detect abnormal connection failure at high RSSI with a high rate + */ + public int detectAbnormalConnectionFailure(String ssid) { + PerNetwork perNetwork = lookupNetwork(ssid); + NetworkConnectionStats recentStats = perNetwork.getRecentStats(); + int recentCountCode = recentStats.getRecentCountCode(); + if (recentCountCode == CNT_AUTHENTICATION_FAILURE) { + return detectAbnormalFailureReason(recentStats, CNT_AUTHENTICATION_FAILURE, + REASON_AUTH_FAILURE, + mDeviceConfigFacade.getAuthFailureHighThrPercent(), + mDeviceConfigFacade.getAuthFailureCountMin(), + CNT_CONNECTION_ATTEMPT); + } else if (recentCountCode == CNT_ASSOCIATION_REJECTION) { + return detectAbnormalFailureReason(recentStats, CNT_ASSOCIATION_REJECTION, + REASON_ASSOC_REJECTION, + mDeviceConfigFacade.getAssocRejectionHighThrPercent(), + mDeviceConfigFacade.getAssocRejectionCountMin(), + CNT_CONNECTION_ATTEMPT); + } else if (recentCountCode == CNT_ASSOCIATION_TIMEOUT) { + return detectAbnormalFailureReason(recentStats, CNT_ASSOCIATION_TIMEOUT, + REASON_ASSOC_TIMEOUT, + mDeviceConfigFacade.getAssocTimeoutHighThrPercent(), + mDeviceConfigFacade.getAssocTimeoutCountMin(), + CNT_CONNECTION_ATTEMPT); + } else if (recentCountCode == CNT_CONNECTION_FAILURE) { + return detectAbnormalFailureReason(recentStats, CNT_CONNECTION_FAILURE, + REASON_CONNECTION_FAILURE, + mDeviceConfigFacade.getConnectionFailureHighThrPercent(), + mDeviceConfigFacade.getConnectionFailureCountMin(), + CNT_CONNECTION_ATTEMPT); + } else { + return REASON_NO_FAILURE; + } + } + + private int detectAbnormalFailureReason(NetworkConnectionStats stats, int countCode, + int reasonCode, int highThresholdPercent, int minCount, int refCountCode) { + // To detect abnormal failure which may trigger bugReport, + // increase the detection threshold by thresholdRatio + int thresholdRatio = + mDeviceConfigFacade.getBugReportThresholdExtraRatio(); + if (isHighPercentageAndEnoughCount(stats, countCode, reasonCode, + highThresholdPercent * thresholdRatio, + minCount * thresholdRatio, + refCountCode)) { + return reasonCode; + } else { + return REASON_NO_FAILURE; + } + } + + private boolean isHighPercentageAndEnoughCount(NetworkConnectionStats stats, int countCode, + int reasonCode, int highThresholdPercent, int minCount, int refCountCode) { + highThresholdPercent = Math.min(highThresholdPercent, 100); + // Use Laplace's rule of succession, useful especially for a small + // connection attempt count + // R = (f+1)/(n+2) with a pseudo count of 2 (one for f and one for s) + return ((stats.getCount(countCode) >= minCount) + && ((stats.getCount(countCode) + 1) * 100) + >= (highThresholdPercent * (stats.getCount(refCountCode) + 2))); } final class PerBssid extends MemoryStoreAccessBase { @@ -999,12 +1066,8 @@ public class WifiScoreCard { private boolean recentStatsHighDetection(FailureStats statsHigh, int countCode, int reasonCode, int highThresholdPercent, int minCount, int refCountCode) { - // Use Laplace's rule of succession, useful especially for a small - // connection attempt count - // R = (f+1)/(n+2) with a pseudo count of 2 (one for f and one for s) - if ((((mRecentStats.getCount(countCode) + 1) * 100) - >= (highThresholdPercent * (mRecentStats.getCount(refCountCode) + 2))) - && (mRecentStats.getCount(countCode) >= minCount)) { + if (isHighPercentageAndEnoughCount(mRecentStats, countCode, reasonCode, + highThresholdPercent, minCount, refCountCode)) { statsHigh.incrementCount(reasonCode); return true; } @@ -1152,6 +1215,7 @@ public class WifiScoreCard { } // Codes for various connection related counts + public static final int CNT_INVALID = -1; public static final int CNT_CONNECTION_ATTEMPT = 0; public static final int CNT_CONNECTION_FAILURE = 1; public static final int CNT_CONNECTION_DURATION_SEC = 2; @@ -1194,7 +1258,7 @@ public class WifiScoreCard { */ public static class NetworkConnectionStats { private final int[] mCount = new int[NUMBER_CONNECTION_CNT_CODE]; - + private int mRecentCountCode = CNT_INVALID; /** * Copy all values * @param src is the source of copy @@ -1203,6 +1267,7 @@ public class WifiScoreCard { for (int i = 0; i < NUMBER_CONNECTION_CNT_CODE; i++) { mCount[i] = src.getCount(i); } + mRecentCountCode = src.mRecentCountCode; } /** @@ -1212,6 +1277,7 @@ public class WifiScoreCard { for (int i = 0; i < NUMBER_CONNECTION_CNT_CODE; i++) { mCount[i] = 0; } + mRecentCountCode = CNT_INVALID; } /** @@ -1224,12 +1290,13 @@ public class WifiScoreCard { } /** - * Set counterer value + * Set counter value * @param countCode is the selected counter * @param cnt is the value set to the selected counter */ public void setCount(@ConnectionCountCode int countCode, int cnt) { mCount[countCode] = cnt; + mRecentCountCode = countCode; } /** @@ -1238,6 +1305,14 @@ public class WifiScoreCard { */ public void incrementCount(@ConnectionCountCode int countCode) { mCount[countCode]++; + mRecentCountCode = countCode; + } + + /** + * Got the recent count code + */ + public int getRecentCountCode() { + return mRecentCountCode; } /** diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java index 0679b8c4f..1930cd15a 100644 --- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java @@ -551,7 +551,12 @@ public class ClientModeImplTest extends WifiBaseTest { mConnectedNetwork = spy(WifiConfigurationTestUtil.createOpenNetwork()); when(mNullAsyncChannel.sendMessageSynchronously(any())).thenReturn(null); when(mWifiScoreCard.getL2KeyAndGroupHint(any())).thenReturn(new Pair<>(null, null)); - when(mDeviceConfigFacade.isAbnormalEapAuthFailureBugreportEnabled()).thenReturn(true); + when(mDeviceConfigFacade.isAbnormalDisconnectionBugreportEnabled()).thenReturn(true); + when(mDeviceConfigFacade.isAbnormalConnectionFailureBugreportEnabled()).thenReturn(true); + when(mWifiScoreCard.detectAbnormalConnectionFailure(anyString())) + .thenReturn(WifiHealthMonitor.REASON_NO_FAILURE); + when(mWifiScoreCard.detectAbnormalDisconnection()) + .thenReturn(WifiHealthMonitor.REASON_NO_FAILURE); when(mThroughputPredictor.predictMaxTxThroughput(any())).thenReturn(90); when(mThroughputPredictor.predictMaxRxThroughput(any())).thenReturn(80); } @@ -1724,8 +1729,6 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(), eq(WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD)); - verify(mWifiScoreCard, never()).detectAbnormalAuthFailure(any()); - assertEquals("DisconnectedState", getCurrentState().getName()); } @@ -1757,6 +1760,8 @@ public class ClientModeImplTest extends WifiBaseTest { .startMocking(); when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(DATA_SUBID); when(SubscriptionManager.isValidSubscriptionId(anyInt())).thenReturn(true); + when(mWifiScoreCard.detectAbnormalConnectionFailure(anyString())) + .thenReturn(WifiHealthMonitor.REASON_AUTH_FAILURE); mCmi.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE, @@ -1767,8 +1772,9 @@ public class ClientModeImplTest extends WifiBaseTest { WifiNative.EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED, config); verify(mDataTelephonyManager).resetCarrierKeysForImsiEncryption(); mockSession.finishMocking(); - verify(mWifiScoreCard).detectAbnormalAuthFailure(anyString()); - verify(mDeviceConfigFacade).isAbnormalEapAuthFailureBugreportEnabled(); + verify(mDeviceConfigFacade).isAbnormalConnectionFailureBugreportEnabled(); + verify(mWifiScoreCard).detectAbnormalConnectionFailure(anyString()); + verify(mWifiDiagnostics).takeBugReport(anyString(), anyString()); } /** @@ -1799,8 +1805,6 @@ public class ClientModeImplTest extends WifiBaseTest { mLooper.dispatchAll(); verify(mDataTelephonyManager, never()).resetCarrierKeysForImsiEncryption(); - verify(mWifiScoreCard).detectAbnormalAuthFailure(null); - verify(mDeviceConfigFacade).isAbnormalEapAuthFailureBugreportEnabled(); } /** @@ -1828,8 +1832,6 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mWifiConfigManager).updateNetworkSelectionStatus(anyInt(), eq(WifiConfiguration.NetworkSelectionStatus .DISABLED_AUTHENTICATION_NO_SUBSCRIPTION)); - verify(mWifiScoreCard, never()).detectAbnormalAuthFailure(null); - verify(mDeviceConfigFacade, never()).isAbnormalEapAuthFailureBugreportEnabled(); } @Test @@ -1851,6 +1853,7 @@ public class ClientModeImplTest extends WifiBaseTest { mLooper.dispatchAll(); assertEquals("DisconnectedState", getCurrentState().getName()); + verify(mWifiDiagnostics, never()).takeBugReport(anyString(), anyString()); } @@ -1865,6 +1868,8 @@ public class ClientModeImplTest extends WifiBaseTest { @Test public void disconnect() throws Exception { + when(mWifiScoreCard.detectAbnormalDisconnection()) + .thenReturn(WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL); InOrder inOrderWifiLockManager = inOrder(mWifiLockManager); connect(); inOrderWifiLockManager.verify(mWifiLockManager).updateWifiClientConnected(true); @@ -1879,6 +1884,8 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mWifiNetworkSuggestionsManager).handleDisconnect(any(), any()); assertEquals("DisconnectedState", getCurrentState().getName()); inOrderWifiLockManager.verify(mWifiLockManager).updateWifiClientConnected(false); + verify(mWifiScoreCard).detectAbnormalDisconnection(); + verify(mWifiDiagnostics).takeBugReport(anyString(), anyString()); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java b/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java index d6a05c7a3..b7136d986 100644 --- a/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java +++ b/tests/wifitests/src/com/android/server/wifi/DeviceConfigFacadeTest.java @@ -170,9 +170,12 @@ public class DeviceConfigFacadeTest extends WifiBaseTest { mDeviceConfigFacade.getAggressiveMacRandomizationSsidAllowlist()); assertEquals(Collections.emptySet(), mDeviceConfigFacade.getAggressiveMacRandomizationSsidBlocklist()); - assertEquals(false, mDeviceConfigFacade.isAbnormalEapAuthFailureBugreportEnabled()); + assertEquals(false, mDeviceConfigFacade.isAbnormalConnectionFailureBugreportEnabled()); + assertEquals(false, mDeviceConfigFacade.isAbnormalDisconnectionBugreportEnabled()); assertEquals(DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT, mDeviceConfigFacade.getHealthMonitorMinNumConnectionAttempt()); + assertEquals(DeviceConfigFacade.DEFAULT_BUG_REPORT_MIN_WINDOW_MS, + mDeviceConfigFacade.getBugReportMinWindowMs()); } /** @@ -242,10 +245,15 @@ public class DeviceConfigFacadeTest extends WifiBaseTest { anyString())).thenReturn(testSsidList); when(DeviceConfig.getString(anyString(), eq("aggressive_randomization_ssid_blocklist"), anyString())).thenReturn(testSsidList); - when(DeviceConfig.getBoolean(anyString(), eq("abnormal_eap_auth_failure_bugreport_enabled"), + when(DeviceConfig.getBoolean(anyString(), + eq("abnormal_connection_failure_bugreport_enabled"), + anyBoolean())).thenReturn(true); + when(DeviceConfig.getBoolean(anyString(), eq("abnormal_disconnection_bugreport_enabled"), anyBoolean())).thenReturn(true); when(DeviceConfig.getInt(anyString(), eq("health_monitor_min_num_connection_attempt"), anyInt())).thenReturn(20); + when(DeviceConfig.getInt(anyString(), eq("bug_report_min_window_ms"), + anyInt())).thenReturn(1000); mOnPropertiesChangedListenerCaptor.getValue().onPropertiesChanged(null); @@ -285,7 +293,9 @@ public class DeviceConfigFacadeTest extends WifiBaseTest { mDeviceConfigFacade.getAggressiveMacRandomizationSsidAllowlist()); assertEquals(testSsidSet, mDeviceConfigFacade.getAggressiveMacRandomizationSsidBlocklist()); - assertEquals(true, mDeviceConfigFacade.isAbnormalEapAuthFailureBugreportEnabled()); + assertEquals(true, mDeviceConfigFacade.isAbnormalConnectionFailureBugreportEnabled()); + assertEquals(true, mDeviceConfigFacade.isAbnormalDisconnectionBugreportEnabled()); assertEquals(20, mDeviceConfigFacade.getHealthMonitorMinNumConnectionAttempt()); + assertEquals(1000, mDeviceConfigFacade.getBugReportMinWindowMs()); } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java index acfc78d7e..6b235b9f7 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java @@ -64,6 +64,7 @@ public class WifiDiagnosticsTest extends WifiBaseTest { @Mock BuildProperties mBuildProperties; @Mock Context mContext; @Mock WifiInjector mWifiInjector; + @Mock DeviceConfigFacade mDeviceConfigFacade; @Spy FakeWifiLog mLog; @Mock LastMileLogger mLastMileLogger; @Mock Runtime mJavaRuntime; @@ -86,6 +87,7 @@ public class WifiDiagnosticsTest extends WifiBaseTest { private static final int[] FATAL_FW_ALERT_LIST = {256, 257, 258}; /** Mock a non fatal firmware alert */ private static final int NON_FATAL_FW_ALERT = 0; + private static final int BUG_REPORT_MIN_WINDOW_MS = 3600_000; private WifiNative.RingBufferStatus mFakeRbs; /** @@ -131,7 +133,8 @@ public class WifiDiagnosticsTest extends WifiBaseTest { when(mWifiInjector.makeLog(anyString())).thenReturn(mLog); when(mWifiInjector.getJavaRuntime()).thenReturn(mJavaRuntime); when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); - + when(mWifiInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); + when(mDeviceConfigFacade.getBugReportMinWindowMs()).thenReturn(BUG_REPORT_MIN_WINDOW_MS); mWifiDiagnostics = new WifiDiagnostics( mContext, mWifiInjector, mWifiNative, mBuildProperties, mLastMileLogger, mClock); mWifiNative.enableVerboseLogging(0); @@ -888,7 +891,7 @@ public class WifiDiagnosticsTest extends WifiBaseTest { mWifiDiagnostics.takeBugReport("", ""); verify(mBugreportManager, times(1)).requestBugreport(any(), any(), any()); // 2nd attempt should fail - when(mClock.getWallClockMillis()).thenReturn(1000_000L); + when(mClock.getWallClockMillis()).thenReturn(BUG_REPORT_MIN_WINDOW_MS - 20L); mWifiDiagnostics.takeBugReport("", ""); verify(mBugreportManager, times(1)).requestBugreport(any(), any(), any()); } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java index e98b03acf..d6dc020b9 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java @@ -154,6 +154,7 @@ public class WifiScoreCardTest extends WifiBaseTest { DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_RATIO_THR_NUMERATOR); when(mDeviceConfigFacade.getHealthMonitorMinNumConnectionAttempt()).thenReturn( DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT); + when(mDeviceConfigFacade.getBugReportThresholdExtraRatio()).thenReturn(1); mWifiScoreCard.enableVerboseLogging(true); } @@ -1106,6 +1107,8 @@ public class WifiScoreCardTest extends WifiBaseTest { perNetwork.updateAfterDailyDetection(); checkShortConnectionExample(perNetwork.getRecentStats(), 1); checkShortConnectionExample(perNetwork.getStatsPrevBuild(), 0); + assertEquals(WifiHealthMonitor.REASON_NO_FAILURE, + mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID())); } /** @@ -1131,11 +1134,13 @@ public class WifiScoreCardTest extends WifiBaseTest { // Add >2x failures after the SW build change int numBadConnectionDays = 4; for (int i = 0; i < numBadConnectionDays; i++) { - makeRecentStatsWithShortConnection(); makeRecentStatsWithAssocTimeOut(); makeRecentStatsWithAuthFailure(); + makeRecentStatsWithShortConnection(); } + assertEquals(WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL, + mWifiScoreCard.detectAbnormalDisconnection()); FailureStats statsDec = new FailureStats(); FailureStats statsInc = new FailureStats(); FailureStats statsHigh = new FailureStats(); @@ -1175,6 +1180,8 @@ public class WifiScoreCardTest extends WifiBaseTest { checkStatsDeltaExample(statsDec, 0); checkStatsDeltaExample(statsInc, 0); checkStatsDeltaExample(statsHigh, 0); + assertEquals(WifiHealthMonitor.REASON_NO_FAILURE, + mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID())); } /** @@ -1197,10 +1204,12 @@ public class WifiScoreCardTest extends WifiBaseTest { for (int i = 0; i < numGoodConnectionDays; i++) { makeRecentStatsWithGoodConnection(); } - makeRecentStatsWithShortConnection(); makeRecentStatsWithAssocTimeOut(); makeRecentStatsWithAuthFailure(); + makeRecentStatsWithShortConnection(); + assertEquals(WifiHealthMonitor.REASON_NO_FAILURE, + mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID())); FailureStats statsDec = new FailureStats(); FailureStats statsInc = new FailureStats(); FailureStats statsHigh = new FailureStats(); @@ -1215,9 +1224,11 @@ public class WifiScoreCardTest extends WifiBaseTest { PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID()); makeRecentStatsWithShortConnection(); // Day 1 - makeRecentStatsWithAssocTimeOut(); makeRecentStatsWithAuthFailure(); + makeRecentStatsWithAssocTimeOut(); + assertEquals(WifiHealthMonitor.REASON_ASSOC_TIMEOUT, + mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID())); FailureStats statsDec = new FailureStats(); FailureStats statsInc = new FailureStats(); FailureStats statsHigh = new FailureStats(); @@ -1226,12 +1237,13 @@ public class WifiScoreCardTest extends WifiBaseTest { checkStatsDeltaExample(statsDec, 0); checkStatsDeltaExample(statsInc, 0); checkStatsDeltaExample(statsHigh, 1); - assertEquals(false, mWifiScoreCard.detectAbnormalAuthFailure(mWifiInfo.getSSID())); } @Test public void testHighAuthFailureRate() throws Exception { + makeRecentStatsWithGoodConnection(); makeRecentStatsWithAuthFailure(); - assertEquals(true, mWifiScoreCard.detectAbnormalAuthFailure(mWifiInfo.getSSID())); + assertEquals(WifiHealthMonitor.REASON_AUTH_FAILURE, + mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID())); } } |