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