SupplicantPnoScannerTest.java revision a8367288377cbaed6371256ca837b7aa22280706
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.scanner; 18 19import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder; 20import static com.android.server.wifi.ScanTestUtil.assertScanDataEquals; 21 22import static org.junit.Assert.*; 23import static org.mockito.Mockito.*; 24 25import android.content.Context; 26import android.net.wifi.WifiConfiguration; 27import android.net.wifi.WifiScanner; 28import android.test.suitebuilder.annotation.SmallTest; 29 30import com.android.internal.R; 31import com.android.server.wifi.MockAlarmManager; 32import com.android.server.wifi.MockLooper; 33import com.android.server.wifi.MockResources; 34import com.android.server.wifi.MockWifiMonitor; 35import com.android.server.wifi.ScanResults; 36import com.android.server.wifi.WifiMonitor; 37import com.android.server.wifi.WifiNative; 38import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 39 40import org.junit.Before; 41import org.junit.Test; 42import org.mockito.InOrder; 43import org.mockito.Mock; 44import org.mockito.MockitoAnnotations; 45 46import java.util.HashSet; 47import java.util.Set; 48 49 50/** 51 * Unit tests for {@link com.android.server.wifi.scanner.SupplicantWifiScannerImpl.setPnoList}. 52 */ 53@SmallTest 54public class SupplicantPnoScannerTest { 55 56 @Mock Context mContext; 57 MockAlarmManager mAlarmManager; 58 MockWifiMonitor mWifiMonitor; 59 MockLooper mLooper; 60 @Mock WifiNative mWifiNative; 61 MockResources mResources; 62 SupplicantWifiScannerImpl mScanner; 63 64 @Before 65 public void setup() throws Exception { 66 MockitoAnnotations.initMocks(this); 67 68 mLooper = new MockLooper(); 69 mAlarmManager = new MockAlarmManager(); 70 mWifiMonitor = new MockWifiMonitor(); 71 mResources = new MockResources(); 72 73 when(mWifiNative.getInterfaceName()).thenReturn("a_test_interface_name"); 74 when(mContext.getSystemService(Context.ALARM_SERVICE)) 75 .thenReturn(mAlarmManager.getAlarmManager()); 76 when(mContext.getResources()).thenReturn(mResources); 77 } 78 79 /** 80 * Verify that the HW disconnected PNO scan triggers a supplicant PNO scan and invokes the 81 * OnPnoNetworkFound callback when the scan results are received. 82 */ 83 @Test 84 public void startHwDisconnectedPnoScan() { 85 createScannerWithHwPnoScanSupport(); 86 87 WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); 88 WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); 89 ScanResults scanResults = createDummyScanResults(); 90 91 InOrder order = inOrder(pnoEventHandler, mWifiNative); 92 // Start PNO scan 93 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 94 expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults); 95 verifyNoMoreInteractions(pnoEventHandler); 96 } 97 98 /** 99 * Verify that we pause & resume HW PNO scan when a single scan is scheduled and invokes the 100 * OnPnoNetworkFound callback when the scan results are received. 101 */ 102 @Test 103 public void pauseResumeHwDisconnectedPnoScanForSingleScan() { 104 createScannerWithHwPnoScanSupport(); 105 106 WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); 107 WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); 108 WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); 109 WifiNative.ScanSettings settings = createDummyScanSettings(); 110 ScanResults scanResults = createDummyScanResults(); 111 112 InOrder order = inOrder(eventHandler, mWifiNative); 113 // Start PNO scan 114 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 115 // Start single scan 116 assertTrue(mScanner.startSingleScan(settings, eventHandler)); 117 // Verify that the PNO scan was paused and single scan runs successfully 118 expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler, 119 expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(), 120 scanResults); 121 verifyNoMoreInteractions(eventHandler); 122 123 order = inOrder(pnoEventHandler, mWifiNative); 124 // Resume PNO scan after the single scan results are received and PNO monitor debounce 125 // alarm fires. 126 assertTrue("dispatch pno monitor alarm", 127 mAlarmManager.dispatch( 128 SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); 129 assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll()); 130 // Now verify that PNO scan is resumed successfully 131 expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults); 132 verifyNoMoreInteractions(pnoEventHandler); 133 } 134 135 /** 136 * Verify that the SW disconnected PNO scan triggers a background scan and invokes the 137 * background scan callbacks when scan results are received. 138 */ 139 @Test 140 public void startSwDisconnectedPnoScan() { 141 createScannerWithSwPnoScanSupport(); 142 doSuccessfulSwPnoScanTest(false); 143 } 144 145 /** 146 * Verify that the HW connected PNO scan triggers a background scan and invokes the 147 * background scan callbacks when scan results are received. 148 */ 149 @Test 150 public void startHwConnectedPnoScan() { 151 createScannerWithHwPnoScanSupport(); 152 doSuccessfulSwPnoScanTest(true); 153 } 154 155 /** 156 * Verify that the SW connected PNO scan triggers a background scan and invokes the 157 * background scan callbacks when scan results are received. 158 */ 159 @Test 160 public void startSwConnectedPnoScan() { 161 createScannerWithSwPnoScanSupport(); 162 doSuccessfulSwPnoScanTest(true); 163 } 164 165 /** 166 * Verify that the HW PNO delayed failure cleans up the scan settings cleanly. 167 * 1. Start Hw PNO. 168 * 2. Start Single Scan which should pause PNO scan. 169 * 3. Fail the PNO scan resume and verify that the OnPnoScanFailed callback is invoked. 170 * 4. Now restart a new PNO scan to ensure that the failure was cleanly handled. 171 */ 172 @Test 173 public void delayedHwDisconnectedPnoScanFailure() { 174 createScannerWithHwPnoScanSupport(); 175 176 WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); 177 WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); 178 WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); 179 WifiNative.ScanSettings settings = createDummyScanSettings(); 180 ScanResults scanResults = createDummyScanResults(); 181 182 InOrder order = inOrder(eventHandler, mWifiNative); 183 // Start PNO scan 184 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 185 // Start single scan 186 assertTrue(mScanner.startSingleScan(settings, eventHandler)); 187 // Verify that the PNO scan was paused and single scan runs successfully 188 expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler, 189 expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(), 190 scanResults); 191 verifyNoMoreInteractions(eventHandler); 192 193 // Fail the PNO resume and check that the OnPnoScanFailed callback is invoked. 194 order = inOrder(pnoEventHandler, mWifiNative); 195 when(mWifiNative.setPnoScan(true)).thenReturn(false); 196 assertTrue("dispatch pno monitor alarm", 197 mAlarmManager.dispatch( 198 SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); 199 assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll()); 200 order.verify(pnoEventHandler).onPnoScanFailed(); 201 verifyNoMoreInteractions(pnoEventHandler); 202 203 // Add a new PNO scan request 204 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 205 assertTrue("dispatch pno monitor alarm", 206 mAlarmManager.dispatch( 207 SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG)); 208 assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll()); 209 expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults); 210 verifyNoMoreInteractions(pnoEventHandler); 211 } 212 213 private void doSuccessfulSwPnoScanTest(boolean isConnectedPno) { 214 WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); 215 WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(isConnectedPno); 216 WifiNative.ScanEventHandler scanEventHandler = mock(WifiNative.ScanEventHandler.class); 217 WifiNative.ScanSettings scanSettings = createDummyScanSettings(); 218 ScanResults scanResults = createDummyScanResults(); 219 220 InOrder order = inOrder(scanEventHandler, mWifiNative); 221 222 // Start PNO scan 223 startSuccessfulPnoScan(scanSettings, pnoSettings, scanEventHandler, pnoEventHandler); 224 225 expectSuccessfulSwPnoScan(order, scanEventHandler, scanResults); 226 227 verifyNoMoreInteractions(pnoEventHandler); 228 } 229 230 private void createScannerWithHwPnoScanSupport() { 231 mResources.setBoolean(R.bool.config_wifi_background_scan_support, true); 232 mScanner = new SupplicantWifiScannerImpl(mContext, mWifiNative, mLooper.getLooper()); 233 } 234 235 private void createScannerWithSwPnoScanSupport() { 236 mResources.setBoolean(R.bool.config_wifi_background_scan_support, false); 237 mScanner = new SupplicantWifiScannerImpl(mContext, mWifiNative, mLooper.getLooper()); 238 } 239 240 private WifiNative.PnoSettings createDummyPnoSettings(boolean isConnected) { 241 WifiNative.PnoSettings pnoSettings = new WifiNative.PnoSettings(); 242 pnoSettings.isConnected = isConnected; 243 pnoSettings.networkList = new WifiNative.PnoNetwork[2]; 244 pnoSettings.networkList[0] = new WifiNative.PnoNetwork(); 245 pnoSettings.networkList[0].ssid = "ssid_pno_1"; 246 pnoSettings.networkList[0].networkId = 1; 247 pnoSettings.networkList[0].priority = 1; 248 pnoSettings.networkList[1] = new WifiNative.PnoNetwork(); 249 pnoSettings.networkList[1].ssid = "ssid_pno_2"; 250 pnoSettings.networkList[1].networkId = 2; 251 pnoSettings.networkList[1].priority = 2; 252 return pnoSettings; 253 } 254 255 private WifiNative.ScanSettings createDummyScanSettings() { 256 WifiNative.ScanSettings settings = new NativeScanSettingsBuilder() 257 .withBasePeriod(10000) 258 .withMaxApPerScan(10) 259 .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 260 WifiScanner.WIFI_BAND_24_GHZ) 261 .build(); 262 return settings; 263 } 264 265 private ScanResults createDummyScanResults() { 266 return ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450); 267 } 268 269 private void startSuccessfulPnoScan(WifiNative.ScanSettings scanSettings, 270 WifiNative.PnoSettings pnoSettings, WifiNative.ScanEventHandler scanEventHandler, 271 WifiNative.PnoEventHandler pnoEventHandler) { 272 when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true); 273 when(mWifiNative.enableNetworkWithoutConnect(anyInt())).thenReturn(true); 274 // Scans succeed 275 when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true); 276 when(mWifiNative.setPnoScan(anyBoolean())).thenReturn(true); 277 278 if (mScanner.isHwPnoSupported(pnoSettings.isConnected)) { 279 // This should happen only for HW PNO scan 280 assertTrue(mScanner.setHwPnoList(pnoSettings, pnoEventHandler)); 281 } else { 282 // This should happen only for SW PNO scan 283 assertTrue(mScanner.startBatchedScan(scanSettings, scanEventHandler)); 284 285 } 286 } 287 288 private Set<Integer> expectedBandScanFreqs(int band) { 289 ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection(); 290 collection.addBand(band); 291 return collection.getSupplicantScanFreqs(); 292 } 293 294 /** 295 * Verify that the PNO scan was successfully started. 296 */ 297 private void expectSuccessfulHwDisconnectedPnoScan(InOrder order, 298 WifiNative.PnoSettings pnoSettings, WifiNative.PnoEventHandler eventHandler, 299 ScanResults scanResults) { 300 for (int i = 0; i < pnoSettings.networkList.length; i++) { 301 WifiNative.PnoNetwork network = pnoSettings.networkList[i]; 302 order.verify(mWifiNative).setNetworkVariable(network.networkId, 303 WifiConfiguration.priorityVarName, Integer.toString(network.priority)); 304 order.verify(mWifiNative).enableNetworkWithoutConnect(network.networkId); 305 } 306 // Verify HW PNO scan started 307 order.verify(mWifiNative).setPnoScan(true); 308 309 // Setup scan results 310 when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList()); 311 312 // Notify scan has finished 313 mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT); 314 assertEquals("dispatch message after results event", 1, mLooper.dispatchAll()); 315 316 order.verify(eventHandler).onPnoNetworkFound(scanResults.getRawScanResults()); 317 } 318 319 /** 320 * Verify that the single scan results were delivered and that the PNO scan was paused and 321 * resumed either side of it. 322 */ 323 private void expectSuccessfulSingleScanWithHwPnoEnabled(InOrder order, 324 WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScanFreqs, 325 Set<Integer> expectedHiddenNetIds, ScanResults scanResults) { 326 // Pause PNO scan first 327 order.verify(mWifiNative).setPnoScan(false); 328 329 order.verify(mWifiNative).scan(eq(expectedScanFreqs), eq(expectedHiddenNetIds)); 330 331 when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList()); 332 333 // Notify scan has finished 334 mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT); 335 assertEquals("dispatch message after results event", 1, mLooper.dispatchAll()); 336 337 order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); 338 assertScanDataEquals(scanResults.getScanData(), mScanner.getLatestSingleScanResults()); 339 } 340 341 /** 342 * Verify that the SW PNO scan was successfully started. This could either be disconnected 343 * or connected PNO. 344 * This is basically ensuring that the background scan runs successfully and returns the 345 * expected result. 346 */ 347 private void expectSuccessfulSwPnoScan(InOrder order, 348 WifiNative.ScanEventHandler eventHandler, ScanResults scanResults) { 349 350 // Verify scan started 351 order.verify(mWifiNative).scan(any(Set.class), any(Set.class)); 352 353 // Make sure that HW PNO scan was not started 354 verify(mWifiNative, never()).setPnoScan(anyBoolean()); 355 356 // Setup scan results 357 when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList()); 358 359 // Notify scan has finished 360 mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT); 361 assertEquals("dispatch message after results event", 1, mLooper.dispatchAll()); 362 363 // Verify background scan results delivered 364 order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); 365 WifiScanner.ScanData[] scanData = mScanner.getLatestBatchedScanResults(true); 366 WifiScanner.ScanData lastScanData = scanData[scanData.length -1]; 367 assertScanDataEquals(scanResults.getScanData(), lastScanData); 368 } 369} 370