diff options
author | xshu <xshu@google.com> | 2019-11-01 17:06:12 -0700 |
---|---|---|
committer | xshu <xshu@google.com> | 2019-11-21 13:37:56 -0800 |
commit | 81112baaccdab303cd586a621ea611f7cdce3dfb (patch) | |
tree | d2f0667adf2280edec2c5556266f7cddcbde5c46 | |
parent | 622b812139bdeb88a675d6126f94b15ed1ff4336 (diff) |
Add exponential backoff on the network level
Use the number of BSSIDs in the BSSID blocklist to determine how long we
should temporarily disable networks.
This check to re-enable networks is done every time before network
selection:
- if the elapsed time from now to the time the network was disabled is
greater than or equal to a timeout then re-enable the network.
The timeout calculated based on how many BSSIDs are in the BSSID
blocklist:
- 0 BSSID = 0ms (re-enable immediately)
- 1 BSSID = 5 minutes
- 2 BSSIDs = 10 minutes
- 3 BSSIDS = 20 minutes
...
Bug: 139287182
Test: atest FrameworksWifiTests
Change-Id: I009c5410898b09045b42adf4a1f48c05a268fba3
4 files changed, 105 insertions, 27 deletions
diff --git a/service/java/com/android/server/wifi/BssidBlocklistMonitor.java b/service/java/com/android/server/wifi/BssidBlocklistMonitor.java index 7aab09cc5..2f0ba5ff1 100644 --- a/service/java/com/android/server/wifi/BssidBlocklistMonitor.java +++ b/service/java/com/android/server/wifi/BssidBlocklistMonitor.java @@ -283,6 +283,15 @@ public class BssidBlocklistMonitor { } /** + * @param ssid + * @return the number of BSSIDs currently in the blocklist for the |ssid|. + */ + public int getNumBlockedBssidsForSsid(@NonNull String ssid) { + return (int) updateAndGetBssidBlocklistInternal() + .filter(entry -> ssid.equals(entry.ssid)).count(); + } + + /** * Gets the BSSIDs that are currently in the blocklist. * @return Set of BSSIDs currently in the blocklist */ diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 18b5562b3..e2dd98522 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -219,6 +219,12 @@ public class WifiConfigManager { private static final int SCAN_RESULT_MAXIMUM_AGE_MS = 40000; /** + * Maximum number of blocked BSSIDs per SSID used for calcualting the duration of temporarily + * disabling a network. + */ + private static final int MAX_BLOCKED_BSSID_PER_NETWORK = 10; + + /** * Maximum age of frequencies last seen to be included in pno scans. (30 days) */ @VisibleForTesting @@ -1892,7 +1898,16 @@ public class WifiConfigManager { long timeDifferenceMs = mClock.getElapsedSinceBootMillis() - networkStatus.getDisableTime(); int disableReason = networkStatus.getNetworkSelectionDisableReason(); - long disableTimeoutMs = NETWORK_SELECTION_DISABLE_TIMEOUT_MS[disableReason]; + int blockedBssids = Math.min(MAX_BLOCKED_BSSID_PER_NETWORK, + mWifiInjector.getBssidBlocklistMonitor() + .getNumBlockedBssidsForSsid(config.SSID)); + // if no BSSIDs are blocked then we should keep trying to connect to something + long disableTimeoutMs = 0; + if (blockedBssids > 0) { + double multiplier = Math.pow(2.0, blockedBssids - 1.0); + disableTimeoutMs = (long) (NETWORK_SELECTION_DISABLE_TIMEOUT_MS[disableReason] + * multiplier); + } if (timeDifferenceMs >= disableTimeoutMs) { return updateNetworkSelectionStatus( config, NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); diff --git a/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java b/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java index 118e3d0df..068859c78 100644 --- a/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java @@ -108,6 +108,16 @@ public class BssidBlocklistMonitorTest { } /** + * Verify getNumBlockedBssidsForSsid returns the correct number of blocked BSSIDs. + */ + @Test + public void testGetNumBlockedBssidsForSsid() { + verifyAddMultipleBssidsToBlocklist(); + assertEquals(2, mBssidBlocklistMonitor.getNumBlockedBssidsForSsid(TEST_SSID_1)); + assertEquals(1, mBssidBlocklistMonitor.getNumBlockedBssidsForSsid(TEST_SSID_2)); + } + + /** * Verify that updateAndGetBssidBlocklist removes expired blocklist entries and clears * all failure counters for those networks. */ diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index 203250e9f..dd1f46db4 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -113,6 +113,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { private static final int TEST_FREQUENCY_1 = 2412; private static final int TEST_FREQUENCY_2 = 5180; private static final int TEST_FREQUENCY_3 = 5240; + private static final int MAX_BLOCKED_BSSID_PER_NETWORK = 10; private static final MacAddress TEST_RANDOMIZED_MAC = MacAddress.fromString("d2:11:19:34:a5:20"); private static final int DATA_SUBID = 1; @@ -139,6 +140,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { @Mock private DeviceConfigFacade mDeviceConfigFacade; @Mock private CarrierNetworkConfig mCarrierNetworkConfig; @Mock private MacAddressUtil mMacAddressUtil; + @Mock private BssidBlocklistMonitor mBssidBlocklistMonitor; private MockResources mResources; private InOrder mContextConfigStoreMockOrder; @@ -218,6 +220,7 @@ public class WifiConfigManagerTest extends WifiBaseTest { when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true); when(mWifiPermissionsUtil.isDeviceOwner(anyInt(), any())).thenReturn(false); when(mWifiPermissionsUtil.isProfileOwner(anyInt(), any())).thenReturn(false); + when(mWifiInjector.getBssidBlocklistMonitor()).thenReturn(mBssidBlocklistMonitor); when(mWifiInjector.getWifiLastResortWatchdog()).thenReturn(mWifiLastResortWatchdog); when(mWifiInjector.getWifiLastResortWatchdog().shouldIgnoreSsidUpdate()) .thenReturn(false); @@ -1152,6 +1155,36 @@ public class WifiConfigManagerTest extends WifiBaseTest { assertFalse(retrievedNetwork.getNetworkSelectionStatus().isNotRecommended()); } + private void verifyDisableNetwork(NetworkUpdateResult result, int reason) { + // First set it to enabled. + verifyUpdateNetworkSelectionStatus( + result.getNetworkId(), NetworkSelectionStatus.NETWORK_SELECTION_ENABLE, 0); + + int disableThreshold = + WifiConfigManager.NETWORK_SELECTION_DISABLE_THRESHOLD[reason]; + for (int i = 1; i <= disableThreshold; i++) { + verifyUpdateNetworkSelectionStatus(result.getNetworkId(), reason, i); + } + } + + private void verifyNetworkIsEnabledAfter(int networkId, long timeout) { + // try enabling this network 1 second earlier than the expected timeout. This + // should fail and the status should remain temporarily disabled. + when(mClock.getElapsedSinceBootMillis()).thenReturn(timeout - 1); + assertFalse(mWifiConfigManager.tryEnableNetwork(networkId)); + NetworkSelectionStatus retrievedStatus = + mWifiConfigManager.getConfiguredNetwork(networkId).getNetworkSelectionStatus(); + assertTrue(retrievedStatus.isNetworkTemporaryDisabled()); + + // Now advance time by the timeout for association rejection and ensure that the + // network is now enabled. + when(mClock.getElapsedSinceBootMillis()).thenReturn(timeout); + assertTrue(mWifiConfigManager.tryEnableNetwork(networkId)); + retrievedStatus = mWifiConfigManager.getConfiguredNetwork(networkId) + .getNetworkSelectionStatus(); + assertTrue(retrievedStatus.isNetworkEnabled()); + } + /** * Verifies the enabling of temporarily disabled network using * {@link WifiConfigManager#tryEnableNetwork(int)}. @@ -1159,39 +1192,50 @@ public class WifiConfigManagerTest extends WifiBaseTest { @Test public void testTryEnableNetwork() { WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); - NetworkUpdateResult result = verifyAddNetworkToWifiConfigManager(openNetwork); - // First set it to enabled. - verifyUpdateNetworkSelectionStatus( - result.getNetworkId(), NetworkSelectionStatus.NETWORK_SELECTION_ENABLE, 0); - - // Now set it to temporarily disabled. The threshold for association rejection is 5, so - // disable it 5 times to actually mark it temporarily disabled. - int assocRejectReason = NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION; - int assocRejectThreshold = - WifiConfigManager.NETWORK_SELECTION_DISABLE_THRESHOLD[assocRejectReason]; - for (int i = 1; i <= assocRejectThreshold; i++) { - verifyUpdateNetworkSelectionStatus(result.getNetworkId(), assocRejectReason, i); + // Verify exponential backoff on the disable duration based on number of BSSIDs in the + // BSSID blocklist + long multiplier = 1; + int disableReason = NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION; + long timeout = 0; + for (int i = 1; i < MAX_BLOCKED_BSSID_PER_NETWORK + 1; i++) { + verifyDisableNetwork(result, disableReason); + int numBssidsInBlocklist = i; + when(mBssidBlocklistMonitor.getNumBlockedBssidsForSsid(anyString())) + .thenReturn(numBssidsInBlocklist); + timeout = WifiConfigManager.NETWORK_SELECTION_DISABLE_TIMEOUT_MS[disableReason] + * multiplier; + multiplier *= 2; + verifyNetworkIsEnabledAfter(result.getNetworkId(), + TEST_ELAPSED_UPDATE_NETWORK_SELECTION_TIME_MILLIS + timeout); } - // Now let's try enabling this network without changing the time, this should fail and the - // status remains temporarily disabled. - assertFalse(mWifiConfigManager.tryEnableNetwork(result.getNetworkId())); - NetworkSelectionStatus retrievedStatus = - mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()) - .getNetworkSelectionStatus(); - assertTrue(retrievedStatus.isNetworkTemporaryDisabled()); + // Verify one last time that the disable duration is capped at some maximum. + verifyDisableNetwork(result, disableReason); + when(mBssidBlocklistMonitor.getNumBlockedBssidsForSsid(anyString())) + .thenReturn(MAX_BLOCKED_BSSID_PER_NETWORK + 1); + verifyNetworkIsEnabledAfter(result.getNetworkId(), + TEST_ELAPSED_UPDATE_NETWORK_SELECTION_TIME_MILLIS + timeout); + } - // Now advance time by the timeout for association rejection and ensure that the network - // is now enabled. - int assocRejectTimeout = - WifiConfigManager.NETWORK_SELECTION_DISABLE_TIMEOUT_MS[assocRejectReason]; - when(mClock.getElapsedSinceBootMillis()) - .thenReturn(TEST_ELAPSED_UPDATE_NETWORK_SELECTION_TIME_MILLIS + assocRejectTimeout); + /** + * Verifies that when no BSSIDs for a network is inside the BSSID blocklist then we + * re-enable a network. + */ + @Test + public void testTryEnableNetworkNoBssidsInBlocklist() { + WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); + NetworkUpdateResult result = verifyAddNetworkToWifiConfigManager(openNetwork); + int disableReason = NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION; + // Verify that with 0 BSSIDs in blocklist we enable the network immediately + verifyDisableNetwork(result, disableReason); + when(mBssidBlocklistMonitor.getNumBlockedBssidsForSsid(anyString())).thenReturn(0); + when(mClock.getElapsedSinceBootMillis()) + .thenReturn(TEST_ELAPSED_UPDATE_NETWORK_SELECTION_TIME_MILLIS); assertTrue(mWifiConfigManager.tryEnableNetwork(result.getNetworkId())); - retrievedStatus = + NetworkSelectionStatus retrievedStatus = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId()) .getNetworkSelectionStatus(); assertTrue(retrievedStatus.isNetworkEnabled()); |