summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorKai Shi <kaishi@google.com>2020-03-25 16:39:36 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-03-25 16:39:36 +0000
commit384286c4bb0ac18583c09fe4326717e441f7ef30 (patch)
tree7204f31e7a41c57fdc53980b9881eec4466198fd /service
parent90ba39085632cfb1864429bb1d03f90f11e86338 (diff)
parentca554bc60a2ba4e7847e696508e058012df47849 (diff)
Merge "WifiHealthMonitor: improve regression detection" into rvc-dev
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/DeviceConfigFacade.java128
-rw-r--r--service/java/com/android/server/wifi/WifiScoreCard.java111
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() {