diff options
author | Kai Shi <kaishi@google.com> | 2020-03-25 16:39:36 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-03-25 16:39:36 +0000 |
commit | 384286c4bb0ac18583c09fe4326717e441f7ef30 (patch) | |
tree | 7204f31e7a41c57fdc53980b9881eec4466198fd /service | |
parent | 90ba39085632cfb1864429bb1d03f90f11e86338 (diff) | |
parent | ca554bc60a2ba4e7847e696508e058012df47849 (diff) |
Merge "WifiHealthMonitor: improve regression detection" into rvc-dev
Diffstat (limited to 'service')
-rw-r--r-- | service/java/com/android/server/wifi/DeviceConfigFacade.java | 128 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiScoreCard.java | 111 |
2 files changed, 147 insertions, 92 deletions
diff --git a/service/java/com/android/server/wifi/DeviceConfigFacade.java b/service/java/com/android/server/wifi/DeviceConfigFacade.java index 0fd0d68e1..7ea346c80 100644 --- a/service/java/com/android/server/wifi/DeviceConfigFacade.java +++ b/service/java/com/android/server/wifi/DeviceConfigFacade.java @@ -65,22 +65,25 @@ public class DeviceConfigFacade { public static final int DEFAULT_TX_PACKET_PER_SECOND_THR = 1; // Default threshold of Rx packet per second public static final int DEFAULT_RX_PACKET_PER_SECOND_THR = 1; - // Default high and low threshold values for various connection failure rates. + // 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_CONNECTION_FAILURE_LOW_THR_PERCENT = 5; - static final int DEFAULT_ASSOC_REJECTION_HIGH_THR_PERCENT = 10; - static final int DEFAULT_ASSOC_REJECTION_LOW_THR_PERCENT = 1; - static final int DEFAULT_ASSOC_TIMEOUT_HIGH_THR_PERCENT = 10; - static final int DEFAULT_ASSOC_TIMEOUT_LOW_THR_PERCENT = 2; - static final int DEFAULT_AUTH_FAILURE_HIGH_THR_PERCENT = 10; - static final int DEFAULT_AUTH_FAILURE_LOW_THR_PERCENT = 2; - // Default high and low threshold values for non-local disconnection rate - // with respect to disconnection count (with a recent RSSI poll) - static final int DEFAULT_SHORT_CONNECTION_NONLOCAL_HIGH_THR_PERCENT = 10; - static final int DEFAULT_SHORT_CONNECTION_NONLOCAL_LOW_THR_PERCENT = 1; - static final int DEFAULT_DISCONNECTION_NONLOCAL_HIGH_THR_PERCENT = 15; - static final int DEFAULT_DISCONNECTION_NONLOCAL_LOW_THR_PERCENT = 1; + 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; + // 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; + static final int DEFAULT_ASSOC_TIMEOUT_COUNT_MIN = 3; + static final int DEFAULT_AUTH_FAILURE_COUNT_MIN = 3; + static final int DEFAULT_SHORT_CONNECTION_NONLOCAL_COUNT_MIN = 3; + static final int DEFAULT_DISCONNECTION_NONLOCAL_COUNT_MIN = 3; + // Numerator part of default ratio threshold values for all cases + static final int DEFAULT_HEALTH_MONITOR_RATIO_THR_NUMERATOR = 4; + // Denominator part of ratio threshold for all cases + static final int HEALTH_MONITOR_RATIO_THR_DENOMINATOR = 2; // Minimum RSSI in dBm for connection stats collection // Connection or disconnection events with RSSI below this threshold are not // included in connection stats collection. @@ -103,17 +106,18 @@ public class DeviceConfigFacade { private int mTxPktPerSecondThr; private int mRxPktPerSecondThr; private int mConnectionFailureHighThrPercent; - private int mConnectionFailureLowThrPercent; + private int mConnectionFailureCountMin; private int mAssocRejectionHighThrPercent; - private int mAssocRejectionLowThrPercent; + private int mAssocRejectionCountMin; private int mAssocTimeoutHighThrPercent; - private int mAssocTimeoutLowThrPercent; + private int mAssocTimeoutCountMin; private int mAuthFailureHighThrPercent; - private int mAuthFailureLowThrPercent; + private int mAuthFailureCountMin; private int mShortConnectionNonlocalHighThrPercent; - private int mShortConnectionNonlocalLowThrPercent; + private int mShortConnectionNonlocalCountMin; private int mDisconnectionNonlocalHighThrPercent; - private int mDisconnectionNonlocalLowThrPercent; + private int mDisconnectionNonlocalCountMin; + private int mHealthMonitorRatioThrNumerator; private int mHealthMonitorMinRssiThrDbm; private Set<String> mRandomizationFlakySsidHotlist; private Set<String> mAggressiveMacRandomizationSsidAllowlist; @@ -173,40 +177,42 @@ public class DeviceConfigFacade { mConnectionFailureHighThrPercent = DeviceConfig.getInt(NAMESPACE, "connection_failure_high_thr_percent", DEFAULT_CONNECTION_FAILURE_HIGH_THR_PERCENT); - mConnectionFailureLowThrPercent = DeviceConfig.getInt(NAMESPACE, - "connection_failure_low_thr_percent", - DEFAULT_CONNECTION_FAILURE_LOW_THR_PERCENT); + mConnectionFailureCountMin = DeviceConfig.getInt(NAMESPACE, + "connection_failure_count_min", + DEFAULT_CONNECTION_FAILURE_COUNT_MIN); mAssocRejectionHighThrPercent = DeviceConfig.getInt(NAMESPACE, "assoc_rejection_high_thr_percent", DEFAULT_ASSOC_REJECTION_HIGH_THR_PERCENT); - mAssocRejectionLowThrPercent = DeviceConfig.getInt(NAMESPACE, - "assoc_rejection_low_thr_percent", - DEFAULT_ASSOC_REJECTION_LOW_THR_PERCENT); + mAssocRejectionCountMin = DeviceConfig.getInt(NAMESPACE, + "assoc_rejection_count_min", + DEFAULT_ASSOC_REJECTION_COUNT_MIN); mAssocTimeoutHighThrPercent = DeviceConfig.getInt(NAMESPACE, "assoc_timeout_high_thr_percent", DEFAULT_ASSOC_TIMEOUT_HIGH_THR_PERCENT); - mAssocTimeoutLowThrPercent = DeviceConfig.getInt(NAMESPACE, - "assoc_timeout_low_thr_percent", - DEFAULT_ASSOC_TIMEOUT_LOW_THR_PERCENT); + mAssocTimeoutCountMin = DeviceConfig.getInt(NAMESPACE, + "assoc_timeout_count_min", + DEFAULT_ASSOC_TIMEOUT_COUNT_MIN); mAuthFailureHighThrPercent = DeviceConfig.getInt(NAMESPACE, "auth_failure_high_thr_percent", DEFAULT_AUTH_FAILURE_HIGH_THR_PERCENT); - mAuthFailureLowThrPercent = DeviceConfig.getInt(NAMESPACE, - "auth_failure_low_thr_percent", - DEFAULT_AUTH_FAILURE_LOW_THR_PERCENT); + mAuthFailureCountMin = DeviceConfig.getInt(NAMESPACE, + "auth_failure_count_min", + DEFAULT_AUTH_FAILURE_COUNT_MIN); mShortConnectionNonlocalHighThrPercent = DeviceConfig.getInt(NAMESPACE, "short_connection_nonlocal_high_thr_percent", DEFAULT_SHORT_CONNECTION_NONLOCAL_HIGH_THR_PERCENT); - mShortConnectionNonlocalLowThrPercent = DeviceConfig.getInt(NAMESPACE, - "short_connection_nonlocal_low_thr_percent", - DEFAULT_SHORT_CONNECTION_NONLOCAL_LOW_THR_PERCENT); + mShortConnectionNonlocalCountMin = DeviceConfig.getInt(NAMESPACE, + "short_connection_nonlocal_count_min", + DEFAULT_SHORT_CONNECTION_NONLOCAL_COUNT_MIN); mDisconnectionNonlocalHighThrPercent = DeviceConfig.getInt(NAMESPACE, "disconnection_nonlocal_high_thr_percent", DEFAULT_DISCONNECTION_NONLOCAL_HIGH_THR_PERCENT); - mDisconnectionNonlocalLowThrPercent = DeviceConfig.getInt(NAMESPACE, - "disconnection_nonlocal_low_thr_percent", - DEFAULT_DISCONNECTION_NONLOCAL_LOW_THR_PERCENT); - + mDisconnectionNonlocalCountMin = DeviceConfig.getInt(NAMESPACE, + "disconnection_nonlocal_count_min", + DEFAULT_DISCONNECTION_NONLOCAL_COUNT_MIN); + mHealthMonitorRatioThrNumerator = DeviceConfig.getInt(NAMESPACE, + "health_monitor_ratio_thr_numerator", + DEFAULT_HEALTH_MONITOR_RATIO_THR_NUMERATOR); mHealthMonitorMinRssiThrDbm = DeviceConfig.getInt(NAMESPACE, "health_monitor_min_rssi_thr_dbm", DEFAULT_HEALTH_MONITOR_MIN_RSSI_THR_DBM); @@ -341,10 +347,10 @@ public class DeviceConfigFacade { } /** - * Gets the low threshold of connection failure rate in percent + * Gets connection failure min count */ - public int getConnectionFailureLowThrPercent() { - return mConnectionFailureLowThrPercent; + public int getConnectionFailureCountMin() { + return mConnectionFailureCountMin; } /** @@ -355,10 +361,10 @@ public class DeviceConfigFacade { } /** - * Gets the low threshold of association rejection rate in percent + * Gets association rejection min count */ - public int getAssocRejectionLowThrPercent() { - return mAssocRejectionLowThrPercent; + public int getAssocRejectionCountMin() { + return mAssocRejectionCountMin; } /** @@ -369,12 +375,13 @@ public class DeviceConfigFacade { } /** - * Gets the low threshold of association timeout rate in percent + * Gets association timeout min count */ - public int getAssocTimeoutLowThrPercent() { - return mAssocTimeoutLowThrPercent; + public int getAssocTimeoutCountMin() { + return mAssocTimeoutCountMin; } + /** * Gets the high threshold of authentication failure rate in percent */ @@ -383,10 +390,10 @@ public class DeviceConfigFacade { } /** - * Gets the low threshold of authentication failure rate in percent + * Gets authentication failure min count */ - public int getAuthFailureLowThrPercent() { - return mAuthFailureLowThrPercent; + public int getAuthFailureCountMin() { + return mAuthFailureCountMin; } /** @@ -397,10 +404,10 @@ public class DeviceConfigFacade { } /** - * Gets the low threshold of nonlocal short connection rate in percent + * Gets nonlocal short connection min count */ - public int getShortConnectionNonlocalLowThrPercent() { - return mShortConnectionNonlocalLowThrPercent; + public int getShortConnectionNonlocalCountMin() { + return mShortConnectionNonlocalCountMin; } /** @@ -411,10 +418,17 @@ public class DeviceConfigFacade { } /** - * Gets the low threshold of nonlocal disconnection rate in percent + * Gets nonlocal disconnection min count + */ + public int getDisconnectionNonlocalCountMin() { + return mDisconnectionNonlocalCountMin; + } + + /** + * Gets health monitor ratio threshold, numerator part */ - public int getDisconnectionNonlocalLowThrPercent() { - return mDisconnectionNonlocalLowThrPercent; + public int getHealthMonitorRatioThrNumerator() { + return mHealthMonitorRatioThrNumerator; } /** diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java index a321ee125..79c9ccb24 100644 --- a/service/java/com/android/server/wifi/WifiScoreCard.java +++ b/service/java/com/android/server/wifi/WifiScoreCard.java @@ -112,7 +112,6 @@ public class WifiScoreCard { static final int SUFFICIENT_RECENT_STATS_ONLY = 1; static final int SUFFICIENT_RECENT_PREV_STATS = 2; - private static final int ONE_HUNDRED_PERCENT = 100; private static final int MAX_FREQUENCIES_PER_SSID = 10; private final Clock mClock; @@ -888,15 +887,12 @@ public class WifiScoreCard { < mDeviceConfigFacade.getHealthMonitorMinNumConnectionAttempt()) { // don't have enough historical data, // so only detect high failure stats without relying on mStatsPrevBuild. - // Increase low threshold so that mStatsPrevBuild is always below it - // statsHigh only depends on mRecentStats. - FailureStats statsDummy = new FailureStats(); - statsDeltaDetectionConnection(statsDummy, statsHigh, ONE_HUNDRED_PERCENT); + recentStatsHighDetectionConnection(statsHigh); return SUFFICIENT_RECENT_STATS_ONLY; } else { // mStatsPrevBuild has enough updates, - // detect improvement or degradation with normal threshold values. - statsDeltaDetectionConnection(statsDec, statsInc, /* thresholdLowOffset */ 0); + // detect improvement or degradation + statsDeltaDetectionConnection(statsDec, statsInc); return SUFFICIENT_RECENT_PREV_STATS; } } @@ -910,77 +906,122 @@ public class WifiScoreCard { } if (mStatsPrevBuild.getCount(CNT_DISCONNECTION) < mDeviceConfigFacade.getHealthMonitorMinNumConnectionAttempt()) { - FailureStats statsDummy = new FailureStats(); - statsDeltaDetectionDisconnection(statsDummy, statsHigh, ONE_HUNDRED_PERCENT); + recentStatsHighDetectionDisconnection(statsHigh); } else { - statsDeltaDetectionDisconnection(statsDec, statsInc, /* thrLowOffset */ 0); + statsDeltaDetectionDisconnection(statsDec, statsInc); } } private void statsDeltaDetectionConnection(FailureStats statsDec, - FailureStats statsInc, int thrLowOffset) { + FailureStats statsInc) { statsDeltaDetection(statsDec, statsInc, CNT_CONNECTION_FAILURE, REASON_CONNECTION_FAILURE, - mDeviceConfigFacade.getConnectionFailureHighThrPercent(), - mDeviceConfigFacade.getConnectionFailureLowThrPercent() + thrLowOffset, + mDeviceConfigFacade.getConnectionFailureCountMin(), CNT_CONNECTION_ATTEMPT); statsDeltaDetection(statsDec, statsInc, CNT_AUTHENTICATION_FAILURE, REASON_AUTH_FAILURE, - mDeviceConfigFacade.getAuthFailureHighThrPercent(), - mDeviceConfigFacade.getAuthFailureLowThrPercent() + thrLowOffset, + mDeviceConfigFacade.getAuthFailureCountMin(), CNT_CONNECTION_ATTEMPT); statsDeltaDetection(statsDec, statsInc, CNT_ASSOCIATION_REJECTION, REASON_ASSOC_REJECTION, - mDeviceConfigFacade.getAssocRejectionHighThrPercent(), - mDeviceConfigFacade.getAssocRejectionLowThrPercent() + thrLowOffset, + mDeviceConfigFacade.getAssocRejectionCountMin(), CNT_CONNECTION_ATTEMPT); statsDeltaDetection(statsDec, statsInc, CNT_ASSOCIATION_TIMEOUT, REASON_ASSOC_TIMEOUT, + mDeviceConfigFacade.getAssocTimeoutCountMin(), + CNT_CONNECTION_ATTEMPT); + } + + private void recentStatsHighDetectionConnection(FailureStats statsHigh) { + recentStatsHighDetection(statsHigh, CNT_CONNECTION_FAILURE, + REASON_CONNECTION_FAILURE, + mDeviceConfigFacade.getConnectionFailureHighThrPercent(), + mDeviceConfigFacade.getConnectionFailureCountMin(), + CNT_CONNECTION_ATTEMPT); + recentStatsHighDetection(statsHigh, CNT_AUTHENTICATION_FAILURE, + REASON_AUTH_FAILURE, + mDeviceConfigFacade.getAuthFailureHighThrPercent(), + mDeviceConfigFacade.getAuthFailureCountMin(), + CNT_CONNECTION_ATTEMPT); + recentStatsHighDetection(statsHigh, CNT_ASSOCIATION_REJECTION, + REASON_ASSOC_REJECTION, + mDeviceConfigFacade.getAssocRejectionHighThrPercent(), + mDeviceConfigFacade.getAssocRejectionCountMin(), + CNT_CONNECTION_ATTEMPT); + recentStatsHighDetection(statsHigh, CNT_ASSOCIATION_TIMEOUT, + REASON_ASSOC_TIMEOUT, mDeviceConfigFacade.getAssocTimeoutHighThrPercent(), - mDeviceConfigFacade.getAssocTimeoutLowThrPercent() + thrLowOffset, + mDeviceConfigFacade.getAssocTimeoutCountMin(), CNT_CONNECTION_ATTEMPT); } private void statsDeltaDetectionDisconnection(FailureStats statsDec, - FailureStats statsInc, int thrLowOffset) { + FailureStats statsInc) { statsDeltaDetection(statsDec, statsInc, CNT_SHORT_CONNECTION_NONLOCAL, REASON_SHORT_CONNECTION_NONLOCAL, - mDeviceConfigFacade.getShortConnectionNonlocalHighThrPercent(), - mDeviceConfigFacade.getShortConnectionNonlocalLowThrPercent() + thrLowOffset, + mDeviceConfigFacade.getShortConnectionNonlocalCountMin(), CNT_DISCONNECTION); statsDeltaDetection(statsDec, statsInc, CNT_DISCONNECTION_NONLOCAL, REASON_DISCONNECTION_NONLOCAL, + mDeviceConfigFacade.getDisconnectionNonlocalCountMin(), + CNT_DISCONNECTION); + } + + private void recentStatsHighDetectionDisconnection(FailureStats statsHigh) { + recentStatsHighDetection(statsHigh, CNT_SHORT_CONNECTION_NONLOCAL, + REASON_SHORT_CONNECTION_NONLOCAL, + mDeviceConfigFacade.getShortConnectionNonlocalHighThrPercent(), + mDeviceConfigFacade.getShortConnectionNonlocalCountMin(), + CNT_DISCONNECTION); + recentStatsHighDetection(statsHigh, CNT_DISCONNECTION_NONLOCAL, + REASON_DISCONNECTION_NONLOCAL, mDeviceConfigFacade.getDisconnectionNonlocalHighThrPercent(), - mDeviceConfigFacade.getDisconnectionNonlocalLowThrPercent() + thrLowOffset, + mDeviceConfigFacade.getDisconnectionNonlocalCountMin(), CNT_DISCONNECTION); } private boolean statsDeltaDetection(FailureStats statsDec, FailureStats statsInc, int countCode, int reasonCode, - int highThreshold, int lowThreshold, int refCountCode) { - if (isRateBelowThreshold(mStatsPrevBuild, countCode, lowThreshold, refCountCode) - && isRateAboveThreshold(mRecentStats, countCode, highThreshold, refCountCode)) { + int minCount, int refCountCode) { + if (isRatioAboveThreshold(mRecentStats, mStatsPrevBuild, countCode, refCountCode) + && mRecentStats.getCount(countCode) >= minCount) { statsInc.incrementCount(reasonCode); return true; } - if (isRateAboveThreshold(mStatsPrevBuild, countCode, highThreshold, refCountCode) - && isRateBelowThreshold(mRecentStats, countCode, lowThreshold, refCountCode)) { + + if (isRatioAboveThreshold(mStatsPrevBuild, mRecentStats, countCode, refCountCode) + && mStatsPrevBuild.getCount(countCode) >= minCount) { statsDec.incrementCount(reasonCode); return true; } return false; } - private boolean isRateAboveThreshold(NetworkConnectionStats stats, - @ConnectionCountCode int countCode, int threshold, int refCountCode) { - return (stats.getCount(countCode) * ONE_HUNDRED_PERCENT) - >= (threshold * stats.getCount(refCountCode)); + 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)) { + statsHigh.incrementCount(reasonCode); + return true; + } + return false; } - private boolean isRateBelowThreshold(NetworkConnectionStats stats, - @ConnectionCountCode int countCode, int threshold, int refCountCode) { - return (stats.getCount(countCode) * ONE_HUNDRED_PERCENT) - <= (threshold * stats.getCount(refCountCode)); + private boolean isRatioAboveThreshold(NetworkConnectionStats stats1, + NetworkConnectionStats stats2, + @ConnectionCountCode int countCode, int refCountCode) { + // Also with Laplace's rule of succession discussed above + // R1 = (stats1(countCode) + 1) / (stats1(refCountCode) + 2) + // R2 = (stats2(countCode) + 1) / (stats2(refCountCode) + 2) + // Check R1 / R2 >= ratioThr + return ((stats1.getCount(countCode) + 1) * (stats2.getCount(refCountCode) + 2) + * mDeviceConfigFacade.HEALTH_MONITOR_RATIO_THR_DENOMINATOR) + >= ((stats1.getCount(refCountCode) + 1) * (stats2.getCount(countCode) + 2) + * mDeviceConfigFacade.getHealthMonitorRatioThrNumerator()); } private boolean isRecentConnectionStatsSufficient() { |