1/* 2 * Copyright 2017 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 org.junit.Assert.assertFalse; 20import static org.junit.Assert.assertTrue; 21import static org.mockito.ArgumentMatchers.any; 22import static org.mockito.ArgumentMatchers.anyBoolean; 23import static org.mockito.ArgumentMatchers.anyInt; 24import static org.mockito.ArgumentMatchers.eq; 25import static org.mockito.Mockito.never; 26import static org.mockito.Mockito.verify; 27import static org.mockito.Mockito.when; 28 29import android.content.Context; 30import android.database.ContentObserver; 31import android.net.wifi.ScanResult; 32import android.net.wifi.WifiConfiguration; 33import android.net.wifi.WifiScanner; 34import android.os.test.TestLooper; 35import android.provider.Settings; 36 37import com.android.server.wifi.util.ScanResultUtil; 38 39import org.junit.Before; 40import org.junit.Test; 41import org.mockito.ArgumentCaptor; 42import org.mockito.InOrder; 43import org.mockito.Mock; 44import org.mockito.Mockito; 45import org.mockito.MockitoAnnotations; 46import org.xmlpull.v1.XmlPullParserException; 47 48import java.io.ByteArrayOutputStream; 49import java.io.IOException; 50import java.io.PrintWriter; 51import java.util.Arrays; 52import java.util.Collections; 53import java.util.Set; 54 55/** 56 * Unit tests for {@link WakeupController}. 57 */ 58public class WakeupControllerTest { 59 60 private static final String SAVED_SSID = "test scan ssid"; 61 private static final int DFS_CHANNEL_FREQ = 5540; 62 63 @Mock private Context mContext; 64 @Mock private WakeupLock mWakeupLock; 65 @Mock private WakeupEvaluator mWakeupEvaluator; 66 @Mock private WakeupOnboarding mWakeupOnboarding; 67 @Mock private WifiConfigStore mWifiConfigStore; 68 @Mock private WifiInjector mWifiInjector; 69 @Mock private WifiScanner mWifiScanner; 70 @Mock private WifiConfigManager mWifiConfigManager; 71 @Mock private FrameworkFacade mFrameworkFacade; 72 @Mock private WifiSettingsStore mWifiSettingsStore; 73 @Mock private WifiWakeMetrics mWifiWakeMetrics; 74 @Mock private WifiController mWifiController; 75 @Mock private WifiNative mWifiNative; 76 77 private TestLooper mLooper; 78 private WakeupController mWakeupController; 79 private WakeupConfigStoreData mWakeupConfigStoreData; 80 private WifiScanner.ScanData[] mTestScanDatas; 81 private ScanResult mTestScanResult; 82 83 /** Initialize objects before each test run. */ 84 @Before 85 public void setUp() { 86 MockitoAnnotations.initMocks(this); 87 88 when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner); 89 when(mWifiInjector.getWifiSettingsStore()).thenReturn(mWifiSettingsStore); 90 when(mWifiInjector.getWifiController()).thenReturn(mWifiController); 91 when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative); 92 when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY)) 93 .thenReturn(new int[]{DFS_CHANNEL_FREQ}); 94 95 when(mWifiSettingsStore.handleWifiToggled(anyBoolean())).thenReturn(true); 96 97 mLooper = new TestLooper(); 98 99 // scanlistener input 100 mTestScanResult = new ScanResult(); 101 mTestScanResult.SSID = SAVED_SSID; 102 mTestScanResult.capabilities = ""; 103 mTestScanResult.frequency = 2412; 104 ScanResult[] scanResults = new ScanResult[1]; 105 scanResults[0] = mTestScanResult; 106 mTestScanDatas = new WifiScanner.ScanData[1]; 107 mTestScanDatas[0] = new WifiScanner.ScanData(0 /* id */, 0 /* flags */, 108 0 /* bucketsScanned */, true /* allChannelsScanned */, scanResults); 109 } 110 111 /** Initializes the wakeupcontroller in the given {@code enabled} state. */ 112 private void initializeWakeupController(boolean enabled) { 113 initializeWakeupController(enabled, true /* isRead */); 114 } 115 116 private void initializeWakeupController(boolean enabled, boolean isRead) { 117 int settingsValue = enabled ? 1 : 0; 118 when(mFrameworkFacade.getIntegerSetting(mContext, 119 Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(settingsValue); 120 when(mWakeupOnboarding.isOnboarded()).thenReturn(true); 121 mWakeupController = new WakeupController(mContext, 122 mLooper.getLooper(), 123 mWakeupLock, 124 mWakeupEvaluator, 125 mWakeupOnboarding, 126 mWifiConfigManager, 127 mWifiConfigStore, 128 mWifiWakeMetrics, 129 mWifiInjector, 130 mFrameworkFacade); 131 132 ArgumentCaptor<WakeupConfigStoreData> captor = 133 ArgumentCaptor.forClass(WakeupConfigStoreData.class); 134 verify(mWifiConfigStore).registerStoreData(captor.capture()); 135 mWakeupConfigStoreData = captor.getValue(); 136 if (isRead) { 137 readUserStore(); 138 } 139 } 140 141 private void readUserStore() { 142 try { 143 mWakeupConfigStoreData.deserializeData(null, 0, false); 144 } catch (XmlPullParserException | IOException e) { 145 // unreachable 146 } 147 } 148 149 private ScanResult createOpenScanResult(String ssid, int frequency) { 150 ScanResult scanResult = new ScanResult(); 151 scanResult.SSID = ssid; 152 scanResult.capabilities = ""; 153 scanResult.frequency = frequency; 154 return scanResult; 155 } 156 157 private void verifyDoesNotEnableWifi() { 158 verify(mWifiSettingsStore, never()).handleWifiToggled(true /* wifiEnabled */); 159 } 160 161 /** 162 * Verify WakeupController is enabled when the settings toggle is true. 163 */ 164 @Test 165 public void verifyEnabledWhenToggledOn() { 166 initializeWakeupController(true /* enabled */); 167 168 assertTrue(mWakeupController.isEnabled()); 169 } 170 171 /** 172 * Verify WakeupController is disabled when the settings toggle is false. 173 */ 174 @Test 175 public void verifyDisabledWhenToggledOff() { 176 initializeWakeupController(false /* enabled */); 177 178 assertFalse(mWakeupController.isEnabled()); 179 } 180 181 /** 182 * Verify WakeupController registers its store data with the WifiConfigStore on construction. 183 */ 184 @Test 185 public void registersWakeupConfigStoreData() { 186 initializeWakeupController(true /* enabled */); 187 verify(mWifiConfigStore).registerStoreData(any(WakeupConfigStoreData.class)); 188 } 189 190 /** 191 * Verify that dump calls also dump the state of the WakeupLock. 192 */ 193 @Test 194 public void dumpIncludesWakeupLock() { 195 initializeWakeupController(true /* enabled */); 196 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 197 PrintWriter writer = new PrintWriter(stream); 198 mWakeupController.dump(null, writer, null); 199 200 verify(mWakeupLock).dump(null, writer, null); 201 } 202 203 /** 204 * Verify that start sets the wakeup lock. 205 */ 206 @Test 207 public void startSetsWakeupLock() { 208 initializeWakeupController(true /* enabled */); 209 mWakeupController.start(); 210 verify(mWakeupLock).setLock(any()); 211 verify(mWifiWakeMetrics).recordStartEvent(anyInt()); 212 } 213 214 /** 215 * Verify that start does not record an ignored start call if the controller is not yet active. 216 */ 217 @Test 218 public void startDoesNotRecordIgnoredStart() { 219 initializeWakeupController(true /* enabled */); 220 mWakeupController.start(); 221 verify(mWifiWakeMetrics, never()).recordIgnoredStart(); 222 } 223 224 /** 225 * Verify that start does not set the wakeup lock when feature is disabled. 226 */ 227 @Test 228 public void startDoesNotSetWakeupLockWhenDisabled() { 229 initializeWakeupController(false /* enabled */); 230 mWakeupController.start(); 231 verify(mWakeupLock, never()).setLock(any()); 232 verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt()); 233 } 234 235 /** 236 * If the controller is already active, verify that start() is ignored and no setup is done. 237 */ 238 @Test 239 public void startIsIgnoredIfAlreadyActive() { 240 initializeWakeupController(true /* enabled */); 241 InOrder lockInOrder = Mockito.inOrder(mWakeupLock); 242 InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics); 243 244 mWakeupController.start(); 245 lockInOrder.verify(mWakeupLock).setLock(any()); 246 metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt()); 247 248 mWakeupController.stop(); 249 mWakeupController.start(); 250 metricsInOrder.verify(mWifiWakeMetrics).recordIgnoredStart(); 251 metricsInOrder.verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt()); 252 lockInOrder.verify(mWakeupLock, never()).setLock(any()); 253 } 254 255 /** 256 * Verify that start registers the scan listener on the wifi scanner. 257 */ 258 @Test 259 public void startRegistersScanListener() { 260 initializeWakeupController(true /* enabled */); 261 mWakeupController.start(); 262 verify(mWifiScanner).registerScanListener(any()); 263 } 264 265 /** 266 * Verify that stop deregisters the scan listener from the wifi scanner. 267 */ 268 @Test 269 public void stopDeresgistersScanListener() { 270 initializeWakeupController(true /* enabled */); 271 mWakeupController.start(); 272 mWakeupController.stop(); 273 verify(mWifiScanner).deregisterScanListener(any()); 274 } 275 276 /** 277 * Verify that reset sets active to false. 278 * 279 * <p>This is accomplished by initiating another call to start and verifying that the wakeup 280 * lock is re-set. 281 */ 282 @Test 283 public void resetSetsActiveToFalse() { 284 initializeWakeupController(true /* enabled */); 285 InOrder lockInOrder = Mockito.inOrder(mWakeupLock); 286 InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics); 287 288 mWakeupController.start(); 289 lockInOrder.verify(mWakeupLock).setLock(any()); 290 metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt()); 291 292 mWakeupController.stop(); 293 mWakeupController.reset(); 294 metricsInOrder.verify(mWifiWakeMetrics).recordResetEvent(0 /* numScans */); 295 296 mWakeupController.start(); 297 lockInOrder.verify(mWakeupLock).setLock(any()); 298 metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt()); 299 } 300 301 /** 302 * Verify that the wakeup lock is initialized with the intersection of ScanResults and saved 303 * networks. 304 */ 305 @Test 306 public void startInitializesWakeupLockWithSavedScanResults() { 307 String ssid1 = "ssid 1"; 308 String ssid2 = "ssid 2"; 309 String quotedSsid = ScanResultUtil.createQuotedSSID(ssid1); 310 311 // saved configs 312 WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(quotedSsid); 313 openNetwork.getNetworkSelectionStatus().setHasEverConnected(true); 314 WifiConfiguration wepNetwork = WifiConfigurationTestUtil.createWepNetwork(); 315 wepNetwork.getNetworkSelectionStatus().setHasEverConnected(true); 316 when(mWifiConfigManager.getSavedNetworks()) 317 .thenReturn(Arrays.asList(openNetwork, wepNetwork)); 318 319 // scan results from most recent scan 320 ScanResult savedScanResult = createOpenScanResult(ssid1, 2412 /* frequency */); 321 ScanResult unsavedScanResult = createOpenScanResult(ssid2, 2412 /* frequency */); 322 323 when(mWifiScanner.getSingleScanResults()) 324 .thenReturn(Arrays.asList(savedScanResult, unsavedScanResult)); 325 326 // intersection of most recent scan + saved configs 327 Set<ScanResultMatchInfo> expectedMatchInfos = 328 Collections.singleton(ScanResultMatchInfo.fromScanResult(savedScanResult)); 329 330 initializeWakeupController(true /* enabled */); 331 mWakeupController.start(); 332 verify(mWakeupLock).setLock(eq(expectedMatchInfos)); 333 verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size()); 334 } 335 336 /** 337 * Verify that start filters out DFS channels. 338 */ 339 @Test 340 public void startFiltersOutDfsScanResults() { 341 String ssidDfs = "DFS scan"; 342 String ssid24 = "2.4 scan"; 343 344 // saved configs 345 WifiConfiguration openNetworkDfs = WifiConfigurationTestUtil 346 .createOpenNetwork(ScanResultUtil.createQuotedSSID(ssidDfs)); 347 openNetworkDfs.getNetworkSelectionStatus().setHasEverConnected(true); 348 WifiConfiguration openNetwork24 = WifiConfigurationTestUtil 349 .createOpenNetwork(ScanResultUtil.createQuotedSSID(ssid24)); 350 openNetwork24.getNetworkSelectionStatus().setHasEverConnected(true); 351 352 when(mWifiConfigManager.getSavedNetworks()) 353 .thenReturn(Arrays.asList(openNetworkDfs, openNetwork24)); 354 355 // scan results from most recent scan 356 ScanResult scanResultDfs = createOpenScanResult(ssidDfs, DFS_CHANNEL_FREQ); 357 ScanResult scanResult24 = createOpenScanResult(ssid24, 2412 /* frequency */); 358 359 when(mWifiScanner.getSingleScanResults()) 360 .thenReturn(Arrays.asList(scanResultDfs, scanResult24)); 361 362 // should filter out scanResultDfs 363 Set<ScanResultMatchInfo> expectedMatchInfos = 364 Collections.singleton(ScanResultMatchInfo.fromScanResult(scanResult24)); 365 366 initializeWakeupController(true /* enabled */); 367 mWakeupController.start(); 368 verify(mWakeupLock).setLock(eq(expectedMatchInfos)); 369 verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size()); 370 } 371 372 /** 373 * Verify that onResults updates the WakeupLock. 374 */ 375 @Test 376 public void onResultsUpdatesWakeupLock() { 377 // saved config 378 WifiConfiguration openNetwork = WifiConfigurationTestUtil 379 .createOpenNetwork(ScanResultUtil.createQuotedSSID(SAVED_SSID)); 380 openNetwork.getNetworkSelectionStatus().setHasEverConnected(true); 381 when(mWifiConfigManager.getSavedNetworks()) 382 .thenReturn(Collections.singletonList(openNetwork)); 383 384 initializeWakeupController(true /* enabled */); 385 mWakeupController.start(); 386 387 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 388 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 389 390 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 391 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 392 393 // incoming scan results 394 scanListener.onResults(mTestScanDatas); 395 396 ScanResultMatchInfo expectedMatchInfo = ScanResultMatchInfo.fromScanResult(mTestScanResult); 397 verify(mWakeupLock).update(eq(Collections.singleton(expectedMatchInfo))); 398 } 399 400 401 /** 402 * Verify that onResults filters out unsaved networks when updating the WakeupLock. 403 */ 404 @Test 405 public void onResultsUpdatesWakeupLockWithOnlySavedNetworks() { 406 // no saved configs 407 when(mWifiConfigManager.getSavedNetworks()).thenReturn(Collections.emptyList()); 408 409 initializeWakeupController(true /* enabled */); 410 mWakeupController.start(); 411 412 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 413 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 414 415 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 416 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 417 418 // incoming scan results 419 scanListener.onResults(mTestScanDatas); 420 421 verify(mWakeupLock).update(eq(Collections.emptySet())); 422 } 423 424 /** 425 * Verify that onResults filters out DFS channels. 426 */ 427 @Test 428 public void onResultsFiltersOutDfsScanResults() { 429 initializeWakeupController(true /* enabled */); 430 mWakeupController.start(); 431 432 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 433 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 434 435 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 436 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 437 438 // incoming scan results 439 mTestScanResult.frequency = DFS_CHANNEL_FREQ; 440 scanListener.onResults(mTestScanDatas); 441 442 verify(mWakeupLock).update(eq(Collections.emptySet())); 443 } 444 445 /** 446 * Verify that the controller searches for viable networks during onResults when WakeupLock is 447 * unlocked. 448 */ 449 @Test 450 public void onResultsSearchesForViableNetworkWhenWakeupLockIsUnlocked() { 451 // unlock wakeup lock 452 when(mWakeupLock.isUnlocked()).thenReturn(true); 453 // do not find viable network 454 when(mWakeupEvaluator.findViableNetwork(any(), any())).thenReturn(null); 455 456 initializeWakeupController(true /* enabled */); 457 mWakeupController.start(); 458 459 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 460 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 461 462 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 463 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 464 465 // incoming scan results 466 scanListener.onResults(mTestScanDatas); 467 468 verify(mWakeupEvaluator).findViableNetwork(any(), any()); 469 verifyDoesNotEnableWifi(); 470 } 471 472 /** 473 * Verify that the controller updates the WakeupLock even if the user is not onboarded. 474 */ 475 @Test 476 public void onResultsUpdatesIfNotOnboarded() { 477 initializeWakeupController(true /* enabled */); 478 when(mWakeupOnboarding.isOnboarded()).thenReturn(false); 479 when(mWakeupLock.isUnlocked()).thenReturn(false); 480 mWakeupController.start(); 481 482 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 483 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 484 485 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 486 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 487 488 // incoming scan results 489 scanListener.onResults(mTestScanDatas); 490 491 verify(mWakeupLock).update(any()); 492 verify(mWakeupLock).isUnlocked(); 493 verifyDoesNotEnableWifi(); 494 } 495 496 /** 497 * Verify that the controller enables wifi and notifies user when all criteria are met. 498 */ 499 @Test 500 public void onResultsEnablesWifi() { 501 // unlock wakeup lock 502 when(mWakeupLock.isUnlocked()).thenReturn(true); 503 // find viable network 504 when(mWakeupEvaluator.findViableNetwork(any(), any())).thenReturn(mTestScanResult); 505 506 initializeWakeupController(true /* enabled */); 507 mWakeupController.start(); 508 509 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 510 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 511 512 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 513 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 514 515 // incoming scan results 516 scanListener.onResults(mTestScanDatas); 517 518 verify(mWakeupEvaluator).findViableNetwork(any(), any()); 519 verify(mWifiSettingsStore).handleWifiToggled(true /* wifiEnabled */); 520 verify(mWifiWakeMetrics).recordWakeupEvent(1 /* numScans */); 521 } 522 523 /** 524 * Verify that the controller will not do any work if the user store has not been read. 525 */ 526 @Test 527 public void controllerDoesNoWorkIfUserStoreIsNotRead() { 528 initializeWakeupController(true /* enabled */, false /* isRead */); 529 mWakeupController.start(); 530 531 ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor = 532 ArgumentCaptor.forClass(WifiScanner.ScanListener.class); 533 534 verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture()); 535 WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue(); 536 537 // incoming scan results 538 scanListener.onResults(mTestScanDatas); 539 540 verify(mWakeupLock, never()).setLock(any()); 541 verify(mWakeupLock, never()).update(any()); 542 verify(mWakeupLock, never()).isUnlocked(); 543 verify(mWakeupOnboarding, never()).maybeShowNotification(); 544 verify(mWakeupEvaluator, never()).findViableNetwork(any(), any()); 545 } 546 547 @Test 548 public void userIsNotOnboardedByInitialization() { 549 initializeWakeupController(true /* enabled */); 550 verify(mWakeupOnboarding, never()).setOnboarded(); 551 } 552 553 @Test 554 public void userIsOnboardedBySettingChange() { 555 initializeWakeupController(true /* enabled */); 556 ArgumentCaptor<ContentObserver> argumentCaptor = 557 ArgumentCaptor.forClass(ContentObserver.class); 558 verify(mFrameworkFacade).registerContentObserver(any(), any(), eq(true), 559 argumentCaptor.capture()); 560 ContentObserver contentObserver = argumentCaptor.getValue(); 561 contentObserver.onChange(false /* selfChange */); 562 verify(mWakeupOnboarding).setOnboarded(); 563 } 564} 565