WifiConnectivityManagerTest.java revision b6686e9d42895f9c2b9f4278cd892149bee04e3a
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig; 20import static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE; 21 22import static org.junit.Assert.*; 23import static org.mockito.Mockito.*; 24 25import android.app.test.MockAnswerUtil.AnswerWithArguments; 26import android.app.test.TestAlarmManager; 27import android.content.Context; 28import android.content.res.Resources; 29import android.net.NetworkScoreManager; 30import android.net.wifi.ScanResult; 31import android.net.wifi.ScanResult.InformationElement; 32import android.net.wifi.SupplicantState; 33import android.net.wifi.WifiConfiguration; 34import android.net.wifi.WifiInfo; 35import android.net.wifi.WifiNetworkScoreCache; 36import android.net.wifi.WifiScanner; 37import android.net.wifi.WifiScanner.PnoScanListener; 38import android.net.wifi.WifiScanner.PnoSettings; 39import android.net.wifi.WifiScanner.ScanData; 40import android.net.wifi.WifiScanner.ScanListener; 41import android.net.wifi.WifiScanner.ScanSettings; 42import android.net.wifi.WifiSsid; 43import android.os.SystemClock; 44import android.os.WorkSource; 45import android.os.test.TestLooper; 46import android.test.suitebuilder.annotation.SmallTest; 47 48import com.android.internal.R; 49 50import org.junit.After; 51import org.junit.Before; 52import org.junit.Ignore; 53import org.junit.Test; 54import org.mockito.ArgumentCaptor; 55import org.mockito.Captor; 56import org.mockito.Mock; 57import org.mockito.MockitoAnnotations; 58 59import java.nio.charset.StandardCharsets; 60import java.util.ArrayList; 61import java.util.HashSet; 62 63/** 64 * Unit tests for {@link com.android.server.wifi.WifiConnectivityManager}. 65 */ 66@SmallTest 67public class WifiConnectivityManagerTest { 68 /** 69 * Called before each test 70 */ 71 @Before 72 public void setUp() throws Exception { 73 MockitoAnnotations.initMocks(this); 74 mResource = mockResource(); 75 mAlarmManager = new TestAlarmManager(); 76 mContext = mockContext(); 77 mWifiStateMachine = mockWifiStateMachine(); 78 mWifiConfigManager = mockWifiConfigManager(); 79 mWifiInfo = getWifiInfo(); 80 mScanData = mockScanData(); 81 mWifiScanner = mockWifiScanner(); 82 mWifiConnectivityHelper = mockWifiConnectivityHelper(); 83 mWifiNS = mockWifiNetworkSelector(); 84 mWifiConnectivityManager = createConnectivityManager(); 85 mWifiConnectivityManager.setWifiEnabled(true); 86 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()); 87 } 88 89 /** 90 * Called after each test 91 */ 92 @After 93 public void cleanup() { 94 validateMockitoUsage(); 95 } 96 97 private Resources mResource; 98 99 private Context mContext; 100 private TestAlarmManager mAlarmManager; 101 private TestLooper mLooper = new TestLooper(); 102 private WifiConnectivityManager mWifiConnectivityManager; 103 private WifiNetworkSelector mWifiNS; 104 private WifiStateMachine mWifiStateMachine; 105 private WifiScanner mWifiScanner; 106 private WifiConnectivityHelper mWifiConnectivityHelper; 107 private ScanData mScanData; 108 private WifiConfigManager mWifiConfigManager; 109 private WifiInfo mWifiInfo; 110 @Mock private FrameworkFacade mFrameworkFacade; 111 @Mock private NetworkScoreManager mNetworkScoreManager; 112 @Mock private Clock mClock; 113 @Mock private WifiLastResortWatchdog mWifiLastResortWatchdog; 114 @Mock private WifiMetrics mWifiMetrics; 115 @Mock private WifiNetworkScoreCache mScoreCache; 116 @Captor ArgumentCaptor<ScanResult> mCandidateScanResultCaptor; 117 private MockResources mResources; 118 119 private static final int CANDIDATE_NETWORK_ID = 0; 120 private static final String CANDIDATE_SSID = "\"AnSsid\""; 121 private static final String CANDIDATE_BSSID = "6c:f3:7f:ae:8c:f3"; 122 private static final String INVALID_SCAN_RESULT_BSSID = "6c:f3:7f:ae:8c:f4"; 123 private static final long CURRENT_SYSTEM_TIME_MS = 1000; 124 125 Resources mockResource() { 126 Resources resource = mock(Resources.class); 127 128 when(resource.getInteger(R.integer.config_wifi_framework_SECURITY_AWARD)).thenReturn(80); 129 when(resource.getInteger(R.integer.config_wifi_framework_SAME_BSSID_AWARD)).thenReturn(24); 130 when(resource.getBoolean( 131 R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true); 132 when(resource.getInteger( 133 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)) 134 .thenReturn(-60); 135 when(resource.getInteger( 136 R.integer.config_wifi_framework_current_network_boost)).thenReturn(16); 137 return resource; 138 } 139 140 Context mockContext() { 141 Context context = mock(Context.class); 142 143 when(context.getResources()).thenReturn(mResource); 144 when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn( 145 mAlarmManager.getAlarmManager()); 146 147 return context; 148 } 149 150 ScanData mockScanData() { 151 ScanData scanData = mock(ScanData.class); 152 153 when(scanData.isAllChannelsScanned()).thenReturn(true); 154 155 return scanData; 156 } 157 158 WifiScanner mockWifiScanner() { 159 WifiScanner scanner = mock(WifiScanner.class); 160 ArgumentCaptor<ScanListener> allSingleScanListenerCaptor = 161 ArgumentCaptor.forClass(ScanListener.class); 162 163 doNothing().when(scanner).registerScanListener(allSingleScanListenerCaptor.capture()); 164 165 ScanData[] scanDatas = new ScanData[1]; 166 scanDatas[0] = mScanData; 167 168 // do a synchronous answer for the ScanListener callbacks 169 doAnswer(new AnswerWithArguments() { 170 public void answer(ScanSettings settings, ScanListener listener, 171 WorkSource workSource) throws Exception { 172 listener.onResults(scanDatas); 173 }}).when(scanner).startBackgroundScan(anyObject(), anyObject(), anyObject()); 174 175 doAnswer(new AnswerWithArguments() { 176 public void answer(ScanSettings settings, ScanListener listener, 177 WorkSource workSource) throws Exception { 178 listener.onResults(scanDatas); 179 allSingleScanListenerCaptor.getValue().onResults(scanDatas); 180 }}).when(scanner).startScan(anyObject(), anyObject(), anyObject()); 181 182 // This unfortunately needs to be a somewhat valid scan result, otherwise 183 // |ScanDetailUtil.toScanDetail| raises exceptions. 184 final ScanResult[] scanResults = new ScanResult[1]; 185 scanResults[0] = new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID), 186 CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", 187 -78, 2450, 1025, 22, 33, 20, 0, 0, true); 188 scanResults[0].informationElements = new InformationElement[1]; 189 scanResults[0].informationElements[0] = new InformationElement(); 190 scanResults[0].informationElements[0].id = InformationElement.EID_SSID; 191 scanResults[0].informationElements[0].bytes = 192 CANDIDATE_SSID.getBytes(StandardCharsets.UTF_8); 193 194 doAnswer(new AnswerWithArguments() { 195 public void answer(ScanSettings settings, PnoSettings pnoSettings, 196 PnoScanListener listener) throws Exception { 197 listener.onPnoNetworkFound(scanResults); 198 }}).when(scanner).startDisconnectedPnoScan(anyObject(), anyObject(), anyObject()); 199 200 doAnswer(new AnswerWithArguments() { 201 public void answer(ScanSettings settings, PnoSettings pnoSettings, 202 PnoScanListener listener) throws Exception { 203 listener.onPnoNetworkFound(scanResults); 204 }}).when(scanner).startConnectedPnoScan(anyObject(), anyObject(), anyObject()); 205 206 return scanner; 207 } 208 209 WifiConnectivityHelper mockWifiConnectivityHelper() { 210 WifiConnectivityHelper connectivityHelper = mock(WifiConnectivityHelper.class); 211 212 when(connectivityHelper.isFirmwareRoamingSupported()).thenReturn(false); 213 214 return connectivityHelper; 215 } 216 217 WifiStateMachine mockWifiStateMachine() { 218 WifiStateMachine stateMachine = mock(WifiStateMachine.class); 219 220 when(stateMachine.isLinkDebouncing()).thenReturn(false); 221 when(stateMachine.isConnected()).thenReturn(false); 222 when(stateMachine.isDisconnected()).thenReturn(true); 223 when(stateMachine.isSupplicantTransientState()).thenReturn(false); 224 225 return stateMachine; 226 } 227 228 WifiNetworkSelector mockWifiNetworkSelector() { 229 WifiNetworkSelector ns = mock(WifiNetworkSelector.class); 230 231 WifiConfiguration candidate = generateWifiConfig( 232 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 233 candidate.BSSID = WifiStateMachine.SUPPLICANT_BSSID_ANY; 234 ScanResult candidateScanResult = new ScanResult(); 235 candidateScanResult.SSID = CANDIDATE_SSID; 236 candidateScanResult.BSSID = CANDIDATE_BSSID; 237 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 238 239 when(ns.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 240 anyBoolean(), anyBoolean())).thenReturn(candidate); 241 return ns; 242 } 243 244 WifiInfo getWifiInfo() { 245 WifiInfo wifiInfo = new WifiInfo(); 246 247 wifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 248 wifiInfo.setBSSID(null); 249 wifiInfo.setSupplicantState(SupplicantState.DISCONNECTED); 250 251 return wifiInfo; 252 } 253 254 WifiConfigManager mockWifiConfigManager() { 255 WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class); 256 257 when(wifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(null); 258 259 // Pass dummy pno network list, otherwise Pno scan requests will not be triggered. 260 PnoSettings.PnoNetwork pnoNetwork = new PnoSettings.PnoNetwork(CANDIDATE_SSID); 261 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = new ArrayList<>(); 262 pnoNetworkList.add(pnoNetwork); 263 when(wifiConfigManager.retrievePnoNetworkList()).thenReturn(pnoNetworkList); 264 when(wifiConfigManager.retrievePnoNetworkList()).thenReturn(pnoNetworkList); 265 266 return wifiConfigManager; 267 } 268 269 WifiConnectivityManager createConnectivityManager() { 270 return new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner, 271 mWifiConfigManager, mWifiInfo, mWifiNS, mWifiConnectivityHelper, 272 mWifiLastResortWatchdog, mWifiMetrics, mLooper.getLooper(), mClock, true, 273 mFrameworkFacade, null, null, null); 274 } 275 276 /** 277 * Wifi enters disconnected state while screen is on. 278 * 279 * Expected behavior: WifiConnectivityManager calls 280 * WifiStateMachine.startConnectToNetwork() with the 281 * expected candidate network ID and BSSID. 282 */ 283 @Test 284 public void enterWifiDisconnectedStateWhenScreenOn() { 285 // Set screen to on 286 mWifiConnectivityManager.handleScreenStateChanged(true); 287 288 // Set WiFi to disconnected state 289 mWifiConnectivityManager.handleConnectionStateChanged( 290 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 291 292 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 293 } 294 295 /** 296 * Wifi enters connected state while screen is on. 297 * 298 * Expected behavior: WifiConnectivityManager calls 299 * WifiStateMachine.startConnectToNetwork() with the 300 * expected candidate network ID and BSSID. 301 */ 302 @Test 303 public void enterWifiConnectedStateWhenScreenOn() { 304 // Set screen to on 305 mWifiConnectivityManager.handleScreenStateChanged(true); 306 307 // Set WiFi to connected state 308 mWifiConnectivityManager.handleConnectionStateChanged( 309 WifiConnectivityManager.WIFI_STATE_CONNECTED); 310 311 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 312 } 313 314 /** 315 * Screen turned on while WiFi in disconnected state. 316 * 317 * Expected behavior: WifiConnectivityManager calls 318 * WifiStateMachine.startConnectToNetwork() with the 319 * expected candidate network ID and BSSID. 320 */ 321 @Test 322 public void turnScreenOnWhenWifiInDisconnectedState() { 323 // Set WiFi to disconnected state 324 mWifiConnectivityManager.handleConnectionStateChanged( 325 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 326 327 // Set screen to on 328 mWifiConnectivityManager.handleScreenStateChanged(true); 329 330 verify(mWifiStateMachine, atLeastOnce()).startConnectToNetwork( 331 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 332 } 333 334 /** 335 * Screen turned on while WiFi in connected state. 336 * 337 * Expected behavior: WifiConnectivityManager calls 338 * WifiStateMachine.startConnectToNetwork() with the 339 * expected candidate network ID and BSSID. 340 */ 341 @Test 342 public void turnScreenOnWhenWifiInConnectedState() { 343 // Set WiFi to connected state 344 mWifiConnectivityManager.handleConnectionStateChanged( 345 WifiConnectivityManager.WIFI_STATE_CONNECTED); 346 347 // Set screen to on 348 mWifiConnectivityManager.handleScreenStateChanged(true); 349 350 verify(mWifiStateMachine, atLeastOnce()).startConnectToNetwork( 351 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 352 } 353 354 /** 355 * Screen turned on while WiFi in connected state but 356 * auto roaming is disabled. 357 * 358 * Expected behavior: WifiConnectivityManager doesn't invoke 359 * WifiStateMachine.startConnectToNetwork() because roaming 360 * is turned off. 361 */ 362 @Test 363 public void turnScreenOnWhenWifiInConnectedStateRoamingDisabled() { 364 // Turn off auto roaming 365 when(mResource.getBoolean( 366 R.bool.config_wifi_framework_enable_associated_network_selection)) 367 .thenReturn(false); 368 mWifiConnectivityManager = createConnectivityManager(); 369 370 // Set WiFi to connected state 371 mWifiConnectivityManager.handleConnectionStateChanged( 372 WifiConnectivityManager.WIFI_STATE_CONNECTED); 373 374 // Set screen to on 375 mWifiConnectivityManager.handleScreenStateChanged(true); 376 377 verify(mWifiStateMachine, times(0)).startConnectToNetwork( 378 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 379 } 380 381 /** 382 * Multiple back to back connection attempts within the rate interval should be rate limited. 383 * 384 * Expected behavior: WifiConnectivityManager calls WifiStateMachine.startConnectToNetwork() 385 * with the expected candidate network ID and BSSID for only the expected number of times within 386 * the given interval. 387 */ 388 @Test 389 public void connectionAttemptRateLimitedWhenScreenOff() { 390 int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE; 391 int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS; 392 int numAttempts = 0; 393 int connectionAttemptIntervals = timeInterval / maxAttemptRate; 394 395 mWifiConnectivityManager.handleScreenStateChanged(false); 396 397 // First attempt the max rate number of connections within the rate interval. 398 long currentTimeStamp = 0; 399 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 400 currentTimeStamp += connectionAttemptIntervals; 401 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 402 // Set WiFi to disconnected state to trigger PNO scan 403 mWifiConnectivityManager.handleConnectionStateChanged( 404 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 405 numAttempts++; 406 } 407 // Now trigger another connection attempt before the rate interval, this should be 408 // skipped because we've crossed rate limit. 409 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 410 // Set WiFi to disconnected state to trigger PNO scan 411 mWifiConnectivityManager.handleConnectionStateChanged( 412 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 413 414 // Verify that we attempt to connect upto the rate. 415 verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork( 416 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 417 } 418 419 /** 420 * Multiple back to back connection attempts outside the rate interval should not be rate 421 * limited. 422 * 423 * Expected behavior: WifiConnectivityManager calls WifiStateMachine.startConnectToNetwork() 424 * with the expected candidate network ID and BSSID for only the expected number of times within 425 * the given interval. 426 */ 427 @Test 428 public void connectionAttemptNotRateLimitedWhenScreenOff() { 429 int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE; 430 int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS; 431 int numAttempts = 0; 432 int connectionAttemptIntervals = timeInterval / maxAttemptRate; 433 434 mWifiConnectivityManager.handleScreenStateChanged(false); 435 436 // First attempt the max rate number of connections within the rate interval. 437 long currentTimeStamp = 0; 438 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 439 currentTimeStamp += connectionAttemptIntervals; 440 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 441 // Set WiFi to disconnected state to trigger PNO scan 442 mWifiConnectivityManager.handleConnectionStateChanged( 443 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 444 numAttempts++; 445 } 446 // Now trigger another connection attempt after the rate interval, this should not be 447 // skipped because we should've evicted the older attempt. 448 when(mClock.getElapsedSinceBootMillis()).thenReturn( 449 currentTimeStamp + connectionAttemptIntervals * 2); 450 // Set WiFi to disconnected state to trigger PNO scan 451 mWifiConnectivityManager.handleConnectionStateChanged( 452 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 453 numAttempts++; 454 455 // Verify that all the connection attempts went through 456 verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork( 457 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 458 } 459 460 /** 461 * Multiple back to back connection attempts after a user selection should not be rate limited. 462 * 463 * Expected behavior: WifiConnectivityManager calls WifiStateMachine.startConnectToNetwork() 464 * with the expected candidate network ID and BSSID for only the expected number of times within 465 * the given interval. 466 */ 467 @Test 468 public void connectionAttemptNotRateLimitedWhenScreenOffAfterUserSelection() { 469 int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE; 470 int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS; 471 int numAttempts = 0; 472 int connectionAttemptIntervals = timeInterval / maxAttemptRate; 473 474 mWifiConnectivityManager.handleScreenStateChanged(false); 475 476 // First attempt the max rate number of connections within the rate interval. 477 long currentTimeStamp = 0; 478 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 479 currentTimeStamp += connectionAttemptIntervals; 480 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 481 // Set WiFi to disconnected state to trigger PNO scan 482 mWifiConnectivityManager.handleConnectionStateChanged( 483 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 484 numAttempts++; 485 } 486 487 mWifiConnectivityManager.setUserConnectChoice(CANDIDATE_NETWORK_ID); 488 489 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 490 currentTimeStamp += connectionAttemptIntervals; 491 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 492 // Set WiFi to disconnected state to trigger PNO scan 493 mWifiConnectivityManager.handleConnectionStateChanged( 494 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 495 numAttempts++; 496 } 497 498 // Verify that all the connection attempts went through 499 verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork( 500 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 501 } 502 503 /** 504 * PNO retry for low RSSI networks. 505 * 506 * Expected behavior: WifiConnectivityManager doubles the low RSSI 507 * network retry delay value after QNS skips the PNO scan results 508 * because of their low RSSI values. 509 */ 510 @Test 511 @Ignore("b/32977707") 512 public void pnoRetryForLowRssiNetwork() { 513 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 514 anyBoolean(), anyBoolean())).thenReturn(null); 515 516 // Set screen to off 517 mWifiConnectivityManager.handleScreenStateChanged(false); 518 519 // Get the current retry delay value 520 int lowRssiNetworkRetryDelayStartValue = mWifiConnectivityManager 521 .getLowRssiNetworkRetryDelay(); 522 523 // Set WiFi to disconnected state to trigger PNO scan 524 mWifiConnectivityManager.handleConnectionStateChanged( 525 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 526 527 // Get the retry delay value after QNS didn't select a 528 // network candicate from the PNO scan results. 529 int lowRssiNetworkRetryDelayAfterPnoValue = mWifiConnectivityManager 530 .getLowRssiNetworkRetryDelay(); 531 532 assertEquals(lowRssiNetworkRetryDelayStartValue * 2, 533 lowRssiNetworkRetryDelayAfterPnoValue); 534 } 535 536 /** 537 * Ensure that the watchdog bite increments the "Pno bad" metric. 538 * 539 * Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find 540 * a candidate while watchdog single scan did. 541 */ 542 @Test 543 @Ignore("b/32977707") 544 public void watchdogBitePnoBadIncrementsMetrics() { 545 // Set screen to off 546 mWifiConnectivityManager.handleScreenStateChanged(false); 547 548 // Set WiFi to disconnected state to trigger PNO scan 549 mWifiConnectivityManager.handleConnectionStateChanged( 550 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 551 552 // Now fire the watchdog alarm and verify the metrics were incremented. 553 mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG); 554 mLooper.dispatchAll(); 555 556 verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoBad(); 557 verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoGood(); 558 } 559 560 /** 561 * Ensure that the watchdog bite increments the "Pno good" metric. 562 * 563 * Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find 564 * a candidate which was the same with watchdog single scan. 565 */ 566 @Test 567 @Ignore("b/32977707") 568 public void watchdogBitePnoGoodIncrementsMetrics() { 569 // Qns returns no candidate after watchdog single scan. 570 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 571 anyBoolean(), anyBoolean())).thenReturn(null); 572 573 // Set screen to off 574 mWifiConnectivityManager.handleScreenStateChanged(false); 575 576 // Set WiFi to disconnected state to trigger PNO scan 577 mWifiConnectivityManager.handleConnectionStateChanged( 578 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 579 580 // Now fire the watchdog alarm and verify the metrics were incremented. 581 mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG); 582 mLooper.dispatchAll(); 583 584 verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoGood(); 585 verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoBad(); 586 } 587 588 /** 589 * Verify that scan interval for screen on and wifi disconnected scenario 590 * is in the exponential backoff fashion. 591 * 592 * Expected behavior: WifiConnectivityManager doubles periodic 593 * scan interval. 594 */ 595 @Test 596 public void checkPeriodicScanIntervalWhenDisconnected() { 597 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 598 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 599 600 // Set screen to ON 601 mWifiConnectivityManager.handleScreenStateChanged(true); 602 603 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 604 // by screen state change can settle 605 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 606 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 607 608 // Set WiFi to disconnected state to trigger periodic scan 609 mWifiConnectivityManager.handleConnectionStateChanged( 610 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 611 612 // Get the first periodic scan interval 613 long firstIntervalMs = mAlarmManager 614 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 615 - currentTimeStamp; 616 assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 617 618 currentTimeStamp += firstIntervalMs; 619 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 620 621 // Now fire the first periodic scan alarm timer 622 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 623 mLooper.dispatchAll(); 624 625 // Get the second periodic scan interval 626 long secondIntervalMs = mAlarmManager 627 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 628 - currentTimeStamp; 629 630 // Verify the intervals are exponential back off 631 assertEquals(firstIntervalMs * 2, secondIntervalMs); 632 633 currentTimeStamp += secondIntervalMs; 634 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 635 636 // Make sure we eventually stay at the maximum scan interval. 637 long intervalMs = 0; 638 for (int i = 0; i < 5; i++) { 639 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 640 mLooper.dispatchAll(); 641 intervalMs = mAlarmManager 642 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 643 - currentTimeStamp; 644 currentTimeStamp += intervalMs; 645 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 646 } 647 648 assertEquals(intervalMs, WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS); 649 } 650 651 /** 652 * Verify that scan interval for screen on and wifi connected scenario 653 * is in the exponential backoff fashion. 654 * 655 * Expected behavior: WifiConnectivityManager doubles periodic 656 * scan interval. 657 */ 658 @Test 659 public void checkPeriodicScanIntervalWhenConnected() { 660 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 661 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 662 663 // Set screen to ON 664 mWifiConnectivityManager.handleScreenStateChanged(true); 665 666 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 667 // by screen state change can settle 668 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 669 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 670 671 // Set WiFi to connected state to trigger periodic scan 672 mWifiConnectivityManager.handleConnectionStateChanged( 673 WifiConnectivityManager.WIFI_STATE_CONNECTED); 674 675 // Get the first periodic scan interval 676 long firstIntervalMs = mAlarmManager 677 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 678 - currentTimeStamp; 679 assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 680 681 currentTimeStamp += firstIntervalMs; 682 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 683 684 // Now fire the first periodic scan alarm timer 685 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 686 mLooper.dispatchAll(); 687 688 // Get the second periodic scan interval 689 long secondIntervalMs = mAlarmManager 690 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 691 - currentTimeStamp; 692 693 // Verify the intervals are exponential back off 694 assertEquals(firstIntervalMs * 2, secondIntervalMs); 695 696 currentTimeStamp += secondIntervalMs; 697 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 698 699 // Make sure we eventually stay at the maximum scan interval. 700 long intervalMs = 0; 701 for (int i = 0; i < 5; i++) { 702 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 703 mLooper.dispatchAll(); 704 intervalMs = mAlarmManager 705 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 706 - currentTimeStamp; 707 currentTimeStamp += intervalMs; 708 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 709 } 710 711 assertEquals(intervalMs, WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS); 712 } 713 714 /** 715 * When screen on trigger a disconnected state change event then a connected state 716 * change event back to back to verify that the minium scan interval is enforced. 717 * 718 * Expected behavior: WifiConnectivityManager start the second periodic single 719 * scan PERIODIC_SCAN_INTERVAL_MS after the first one. 720 */ 721 @Test 722 public void checkMinimumPeriodicScanIntervalWhenScreenOnAndConnected() { 723 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 724 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 725 726 // Set screen to ON 727 mWifiConnectivityManager.handleScreenStateChanged(true); 728 729 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 730 // by screen state change can settle 731 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 732 long scanForDisconnectedTimeStamp = currentTimeStamp; 733 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 734 735 // Set WiFi to disconnected state which triggers a scan immediately 736 mWifiConnectivityManager.handleConnectionStateChanged( 737 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 738 verify(mWifiScanner, times(1)).startScan(anyObject(), anyObject(), anyObject()); 739 740 // Set up time stamp for when entering CONNECTED state 741 currentTimeStamp += 2000; 742 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 743 744 // Set WiFi to connected state to trigger its periodic scan 745 mWifiConnectivityManager.handleConnectionStateChanged( 746 WifiConnectivityManager.WIFI_STATE_CONNECTED); 747 748 // The very first scan triggered for connected state is actually via the alarm timer 749 // and it obeys the minimum scan interval 750 long firstScanForConnectedTimeStamp = mAlarmManager 751 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 752 753 // Verify that the first scan for connected state is scheduled PERIODIC_SCAN_INTERVAL_MS 754 // after the scan for disconnected state 755 assertEquals(firstScanForConnectedTimeStamp, scanForDisconnectedTimeStamp 756 + WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 757 } 758 759 /** 760 * When screen on trigger a connected state change event then a disconnected state 761 * change event back to back to verify that a scan is fired immediately for the 762 * disconnected state change event. 763 * 764 * Expected behavior: WifiConnectivityManager directly starts the periodic immediately 765 * for the disconnected state change event. The second scan for disconnected state is 766 * via alarm timer. 767 */ 768 @Test 769 public void scanImmediatelyWhenScreenOnAndDisconnected() { 770 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 771 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 772 773 // Set screen to ON 774 mWifiConnectivityManager.handleScreenStateChanged(true); 775 776 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 777 // by screen state change can settle 778 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 779 long scanForConnectedTimeStamp = currentTimeStamp; 780 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 781 782 // Set WiFi to connected state to trigger the periodic scan 783 mWifiConnectivityManager.handleConnectionStateChanged( 784 WifiConnectivityManager.WIFI_STATE_CONNECTED); 785 verify(mWifiScanner, times(1)).startScan(anyObject(), anyObject(), anyObject()); 786 787 // Set up the time stamp for when entering DISCONNECTED state 788 currentTimeStamp += 2000; 789 long enteringDisconnectedStateTimeStamp = currentTimeStamp; 790 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 791 792 // Set WiFi to disconnected state to trigger its periodic scan 793 mWifiConnectivityManager.handleConnectionStateChanged( 794 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 795 796 // Verify the very first scan for DISCONNECTED state is fired immediately 797 verify(mWifiScanner, times(2)).startScan(anyObject(), anyObject(), anyObject()); 798 long secondScanForDisconnectedTimeStamp = mAlarmManager 799 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 800 801 // Verify that the second scan is scheduled PERIODIC_SCAN_INTERVAL_MS after 802 // entering DISCONNECTED state. 803 assertEquals(secondScanForDisconnectedTimeStamp, enteringDisconnectedStateTimeStamp 804 + WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 805 } 806 807 /** 808 * When screen on trigger a connection state change event and a forced connectivity 809 * scan event back to back to verify that the minimum scan interval is not applied 810 * in this scenario. 811 * 812 * Expected behavior: WifiConnectivityManager starts the second periodic single 813 * scan immediately. 814 */ 815 @Test 816 public void checkMinimumPeriodicScanIntervalNotEnforced() { 817 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 818 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 819 820 // Set screen to ON 821 mWifiConnectivityManager.handleScreenStateChanged(true); 822 823 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 824 // by screen state change can settle 825 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 826 long firstScanTimeStamp = currentTimeStamp; 827 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 828 829 // Set WiFi to connected state to trigger the periodic scan 830 mWifiConnectivityManager.handleConnectionStateChanged( 831 WifiConnectivityManager.WIFI_STATE_CONNECTED); 832 833 // Set the second scan attempt time stamp 834 currentTimeStamp += 2000; 835 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 836 837 // Allow untrusted networks so WifiConnectivityManager starts a periodic scan 838 // immediately. 839 mWifiConnectivityManager.setUntrustedConnectionAllowed(true); 840 841 // Get the second periodic scan actual time stamp. Note, this scan is not 842 // started from the AlarmManager. 843 long secondScanTimeStamp = mWifiConnectivityManager.getLastPeriodicSingleScanTimeStamp(); 844 845 // Verify that the second scan is fired immediately 846 assertEquals(secondScanTimeStamp, currentTimeStamp); 847 } 848 849 /** 850 * Verify that we perform full band scan when the currently connected network's tx/rx success 851 * rate is low. 852 * 853 * Expected behavior: WifiConnectivityManager does full band scan. 854 */ 855 @Test 856 public void checkSingleScanSettingsWhenConnectedWithLowDataRate() { 857 mWifiInfo.txSuccessRate = 0; 858 mWifiInfo.rxSuccessRate = 0; 859 860 final HashSet<Integer> channelList = new HashSet<>(); 861 channelList.add(1); 862 channelList.add(2); 863 channelList.add(3); 864 865 when(mWifiStateMachine.getCurrentWifiConfiguration()) 866 .thenReturn(new WifiConfiguration()); 867 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 868 anyInt())).thenReturn(channelList); 869 870 doAnswer(new AnswerWithArguments() { 871 public void answer(ScanSettings settings, ScanListener listener, 872 WorkSource workSource) throws Exception { 873 assertEquals(settings.band, WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 874 assertNull(settings.channels); 875 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 876 877 // Set screen to ON 878 mWifiConnectivityManager.handleScreenStateChanged(true); 879 880 // Set WiFi to connected state to trigger periodic scan 881 mWifiConnectivityManager.handleConnectionStateChanged( 882 WifiConnectivityManager.WIFI_STATE_CONNECTED); 883 884 verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 885 } 886 887 /** 888 * Verify that we perform partial scan when the currently connected network's tx/rx success 889 * rate is high and when the currently connected network is present in scan 890 * cache in WifiConfigManager. 891 * 892 * Expected behavior: WifiConnectivityManager does full band scan. 893 */ 894 @Test 895 public void checkSingleScanSettingsWhenConnectedWithHighDataRate() { 896 mWifiInfo.txSuccessRate = WifiConnectivityManager.MAX_TX_PACKET_FOR_FULL_SCANS * 2; 897 mWifiInfo.rxSuccessRate = WifiConnectivityManager.MAX_RX_PACKET_FOR_FULL_SCANS * 2; 898 899 final HashSet<Integer> channelList = new HashSet<>(); 900 channelList.add(1); 901 channelList.add(2); 902 channelList.add(3); 903 904 when(mWifiStateMachine.getCurrentWifiConfiguration()) 905 .thenReturn(new WifiConfiguration()); 906 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 907 anyInt())).thenReturn(channelList); 908 909 doAnswer(new AnswerWithArguments() { 910 public void answer(ScanSettings settings, ScanListener listener, 911 WorkSource workSource) throws Exception { 912 assertEquals(settings.band, WifiScanner.WIFI_BAND_UNSPECIFIED); 913 assertEquals(settings.channels.length, channelList.size()); 914 for (int chanIdx = 0; chanIdx < settings.channels.length; chanIdx++) { 915 assertTrue(channelList.contains(settings.channels[chanIdx].frequency)); 916 } 917 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 918 919 // Set screen to ON 920 mWifiConnectivityManager.handleScreenStateChanged(true); 921 922 // Set WiFi to connected state to trigger periodic scan 923 mWifiConnectivityManager.handleConnectionStateChanged( 924 WifiConnectivityManager.WIFI_STATE_CONNECTED); 925 926 verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 927 } 928 929 /** 930 * Verify that we fall back to full band scan when the currently connected network's tx/rx 931 * success rate is high and the currently connected network is not present in scan cache in 932 * WifiConfigManager. This is simulated by returning an empty hashset in |makeChannelList|. 933 * 934 * Expected behavior: WifiConnectivityManager does full band scan. 935 */ 936 @Test 937 public void checkSingleScanSettingsWhenConnectedWithHighDataRateNotInCache() { 938 mWifiInfo.txSuccessRate = WifiConnectivityManager.MAX_TX_PACKET_FOR_FULL_SCANS * 2; 939 mWifiInfo.rxSuccessRate = WifiConnectivityManager.MAX_RX_PACKET_FOR_FULL_SCANS * 2; 940 941 final HashSet<Integer> channelList = new HashSet<>(); 942 943 when(mWifiStateMachine.getCurrentWifiConfiguration()) 944 .thenReturn(new WifiConfiguration()); 945 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 946 anyInt())).thenReturn(channelList); 947 948 doAnswer(new AnswerWithArguments() { 949 public void answer(ScanSettings settings, ScanListener listener, 950 WorkSource workSource) throws Exception { 951 assertEquals(settings.band, WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 952 assertNull(settings.channels); 953 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 954 955 // Set screen to ON 956 mWifiConnectivityManager.handleScreenStateChanged(true); 957 958 // Set WiFi to connected state to trigger periodic scan 959 mWifiConnectivityManager.handleConnectionStateChanged( 960 WifiConnectivityManager.WIFI_STATE_CONNECTED); 961 962 verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 963 } 964 965 /** 966 * Verify that we retry connectivity scan up to MAX_SCAN_RESTART_ALLOWED times 967 * when Wifi somehow gets into a bad state and fails to scan. 968 * 969 * Expected behavior: WifiConnectivityManager schedules connectivity scan 970 * MAX_SCAN_RESTART_ALLOWED times. 971 */ 972 @Test 973 public void checkMaximumScanRetry() { 974 // Set screen to ON 975 mWifiConnectivityManager.handleScreenStateChanged(true); 976 977 doAnswer(new AnswerWithArguments() { 978 public void answer(ScanSettings settings, ScanListener listener, 979 WorkSource workSource) throws Exception { 980 listener.onFailure(-1, "ScanFailure"); 981 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 982 983 // Set WiFi to disconnected state to trigger the single scan based periodic scan 984 mWifiConnectivityManager.handleConnectionStateChanged( 985 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 986 987 // Fire the alarm timer 2x timers 988 for (int i = 0; i < (WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED * 2); i++) { 989 mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG); 990 mLooper.dispatchAll(); 991 } 992 993 // Verify that the connectivity scan has been retried for MAX_SCAN_RESTART_ALLOWED 994 // times. Note, WifiScanner.startScan() is invoked MAX_SCAN_RESTART_ALLOWED + 1 times. 995 // The very first scan is the initial one, and the other MAX_SCAN_RESTART_ALLOWED 996 // are the retrial ones. 997 verify(mWifiScanner, times(WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED + 1)).startScan( 998 anyObject(), anyObject(), anyObject()); 999 } 1000 1001 /** 1002 * Listen to scan results not requested by WifiConnectivityManager and 1003 * act on them. 1004 * 1005 * Expected behavior: WifiConnectivityManager calls 1006 * WifiStateMachine.startConnectToNetwork() with the 1007 * expected candidate network ID and BSSID. 1008 */ 1009 @Test 1010 public void listenToAllSingleScanResults() { 1011 ScanSettings settings = new ScanSettings(); 1012 ScanListener scanListener = mock(ScanListener.class); 1013 1014 // Request a single scan outside of WifiConnectivityManager. 1015 mWifiScanner.startScan(settings, scanListener, WIFI_WORK_SOURCE); 1016 1017 // Verify that WCM receives the scan results and initiates a connection 1018 // to the network. 1019 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1020 } 1021 1022 /** 1023 * Verify that a forced connectivity scan waits for full band scan 1024 * results. 1025 * 1026 * Expected behavior: WifiConnectivityManager doesn't invoke 1027 * WifiStateMachine.startConnectToNetwork() when full band scan 1028 * results are not available. 1029 */ 1030 @Test 1031 public void waitForFullBandScanResults() { 1032 // Set WiFi to connected state. 1033 mWifiConnectivityManager.handleConnectionStateChanged( 1034 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1035 1036 // Set up as partial scan results. 1037 when(mScanData.isAllChannelsScanned()).thenReturn(false); 1038 1039 // Force a connectivity scan which enables WifiConnectivityManager 1040 // to wait for full band scan results. 1041 mWifiConnectivityManager.forceConnectivityScan(); 1042 1043 // No roaming because no full band scan results. 1044 verify(mWifiStateMachine, times(0)).startConnectToNetwork( 1045 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1046 1047 // Set up as full band scan results. 1048 when(mScanData.isAllChannelsScanned()).thenReturn(true); 1049 1050 // Force a connectivity scan which enables WifiConnectivityManager 1051 // to wait for full band scan results. 1052 mWifiConnectivityManager.forceConnectivityScan(); 1053 1054 // Roaming attempt because full band scan results are available. 1055 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1056 } 1057 1058 /** 1059 * Verify the BSSID blacklist implementation. 1060 * 1061 * Expected behavior: A BSSID gets blacklisted after being disabled 1062 * for 3 times, and becomes available after being re-enabled. 1063 */ 1064 @Test 1065 public void blacklistAndReenableBssid() { 1066 String bssid = "6c:f3:7f:ae:8c:f3"; 1067 1068 // Verify that a BSSID gets blacklisted only after being disabled 1069 // for BSSID_BLACKLIST_THRESHOLD times for reasons other than 1070 // REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA. 1071 for (int i = 0; i < WifiConnectivityManager.BSSID_BLACKLIST_THRESHOLD; i++) { 1072 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1073 mWifiConnectivityManager.trackBssid(bssid, false, 1); 1074 } 1075 1076 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1077 1078 // Re-enable the bssid. 1079 mWifiConnectivityManager.trackBssid(bssid, true, 1); 1080 1081 // The bssid should no longer be blacklisted. 1082 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1083 } 1084 1085 /** 1086 * Verify that a network gets blacklisted immediately if it is unable 1087 * to handle new stations. 1088 */ 1089 @Test 1090 public void blacklistNetworkImmediatelyIfApHasNoCapacityForNewStation() { 1091 String bssid = "6c:f3:7f:ae:8c:f3"; 1092 1093 mWifiConnectivityManager.trackBssid(bssid, false, 1094 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1095 1096 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1097 } 1098 1099 /** 1100 * Verify that a blacklisted BSSID becomes available only after 1101 * BSSID_BLACKLIST_EXPIRE_TIME_MS. 1102 */ 1103 @Test 1104 public void verifyBlacklistRefreshedAfterScanResults() { 1105 String bssid = "6c:f3:7f:ae:8c:f3"; 1106 1107 mWifiConnectivityManager.trackBssid(bssid, false, 1108 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1109 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1110 1111 // Force a connectivity scan in less than BSSID_BLACKLIST_EXPIRE_TIME_MS. 1112 // Arrival of scan results will trigger WifiConnectivityManager to refresh its 1113 // BSSID blacklist. Verify that the blacklisted BSSId is not freed because 1114 // its blacklist expiration time hasn't reached yet. 1115 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() 1116 + WifiConnectivityManager.BSSID_BLACKLIST_EXPIRE_TIME_MS / 2); 1117 mWifiConnectivityManager.forceConnectivityScan(); 1118 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1119 1120 // Force another connectivity scan at BSSID_BLACKLIST_EXPIRE_TIME_MS from when the 1121 // BSSID was blacklisted. Verify that the blacklisted BSSId is freed. 1122 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() 1123 + WifiConnectivityManager.BSSID_BLACKLIST_EXPIRE_TIME_MS); 1124 mWifiConnectivityManager.forceConnectivityScan(); 1125 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1126 } 1127 1128 /** 1129 * When WifiConnectivityManager is on and Wifi client mode is enabled, framework 1130 * queries firmware via WifiConnectivityHelper to check if firmware roaming is 1131 * supported and its capability. 1132 * 1133 * Expected behavior: WifiConnectivityManager#setWifiEnabled calls into 1134 * WifiConnectivityHelper#getFirmwareRoamingInfo 1135 */ 1136 @Test 1137 public void verifyGetFirmwareRoamingInfoIsCalledWhenEnableWiFiAndWcmOn() { 1138 reset(mWifiConnectivityHelper); 1139 // WifiConnectivityManager is on by default 1140 mWifiConnectivityManager.setWifiEnabled(true); 1141 verify(mWifiConnectivityHelper).getFirmwareRoamingInfo(); 1142 } 1143 1144 /** 1145 * When WifiConnectivityManager is off, verify that framework does not 1146 * query firmware via WifiConnectivityHelper to check if firmware roaming is 1147 * supported and its capability when enabling Wifi client mode. 1148 * 1149 * Expected behavior: WifiConnectivityManager#setWifiEnabled does not call into 1150 * WifiConnectivityHelper#getFirmwareRoamingInfo 1151 */ 1152 @Test 1153 public void verifyGetFirmwareRoamingInfoIsNotCalledWhenEnableWiFiAndWcmOff() { 1154 reset(mWifiConnectivityHelper); 1155 mWifiConnectivityManager.enable(false); 1156 mWifiConnectivityManager.setWifiEnabled(true); 1157 verify(mWifiConnectivityHelper, times(0)).getFirmwareRoamingInfo(); 1158 } 1159 1160 /* 1161 * Firmware supports controlled roaming. 1162 * Connect to a network which doesn't have a config specified BSSID. 1163 * 1164 * Expected behavior: WifiConnectivityManager calls 1165 * WifiStateMachine.startConnectToNetwork() with the 1166 * expected candidate network ID, and the BSSID value should be 1167 * 'any' since firmware controls the roaming. 1168 */ 1169 @Test 1170 public void useAnyBssidToConnectWhenFirmwareRoamingOnAndConfigHasNoBssidSpecified() { 1171 // Firmware controls roaming 1172 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1173 1174 // Set screen to on 1175 mWifiConnectivityManager.handleScreenStateChanged(true); 1176 1177 // Set WiFi to disconnected state 1178 mWifiConnectivityManager.handleConnectionStateChanged( 1179 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1180 1181 verify(mWifiStateMachine).startConnectToNetwork( 1182 CANDIDATE_NETWORK_ID, WifiStateMachine.SUPPLICANT_BSSID_ANY); 1183 } 1184 1185 /* 1186 * Firmware supports controlled roaming. 1187 * Connect to a network which has a config specified BSSID. 1188 * 1189 * Expected behavior: WifiConnectivityManager calls 1190 * WifiStateMachine.startConnectToNetwork() with the 1191 * expected candidate network ID, and the BSSID value should be 1192 * the config specified one. 1193 */ 1194 @Test 1195 public void useConfigSpecifiedBssidToConnectWhenFirmwareRoamingOn() { 1196 // Firmware controls roaming 1197 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1198 1199 // Set up the candidate configuration such that it has a BSSID specified. 1200 WifiConfiguration candidate = generateWifiConfig( 1201 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1202 candidate.BSSID = CANDIDATE_BSSID; // config specified 1203 ScanResult candidateScanResult = new ScanResult(); 1204 candidateScanResult.SSID = CANDIDATE_SSID; 1205 candidateScanResult.BSSID = CANDIDATE_BSSID; 1206 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1207 1208 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1209 anyBoolean(), anyBoolean())).thenReturn(candidate); 1210 1211 // Set screen to on 1212 mWifiConnectivityManager.handleScreenStateChanged(true); 1213 1214 // Set WiFi to disconnected state 1215 mWifiConnectivityManager.handleConnectionStateChanged( 1216 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1217 1218 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1219 } 1220 1221 /* 1222 * Firmware does not support controlled roaming. 1223 * Connect to a network which doesn't have a config specified BSSID. 1224 * 1225 * Expected behavior: WifiConnectivityManager calls 1226 * WifiStateMachine.startConnectToNetwork() with the expected candidate network ID, 1227 * and the BSSID value should be the candidate scan result specified. 1228 */ 1229 @Test 1230 public void useScanResultBssidToConnectWhenFirmwareRoamingOffAndConfigHasNoBssidSpecified() { 1231 // Set screen to on 1232 mWifiConnectivityManager.handleScreenStateChanged(true); 1233 1234 // Set WiFi to disconnected state 1235 mWifiConnectivityManager.handleConnectionStateChanged( 1236 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1237 1238 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1239 } 1240 1241 /* 1242 * Firmware does not support controlled roaming. 1243 * Connect to a network which has a config specified BSSID. 1244 * 1245 * Expected behavior: WifiConnectivityManager calls 1246 * WifiStateMachine.startConnectToNetwork() with the expected candidate network ID, 1247 * and the BSSID value should be the config specified one. 1248 */ 1249 @Test 1250 public void useConfigSpecifiedBssidToConnectionWhenFirmwareRoamingOff() { 1251 // Set up the candidate configuration such that it has a BSSID specified. 1252 WifiConfiguration candidate = generateWifiConfig( 1253 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1254 candidate.BSSID = CANDIDATE_BSSID; // config specified 1255 ScanResult candidateScanResult = new ScanResult(); 1256 candidateScanResult.SSID = CANDIDATE_SSID; 1257 candidateScanResult.BSSID = CANDIDATE_BSSID; 1258 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1259 1260 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1261 anyBoolean(), anyBoolean())).thenReturn(candidate); 1262 1263 // Set screen to on 1264 mWifiConnectivityManager.handleScreenStateChanged(true); 1265 1266 // Set WiFi to disconnected state 1267 mWifiConnectivityManager.handleConnectionStateChanged( 1268 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1269 1270 verify(mWifiStateMachine).startConnectToNetwork(CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1271 } 1272 1273 /** 1274 * Firmware does not support controlled roaming. 1275 * WiFi in connected state, framework triggers roaming. 1276 * 1277 * Expected behavior: WifiConnectivityManager invokes 1278 * WifiStateMachine.startRoamToNetwork(). 1279 */ 1280 @Test 1281 public void frameworkInitiatedRoaming() { 1282 // Mock the currently connected network which has the same networkID and 1283 // SSID as the one to be selected. 1284 WifiConfiguration currentNetwork = generateWifiConfig( 1285 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1286 when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork); 1287 1288 // Set WiFi to connected state 1289 mWifiConnectivityManager.handleConnectionStateChanged( 1290 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1291 1292 // Set screen to on 1293 mWifiConnectivityManager.handleScreenStateChanged(true); 1294 1295 verify(mWifiStateMachine).startRoamToNetwork(eq(CANDIDATE_NETWORK_ID), 1296 mCandidateScanResultCaptor.capture()); 1297 assertEquals(mCandidateScanResultCaptor.getValue().BSSID, CANDIDATE_BSSID); 1298 } 1299 1300 /** 1301 * Firmware supports controlled roaming. 1302 * WiFi in connected state, framework does not trigger roaming 1303 * as it's handed off to the firmware. 1304 * 1305 * Expected behavior: WifiConnectivityManager doesn't invoke 1306 * WifiStateMachine.startRoamToNetwork(). 1307 */ 1308 @Test 1309 public void noFrameworkRoamingIfConnectedAndFirmwareRoamingSupported() { 1310 // Mock the currently connected network which has the same networkID and 1311 // SSID as the one to be selected. 1312 WifiConfiguration currentNetwork = generateWifiConfig( 1313 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1314 when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork); 1315 1316 // Firmware controls roaming 1317 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1318 1319 // Set WiFi to connected state 1320 mWifiConnectivityManager.handleConnectionStateChanged( 1321 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1322 1323 // Set screen to on 1324 mWifiConnectivityManager.handleScreenStateChanged(true); 1325 1326 verify(mWifiStateMachine, times(0)).startRoamToNetwork(anyInt(), anyObject()); 1327 } 1328 1329 /* 1330 * Wifi in disconnected state. Drop the connection attempt if the recommended 1331 * network configuration has a BSSID specified but the scan result BSSID doesn't 1332 * match it. 1333 * 1334 * Expected behavior: WifiConnectivityManager doesn't invoke 1335 * WifiStateMachine.startConnectToNetwork(). 1336 */ 1337 @Test 1338 public void dropConnectAttemptIfConfigSpecifiedBssidDifferentFromScanResultBssid() { 1339 // Set up the candidate configuration such that it has a BSSID specified. 1340 WifiConfiguration candidate = generateWifiConfig( 1341 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1342 candidate.BSSID = CANDIDATE_BSSID; // config specified 1343 ScanResult candidateScanResult = new ScanResult(); 1344 candidateScanResult.SSID = CANDIDATE_SSID; 1345 // Set up the scan result BSSID to be different from the config specified one. 1346 candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID; 1347 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1348 1349 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1350 anyBoolean(), anyBoolean())).thenReturn(candidate); 1351 1352 // Set screen to on 1353 mWifiConnectivityManager.handleScreenStateChanged(true); 1354 1355 // Set WiFi to disconnected state 1356 mWifiConnectivityManager.handleConnectionStateChanged( 1357 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1358 1359 verify(mWifiStateMachine, times(0)).startConnectToNetwork( 1360 CANDIDATE_NETWORK_ID, CANDIDATE_BSSID); 1361 } 1362 1363 /* 1364 * Wifi in connected state. Drop the roaming attempt if the recommended 1365 * network configuration has a BSSID specified but the scan result BSSID doesn't 1366 * match it. 1367 * 1368 * Expected behavior: WifiConnectivityManager doesn't invoke 1369 * WifiStateMachine.startRoamToNetwork(). 1370 */ 1371 @Test 1372 public void dropRoamingAttemptIfConfigSpecifiedBssidDifferentFromScanResultBssid() { 1373 // Mock the currently connected network which has the same networkID and 1374 // SSID as the one to be selected. 1375 WifiConfiguration currentNetwork = generateWifiConfig( 1376 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1377 when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork); 1378 1379 // Set up the candidate configuration such that it has a BSSID specified. 1380 WifiConfiguration candidate = generateWifiConfig( 1381 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1382 candidate.BSSID = CANDIDATE_BSSID; // config specified 1383 ScanResult candidateScanResult = new ScanResult(); 1384 candidateScanResult.SSID = CANDIDATE_SSID; 1385 // Set up the scan result BSSID to be different from the config specified one. 1386 candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID; 1387 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1388 1389 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1390 anyBoolean(), anyBoolean())).thenReturn(candidate); 1391 1392 // Set WiFi to connected state 1393 mWifiConnectivityManager.handleConnectionStateChanged( 1394 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1395 1396 // Set screen to on 1397 mWifiConnectivityManager.handleScreenStateChanged(true); 1398 1399 verify(mWifiStateMachine, times(0)).startRoamToNetwork(anyInt(), anyObject()); 1400 } 1401} 1402