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 android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE; 20import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY; 21 22import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig; 23import static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE; 24 25import static org.junit.Assert.*; 26import static org.mockito.Mockito.*; 27 28import android.app.test.MockAnswerUtil.AnswerWithArguments; 29import android.app.test.TestAlarmManager; 30import android.content.Context; 31import android.content.pm.PackageManager; 32import android.content.res.Resources; 33import android.net.NetworkScoreManager; 34import android.net.wifi.ScanResult; 35import android.net.wifi.ScanResult.InformationElement; 36import android.net.wifi.SupplicantState; 37import android.net.wifi.WifiConfiguration; 38import android.net.wifi.WifiInfo; 39import android.net.wifi.WifiNetworkScoreCache; 40import android.net.wifi.WifiScanner; 41import android.net.wifi.WifiScanner.PnoScanListener; 42import android.net.wifi.WifiScanner.PnoSettings; 43import android.net.wifi.WifiScanner.ScanData; 44import android.net.wifi.WifiScanner.ScanListener; 45import android.net.wifi.WifiScanner.ScanSettings; 46import android.net.wifi.WifiSsid; 47import android.os.Process; 48import android.os.SystemClock; 49import android.os.WorkSource; 50import android.os.test.TestLooper; 51import android.support.test.filters.SmallTest; 52import android.util.LocalLog; 53 54import com.android.internal.R; 55 56import org.junit.After; 57import org.junit.Before; 58import org.junit.Test; 59import org.mockito.ArgumentCaptor; 60import org.mockito.Captor; 61import org.mockito.Mock; 62import org.mockito.MockitoAnnotations; 63 64import java.io.FileDescriptor; 65import java.io.PrintWriter; 66import java.io.StringWriter; 67import java.nio.charset.StandardCharsets; 68import java.util.ArrayList; 69import java.util.HashSet; 70import java.util.List; 71import java.util.stream.Collectors; 72 73/** 74 * Unit tests for {@link com.android.server.wifi.WifiConnectivityManager}. 75 */ 76@SmallTest 77public class WifiConnectivityManagerTest { 78 /** 79 * Called before each test 80 */ 81 @Before 82 public void setUp() throws Exception { 83 MockitoAnnotations.initMocks(this); 84 mResource = mockResource(); 85 mAlarmManager = new TestAlarmManager(); 86 mContext = mockContext(); 87 mLocalLog = new LocalLog(512); 88 mWifiStateMachine = mockWifiStateMachine(); 89 mWifiConfigManager = mockWifiConfigManager(); 90 mWifiInfo = getWifiInfo(); 91 mScanData = mockScanData(); 92 mWifiScanner = mockWifiScanner(); 93 mWifiConnectivityHelper = mockWifiConnectivityHelper(); 94 mWifiNS = mockWifiNetworkSelector(); 95 mWifiConnectivityManager = createConnectivityManager(); 96 verify(mWifiConfigManager).setOnSavedNetworkUpdateListener(anyObject()); 97 mWifiConnectivityManager.setWifiEnabled(true); 98 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()); 99 mFullScanMaxTxPacketRate = mResource.getInteger( 100 R.integer.config_wifi_framework_max_tx_rate_for_full_scan); 101 mFullScanMaxRxPacketRate = mResource.getInteger( 102 R.integer.config_wifi_framework_max_rx_rate_for_full_scan); 103 when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true); 104 } 105 106 /** 107 * Called after each test 108 */ 109 @After 110 public void cleanup() { 111 validateMockitoUsage(); 112 } 113 114 private Resources mResource; 115 116 private Context mContext; 117 private TestAlarmManager mAlarmManager; 118 private TestLooper mLooper = new TestLooper(); 119 private WifiConnectivityManager mWifiConnectivityManager; 120 private WifiNetworkSelector mWifiNS; 121 private WifiStateMachine mWifiStateMachine; 122 private WifiScanner mWifiScanner; 123 private WifiConnectivityHelper mWifiConnectivityHelper; 124 private ScanData mScanData; 125 private WifiConfigManager mWifiConfigManager; 126 private WifiInfo mWifiInfo; 127 private LocalLog mLocalLog; 128 @Mock private FrameworkFacade mFrameworkFacade; 129 @Mock private NetworkScoreManager mNetworkScoreManager; 130 @Mock private Clock mClock; 131 @Mock private WifiLastResortWatchdog mWifiLastResortWatchdog; 132 @Mock private OpenNetworkNotifier mOpenNetworkNotifier; 133 @Mock private CarrierNetworkNotifier mCarrierNetworkNotifier; 134 @Mock private CarrierNetworkConfig mCarrierNetworkConfig; 135 @Mock private WifiMetrics mWifiMetrics; 136 @Mock private WifiNetworkScoreCache mScoreCache; 137 @Captor ArgumentCaptor<ScanResult> mCandidateScanResultCaptor; 138 @Captor ArgumentCaptor<ArrayList<String>> mBssidBlacklistCaptor; 139 @Captor ArgumentCaptor<ArrayList<String>> mSsidWhitelistCaptor; 140 @Captor ArgumentCaptor<WifiConfigManager.OnSavedNetworkUpdateListener> 141 mSavedNetworkUpdateListenerCaptor; 142 private MockResources mResources; 143 private int mFullScanMaxTxPacketRate; 144 private int mFullScanMaxRxPacketRate; 145 146 private static final int CANDIDATE_NETWORK_ID = 0; 147 private static final String CANDIDATE_SSID = "\"AnSsid\""; 148 private static final String CANDIDATE_BSSID = "6c:f3:7f:ae:8c:f3"; 149 private static final String INVALID_SCAN_RESULT_BSSID = "6c:f3:7f:ae:8c:f4"; 150 private static final long CURRENT_SYSTEM_TIME_MS = 1000; 151 private static final int MAX_BSSID_BLACKLIST_SIZE = 16; 152 153 154 Resources mockResource() { 155 Resources resource = mock(Resources.class); 156 157 when(resource.getInteger(R.integer.config_wifi_framework_SECURITY_AWARD)).thenReturn(80); 158 when(resource.getInteger(R.integer.config_wifi_framework_SAME_BSSID_AWARD)).thenReturn(24); 159 when(resource.getBoolean( 160 R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true); 161 when(resource.getInteger( 162 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)) 163 .thenReturn(-60); 164 when(resource.getInteger( 165 R.integer.config_wifi_framework_current_network_boost)).thenReturn(16); 166 when(resource.getInteger( 167 R.integer.config_wifi_framework_max_tx_rate_for_full_scan)).thenReturn(8); 168 when(resource.getInteger( 169 R.integer.config_wifi_framework_max_rx_rate_for_full_scan)).thenReturn(16); 170 return resource; 171 } 172 173 Context mockContext() { 174 Context context = mock(Context.class); 175 176 when(context.getResources()).thenReturn(mResource); 177 when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn( 178 mAlarmManager.getAlarmManager()); 179 when(context.getPackageManager()).thenReturn(mock(PackageManager.class)); 180 181 return context; 182 } 183 184 ScanData mockScanData() { 185 ScanData scanData = mock(ScanData.class); 186 187 when(scanData.isAllChannelsScanned()).thenReturn(true); 188 189 return scanData; 190 } 191 192 WifiScanner mockWifiScanner() { 193 WifiScanner scanner = mock(WifiScanner.class); 194 ArgumentCaptor<ScanListener> allSingleScanListenerCaptor = 195 ArgumentCaptor.forClass(ScanListener.class); 196 197 doNothing().when(scanner).registerScanListener(allSingleScanListenerCaptor.capture()); 198 199 ScanData[] scanDatas = new ScanData[1]; 200 scanDatas[0] = mScanData; 201 202 // do a synchronous answer for the ScanListener callbacks 203 doAnswer(new AnswerWithArguments() { 204 public void answer(ScanSettings settings, ScanListener listener, 205 WorkSource workSource) throws Exception { 206 listener.onResults(scanDatas); 207 }}).when(scanner).startBackgroundScan(anyObject(), anyObject(), anyObject()); 208 209 doAnswer(new AnswerWithArguments() { 210 public void answer(ScanSettings settings, ScanListener listener, 211 WorkSource workSource) throws Exception { 212 listener.onResults(scanDatas); 213 // WCM processes scan results received via onFullResult (even though they're the 214 // same as onResult for single scans). 215 if (mScanData != null && mScanData.getResults() != null) { 216 for (int i = 0; i < mScanData.getResults().length; i++) { 217 allSingleScanListenerCaptor.getValue().onFullResult( 218 mScanData.getResults()[i]); 219 } 220 } 221 allSingleScanListenerCaptor.getValue().onResults(scanDatas); 222 }}).when(scanner).startScan(anyObject(), anyObject(), anyObject()); 223 224 // This unfortunately needs to be a somewhat valid scan result, otherwise 225 // |ScanDetailUtil.toScanDetail| raises exceptions. 226 final ScanResult[] scanResults = new ScanResult[1]; 227 scanResults[0] = new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID), 228 CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", 229 -78, 2450, 1025, 22, 33, 20, 0, 0, true); 230 scanResults[0].informationElements = new InformationElement[1]; 231 scanResults[0].informationElements[0] = new InformationElement(); 232 scanResults[0].informationElements[0].id = InformationElement.EID_SSID; 233 scanResults[0].informationElements[0].bytes = 234 CANDIDATE_SSID.getBytes(StandardCharsets.UTF_8); 235 236 doAnswer(new AnswerWithArguments() { 237 public void answer(ScanSettings settings, PnoSettings pnoSettings, 238 PnoScanListener listener) throws Exception { 239 listener.onPnoNetworkFound(scanResults); 240 }}).when(scanner).startDisconnectedPnoScan(anyObject(), anyObject(), anyObject()); 241 242 doAnswer(new AnswerWithArguments() { 243 public void answer(ScanSettings settings, PnoSettings pnoSettings, 244 PnoScanListener listener) throws Exception { 245 listener.onPnoNetworkFound(scanResults); 246 }}).when(scanner).startConnectedPnoScan(anyObject(), anyObject(), anyObject()); 247 248 return scanner; 249 } 250 251 WifiConnectivityHelper mockWifiConnectivityHelper() { 252 WifiConnectivityHelper connectivityHelper = mock(WifiConnectivityHelper.class); 253 254 when(connectivityHelper.isFirmwareRoamingSupported()).thenReturn(false); 255 when(connectivityHelper.getMaxNumBlacklistBssid()).thenReturn(MAX_BSSID_BLACKLIST_SIZE); 256 257 return connectivityHelper; 258 } 259 260 WifiStateMachine mockWifiStateMachine() { 261 WifiStateMachine stateMachine = mock(WifiStateMachine.class); 262 263 when(stateMachine.isConnected()).thenReturn(false); 264 when(stateMachine.isDisconnected()).thenReturn(true); 265 when(stateMachine.isSupplicantTransientState()).thenReturn(false); 266 267 return stateMachine; 268 } 269 270 WifiNetworkSelector mockWifiNetworkSelector() { 271 WifiNetworkSelector ns = mock(WifiNetworkSelector.class); 272 273 WifiConfiguration candidate = generateWifiConfig( 274 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 275 candidate.BSSID = WifiStateMachine.SUPPLICANT_BSSID_ANY; 276 ScanResult candidateScanResult = new ScanResult(); 277 candidateScanResult.SSID = CANDIDATE_SSID; 278 candidateScanResult.BSSID = CANDIDATE_BSSID; 279 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 280 281 when(ns.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 282 anyBoolean(), anyBoolean())).thenReturn(candidate); 283 return ns; 284 } 285 286 WifiInfo getWifiInfo() { 287 WifiInfo wifiInfo = new WifiInfo(); 288 289 wifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 290 wifiInfo.setBSSID(null); 291 wifiInfo.setSupplicantState(SupplicantState.DISCONNECTED); 292 293 return wifiInfo; 294 } 295 296 WifiConfigManager mockWifiConfigManager() { 297 WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class); 298 299 when(wifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(null); 300 301 // Pass dummy pno network list, otherwise Pno scan requests will not be triggered. 302 PnoSettings.PnoNetwork pnoNetwork = new PnoSettings.PnoNetwork(CANDIDATE_SSID); 303 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = new ArrayList<>(); 304 pnoNetworkList.add(pnoNetwork); 305 when(wifiConfigManager.retrievePnoNetworkList()).thenReturn(pnoNetworkList); 306 when(wifiConfigManager.retrievePnoNetworkList()).thenReturn(pnoNetworkList); 307 doNothing().when(wifiConfigManager).setOnSavedNetworkUpdateListener( 308 mSavedNetworkUpdateListenerCaptor.capture()); 309 310 return wifiConfigManager; 311 } 312 313 WifiConnectivityManager createConnectivityManager() { 314 return new WifiConnectivityManager(mContext, 315 new ScoringParams(mContext), 316 mWifiStateMachine, mWifiScanner, 317 mWifiConfigManager, mWifiInfo, mWifiNS, mWifiConnectivityHelper, 318 mWifiLastResortWatchdog, mOpenNetworkNotifier, mCarrierNetworkNotifier, 319 mCarrierNetworkConfig, mWifiMetrics, mLooper.getLooper(), mClock, mLocalLog, true, 320 mFrameworkFacade, null, null, null); 321 } 322 323 /** 324 * Wifi enters disconnected state while screen is on. 325 * 326 * Expected behavior: WifiConnectivityManager calls 327 * WifiStateMachine.startConnectToNetwork() with the 328 * expected candidate network ID and BSSID. 329 */ 330 @Test 331 public void enterWifiDisconnectedStateWhenScreenOn() { 332 // Set screen to on 333 mWifiConnectivityManager.handleScreenStateChanged(true); 334 335 // Set WiFi to disconnected state 336 mWifiConnectivityManager.handleConnectionStateChanged( 337 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 338 339 verify(mWifiStateMachine).startConnectToNetwork( 340 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 341 } 342 343 /** 344 * Wifi enters connected state while screen is on. 345 * 346 * Expected behavior: WifiConnectivityManager calls 347 * WifiStateMachine.startConnectToNetwork() with the 348 * expected candidate network ID and BSSID. 349 */ 350 @Test 351 public void enterWifiConnectedStateWhenScreenOn() { 352 // Set screen to on 353 mWifiConnectivityManager.handleScreenStateChanged(true); 354 355 // Set WiFi to connected state 356 mWifiConnectivityManager.handleConnectionStateChanged( 357 WifiConnectivityManager.WIFI_STATE_CONNECTED); 358 359 verify(mWifiStateMachine).startConnectToNetwork( 360 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 361 } 362 363 /** 364 * Screen turned on while WiFi in disconnected state. 365 * 366 * Expected behavior: WifiConnectivityManager calls 367 * WifiStateMachine.startConnectToNetwork() with the 368 * expected candidate network ID and BSSID. 369 */ 370 @Test 371 public void turnScreenOnWhenWifiInDisconnectedState() { 372 // Set WiFi to disconnected state 373 mWifiConnectivityManager.handleConnectionStateChanged( 374 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 375 376 // Set screen to on 377 mWifiConnectivityManager.handleScreenStateChanged(true); 378 379 verify(mWifiStateMachine, atLeastOnce()).startConnectToNetwork( 380 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 381 } 382 383 /** 384 * Screen turned on while WiFi in connected state. 385 * 386 * Expected behavior: WifiConnectivityManager calls 387 * WifiStateMachine.startConnectToNetwork() with the 388 * expected candidate network ID and BSSID. 389 */ 390 @Test 391 public void turnScreenOnWhenWifiInConnectedState() { 392 // Set WiFi to connected state 393 mWifiConnectivityManager.handleConnectionStateChanged( 394 WifiConnectivityManager.WIFI_STATE_CONNECTED); 395 396 // Set screen to on 397 mWifiConnectivityManager.handleScreenStateChanged(true); 398 399 verify(mWifiStateMachine, atLeastOnce()).startConnectToNetwork( 400 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 401 } 402 403 /** 404 * Screen turned on while WiFi in connected state but 405 * auto roaming is disabled. 406 * 407 * Expected behavior: WifiConnectivityManager doesn't invoke 408 * WifiStateMachine.startConnectToNetwork() because roaming 409 * is turned off. 410 */ 411 @Test 412 public void turnScreenOnWhenWifiInConnectedStateRoamingDisabled() { 413 // Turn off auto roaming 414 when(mResource.getBoolean( 415 R.bool.config_wifi_framework_enable_associated_network_selection)) 416 .thenReturn(false); 417 mWifiConnectivityManager = createConnectivityManager(); 418 419 // Set WiFi to connected state 420 mWifiConnectivityManager.handleConnectionStateChanged( 421 WifiConnectivityManager.WIFI_STATE_CONNECTED); 422 423 // Set screen to on 424 mWifiConnectivityManager.handleScreenStateChanged(true); 425 426 verify(mWifiStateMachine, times(0)).startConnectToNetwork( 427 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 428 } 429 430 /** 431 * Multiple back to back connection attempts within the rate interval should be rate limited. 432 * 433 * Expected behavior: WifiConnectivityManager calls WifiStateMachine.startConnectToNetwork() 434 * with the expected candidate network ID and BSSID for only the expected number of times within 435 * the given interval. 436 */ 437 @Test 438 public void connectionAttemptRateLimitedWhenScreenOff() { 439 int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE; 440 int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS; 441 int numAttempts = 0; 442 int connectionAttemptIntervals = timeInterval / maxAttemptRate; 443 444 mWifiConnectivityManager.handleScreenStateChanged(false); 445 446 // First attempt the max rate number of connections within the rate interval. 447 long currentTimeStamp = 0; 448 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 449 currentTimeStamp += connectionAttemptIntervals; 450 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 451 // Set WiFi to disconnected state to trigger PNO scan 452 mWifiConnectivityManager.handleConnectionStateChanged( 453 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 454 numAttempts++; 455 } 456 // Now trigger another connection attempt before the rate interval, this should be 457 // skipped because we've crossed rate limit. 458 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 459 // Set WiFi to disconnected state to trigger PNO scan 460 mWifiConnectivityManager.handleConnectionStateChanged( 461 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 462 463 // Verify that we attempt to connect upto the rate. 464 verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork( 465 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 466 } 467 468 /** 469 * Multiple back to back connection attempts outside the rate interval should not be rate 470 * limited. 471 * 472 * Expected behavior: WifiConnectivityManager calls WifiStateMachine.startConnectToNetwork() 473 * with the expected candidate network ID and BSSID for only the expected number of times within 474 * the given interval. 475 */ 476 @Test 477 public void connectionAttemptNotRateLimitedWhenScreenOff() { 478 int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE; 479 int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS; 480 int numAttempts = 0; 481 int connectionAttemptIntervals = timeInterval / maxAttemptRate; 482 483 mWifiConnectivityManager.handleScreenStateChanged(false); 484 485 // First attempt the max rate number of connections within the rate interval. 486 long currentTimeStamp = 0; 487 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 488 currentTimeStamp += connectionAttemptIntervals; 489 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 490 // Set WiFi to disconnected state to trigger PNO scan 491 mWifiConnectivityManager.handleConnectionStateChanged( 492 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 493 numAttempts++; 494 } 495 // Now trigger another connection attempt after the rate interval, this should not be 496 // skipped because we should've evicted the older attempt. 497 when(mClock.getElapsedSinceBootMillis()).thenReturn( 498 currentTimeStamp + connectionAttemptIntervals * 2); 499 // Set WiFi to disconnected state to trigger PNO scan 500 mWifiConnectivityManager.handleConnectionStateChanged( 501 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 502 numAttempts++; 503 504 // Verify that all the connection attempts went through 505 verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork( 506 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 507 } 508 509 /** 510 * Multiple back to back connection attempts after a user selection should not be rate limited. 511 * 512 * Expected behavior: WifiConnectivityManager calls WifiStateMachine.startConnectToNetwork() 513 * with the expected candidate network ID and BSSID for only the expected number of times within 514 * the given interval. 515 */ 516 @Test 517 public void connectionAttemptNotRateLimitedWhenScreenOffAfterUserSelection() { 518 int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE; 519 int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS; 520 int numAttempts = 0; 521 int connectionAttemptIntervals = timeInterval / maxAttemptRate; 522 523 mWifiConnectivityManager.handleScreenStateChanged(false); 524 525 // First attempt the max rate number of connections within the rate interval. 526 long currentTimeStamp = 0; 527 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 528 currentTimeStamp += connectionAttemptIntervals; 529 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 530 // Set WiFi to disconnected state to trigger PNO scan 531 mWifiConnectivityManager.handleConnectionStateChanged( 532 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 533 numAttempts++; 534 } 535 536 mWifiConnectivityManager.setUserConnectChoice(CANDIDATE_NETWORK_ID); 537 mWifiConnectivityManager.prepareForForcedConnection(CANDIDATE_NETWORK_ID); 538 539 for (int attempt = 0; attempt < maxAttemptRate; attempt++) { 540 currentTimeStamp += connectionAttemptIntervals; 541 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 542 // Set WiFi to disconnected state to trigger PNO scan 543 mWifiConnectivityManager.handleConnectionStateChanged( 544 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 545 numAttempts++; 546 } 547 548 // Verify that all the connection attempts went through 549 verify(mWifiStateMachine, times(numAttempts)).startConnectToNetwork( 550 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 551 } 552 553 /** 554 * PNO retry for low RSSI networks. 555 * 556 * Expected behavior: WifiConnectivityManager doubles the low RSSI 557 * network retry delay value after QNS skips the PNO scan results 558 * because of their low RSSI values. 559 */ 560 @Test 561 public void pnoRetryForLowRssiNetwork() { 562 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 563 anyBoolean(), anyBoolean())).thenReturn(null); 564 565 // Set screen to off 566 mWifiConnectivityManager.handleScreenStateChanged(false); 567 568 // Get the current retry delay value 569 int lowRssiNetworkRetryDelayStartValue = mWifiConnectivityManager 570 .getLowRssiNetworkRetryDelay(); 571 572 // Set WiFi to disconnected state to trigger PNO scan 573 mWifiConnectivityManager.handleConnectionStateChanged( 574 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 575 576 // Get the retry delay value after QNS didn't select a 577 // network candicate from the PNO scan results. 578 int lowRssiNetworkRetryDelayAfterPnoValue = mWifiConnectivityManager 579 .getLowRssiNetworkRetryDelay(); 580 581 assertEquals(lowRssiNetworkRetryDelayStartValue * 2, 582 lowRssiNetworkRetryDelayAfterPnoValue); 583 } 584 585 /** 586 * Ensure that the watchdog bite increments the "Pno bad" metric. 587 * 588 * Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find 589 * a candidate while watchdog single scan did. 590 */ 591 @Test 592 public void watchdogBitePnoBadIncrementsMetrics() { 593 // Set screen to off 594 mWifiConnectivityManager.handleScreenStateChanged(false); 595 596 // Set WiFi to disconnected state to trigger PNO scan 597 mWifiConnectivityManager.handleConnectionStateChanged( 598 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 599 600 // Now fire the watchdog alarm and verify the metrics were incremented. 601 mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG); 602 mLooper.dispatchAll(); 603 604 verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoBad(); 605 verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoGood(); 606 } 607 608 /** 609 * Ensure that the watchdog bite increments the "Pno good" metric. 610 * 611 * Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find 612 * a candidate which was the same with watchdog single scan. 613 */ 614 @Test 615 public void watchdogBitePnoGoodIncrementsMetrics() { 616 // Qns returns no candidate after watchdog single scan. 617 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 618 anyBoolean(), anyBoolean())).thenReturn(null); 619 620 // Set screen to off 621 mWifiConnectivityManager.handleScreenStateChanged(false); 622 623 // Set WiFi to disconnected state to trigger PNO scan 624 mWifiConnectivityManager.handleConnectionStateChanged( 625 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 626 627 // Now fire the watchdog alarm and verify the metrics were incremented. 628 mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG); 629 mLooper.dispatchAll(); 630 631 verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoGood(); 632 verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoBad(); 633 } 634 635 /** 636 * {@link OpenNetworkNotifier} handles scan results on network selection. 637 * 638 * Expected behavior: ONA handles scan results 639 */ 640 @Test 641 public void wifiDisconnected_noConnectionCandidate_openNetworkNotifierScanResultsHandled() { 642 // no connection candidate selected 643 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 644 anyBoolean(), anyBoolean())).thenReturn(null); 645 646 List<ScanDetail> expectedOpenNetworks = new ArrayList<>(); 647 expectedOpenNetworks.add( 648 new ScanDetail( 649 new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID), 650 CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", -78, 2450, 651 1025, 22, 33, 20, 0, 0, true), null)); 652 653 when(mWifiNS.getFilteredScanDetailsForOpenUnsavedNetworks()) 654 .thenReturn(expectedOpenNetworks); 655 656 // Set WiFi to disconnected state to trigger PNO scan 657 mWifiConnectivityManager.handleConnectionStateChanged( 658 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 659 660 verify(mOpenNetworkNotifier).handleScanResults(expectedOpenNetworks); 661 } 662 663 /** 664 * When wifi is connected, {@link OpenNetworkNotifier} handles the Wi-Fi connected behavior. 665 * 666 * Expected behavior: ONA handles connected behavior 667 */ 668 @Test 669 public void wifiConnected_openNetworkNotifierHandlesConnection() { 670 // Set WiFi to connected state 671 mWifiConnectivityManager.handleConnectionStateChanged( 672 WifiConnectivityManager.WIFI_STATE_CONNECTED); 673 674 verify(mOpenNetworkNotifier).handleWifiConnected(); 675 } 676 677 /** 678 * When wifi is connected, {@link OpenNetworkNotifier} handles connection state 679 * change. 680 * 681 * Expected behavior: ONA does not clear pending notification. 682 */ 683 @Test 684 public void wifiDisconnected_openNetworkNotifierDoesNotClearPendingNotification() { 685 // Set WiFi to disconnected state 686 mWifiConnectivityManager.handleConnectionStateChanged( 687 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 688 689 verify(mOpenNetworkNotifier, never()).clearPendingNotification(anyBoolean()); 690 } 691 692 /** 693 * When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} handles the connection 694 * failure. A failure code that is not {@link WifiMetrics.ConnectionEvent#FAILURE_NONE} 695 * represents a connection failure. 696 * 697 * Expected behavior: ONA handles connection failure. 698 */ 699 @Test 700 public void wifiConnectionEndsWithFailure_openNetworkNotifierHandlesConnectionFailure() { 701 mWifiConnectivityManager.handleConnectionAttemptEnded( 702 WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED); 703 704 verify(mOpenNetworkNotifier).handleConnectionFailure(); 705 } 706 707 /** 708 * When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} does not handle connection 709 * failure after a successful connection. {@link WifiMetrics.ConnectionEvent#FAILURE_NONE} 710 * represents a successful connection. 711 * 712 * Expected behavior: ONA does nothing. 713 */ 714 @Test 715 public void wifiConnectionEndsWithSuccess_openNetworkNotifierDoesNotHandleConnectionFailure() { 716 mWifiConnectivityManager.handleConnectionAttemptEnded( 717 WifiMetrics.ConnectionEvent.FAILURE_NONE); 718 719 verify(mOpenNetworkNotifier, never()).handleConnectionFailure(); 720 } 721 722 /** 723 * When Wi-Fi is disabled, clear the pending notification and reset notification repeat delay. 724 * 725 * Expected behavior: clear pending notification and reset notification repeat delay 726 * */ 727 @Test 728 public void openNetworkNotifierClearsPendingNotificationOnWifiDisabled() { 729 mWifiConnectivityManager.setWifiEnabled(false); 730 731 verify(mOpenNetworkNotifier).clearPendingNotification(true /* resetRepeatDelay */); 732 } 733 734 /** 735 * Verify that the ONA controller tracks screen state changes. 736 */ 737 @Test 738 public void openNetworkNotifierTracksScreenStateChanges() { 739 mWifiConnectivityManager.handleScreenStateChanged(false); 740 741 verify(mOpenNetworkNotifier).handleScreenStateChanged(false); 742 743 mWifiConnectivityManager.handleScreenStateChanged(true); 744 745 verify(mOpenNetworkNotifier).handleScreenStateChanged(true); 746 } 747 748 /** 749 * {@link CarrierNetworkNotifier} handles scan results on network selection. 750 * 751 * Expected behavior: CarrierNetworkNotifier handles scan results 752 */ 753 @Test 754 public void wifiDisconnected_noConnectionCandidate_CarrierNetworkNotifierScanResultsHandled() { 755 // no connection candidate selected 756 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 757 anyBoolean(), anyBoolean())).thenReturn(null); 758 759 List<ScanDetail> expectedCarrierNetworks = new ArrayList<>(); 760 expectedCarrierNetworks.add( 761 new ScanDetail( 762 new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID), 763 CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "[EAP][ESS]", -78, 2450, 764 1025, 22, 33, 20, 0, 0, true), null)); 765 766 when(mWifiNS.getFilteredScanDetailsForCarrierUnsavedNetworks(any())) 767 .thenReturn(expectedCarrierNetworks); 768 769 // Set WiFi to disconnected state to trigger PNO scan 770 mWifiConnectivityManager.handleConnectionStateChanged( 771 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 772 773 verify(mCarrierNetworkNotifier).handleScanResults(expectedCarrierNetworks); 774 } 775 776 /** 777 * {@link CarrierNetworkNotifier} does not handle scan results on network selection if carrier 778 * encryption info is not available. 779 * 780 * Expected behavior: CarrierNetworkNotifier does not handle scan results 781 */ 782 @Test 783 public void whenNoEncryptionInfoAvailable_CarrierNetworkNotifierDoesNotHandleScanResults() { 784 // no connection candidate selected 785 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 786 anyBoolean(), anyBoolean())).thenReturn(null); 787 788 List<ScanDetail> expectedCarrierNetworks = new ArrayList<>(); 789 expectedCarrierNetworks.add( 790 new ScanDetail( 791 new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID), 792 CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "[EAP][ESS]", -78, 2450, 793 1025, 22, 33, 20, 0, 0, true), null)); 794 795 when(mWifiNS.getFilteredScanDetailsForCarrierUnsavedNetworks(any())) 796 .thenReturn(expectedCarrierNetworks); 797 when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(false); 798 799 // Set WiFi to disconnected state to trigger PNO scan 800 mWifiConnectivityManager.handleConnectionStateChanged( 801 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 802 803 verify(mCarrierNetworkNotifier, never()).handleScanResults(expectedCarrierNetworks); 804 } 805 806 /** 807 * When wifi is connected, {@link CarrierNetworkNotifier} handles the Wi-Fi connected behavior. 808 * 809 * Expected behavior: CarrierNetworkNotifier handles connected behavior 810 */ 811 @Test 812 public void wifiConnected_carrierNetworkNotifierHandlesConnection() { 813 // Set WiFi to connected state 814 mWifiConnectivityManager.handleConnectionStateChanged( 815 WifiConnectivityManager.WIFI_STATE_CONNECTED); 816 817 verify(mCarrierNetworkNotifier).handleWifiConnected(); 818 } 819 820 /** 821 * When wifi is connected, {@link CarrierNetworkNotifier} handles connection state 822 * change. 823 * 824 * Expected behavior: CarrierNetworkNotifer does not clear pending notification. 825 */ 826 @Test 827 public void wifiDisconnected_carrierNetworkNotifierDoesNotClearPendingNotification() { 828 // Set WiFi to disconnected state 829 mWifiConnectivityManager.handleConnectionStateChanged( 830 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 831 832 verify(mCarrierNetworkNotifier, never()).clearPendingNotification(anyBoolean()); 833 } 834 835 /** 836 * When a Wi-Fi connection attempt ends, {@link CarrierNetworkNotifier} handles the connection 837 * failure. A failure code that is not {@link WifiMetrics.ConnectionEvent#FAILURE_NONE} 838 * represents a connection failure. 839 * 840 * Expected behavior: CarrierNetworkNotifier handles connection failure. 841 */ 842 @Test 843 public void wifiConnectionEndsWithFailure_carrierNetworkNotifierHandlesConnectionFailure() { 844 mWifiConnectivityManager.handleConnectionAttemptEnded( 845 WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED); 846 847 verify(mCarrierNetworkNotifier).handleConnectionFailure(); 848 } 849 850 /** 851 * When a Wi-Fi connection attempt ends, {@link CarrierNetworkNotifier} does not handle 852 * connection failure after a successful connection. 853 * {@link WifiMetrics.ConnectionEvent#FAILURE_NONE} represents a successful connection. 854 * 855 * Expected behavior: CarrierNetworkNotifier does nothing. 856 */ 857 @Test 858 public void 859 wifiConnectionEndsWithSuccess_carrierNetworkNotifierDoesNotHandleConnectionFailure() { 860 mWifiConnectivityManager.handleConnectionAttemptEnded( 861 WifiMetrics.ConnectionEvent.FAILURE_NONE); 862 863 verify(mCarrierNetworkNotifier, never()).handleConnectionFailure(); 864 } 865 866 /** 867 * When Wi-Fi is disabled, clear the pending notification and reset notification repeat delay. 868 * 869 * Expected behavior: clear pending notification and reset notification repeat delay 870 * */ 871 @Test 872 public void carrierNetworkNotifierClearsPendingNotificationOnWifiDisabled() { 873 mWifiConnectivityManager.setWifiEnabled(false); 874 875 verify(mCarrierNetworkNotifier).clearPendingNotification(true /* resetRepeatDelay */); 876 } 877 878 /** 879 * Verify that the CarrierNetworkNotifier tracks screen state changes. 880 */ 881 @Test 882 public void carrierNetworkNotifierTracksScreenStateChanges() { 883 mWifiConnectivityManager.handleScreenStateChanged(false); 884 885 verify(mCarrierNetworkNotifier).handleScreenStateChanged(false); 886 887 mWifiConnectivityManager.handleScreenStateChanged(true); 888 889 verify(mCarrierNetworkNotifier).handleScreenStateChanged(true); 890 } 891 892 /** 893 * Verify that scan interval for screen on and wifi disconnected scenario 894 * is in the exponential backoff fashion. 895 * 896 * Expected behavior: WifiConnectivityManager doubles periodic 897 * scan interval. 898 */ 899 @Test 900 public void checkPeriodicScanIntervalWhenDisconnected() { 901 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 902 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 903 904 // Set screen to ON 905 mWifiConnectivityManager.handleScreenStateChanged(true); 906 907 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 908 // by screen state change can settle 909 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 910 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 911 912 // Set WiFi to disconnected state to trigger periodic scan 913 mWifiConnectivityManager.handleConnectionStateChanged( 914 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 915 916 // Get the first periodic scan interval 917 long firstIntervalMs = mAlarmManager 918 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 919 - currentTimeStamp; 920 assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 921 922 currentTimeStamp += firstIntervalMs; 923 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 924 925 // Now fire the first periodic scan alarm timer 926 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 927 mLooper.dispatchAll(); 928 929 // Get the second periodic scan interval 930 long secondIntervalMs = mAlarmManager 931 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 932 - currentTimeStamp; 933 934 // Verify the intervals are exponential back off 935 assertEquals(firstIntervalMs * 2, secondIntervalMs); 936 937 currentTimeStamp += secondIntervalMs; 938 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 939 940 // Make sure we eventually stay at the maximum scan interval. 941 long intervalMs = 0; 942 for (int i = 0; i < 5; i++) { 943 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 944 mLooper.dispatchAll(); 945 intervalMs = mAlarmManager 946 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 947 - currentTimeStamp; 948 currentTimeStamp += intervalMs; 949 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 950 } 951 952 assertEquals(intervalMs, WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS); 953 } 954 955 /** 956 * Verify that scan interval for screen on and wifi connected scenario 957 * is in the exponential backoff fashion. 958 * 959 * Expected behavior: WifiConnectivityManager doubles periodic 960 * scan interval. 961 */ 962 @Test 963 public void checkPeriodicScanIntervalWhenConnected() { 964 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 965 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 966 967 // Set screen to ON 968 mWifiConnectivityManager.handleScreenStateChanged(true); 969 970 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 971 // by screen state change can settle 972 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 973 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 974 975 // Set WiFi to connected state to trigger periodic scan 976 mWifiConnectivityManager.handleConnectionStateChanged( 977 WifiConnectivityManager.WIFI_STATE_CONNECTED); 978 979 // Get the first periodic scan interval 980 long firstIntervalMs = mAlarmManager 981 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 982 - currentTimeStamp; 983 assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 984 985 currentTimeStamp += firstIntervalMs; 986 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 987 988 // Now fire the first periodic scan alarm timer 989 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 990 mLooper.dispatchAll(); 991 992 // Get the second periodic scan interval 993 long secondIntervalMs = mAlarmManager 994 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 995 - currentTimeStamp; 996 997 // Verify the intervals are exponential back off 998 assertEquals(firstIntervalMs * 2, secondIntervalMs); 999 1000 currentTimeStamp += secondIntervalMs; 1001 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1002 1003 // Make sure we eventually stay at the maximum scan interval. 1004 long intervalMs = 0; 1005 for (int i = 0; i < 5; i++) { 1006 mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 1007 mLooper.dispatchAll(); 1008 intervalMs = mAlarmManager 1009 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 1010 - currentTimeStamp; 1011 currentTimeStamp += intervalMs; 1012 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1013 } 1014 1015 assertEquals(intervalMs, WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS); 1016 } 1017 1018 /** 1019 * When screen on trigger a disconnected state change event then a connected state 1020 * change event back to back to verify that the minium scan interval is enforced. 1021 * 1022 * Expected behavior: WifiConnectivityManager start the second periodic single 1023 * scan PERIODIC_SCAN_INTERVAL_MS after the first one. 1024 */ 1025 @Test 1026 public void checkMinimumPeriodicScanIntervalWhenScreenOnAndConnected() { 1027 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 1028 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1029 1030 // Set screen to ON 1031 mWifiConnectivityManager.handleScreenStateChanged(true); 1032 1033 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 1034 // by screen state change can settle 1035 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 1036 long scanForDisconnectedTimeStamp = currentTimeStamp; 1037 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1038 1039 // Set WiFi to disconnected state which triggers a scan immediately 1040 mWifiConnectivityManager.handleConnectionStateChanged( 1041 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1042 verify(mWifiScanner, times(1)).startScan(anyObject(), anyObject(), anyObject()); 1043 1044 // Set up time stamp for when entering CONNECTED state 1045 currentTimeStamp += 2000; 1046 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1047 1048 // Set WiFi to connected state to trigger its periodic scan 1049 mWifiConnectivityManager.handleConnectionStateChanged( 1050 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1051 1052 // The very first scan triggered for connected state is actually via the alarm timer 1053 // and it obeys the minimum scan interval 1054 long firstScanForConnectedTimeStamp = mAlarmManager 1055 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 1056 1057 // Verify that the first scan for connected state is scheduled PERIODIC_SCAN_INTERVAL_MS 1058 // after the scan for disconnected state 1059 assertEquals(firstScanForConnectedTimeStamp, scanForDisconnectedTimeStamp 1060 + WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 1061 } 1062 1063 /** 1064 * When screen on trigger a connected state change event then a disconnected state 1065 * change event back to back to verify that a scan is fired immediately for the 1066 * disconnected state change event. 1067 * 1068 * Expected behavior: WifiConnectivityManager directly starts the periodic immediately 1069 * for the disconnected state change event. The second scan for disconnected state is 1070 * via alarm timer. 1071 */ 1072 @Test 1073 public void scanImmediatelyWhenScreenOnAndDisconnected() { 1074 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 1075 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1076 1077 // Set screen to ON 1078 mWifiConnectivityManager.handleScreenStateChanged(true); 1079 1080 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 1081 // by screen state change can settle 1082 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 1083 long scanForConnectedTimeStamp = currentTimeStamp; 1084 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1085 1086 // Set WiFi to connected state to trigger the periodic scan 1087 mWifiConnectivityManager.handleConnectionStateChanged( 1088 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1089 verify(mWifiScanner, times(1)).startScan(anyObject(), anyObject(), anyObject()); 1090 1091 // Set up the time stamp for when entering DISCONNECTED state 1092 currentTimeStamp += 2000; 1093 long enteringDisconnectedStateTimeStamp = currentTimeStamp; 1094 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1095 1096 // Set WiFi to disconnected state to trigger its periodic scan 1097 mWifiConnectivityManager.handleConnectionStateChanged( 1098 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1099 1100 // Verify the very first scan for DISCONNECTED state is fired immediately 1101 verify(mWifiScanner, times(2)).startScan(anyObject(), anyObject(), anyObject()); 1102 long secondScanForDisconnectedTimeStamp = mAlarmManager 1103 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG); 1104 1105 // Verify that the second scan is scheduled PERIODIC_SCAN_INTERVAL_MS after 1106 // entering DISCONNECTED state. 1107 assertEquals(secondScanForDisconnectedTimeStamp, enteringDisconnectedStateTimeStamp 1108 + WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 1109 } 1110 1111 /** 1112 * When screen on trigger a connection state change event and a forced connectivity 1113 * scan event back to back to verify that the minimum scan interval is not applied 1114 * in this scenario. 1115 * 1116 * Expected behavior: WifiConnectivityManager starts the second periodic single 1117 * scan immediately. 1118 */ 1119 @Test 1120 public void checkMinimumPeriodicScanIntervalNotEnforced() { 1121 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 1122 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1123 1124 // Set screen to ON 1125 mWifiConnectivityManager.handleScreenStateChanged(true); 1126 1127 // Wait for MAX_PERIODIC_SCAN_INTERVAL_MS so that any impact triggered 1128 // by screen state change can settle 1129 currentTimeStamp += WifiConnectivityManager.MAX_PERIODIC_SCAN_INTERVAL_MS; 1130 long firstScanTimeStamp = currentTimeStamp; 1131 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1132 1133 // Set WiFi to connected state to trigger the periodic scan 1134 mWifiConnectivityManager.handleConnectionStateChanged( 1135 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1136 1137 // Set the second scan attempt time stamp 1138 currentTimeStamp += 2000; 1139 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1140 1141 // Allow untrusted networks so WifiConnectivityManager starts a periodic scan 1142 // immediately. 1143 mWifiConnectivityManager.setUntrustedConnectionAllowed(true); 1144 1145 // Get the second periodic scan actual time stamp. Note, this scan is not 1146 // started from the AlarmManager. 1147 long secondScanTimeStamp = mWifiConnectivityManager.getLastPeriodicSingleScanTimeStamp(); 1148 1149 // Verify that the second scan is fired immediately 1150 assertEquals(secondScanTimeStamp, currentTimeStamp); 1151 } 1152 1153 /** 1154 * Verify that we perform full band scan when the currently connected network's tx/rx success 1155 * rate is low. 1156 * 1157 * Expected behavior: WifiConnectivityManager does full band scan. 1158 */ 1159 @Test 1160 public void checkSingleScanSettingsWhenConnectedWithLowDataRate() { 1161 mWifiInfo.txSuccessRate = 0; 1162 mWifiInfo.rxSuccessRate = 0; 1163 1164 final HashSet<Integer> channelList = new HashSet<>(); 1165 channelList.add(1); 1166 channelList.add(2); 1167 channelList.add(3); 1168 1169 when(mWifiStateMachine.getCurrentWifiConfiguration()) 1170 .thenReturn(new WifiConfiguration()); 1171 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 1172 anyInt())).thenReturn(channelList); 1173 1174 doAnswer(new AnswerWithArguments() { 1175 public void answer(ScanSettings settings, ScanListener listener, 1176 WorkSource workSource) throws Exception { 1177 assertEquals(settings.band, WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 1178 assertNull(settings.channels); 1179 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1180 1181 // Set screen to ON 1182 mWifiConnectivityManager.handleScreenStateChanged(true); 1183 1184 // Set WiFi to connected state to trigger periodic scan 1185 mWifiConnectivityManager.handleConnectionStateChanged( 1186 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1187 1188 verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1189 } 1190 1191 /** 1192 * Verify that we perform partial scan when the currently connected network's tx/rx success 1193 * rate is high and when the currently connected network is present in scan 1194 * cache in WifiConfigManager. 1195 * WifiConnectivityManager does partial scan only when firmware roaming is not supported. 1196 * 1197 * Expected behavior: WifiConnectivityManager does partial scan. 1198 */ 1199 @Test 1200 public void checkPartialScanRequestedWithHighDataRateWithoutFwRoaming() { 1201 mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2; 1202 mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2; 1203 1204 final HashSet<Integer> channelList = new HashSet<>(); 1205 channelList.add(1); 1206 channelList.add(2); 1207 channelList.add(3); 1208 1209 when(mWifiStateMachine.getCurrentWifiConfiguration()) 1210 .thenReturn(new WifiConfiguration()); 1211 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 1212 anyInt())).thenReturn(channelList); 1213 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(false); 1214 1215 doAnswer(new AnswerWithArguments() { 1216 public void answer(ScanSettings settings, ScanListener listener, 1217 WorkSource workSource) throws Exception { 1218 assertEquals(settings.band, WifiScanner.WIFI_BAND_UNSPECIFIED); 1219 assertEquals(settings.channels.length, channelList.size()); 1220 for (int chanIdx = 0; chanIdx < settings.channels.length; chanIdx++) { 1221 assertTrue(channelList.contains(settings.channels[chanIdx].frequency)); 1222 } 1223 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1224 1225 // Set screen to ON 1226 mWifiConnectivityManager.handleScreenStateChanged(true); 1227 1228 // Set WiFi to connected state to trigger periodic scan 1229 mWifiConnectivityManager.handleConnectionStateChanged( 1230 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1231 1232 verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1233 } 1234 1235 /** 1236 * Verify that we skip the partial scan when: 1237 * 1. The currently connected network's tx/rx success rate is high. 1238 * 2. When the currently connected network is present in scan 1239 * cache in WifiConfigManager. 1240 * 3. When firmware roaming is supported. 1241 * Expected behavior: WifiConnectivityManager does no scan, but periodic scans 1242 * are still scheduled. 1243 */ 1244 @Test 1245 public void checkPartialScanSkippedWithHighDataRateWithFwRoaming() { 1246 mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2; 1247 mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2; 1248 1249 long currentTimeStamp = CURRENT_SYSTEM_TIME_MS; 1250 when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp); 1251 1252 final HashSet<Integer> channelList = new HashSet<>(); 1253 channelList.add(1); 1254 channelList.add(2); 1255 channelList.add(3); 1256 1257 when(mWifiStateMachine.getCurrentWifiConfiguration()) 1258 .thenReturn(new WifiConfiguration()); 1259 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 1260 anyInt())).thenReturn(channelList); 1261 // No scan will be requested when firmware roaming control is not supported. 1262 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1263 1264 // Set screen to ON 1265 mWifiConnectivityManager.handleScreenStateChanged(true); 1266 1267 // Set WiFi to connected state to trigger periodic scan 1268 mWifiConnectivityManager.handleConnectionStateChanged( 1269 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1270 1271 verify(mWifiScanner, never()).startScan(anyObject(), anyObject(), anyObject()); 1272 1273 // Get the first periodic scan interval to check that we are still scheduling 1274 // periodic scans. 1275 long firstIntervalMs = mAlarmManager 1276 .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG) 1277 - currentTimeStamp; 1278 assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS); 1279 } 1280 1281 /** 1282 * Verify that we fall back to full band scan when the currently connected network's tx/rx 1283 * success rate is high and the currently connected network is not present in scan cache in 1284 * WifiConfigManager. This is simulated by returning an empty hashset in |makeChannelList|. 1285 * 1286 * Expected behavior: WifiConnectivityManager does full band scan. 1287 */ 1288 @Test 1289 public void checkSingleScanSettingsWhenConnectedWithHighDataRateNotInCache() { 1290 mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2; 1291 mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2; 1292 1293 final HashSet<Integer> channelList = new HashSet<>(); 1294 1295 when(mWifiStateMachine.getCurrentWifiConfiguration()) 1296 .thenReturn(new WifiConfiguration()); 1297 when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(), 1298 anyInt())).thenReturn(channelList); 1299 1300 doAnswer(new AnswerWithArguments() { 1301 public void answer(ScanSettings settings, ScanListener listener, 1302 WorkSource workSource) throws Exception { 1303 assertEquals(settings.band, WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 1304 assertNull(settings.channels); 1305 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1306 1307 // Set screen to ON 1308 mWifiConnectivityManager.handleScreenStateChanged(true); 1309 1310 // Set WiFi to connected state to trigger periodic scan 1311 mWifiConnectivityManager.handleConnectionStateChanged( 1312 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1313 1314 verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1315 } 1316 1317 /** 1318 * Verify that we retry connectivity scan up to MAX_SCAN_RESTART_ALLOWED times 1319 * when Wifi somehow gets into a bad state and fails to scan. 1320 * 1321 * Expected behavior: WifiConnectivityManager schedules connectivity scan 1322 * MAX_SCAN_RESTART_ALLOWED times. 1323 */ 1324 @Test 1325 public void checkMaximumScanRetry() { 1326 // Set screen to ON 1327 mWifiConnectivityManager.handleScreenStateChanged(true); 1328 1329 doAnswer(new AnswerWithArguments() { 1330 public void answer(ScanSettings settings, ScanListener listener, 1331 WorkSource workSource) throws Exception { 1332 listener.onFailure(-1, "ScanFailure"); 1333 }}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject()); 1334 1335 // Set WiFi to disconnected state to trigger the single scan based periodic scan 1336 mWifiConnectivityManager.handleConnectionStateChanged( 1337 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1338 1339 // Fire the alarm timer 2x timers 1340 for (int i = 0; i < (WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED * 2); i++) { 1341 mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG); 1342 mLooper.dispatchAll(); 1343 } 1344 1345 // Verify that the connectivity scan has been retried for MAX_SCAN_RESTART_ALLOWED 1346 // times. Note, WifiScanner.startScan() is invoked MAX_SCAN_RESTART_ALLOWED + 1 times. 1347 // The very first scan is the initial one, and the other MAX_SCAN_RESTART_ALLOWED 1348 // are the retrial ones. 1349 verify(mWifiScanner, times(WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED + 1)).startScan( 1350 anyObject(), anyObject(), anyObject()); 1351 } 1352 1353 /** 1354 * Listen to scan results not requested by WifiConnectivityManager and 1355 * act on them. 1356 * 1357 * Expected behavior: WifiConnectivityManager calls 1358 * WifiStateMachine.startConnectToNetwork() with the 1359 * expected candidate network ID and BSSID. 1360 */ 1361 @Test 1362 public void listenToAllSingleScanResults() { 1363 ScanSettings settings = new ScanSettings(); 1364 ScanListener scanListener = mock(ScanListener.class); 1365 1366 // Request a single scan outside of WifiConnectivityManager. 1367 mWifiScanner.startScan(settings, scanListener, WIFI_WORK_SOURCE); 1368 1369 // Verify that WCM receives the scan results and initiates a connection 1370 // to the network. 1371 verify(mWifiStateMachine).startConnectToNetwork( 1372 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1373 } 1374 1375 /** 1376 * Verify that a forced connectivity scan waits for full band scan 1377 * results. 1378 * 1379 * Expected behavior: WifiConnectivityManager doesn't invoke 1380 * WifiStateMachine.startConnectToNetwork() when full band scan 1381 * results are not available. 1382 */ 1383 @Test 1384 public void waitForFullBandScanResults() { 1385 // Set WiFi to connected state. 1386 mWifiConnectivityManager.handleConnectionStateChanged( 1387 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1388 1389 // Set up as partial scan results. 1390 when(mScanData.isAllChannelsScanned()).thenReturn(false); 1391 1392 // Force a connectivity scan which enables WifiConnectivityManager 1393 // to wait for full band scan results. 1394 mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE); 1395 1396 // No roaming because no full band scan results. 1397 verify(mWifiStateMachine, times(0)).startConnectToNetwork( 1398 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1399 1400 // Set up as full band scan results. 1401 when(mScanData.isAllChannelsScanned()).thenReturn(true); 1402 1403 // Force a connectivity scan which enables WifiConnectivityManager 1404 // to wait for full band scan results. 1405 mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE); 1406 1407 // Roaming attempt because full band scan results are available. 1408 verify(mWifiStateMachine).startConnectToNetwork( 1409 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1410 } 1411 1412 /** 1413 * Verify the BSSID blacklist implementation. 1414 * 1415 * Expected behavior: A BSSID gets blacklisted after being disabled 1416 * for 3 times, and becomes available after being re-enabled. Firmware 1417 * controlled roaming is supported, its roaming configuration needs to be 1418 * updated as well. 1419 */ 1420 @Test 1421 public void blacklistAndReenableBssid() { 1422 String bssid = "6c:f3:7f:ae:8c:f3"; 1423 1424 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1425 // Verify that a BSSID gets blacklisted only after being disabled 1426 // for BSSID_BLACKLIST_THRESHOLD times for reasons other than 1427 // REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA. 1428 for (int i = 0; i < WifiConnectivityManager.BSSID_BLACKLIST_THRESHOLD; i++) { 1429 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1430 mWifiConnectivityManager.trackBssid(bssid, false, 1); 1431 } 1432 1433 // Verify the BSSID is now blacklisted. 1434 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1435 // Verify the BSSID gets sent to firmware. 1436 verify(mWifiConnectivityHelper).setFirmwareRoamingConfiguration( 1437 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1438 assertTrue(mBssidBlacklistCaptor.getValue().contains(bssid)); 1439 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1440 1441 // Re-enable the bssid. 1442 mWifiConnectivityManager.trackBssid(bssid, true, 1); 1443 1444 // Verify the bssid is no longer blacklisted. 1445 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1446 // Verify the BSSID gets cleared from firmware. 1447 verify(mWifiConnectivityHelper, times(2)).setFirmwareRoamingConfiguration( 1448 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1449 assertFalse(mBssidBlacklistCaptor.getValue().contains(bssid)); 1450 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1451 } 1452 1453 /** 1454 * Verify that a network gets blacklisted immediately if it is unable 1455 * to handle new stations. 1456 */ 1457 @Test 1458 public void blacklistNetworkImmediatelyIfApHasNoCapacityForNewStation() { 1459 String bssid = "6c:f3:7f:ae:8c:f3"; 1460 1461 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1462 // Blacklist the BSSID 1463 mWifiConnectivityManager.trackBssid(bssid, false, 1464 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1465 1466 // Verify the BSSID is now blacklisted. 1467 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1468 // Verify the BSSID gets sent to firmware. 1469 verify(mWifiConnectivityHelper).setFirmwareRoamingConfiguration( 1470 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1471 assertTrue(mBssidBlacklistCaptor.getValue().contains(bssid)); 1472 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1473 } 1474 1475 /** 1476 * Verify that a blacklisted BSSID becomes available only after 1477 * BSSID_BLACKLIST_EXPIRE_TIME_MS. 1478 */ 1479 @Test 1480 public void verifyBlacklistRefreshedAfterScanResults() { 1481 String bssid = "6c:f3:7f:ae:8c:f3"; 1482 1483 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1484 // Blacklist the BSSID. 1485 mWifiConnectivityManager.trackBssid(bssid, false, 1486 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1487 1488 // Verify the BSSID is now blacklisted. 1489 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1490 // Verify the BSSID gets sent to firmware. 1491 verify(mWifiConnectivityHelper).setFirmwareRoamingConfiguration( 1492 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1493 assertTrue(mBssidBlacklistCaptor.getValue().contains(bssid)); 1494 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1495 1496 // Force a connectivity scan in less than BSSID_BLACKLIST_EXPIRE_TIME_MS. 1497 // Arrival of scan results will trigger WifiConnectivityManager to refresh its 1498 // BSSID blacklist. Verify that the blacklisted BSSId is not freed because 1499 // its blacklist expiration time hasn't reached yet. 1500 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() 1501 + WifiConnectivityManager.BSSID_BLACKLIST_EXPIRE_TIME_MS / 2); 1502 mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE); 1503 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1504 1505 // Force another connectivity scan at BSSID_BLACKLIST_EXPIRE_TIME_MS from when the 1506 // BSSID was blacklisted. Verify that the blacklisted BSSId is freed. 1507 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() 1508 + WifiConnectivityManager.BSSID_BLACKLIST_EXPIRE_TIME_MS); 1509 mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE); 1510 1511 // Verify the BSSID is no longer blacklisted. 1512 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1513 // Verify the BSSID gets cleared from firmware. 1514 verify(mWifiConnectivityHelper, times(2)).setFirmwareRoamingConfiguration( 1515 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1516 assertFalse(mBssidBlacklistCaptor.getValue().contains(bssid)); 1517 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1518 } 1519 1520 /** 1521 * Verify that BSSID blacklist gets cleared when exiting Wifi client mode. 1522 */ 1523 @Test 1524 public void clearBssidBlacklistWhenExitingWifiClientMode() { 1525 String bssid = "6c:f3:7f:ae:8c:f3"; 1526 1527 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1528 1529 // Blacklist the BSSID. 1530 mWifiConnectivityManager.trackBssid(bssid, false, 1531 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1532 1533 // Verify the BSSID is now blacklisted. 1534 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1535 // Verify the BSSID gets sent to firmware. 1536 verify(mWifiConnectivityHelper).setFirmwareRoamingConfiguration( 1537 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1538 assertTrue(mBssidBlacklistCaptor.getValue().contains(bssid)); 1539 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1540 1541 // Exit Wifi client mode. 1542 mWifiConnectivityManager.setWifiEnabled(false); 1543 1544 // Verify the BSSID blacklist is empty. 1545 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1546 verify(mWifiConnectivityHelper, times(2)).setFirmwareRoamingConfiguration( 1547 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1548 assertTrue(mBssidBlacklistCaptor.getValue().isEmpty()); 1549 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1550 } 1551 1552 /** 1553 * Verify that BSSID blacklist gets cleared when preparing for a forced connection 1554 * initiated by user/app. 1555 */ 1556 @Test 1557 public void clearBssidBlacklistWhenPreparingForForcedConnection() { 1558 String bssid = "6c:f3:7f:ae:8c:f3"; 1559 1560 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1561 1562 // Blacklist the BSSID. 1563 mWifiConnectivityManager.trackBssid(bssid, false, 1564 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1565 1566 // Verify the BSSID is now blacklisted. 1567 assertTrue(mWifiConnectivityManager.isBssidDisabled(bssid)); 1568 // Verify the BSSID gets sent to firmware. 1569 verify(mWifiConnectivityHelper).setFirmwareRoamingConfiguration( 1570 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1571 assertTrue(mBssidBlacklistCaptor.getValue().contains(bssid)); 1572 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1573 1574 // Prepare for a forced connection attempt. 1575 mWifiConnectivityManager.prepareForForcedConnection(1); 1576 1577 // Verify the BSSID blacklist is empty. 1578 assertFalse(mWifiConnectivityManager.isBssidDisabled(bssid)); 1579 verify(mWifiConnectivityHelper, times(2)).setFirmwareRoamingConfiguration( 1580 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1581 assertTrue(mBssidBlacklistCaptor.getValue().isEmpty()); 1582 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1583 } 1584 1585 /** 1586 /** 1587 * Verify that BSSID blacklist gets trimmed down to fit firmware capability. 1588 */ 1589 @Test 1590 public void trimDownBssidBlacklistForFirmware() { 1591 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1592 1593 // Blacklist more than MAX_BSSID_BLACKLIST_SIZE BSSIDs. 1594 for (int i = 0; i < MAX_BSSID_BLACKLIST_SIZE + 6; i++) { 1595 StringBuilder bssid = new StringBuilder("55:44:33:22:11:00"); 1596 bssid.setCharAt(16, (char) ('0' + i)); 1597 mWifiConnectivityManager.trackBssid(bssid.toString(), false, 1598 WifiConnectivityManager.REASON_CODE_AP_UNABLE_TO_HANDLE_NEW_STA); 1599 // Verify that up to MAX_BSSID_BLACKLIST_SIZE BSSIDs gets sent to firmware. 1600 verify(mWifiConnectivityHelper, times(i + 1)).setFirmwareRoamingConfiguration( 1601 mBssidBlacklistCaptor.capture(), mSsidWhitelistCaptor.capture()); 1602 assertEquals((i + 1) < MAX_BSSID_BLACKLIST_SIZE ? (i + 1) : MAX_BSSID_BLACKLIST_SIZE, 1603 mBssidBlacklistCaptor.getValue().size()); 1604 assertTrue(mSsidWhitelistCaptor.getValue().isEmpty()); 1605 } 1606 } 1607 1608 /** 1609 * When WifiConnectivityManager is on and Wifi client mode is enabled, framework 1610 * queries firmware via WifiConnectivityHelper to check if firmware roaming is 1611 * supported and its capability. 1612 * 1613 * Expected behavior: WifiConnectivityManager#setWifiEnabled calls into 1614 * WifiConnectivityHelper#getFirmwareRoamingInfo 1615 */ 1616 @Test 1617 public void verifyGetFirmwareRoamingInfoIsCalledWhenEnableWiFiAndWcmOn() { 1618 reset(mWifiConnectivityHelper); 1619 // WifiConnectivityManager is on by default 1620 mWifiConnectivityManager.setWifiEnabled(true); 1621 verify(mWifiConnectivityHelper).getFirmwareRoamingInfo(); 1622 } 1623 1624 /** 1625 * When WifiConnectivityManager is off, verify that framework does not 1626 * query firmware via WifiConnectivityHelper to check if firmware roaming is 1627 * supported and its capability when enabling Wifi client mode. 1628 * 1629 * Expected behavior: WifiConnectivityManager#setWifiEnabled does not call into 1630 * WifiConnectivityHelper#getFirmwareRoamingInfo 1631 */ 1632 @Test 1633 public void verifyGetFirmwareRoamingInfoIsNotCalledWhenEnableWiFiAndWcmOff() { 1634 reset(mWifiConnectivityHelper); 1635 mWifiConnectivityManager.enable(false); 1636 mWifiConnectivityManager.setWifiEnabled(true); 1637 verify(mWifiConnectivityHelper, times(0)).getFirmwareRoamingInfo(); 1638 } 1639 1640 /* 1641 * Firmware supports controlled roaming. 1642 * Connect to a network which doesn't have a config specified BSSID. 1643 * 1644 * Expected behavior: WifiConnectivityManager calls 1645 * WifiStateMachine.startConnectToNetwork() with the 1646 * expected candidate network ID, and the BSSID value should be 1647 * 'any' since firmware controls the roaming. 1648 */ 1649 @Test 1650 public void useAnyBssidToConnectWhenFirmwareRoamingOnAndConfigHasNoBssidSpecified() { 1651 // Firmware controls roaming 1652 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1653 1654 // Set screen to on 1655 mWifiConnectivityManager.handleScreenStateChanged(true); 1656 1657 // Set WiFi to disconnected state 1658 mWifiConnectivityManager.handleConnectionStateChanged( 1659 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1660 1661 verify(mWifiStateMachine).startConnectToNetwork( 1662 CANDIDATE_NETWORK_ID, Process.WIFI_UID, WifiStateMachine.SUPPLICANT_BSSID_ANY); 1663 } 1664 1665 /* 1666 * Firmware supports controlled roaming. 1667 * Connect to a network which has a config specified BSSID. 1668 * 1669 * Expected behavior: WifiConnectivityManager calls 1670 * WifiStateMachine.startConnectToNetwork() with the 1671 * expected candidate network ID, and the BSSID value should be 1672 * the config specified one. 1673 */ 1674 @Test 1675 public void useConfigSpecifiedBssidToConnectWhenFirmwareRoamingOn() { 1676 // Firmware controls roaming 1677 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1678 1679 // Set up the candidate configuration such that it has a BSSID specified. 1680 WifiConfiguration candidate = generateWifiConfig( 1681 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1682 candidate.BSSID = CANDIDATE_BSSID; // config specified 1683 ScanResult candidateScanResult = new ScanResult(); 1684 candidateScanResult.SSID = CANDIDATE_SSID; 1685 candidateScanResult.BSSID = CANDIDATE_BSSID; 1686 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1687 1688 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1689 anyBoolean(), anyBoolean())).thenReturn(candidate); 1690 1691 // Set screen to on 1692 mWifiConnectivityManager.handleScreenStateChanged(true); 1693 1694 // Set WiFi to disconnected state 1695 mWifiConnectivityManager.handleConnectionStateChanged( 1696 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1697 1698 verify(mWifiStateMachine).startConnectToNetwork( 1699 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1700 } 1701 1702 /* 1703 * Firmware does not support controlled roaming. 1704 * Connect to a network which doesn't have a config specified BSSID. 1705 * 1706 * Expected behavior: WifiConnectivityManager calls 1707 * WifiStateMachine.startConnectToNetwork() with the expected candidate network ID, 1708 * and the BSSID value should be the candidate scan result specified. 1709 */ 1710 @Test 1711 public void useScanResultBssidToConnectWhenFirmwareRoamingOffAndConfigHasNoBssidSpecified() { 1712 // Set screen to on 1713 mWifiConnectivityManager.handleScreenStateChanged(true); 1714 1715 // Set WiFi to disconnected state 1716 mWifiConnectivityManager.handleConnectionStateChanged( 1717 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1718 1719 verify(mWifiStateMachine).startConnectToNetwork( 1720 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1721 } 1722 1723 /* 1724 * Firmware does not support controlled roaming. 1725 * Connect to a network which has a config specified BSSID. 1726 * 1727 * Expected behavior: WifiConnectivityManager calls 1728 * WifiStateMachine.startConnectToNetwork() with the expected candidate network ID, 1729 * and the BSSID value should be the config specified one. 1730 */ 1731 @Test 1732 public void useConfigSpecifiedBssidToConnectionWhenFirmwareRoamingOff() { 1733 // Set up the candidate configuration such that it has a BSSID specified. 1734 WifiConfiguration candidate = generateWifiConfig( 1735 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1736 candidate.BSSID = CANDIDATE_BSSID; // config specified 1737 ScanResult candidateScanResult = new ScanResult(); 1738 candidateScanResult.SSID = CANDIDATE_SSID; 1739 candidateScanResult.BSSID = CANDIDATE_BSSID; 1740 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1741 1742 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1743 anyBoolean(), anyBoolean())).thenReturn(candidate); 1744 1745 // Set screen to on 1746 mWifiConnectivityManager.handleScreenStateChanged(true); 1747 1748 // Set WiFi to disconnected state 1749 mWifiConnectivityManager.handleConnectionStateChanged( 1750 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1751 1752 verify(mWifiStateMachine).startConnectToNetwork( 1753 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1754 } 1755 1756 /** 1757 * Firmware does not support controlled roaming. 1758 * WiFi in connected state, framework triggers roaming. 1759 * 1760 * Expected behavior: WifiConnectivityManager invokes 1761 * WifiStateMachine.startRoamToNetwork(). 1762 */ 1763 @Test 1764 public void frameworkInitiatedRoaming() { 1765 // Mock the currently connected network which has the same networkID and 1766 // SSID as the one to be selected. 1767 WifiConfiguration currentNetwork = generateWifiConfig( 1768 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1769 when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork); 1770 1771 // Set WiFi to connected state 1772 mWifiConnectivityManager.handleConnectionStateChanged( 1773 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1774 1775 // Set screen to on 1776 mWifiConnectivityManager.handleScreenStateChanged(true); 1777 1778 verify(mWifiStateMachine).startRoamToNetwork(eq(CANDIDATE_NETWORK_ID), 1779 mCandidateScanResultCaptor.capture()); 1780 assertEquals(mCandidateScanResultCaptor.getValue().BSSID, CANDIDATE_BSSID); 1781 } 1782 1783 /** 1784 * Firmware supports controlled roaming. 1785 * WiFi in connected state, framework does not trigger roaming 1786 * as it's handed off to the firmware. 1787 * 1788 * Expected behavior: WifiConnectivityManager doesn't invoke 1789 * WifiStateMachine.startRoamToNetwork(). 1790 */ 1791 @Test 1792 public void noFrameworkRoamingIfConnectedAndFirmwareRoamingSupported() { 1793 // Mock the currently connected network which has the same networkID and 1794 // SSID as the one to be selected. 1795 WifiConfiguration currentNetwork = generateWifiConfig( 1796 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1797 when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork); 1798 1799 // Firmware controls roaming 1800 when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true); 1801 1802 // Set WiFi to connected state 1803 mWifiConnectivityManager.handleConnectionStateChanged( 1804 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1805 1806 // Set screen to on 1807 mWifiConnectivityManager.handleScreenStateChanged(true); 1808 1809 verify(mWifiStateMachine, times(0)).startRoamToNetwork(anyInt(), anyObject()); 1810 } 1811 1812 /* 1813 * Wifi in disconnected state. Drop the connection attempt if the recommended 1814 * network configuration has a BSSID specified but the scan result BSSID doesn't 1815 * match it. 1816 * 1817 * Expected behavior: WifiConnectivityManager doesn't invoke 1818 * WifiStateMachine.startConnectToNetwork(). 1819 */ 1820 @Test 1821 public void dropConnectAttemptIfConfigSpecifiedBssidDifferentFromScanResultBssid() { 1822 // Set up the candidate configuration such that it has a BSSID specified. 1823 WifiConfiguration candidate = generateWifiConfig( 1824 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1825 candidate.BSSID = CANDIDATE_BSSID; // config specified 1826 ScanResult candidateScanResult = new ScanResult(); 1827 candidateScanResult.SSID = CANDIDATE_SSID; 1828 // Set up the scan result BSSID to be different from the config specified one. 1829 candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID; 1830 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1831 1832 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1833 anyBoolean(), anyBoolean())).thenReturn(candidate); 1834 1835 // Set screen to on 1836 mWifiConnectivityManager.handleScreenStateChanged(true); 1837 1838 // Set WiFi to disconnected state 1839 mWifiConnectivityManager.handleConnectionStateChanged( 1840 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1841 1842 verify(mWifiStateMachine, times(0)).startConnectToNetwork( 1843 CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID); 1844 } 1845 1846 /* 1847 * Wifi in connected state. Drop the roaming attempt if the recommended 1848 * network configuration has a BSSID specified but the scan result BSSID doesn't 1849 * match it. 1850 * 1851 * Expected behavior: WifiConnectivityManager doesn't invoke 1852 * WifiStateMachine.startRoamToNetwork(). 1853 */ 1854 @Test 1855 public void dropRoamingAttemptIfConfigSpecifiedBssidDifferentFromScanResultBssid() { 1856 // Mock the currently connected network which has the same networkID and 1857 // SSID as the one to be selected. 1858 WifiConfiguration currentNetwork = generateWifiConfig( 1859 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1860 when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork); 1861 1862 // Set up the candidate configuration such that it has a BSSID specified. 1863 WifiConfiguration candidate = generateWifiConfig( 1864 0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null); 1865 candidate.BSSID = CANDIDATE_BSSID; // config specified 1866 ScanResult candidateScanResult = new ScanResult(); 1867 candidateScanResult.SSID = CANDIDATE_SSID; 1868 // Set up the scan result BSSID to be different from the config specified one. 1869 candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID; 1870 candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult); 1871 1872 when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), 1873 anyBoolean(), anyBoolean())).thenReturn(candidate); 1874 1875 // Set WiFi to connected state 1876 mWifiConnectivityManager.handleConnectionStateChanged( 1877 WifiConnectivityManager.WIFI_STATE_CONNECTED); 1878 1879 // Set screen to on 1880 mWifiConnectivityManager.handleScreenStateChanged(true); 1881 1882 verify(mWifiStateMachine, times(0)).startRoamToNetwork(anyInt(), anyObject()); 1883 } 1884 1885 /** 1886 * Dump local log buffer. 1887 * 1888 * Expected behavior: Logs dumped from WifiConnectivityManager.dump() 1889 * contain the message we put in mLocalLog. 1890 */ 1891 @Test 1892 public void dumpLocalLog() { 1893 final String localLogMessage = "This is a message from the test"; 1894 mLocalLog.log(localLogMessage); 1895 1896 StringWriter sw = new StringWriter(); 1897 PrintWriter pw = new PrintWriter(sw); 1898 mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{}); 1899 assertTrue(sw.toString().contains(localLogMessage)); 1900 } 1901 1902 /** 1903 * Dump ONA controller. 1904 * 1905 * Expected behavior: {@link OpenNetworkNotifier#dump(FileDescriptor, PrintWriter, 1906 * String[])} is invoked. 1907 */ 1908 @Test 1909 public void dumpNotificationController() { 1910 StringWriter sw = new StringWriter(); 1911 PrintWriter pw = new PrintWriter(sw); 1912 mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{}); 1913 1914 verify(mOpenNetworkNotifier).dump(any(), any(), any()); 1915 } 1916 1917 /** 1918 * Create scan data with different radio chain infos: 1919 * First scan result has null radio chain info (No DBS support). 1920 * Second scan result has empty radio chain info (No DBS support). 1921 * Third scan result has 1 radio chain info (DBS scan). 1922 * Fourth scan result has 2 radio chain info (non-DBS scan). 1923 */ 1924 private ScanData createScanDataWithDifferentRadioChainInfos() { 1925 // Create 4 scan results. 1926 ScanData[] scanDatas = 1927 ScanTestUtil.createScanDatas(new int[][]{{5150, 5175, 2412, 2400}}, new int[]{0}); 1928 // WCM barfs if the scan result does not have an IE. 1929 scanDatas[0].getResults()[0].informationElements = new InformationElement[0]; 1930 scanDatas[0].getResults()[1].informationElements = new InformationElement[0]; 1931 scanDatas[0].getResults()[2].informationElements = new InformationElement[0]; 1932 scanDatas[0].getResults()[3].informationElements = new InformationElement[0]; 1933 scanDatas[0].getResults()[0].radioChainInfos = null; 1934 scanDatas[0].getResults()[1].radioChainInfos = new ScanResult.RadioChainInfo[0]; 1935 scanDatas[0].getResults()[2].radioChainInfos = new ScanResult.RadioChainInfo[1]; 1936 scanDatas[0].getResults()[3].radioChainInfos = new ScanResult.RadioChainInfo[2]; 1937 1938 return scanDatas[0]; 1939 } 1940 1941 /** 1942 * If |config_wifi_framework_use_single_radio_chain_scan_results_network_selection| flag is 1943 * false, WifiConnectivityManager should filter scan results which contain scans from a single 1944 * radio chain (i.e DBS scan). 1945 * Note: 1946 * a) ScanResult with no radio chain indicates a lack of DBS support on the device. 1947 * b) ScanResult with 2 radio chain info indicates a scan done using both the radio chains 1948 * on a DBS supported device. 1949 * 1950 * Expected behavior: WifiConnectivityManager invokes 1951 * {@link WifiNetworkSelector#selectNetwork(List, HashSet, WifiInfo, boolean, boolean, boolean)} 1952 * after filtering out the scan results obtained via DBS scan. 1953 */ 1954 @Test 1955 public void filterScanResultsWithOneRadioChainInfoForNetworkSelectionIfConfigDisabled() { 1956 when(mResource.getBoolean( 1957 R.bool.config_wifi_framework_use_single_radio_chain_scan_results_network_selection)) 1958 .thenReturn(false); 1959 when(mWifiNS.selectNetwork(any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean())) 1960 .thenReturn(null); 1961 mWifiConnectivityManager = createConnectivityManager(); 1962 1963 mScanData = createScanDataWithDifferentRadioChainInfos(); 1964 1965 // Capture scan details which were sent to network selector. 1966 final List<ScanDetail> capturedScanDetails = new ArrayList<>(); 1967 doAnswer(new AnswerWithArguments() { 1968 public WifiConfiguration answer( 1969 List<ScanDetail> scanDetails, HashSet<String> bssidBlacklist, WifiInfo wifiInfo, 1970 boolean connected, boolean disconnected, boolean untrustedNetworkAllowed) 1971 throws Exception { 1972 capturedScanDetails.addAll(scanDetails); 1973 return null; 1974 }}).when(mWifiNS).selectNetwork( 1975 any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean()); 1976 1977 // Set WiFi to disconnected state with screen on which triggers a scan immediately. 1978 mWifiConnectivityManager.setWifiEnabled(true); 1979 mWifiConnectivityManager.handleScreenStateChanged(true); 1980 mWifiConnectivityManager.handleConnectionStateChanged( 1981 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 1982 1983 // We should have filtered out the 3rd scan result. 1984 assertEquals(3, capturedScanDetails.size()); 1985 List<ScanResult> capturedScanResults = 1986 capturedScanDetails.stream().map(ScanDetail::getScanResult) 1987 .collect(Collectors.toList()); 1988 1989 assertEquals(3, capturedScanResults.size()); 1990 assertTrue(capturedScanResults.contains(mScanData.getResults()[0])); 1991 assertTrue(capturedScanResults.contains(mScanData.getResults()[1])); 1992 assertFalse(capturedScanResults.contains(mScanData.getResults()[2])); 1993 assertTrue(capturedScanResults.contains(mScanData.getResults()[3])); 1994 } 1995 1996 /** 1997 * If |config_wifi_framework_use_single_radio_chain_scan_results_network_selection| flag is 1998 * true, WifiConnectivityManager should not filter scan results which contain scans from a 1999 * single radio chain (i.e DBS scan). 2000 * Note: 2001 * a) ScanResult with no radio chain indicates a lack of DBS support on the device. 2002 * b) ScanResult with 2 radio chain info indicates a scan done using both the radio chains 2003 * on a DBS supported device. 2004 * 2005 * Expected behavior: WifiConnectivityManager invokes 2006 * {@link WifiNetworkSelector#selectNetwork(List, HashSet, WifiInfo, boolean, boolean, boolean)} 2007 * after filtering out the scan results obtained via DBS scan. 2008 */ 2009 @Test 2010 public void dontFilterScanResultsWithOneRadioChainInfoForNetworkSelectionIfConfigEnabled() { 2011 when(mResource.getBoolean( 2012 R.bool.config_wifi_framework_use_single_radio_chain_scan_results_network_selection)) 2013 .thenReturn(true); 2014 when(mWifiNS.selectNetwork(any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean())) 2015 .thenReturn(null); 2016 mWifiConnectivityManager = createConnectivityManager(); 2017 2018 mScanData = createScanDataWithDifferentRadioChainInfos(); 2019 2020 // Capture scan details which were sent to network selector. 2021 final List<ScanDetail> capturedScanDetails = new ArrayList<>(); 2022 doAnswer(new AnswerWithArguments() { 2023 public WifiConfiguration answer( 2024 List<ScanDetail> scanDetails, HashSet<String> bssidBlacklist, WifiInfo wifiInfo, 2025 boolean connected, boolean disconnected, boolean untrustedNetworkAllowed) 2026 throws Exception { 2027 capturedScanDetails.addAll(scanDetails); 2028 return null; 2029 }}).when(mWifiNS).selectNetwork( 2030 any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean()); 2031 2032 // Set WiFi to disconnected state with screen on which triggers a scan immediately. 2033 mWifiConnectivityManager.setWifiEnabled(true); 2034 mWifiConnectivityManager.handleScreenStateChanged(true); 2035 mWifiConnectivityManager.handleConnectionStateChanged( 2036 WifiConnectivityManager.WIFI_STATE_DISCONNECTED); 2037 2038 // We should not filter any of the scan results. 2039 assertEquals(4, capturedScanDetails.size()); 2040 List<ScanResult> capturedScanResults = 2041 capturedScanDetails.stream().map(ScanDetail::getScanResult) 2042 .collect(Collectors.toList()); 2043 2044 assertEquals(4, capturedScanResults.size()); 2045 assertTrue(capturedScanResults.contains(mScanData.getResults()[0])); 2046 assertTrue(capturedScanResults.contains(mScanData.getResults()[1])); 2047 assertTrue(capturedScanResults.contains(mScanData.getResults()[2])); 2048 assertTrue(capturedScanResults.contains(mScanData.getResults()[3])); 2049 } 2050 2051 /** 2052 * Disabling the network temporarily due to lack of internet is a special reason for which we 2053 * don't want WCM to trigger a disconnect (by removing the network from supplicant). 2054 */ 2055 @Test 2056 public void dontDisconnectIfNetworkTemporarilyDisabledDueToNoInternet() { 2057 assertNotNull(mSavedNetworkUpdateListenerCaptor.getValue()); 2058 2059 mSavedNetworkUpdateListenerCaptor.getValue() 2060 .onSavedNetworkPermanentlyDisabled(0, DISABLED_AUTHENTICATION_FAILURE); 2061 verify(mWifiConnectivityHelper).removeNetworkIfCurrent(0); 2062 2063 mSavedNetworkUpdateListenerCaptor.getValue() 2064 .onSavedNetworkPermanentlyDisabled(0, DISABLED_NO_INTERNET_TEMPORARY); 2065 // Don't remove network. 2066 } 2067} 2068