From 622b812139bdeb88a675d6126f94b15ed1ff4336 Mon Sep 17 00:00:00 2001 From: xshu Date: Thu, 31 Oct 2019 10:33:33 -0700 Subject: Add exponential backoff to Bssid blocklist time Stores the blocklist streak per failure reason inside WifiScoreCard. This information is used in this CL to expedite blocklisting to known failing APs as well as to calculate for the blocklist duration with exponential backoff. Bug: 139287182 Test: atest FrameworksWifiTests Test: Verified in dumpsys that the blocklist duration increases with consistently repeating failures Change-Id: I87273dfc4b2ea68722e84936c44ec123e26146da --- .../server/wifi/BssidBlocklistMonitorTest.java | 126 ++++++++++++++++++++- .../android/server/wifi/ClientModeImplTest.java | 22 ++-- .../com/android/server/wifi/WifiScoreCardTest.java | 27 +++++ 3 files changed, 162 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java b/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java index 985dd45c8..118e3d0df 100644 --- a/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java @@ -30,6 +30,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * Unit tests for {@link com.android.server.wifi.BssidBlocklistMonitor}. @@ -45,13 +46,16 @@ public class BssidBlocklistMonitorTest { private static final String TEST_BSSID_3 = "0a:08:5c:67:89:02"; private static final int TEST_L2_FAILURE = BssidBlocklistMonitor.REASON_ASSOCIATION_REJECTION; private static final int TEST_DHCP_FAILURE = BssidBlocklistMonitor.REASON_DHCP_FAILURE; - private static final long BASE_BLOCKLIST_DURATION = 5 * 60 * 1000; // 5 minutes + private static final long BASE_BLOCKLIST_DURATION = TimeUnit.MINUTES.toMillis(5); // 5 minutes + private static final long MAX_BLOCKLIST_DURATION = TimeUnit.HOURS.toMillis(18); // 18 hours + private static final int FAILURE_STREAK_CAP = 7; private static final int NUM_FAILURES_TO_BLOCKLIST = 3; @Mock private WifiConnectivityHelper mWifiConnectivityHelper; @Mock private WifiLastResortWatchdog mWifiLastResortWatchdog; @Mock private Clock mClock; @Mock private LocalLog mLocalLog; + @Mock private WifiScoreCard mWifiScoreCard; private BssidBlocklistMonitor mBssidBlocklistMonitor; @@ -63,7 +67,7 @@ public class BssidBlocklistMonitorTest { when(mWifiConnectivityHelper.getMaxNumBlacklistBssid()) .thenReturn(TEST_NUM_MAX_FIRMWARE_SUPPORT_BSSIDS); mBssidBlocklistMonitor = new BssidBlocklistMonitor(mWifiConnectivityHelper, - mWifiLastResortWatchdog, mClock, mLocalLog); + mWifiLastResortWatchdog, mClock, mLocalLog, mWifiScoreCard); } private void verifyAddTestBssidToBlocklist() { @@ -115,10 +119,48 @@ public class BssidBlocklistMonitorTest { assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); // Verify that TEST_BSSID_1 is removed from the blocklist after the timeout duration. + // By default there is no blocklist streak so the timeout duration is simply + // BASE_BLOCKLIST_DURATION when(mClock.getWallClockMillis()).thenReturn(BASE_BLOCKLIST_DURATION + 1); assertEquals(0, mBssidBlocklistMonitor.updateAndGetBssidBlocklist().size()); } + /** + * Verify that when adding a AP that had already been failing (therefore has a blocklist + * streak), we are setting the blocklist duration using an exponential backoff technique. + */ + @Test + public void testBssidIsRemoveFromBlocklistAfterTimoutExponentialBackoff() { + verifyAddTestBssidToBlocklist(); + int multiplier = 2; + for (int i = 1; i <= FAILURE_STREAK_CAP; i++) { + when(mWifiScoreCard.getBssidBlocklistStreak(anyString(), anyString(), anyInt())) + .thenReturn(i); + when(mClock.getWallClockMillis()).thenReturn(0L); + verifyAddTestBssidToBlocklist(); + + // calculate the expected blocklist duration then verify that timeout happens + // exactly after the duration. + long duration = multiplier * BASE_BLOCKLIST_DURATION; + when(mClock.getWallClockMillis()).thenReturn(duration); + assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); + when(mClock.getWallClockMillis()).thenReturn(duration + 1); + assertEquals(0, mBssidBlocklistMonitor.updateAndGetBssidBlocklist().size()); + + multiplier *= 2; + } + + // finally verify that the timout is capped at some max value + when(mWifiScoreCard.getBssidBlocklistStreak(anyString(), anyString(), anyInt())) + .thenReturn(FAILURE_STREAK_CAP + 1); + when(mClock.getWallClockMillis()).thenReturn(0L); + verifyAddTestBssidToBlocklist(); + when(mClock.getWallClockMillis()).thenReturn(MAX_BLOCKLIST_DURATION); + assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); + when(mClock.getWallClockMillis()).thenReturn(MAX_BLOCKLIST_DURATION + 1); + assertEquals(0, mBssidBlocklistMonitor.updateAndGetBssidBlocklist().size()); + } + /** * Verify that consecutive failures will add a BSSID to blocklist. */ @@ -139,6 +181,19 @@ public class BssidBlocklistMonitorTest { assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); } + /** + * Verify that when the BSSID blocklist streak is greater or equal to 1, then we block a + * BSSID on a single failure regardless of failure type. + */ + @Test + public void testBlocklistStreakExpeditesAddingToBlocklist() { + when(mWifiScoreCard.getBssidBlocklistStreak(anyString(), anyString(), anyInt())) + .thenReturn(1); + assertTrue(mBssidBlocklistMonitor.handleBssidConnectionFailure( + TEST_BSSID_1, TEST_SSID_1, TEST_L2_FAILURE)); + assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); + } + /** * Verify that onSuccessfulConnection resets L2 related failure counts. */ @@ -149,7 +204,7 @@ public class BssidBlocklistMonitorTest { NUM_FAILURES_TO_BLOCKLIST - 1); // Verify that a connection success event will clear the failure count. - mBssidBlocklistMonitor.handleBssidConnectionSuccess(TEST_BSSID_1); + mBssidBlocklistMonitor.handleBssidConnectionSuccess(TEST_BSSID_1, TEST_SSID_1); handleBssidConnectionFailureMultipleTimes(TEST_BSSID_1, TEST_L2_FAILURE, NUM_FAILURES_TO_BLOCKLIST - 1); @@ -170,8 +225,8 @@ public class BssidBlocklistMonitorTest { handleBssidConnectionFailureMultipleTimes(TEST_BSSID_1, TEST_DHCP_FAILURE, NUM_FAILURES_TO_BLOCKLIST - 1); - // Verify that a network validation success event will clear the failure count. - mBssidBlocklistMonitor.handleDhcpProvisioningSuccess(TEST_BSSID_1); + // Verify that a dhcp provisioning success event will clear appropirate failure counts. + mBssidBlocklistMonitor.handleDhcpProvisioningSuccess(TEST_BSSID_1, TEST_SSID_1); handleBssidConnectionFailureMultipleTimes(TEST_BSSID_1, TEST_DHCP_FAILURE, NUM_FAILURES_TO_BLOCKLIST - 1); @@ -183,6 +238,46 @@ public class BssidBlocklistMonitorTest { assertTrue(mBssidBlocklistMonitor.updateAndGetBssidBlocklist().contains(TEST_BSSID_1)); } + /** + * Verify that handleBssidConnectionSuccess resets appropriate blocklist streak counts. + */ + @Test + public void testNetworkConnectionResetsBlocklistStreak() { + mBssidBlocklistMonitor.handleBssidConnectionSuccess(TEST_BSSID_1, TEST_SSID_1); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_WRONG_PASSWORD); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_EAP_FAILURE); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_ASSOCIATION_REJECTION); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_AUTHENTICATION_FAILURE); + } + + /** + * Verify that handleDhcpProvisioningSuccess resets appropriate blocklist streak counts. + */ + @Test + public void testDhcpProvisioningResetsBlocklistStreak() { + mBssidBlocklistMonitor.handleDhcpProvisioningSuccess(TEST_BSSID_1, TEST_SSID_1); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_DHCP_FAILURE); + } + + /** + * Verify that handleNetworkValidationSuccess resets appropriate blocklist streak counts. + */ + @Test + public void testNetworkValidationResetsBlocklistStreak() { + mBssidBlocklistMonitor.handleNetworkValidationSuccess(TEST_BSSID_1, TEST_SSID_1); + verify(mWifiScoreCard).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE); + } + /** * Verify that L3 failure counts are not affected when L2 failure counts are reset. */ @@ -194,11 +289,30 @@ public class BssidBlocklistMonitorTest { assertEquals(0, mBssidBlocklistMonitor.updateAndGetBssidBlocklist().size()); // Verify that the failure counter is not cleared by |handleBssidConnectionSuccess|. - mBssidBlocklistMonitor.handleBssidConnectionSuccess(TEST_BSSID_1); + mBssidBlocklistMonitor.handleBssidConnectionSuccess(TEST_BSSID_1, TEST_SSID_1); handleBssidConnectionFailureMultipleTimes(TEST_BSSID_1, TEST_DHCP_FAILURE, 1); assertEquals(1, mBssidBlocklistMonitor.updateAndGetBssidBlocklist().size()); } + /** + * Verify that the blocklist streak is incremented after adding a BSSID to blocklist. + * And then verify the blocklist streak is not reset by a regular timeout. + */ + public void testIncrementingBlocklistStreakCount() { + verifyAddTestBssidToBlocklist(); + // verify that the blocklist streak is incremented + verify(mWifiScoreCard).incrementBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA); + + // Verify that TEST_BSSID_1 is removed from the blocklist after the timeout duration. + when(mClock.getWallClockMillis()).thenReturn(BASE_BLOCKLIST_DURATION + 1); + assertEquals(0, mBssidBlocklistMonitor.updateAndGetBssidBlocklist().size()); + + // But the blacklist streak count is not cleared + verify(mWifiScoreCard, never()).resetBssidBlocklistStreak(TEST_SSID_1, TEST_BSSID_1, + BssidBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA); + } + /** * Verify that when a failure signal is received for a BSSID with different SSID from before, * then the failure counts are reset. diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java index b59ee2a2a..51300190a 100644 --- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java @@ -958,6 +958,10 @@ public class ClientModeImplTest extends WifiBaseTest { when(mScanDetailCache.getScanResult(sBSSID)).thenReturn( getGoogleGuestScanDetail(TEST_RSSI, sBSSID, sFreq).getScanResult()); + mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, + new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.ASSOCIATED)); + mLooper.dispatchAll(); + mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); mLooper.dispatchAll(); @@ -1550,10 +1554,14 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt(), any()); + mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, + new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.ASSOCIATED)); + mLooper.dispatchAll(); + mCmi.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID); mLooper.dispatchAll(); + verify(mBssidBlocklistMonitor).handleBssidConnectionSuccess(sBSSID, sSSID); - verify(mBssidBlocklistMonitor).handleBssidConnectionSuccess(sBSSID); mCmi.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0, new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED)); mLooper.dispatchAll(); @@ -1571,8 +1579,8 @@ public class ClientModeImplTest extends WifiBaseTest { sSSID, BssidBlocklistMonitor.REASON_DHCP_FAILURE); verify(mBssidBlocklistMonitor, times(2)).handleBssidConnectionFailure(sBSSID, sSSID, BssidBlocklistMonitor.REASON_DHCP_FAILURE); - verify(mBssidBlocklistMonitor, never()).handleDhcpProvisioningSuccess(sBSSID); - verify(mBssidBlocklistMonitor, never()).handleNetworkValidationSuccess(sBSSID); + verify(mBssidBlocklistMonitor, never()).handleDhcpProvisioningSuccess(sBSSID, sSSID); + verify(mBssidBlocklistMonitor, never()).handleNetworkValidationSuccess(sBSSID, sSSID); } /** @@ -3402,9 +3410,9 @@ public class ClientModeImplTest extends WifiBaseTest { public void verifyNetworkSelectionEnableOnInternetValidation() throws Exception { // Simulate the first connection. connect(); - verify(mBssidBlocklistMonitor).handleBssidConnectionSuccess(sBSSID); - verify(mBssidBlocklistMonitor).handleDhcpProvisioningSuccess(sBSSID); - verify(mBssidBlocklistMonitor, never()).handleNetworkValidationSuccess(sBSSID); + verify(mBssidBlocklistMonitor).handleBssidConnectionSuccess(sBSSID, sSSID); + verify(mBssidBlocklistMonitor).handleDhcpProvisioningSuccess(sBSSID, sSSID); + verify(mBssidBlocklistMonitor, never()).handleNetworkValidationSuccess(sBSSID, sSSID); ArgumentCaptor messengerCaptor = ArgumentCaptor.forClass(Messenger.class); verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(), @@ -3425,7 +3433,7 @@ public class ClientModeImplTest extends WifiBaseTest { verify(mWifiConfigManager).updateNetworkSelectionStatus( FRAMEWORK_NETWORK_ID, NETWORK_SELECTION_ENABLE); verify(mWifiScoreCard).noteValidationSuccess(any()); - verify(mBssidBlocklistMonitor).handleNetworkValidationSuccess(sBSSID); + verify(mBssidBlocklistMonitor).handleNetworkValidationSuccess(sBSSID, sSSID); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java index 5c2fc0a27..f1590144a 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java @@ -61,6 +61,9 @@ public class WifiScoreCardTest extends WifiBaseTest { static final double TOL = 1e-6; // for assertEquals(double, double, tolerance) + static final int TEST_BSSID_FAILURE_REASON = + BssidBlocklistMonitor.REASON_ASSOCIATION_REJECTION; + WifiScoreCard mWifiScoreCard; @Mock Clock mClock; @@ -126,6 +129,30 @@ public class WifiScoreCardTest extends WifiBaseTest { assertNotEquals(perBssid.l2Key, mWifiScoreCard.fetchByBssid(TEST_BSSID_2).l2Key); } + /** + * Test the get, increment, and removal of Bssid blocklist streak counts. + */ + @Test + public void testBssidBlocklistStreakOperations() { + mWifiInfo.setSSID(TEST_SSID_1); + mWifiInfo.setBSSID(TEST_BSSID_1.toString()); + mWifiScoreCard.noteIpConfiguration(mWifiInfo); + + String ssid = mWifiInfo.getSSID(); + String bssid = mWifiInfo.getBSSID(); + assertEquals(0, mWifiScoreCard.getBssidBlocklistStreak( + ssid, bssid, TEST_BSSID_FAILURE_REASON)); + for (int i = 1; i < 3; i++) { + assertEquals(i, mWifiScoreCard.incrementBssidBlocklistStreak( + ssid, bssid, TEST_BSSID_FAILURE_REASON)); + assertEquals(i, mWifiScoreCard.getBssidBlocklistStreak( + ssid, bssid, TEST_BSSID_FAILURE_REASON)); + } + mWifiScoreCard.resetBssidBlocklistStreak(ssid, bssid, TEST_BSSID_FAILURE_REASON); + assertEquals(0, mWifiScoreCard.getBssidBlocklistStreak( + ssid, bssid, TEST_BSSID_FAILURE_REASON)); + } + /** * Test identifiers. */ -- cgit v1.2.3