summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxshu <xshu@google.com>2019-11-01 17:06:12 -0700
committerxshu <xshu@google.com>2019-11-21 13:37:56 -0800
commit81112baaccdab303cd586a621ea611f7cdce3dfb (patch)
treed2f0667adf2280edec2c5556266f7cddcbde5c46
parent622b812139bdeb88a675d6126f94b15ed1ff4336 (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
-rw-r--r--service/java/com/android/server/wifi/BssidBlocklistMonitor.java9
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java17
-rw-r--r--tests/wifitests/src/com/android/server/wifi/BssidBlocklistMonitorTest.java10
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java96
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());