From 6d8147c663bfbe7507287054b0483feaf30d7c05 Mon Sep 17 00:00:00 2001 From: Kai Shi Date: Tue, 16 Jun 2020 21:09:17 -0700 Subject: Check deauth reason and FW alert for abnormal disconnection 1)To improve abnormal disconnection detection, add deauth reason and FW alert check. The list of reason codes is configurable through a 64-bit mask and FW alert valid time is also configurable. 2)Move other abnormal connection failure and disconnection detection timing related parameters to DeviceConfig. 3)Log last rssi poll valid time in wifi metrics. 4)Reduce default value of rssi poll valid time from 3.1s to 2.1s 5)Reduce default value of scan rssi valid time for stationary state from 20s to 8s because mobility state detection could be delayed. Updated-PDD: TRUE Bug: 159178185 Test: atest com.android.server.wifi Change-Id: I6e131f149d242e5dbf0b8b0087303e85ed428f9f Merged-In: Ifbd5519841d616651cacc846056eda6ff64393e0 --- .../android/server/wifi/DeviceConfigFacade.java | 92 +++++++++++++++++++++- .../com/android/server/wifi/WifiDiagnostics.java | 1 + .../com/android/server/wifi/WifiHealthMonitor.java | 12 ++- .../java/com/android/server/wifi/WifiMetrics.java | 9 +++ .../com/android/server/wifi/WifiScoreCard.java | 59 +++++++++----- service/proto/src/metrics.proto | 3 + 6 files changed, 150 insertions(+), 26 deletions(-) (limited to 'service') diff --git a/service/java/com/android/server/wifi/DeviceConfigFacade.java b/service/java/com/android/server/wifi/DeviceConfigFacade.java index cfd2ad081..0e43a0891 100644 --- a/service/java/com/android/server/wifi/DeviceConfigFacade.java +++ b/service/java/com/android/server/wifi/DeviceConfigFacade.java @@ -107,7 +107,28 @@ public class DeviceConfigFacade { // At low traffic, Rx link speed values below the following threshold // are ignored because it could be due to low rate management frames static final int DEFAULT_RX_LINK_SPEED_LOW_THRESHOLD_MBPS = 9; - + // Default health monitor short connection duration threshold in ms + static final int DEFAULT_HEALTH_MONITOR_SHORT_CONNECTION_DURATION_THR_MS = 20_000; + + // Default mask for abnormal disconnection reason codes. + // Each bit of mask corresponds to a reason code defined in 802.11 standard section 9.4.1.7 + // For example, b0 for reason code 0, b1 for reason code 1, etc. + // Bits below are abnormal disconnection reasons and thus are set to 1 + // b0: reserved (e.g., STA heartbeat failure) + // b2: invalid auth + // b4: disassociated due to inactivity + // b6 and b7: invalid class 2 and 3 frames + // b34: disassociated due to missing ACKs + static final long DEFAULT_ABNORMAL_DISCONNECTION_REASON_CODE_MASK = 0x4_0000_00d5L; + // Default maximum interval between last RSSI poll and disconnection + static final int DEFAULT_HEALTH_MONITOR_RSSI_POLL_VALID_TIME_MS = 2_100; + // Default maximum interval between scan and connection attempt in non-stationary state + static final int DEFAULT_NONSTATIONARY_SCAN_RSSI_VALID_TIME_MS = 5_000; + // Default maximum interval between scan and connection attempt in stationary state + static final int DEFAULT_STATIONARY_SCAN_RSSI_VALID_TIME_MS = 8_000; + // Default health monitor firmware alert valid time. + // -1 disables firmware alert time check + static final int DEFAULT_HEALTH_MONITOR_FW_ALERT_VALID_TIME_MS = -1; // Cached values of fields updated via updateDeviceConfigFlags() private boolean mIsAbnormalConnectionBugreportEnabled; private int mAbnormalConnectionDurationMs; @@ -150,6 +171,12 @@ public class DeviceConfigFacade { private int mOverlappingConnectionDurationThresholdMs; private int mTxLinkSpeedLowThresholdMbps; private int mRxLinkSpeedLowThresholdMbps; + private int mHealthMonitorShortConnectionDurationThrMs; + private long mAbnormalDisconnectionReasonCodeMask; + private int mHealthMonitorRssiPollValidTimeMs; + private int mNonstationaryScanRssiValidTimeMs; + private int mStationaryScanRssiValidTimeMs; + private int mHealthMonitorFwAlertValidTimeMs; public DeviceConfigFacade(Context context, Handler handler, WifiMetrics wifiMetrics) { mContext = context; @@ -278,6 +305,26 @@ public class DeviceConfigFacade { mRxLinkSpeedLowThresholdMbps = DeviceConfig.getInt(NAMESPACE, "rx_link_speed_low_threshold_mbps", DEFAULT_RX_LINK_SPEED_LOW_THRESHOLD_MBPS); + mHealthMonitorShortConnectionDurationThrMs = DeviceConfig.getInt(NAMESPACE, + "health_monitor_short_connection_duration_thr_ms", + DEFAULT_HEALTH_MONITOR_SHORT_CONNECTION_DURATION_THR_MS); + mAbnormalDisconnectionReasonCodeMask = DeviceConfig.getLong(NAMESPACE, + "abnormal_disconnection_reason_code_mask", + DEFAULT_ABNORMAL_DISCONNECTION_REASON_CODE_MASK); + mHealthMonitorRssiPollValidTimeMs = DeviceConfig.getInt(NAMESPACE, + "health_monitor_rssi_poll_valid_time_ms", + DEFAULT_HEALTH_MONITOR_RSSI_POLL_VALID_TIME_MS); + mNonstationaryScanRssiValidTimeMs = DeviceConfig.getInt(NAMESPACE, + "nonstationary_scan_rssi_valid_time_ms", + DEFAULT_NONSTATIONARY_SCAN_RSSI_VALID_TIME_MS); + mStationaryScanRssiValidTimeMs = DeviceConfig.getInt(NAMESPACE, + "stationary_scan_rssi_valid_time_ms", + DEFAULT_STATIONARY_SCAN_RSSI_VALID_TIME_MS); + mHealthMonitorFwAlertValidTimeMs = DeviceConfig.getInt(NAMESPACE, + "health_monitor_fw_alert_valid_time_ms", + DEFAULT_HEALTH_MONITOR_FW_ALERT_VALID_TIME_MS); + mWifiMetrics.setHealthMonitorRssiPollValidTimeMs(mHealthMonitorRssiPollValidTimeMs); + } private Set getUnmodifiableSetQuoted(String key) { @@ -583,4 +630,47 @@ public class DeviceConfigFacade { public int getRxLinkSpeedLowThresholdMbps() { return mRxLinkSpeedLowThresholdMbps; } + + /** + * Gets health monitor short connection duration threshold in ms + */ + public int getHealthMonitorShortConnectionDurationThrMs() { + return mHealthMonitorShortConnectionDurationThrMs; + } + + /** + * Gets abnormal disconnection reason code mask + */ + public long getAbnormalDisconnectionReasonCodeMask() { + return mAbnormalDisconnectionReasonCodeMask; + } + + /** + * Gets health monitor RSSI poll valid time in ms + */ + public int getHealthMonitorRssiPollValidTimeMs() { + return mHealthMonitorRssiPollValidTimeMs; + } + + /** + * Gets scan rssi valid time in ms when device is in non-stationary state + */ + public int getNonstationaryScanRssiValidTimeMs() { + return mNonstationaryScanRssiValidTimeMs; + } + + /** + * Gets scan rssi valid time in ms when device is in stationary state + */ + public int getStationaryScanRssiValidTimeMs() { + return mStationaryScanRssiValidTimeMs; + } + + /** + * Gets health monitor firmware alert valid time in ms, + * -1 disables firmware alert time check + */ + public int getHealthMonitorFwAlertValidTimeMs() { + return mHealthMonitorFwAlertValidTimeMs; + } } diff --git a/service/java/com/android/server/wifi/WifiDiagnostics.java b/service/java/com/android/server/wifi/WifiDiagnostics.java index a2328cd26..db9b075a4 100644 --- a/service/java/com/android/server/wifi/WifiDiagnostics.java +++ b/service/java/com/android/server/wifi/WifiDiagnostics.java @@ -473,6 +473,7 @@ class WifiDiagnostics extends BaseWifiDiagnostics { synchronized void onWifiAlert(int errorCode, @NonNull byte[] buffer) { captureAlertData(errorCode, buffer); mWifiMetrics.logFirmwareAlert(errorCode); + mWifiInjector.getWifiScoreCard().noteFirmwareAlert(errorCode); } /** diff --git a/service/java/com/android/server/wifi/WifiHealthMonitor.java b/service/java/com/android/server/wifi/WifiHealthMonitor.java index 8ab3a74a6..38da1578b 100644 --- a/service/java/com/android/server/wifi/WifiHealthMonitor.java +++ b/service/java/com/android/server/wifi/WifiHealthMonitor.java @@ -94,14 +94,11 @@ public class WifiHealthMonitor { private static final int MIN_NUM_BSSID_SCAN_2G = 2; // Minimum number of BSSIDs found above 2G with a normal scan private static final int MIN_NUM_BSSID_SCAN_ABOVE_2G = 2; - static final int DEFAULT_SCAN_RSSI_VALID_TIME_MS = 5_000; - static final int STATIONARY_SCAN_RSSI_VALID_TIME_MS = 20_000; - // Minimum Tx speed in Mbps for disconnection stats collection - // Disconnection events with Tx speed below this threshold are not - // included in connection stats collection. static final int HEALTH_MONITOR_COUNT_TX_SPEED_MIN_MBPS = 54; - static final int HEALTH_MONITOR_MIN_TX_PACKET_PER_SEC = 2; + // Minimum Tx packet per seconds for disconnection stats collection + static final int HEALTH_MONITOR_MIN_TX_PACKET_PER_SEC = 4; + private final Context mContext; private final WifiConfigManager mWifiConfigManager; private final WifiScoreCard mWifiScoreCard; @@ -222,7 +219,8 @@ public class WifiHealthMonitor { */ public int getScanRssiValidTimeMs() { return (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_STATIONARY) - ? STATIONARY_SCAN_RSSI_VALID_TIME_MS : DEFAULT_SCAN_RSSI_VALID_TIME_MS; + ? mDeviceConfigFacade.getStationaryScanRssiValidTimeMs() : + mDeviceConfigFacade.getNonstationaryScanRssiValidTimeMs(); } /** diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index a704f10da..437d00261 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -6415,6 +6415,15 @@ public class WifiMetrics { } } + /** + * Sets health monitor RSSI poll valid time in ms + */ + public void setHealthMonitorRssiPollValidTimeMs(int rssiPollValidTimeMs) { + synchronized (mLock) { + mExperimentValues.healthMonitorRssiPollValidTimeMs = rssiPollValidTimeMs; + } + } + /** * Increment connection duration while link layer stats report are on */ diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java index ca77e8396..64da835f0 100644 --- a/service/java/com/android/server/wifi/WifiScoreCard.java +++ b/service/java/com/android/server/wifi/WifiScoreCard.java @@ -70,7 +70,6 @@ import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -102,11 +101,6 @@ public class WifiScoreCard { public static final String PER_BSSID_DATA_NAME = "scorecard.proto"; public static final String PER_NETWORK_DATA_NAME = "perNetworkData"; - // Maximum connection duration in seconds to qualify short connection - private static final int SHORT_CONNECTION_DURATION_MAX_SEC = 20; - // Maximum interval between last RSSI poll and disconnection to qualify - // disconnection stats collection. - private static final int LAST_RSSI_POLL_MAX_INTERVAL_MS = 3_100; static final int INSUFFICIENT_RECENT_STATS = 0; static final int SUFFICIENT_RECENT_STATS_ONLY = 1; @@ -233,6 +227,8 @@ public class WifiScoreCard { private boolean mNonlocalDisconnection = false; private int mDisconnectionReason; + private long mFirmwareAlertTimeMs = TS_NONE; + /** * @param clock is the time source * @param l2KeySeed is for making our L2Keys usable only on this device @@ -292,6 +288,7 @@ public class WifiScoreCard { mPolled = false; mValidatedThisConnectionAtLeastOnce = false; mNonlocalDisconnection = false; + mFirmwareAlertTimeMs = TS_NONE; } /** @@ -410,6 +407,7 @@ public class WifiScoreCard { mPolled = false; mSsidPrev = mSsidCurr; mSsidCurr = ssid; + mFirmwareAlertTimeMs = TS_NONE; updatePerNetwork(Event.CONNECTION_ATTEMPT, ssid, scanRssi, LINK_SPEED_UNKNOWN, UNKNOWN_REASON); @@ -435,6 +433,14 @@ public class WifiScoreCard { logd("nonlocal disconnection with reason: " + reason); } + /** + * Record firmware alert timestamp and error code + */ + public void noteFirmwareAlert(int errorCode) { + mFirmwareAlertTimeMs = mClock.getElapsedSinceBootMillis(); + logd("firmware alert with error code: " + errorCode); + } + /** * Updates the score card after a failed connection attempt * @@ -870,7 +876,7 @@ public class WifiScoreCard { void updateEventStats(Event event, int rssi, int txSpeed, int failureReason) { finishPendingRead(); - long currTimeMs = mClock.getWallClockMillis(); + long currTimeMs = mClock.getElapsedSinceBootMillis(); switch (event) { case SIGNAL_POLL: mLastRssiPoll = rssi; @@ -927,11 +933,9 @@ public class WifiScoreCard { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("SSID: ").append(ssid).append("\n"); - Calendar c = Calendar.getInstance(); if (mLastRssiPollTimeMs != TS_NONE) { sb.append(" LastRssiPollTime: "); - c.setTimeInMillis(mLastRssiPollTimeMs); - sb.append(String.format("%tm-%td %tH:%tM:%tS", c, c, c, c, c)); + sb.append(mLastRssiPollTimeMs); } sb.append(" LastRssiPoll: " + mLastRssiPoll); sb.append(" LastTxSpeedPoll: " + mLastTxSpeedPoll); @@ -943,21 +947,33 @@ public class WifiScoreCard { } private void handleDisconnection() { if (mConnectionSessionStartTimeMs > TS_NONE) { - long currTimeMs = mClock.getWallClockMillis(); - int currSessionDurationSec = (int) ((currTimeMs - - mConnectionSessionStartTimeMs) / 1000); + long currTimeMs = mClock.getElapsedSinceBootMillis(); + int currSessionDurationMs = (int) (currTimeMs - mConnectionSessionStartTimeMs); + int currSessionDurationSec = currSessionDurationMs / 1000; mRecentStats.accumulate(CNT_CONNECTION_DURATION_SEC, currSessionDurationSec); long timeSinceLastRssiPollMs = currTimeMs - mLastRssiPollTimeMs; - boolean hasRecentRssiPoll = (mLastRssiPollTimeMs > TS_NONE - && timeSinceLastRssiPollMs <= LAST_RSSI_POLL_MAX_INTERVAL_MS); + boolean hasRecentRssiPoll = mLastRssiPollTimeMs > TS_NONE + && timeSinceLastRssiPollMs <= mDeviceConfigFacade + .getHealthMonitorRssiPollValidTimeMs(); if (hasRecentRssiPoll) { mRecentStats.incrementCount(CNT_DISCONNECTION); } + int fwAlertValidTimeMs = mDeviceConfigFacade.getHealthMonitorFwAlertValidTimeMs(); + long timeSinceLastFirmAlert = currTimeMs - mFirmwareAlertTimeMs; + boolean isInvalidFwAlertTime = mFirmwareAlertTimeMs == TS_NONE; + boolean disableFwAlertCheck = fwAlertValidTimeMs == -1; + boolean passFirmwareAlertCheck = disableFwAlertCheck ? true : (isInvalidFwAlertTime + ? false : timeSinceLastFirmAlert < fwAlertValidTimeMs); + boolean hasHighRssiOrHighTxSpeed = + mLastRssiPoll >= mDeviceConfigFacade.getHealthMonitorMinRssiThrDbm() + || mLastTxSpeedPoll >= HEALTH_MONITOR_COUNT_TX_SPEED_MIN_MBPS; if (mNonlocalDisconnection && hasRecentRssiPoll - && (mLastRssiPoll >= mDeviceConfigFacade.getHealthMonitorMinRssiThrDbm() - || mLastTxSpeedPoll >= HEALTH_MONITOR_COUNT_TX_SPEED_MIN_MBPS)) { + && isAbnormalDisconnectionReason(mDisconnectionReason) + && passFirmwareAlertCheck + && hasHighRssiOrHighTxSpeed) { mRecentStats.incrementCount(CNT_DISCONNECTION_NONLOCAL); - if (currSessionDurationSec <= SHORT_CONNECTION_DURATION_MAX_SEC) { + if (currSessionDurationMs <= mDeviceConfigFacade + .getHealthMonitorShortConnectionDurationThrMs()) { mRecentStats.incrementCount(CNT_SHORT_CONNECTION_NONLOCAL); } } @@ -968,6 +984,13 @@ public class WifiScoreCard { mConnectionSessionStartTimeMs = TS_NONE; mLastRssiPollTimeMs = TS_NONE; } + + private boolean isAbnormalDisconnectionReason(int disconnectionReason) { + long mask = mDeviceConfigFacade.getAbnormalDisconnectionReasonCodeMask(); + return disconnectionReason >= 0 && disconnectionReason <= 63 + && ((mask >> disconnectionReason) & 0x1) == 0x1; + } + @NonNull NetworkConnectionStats getRecentStats() { return mRecentStats; } diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index 01ad65093..e7c0ec89a 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -2140,6 +2140,9 @@ message ExperimentValues { // Threshold of CCA level above which to trigger a data stall in percentage optional int32 data_stall_cca_level_thr = 9; + + // Health monitor RSSI poll valid time in ms + optional int32 health_monitor_rssi_poll_valid_time_ms = 10; } message BssidBlocklistStats { -- cgit v1.2.3