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 17 package com.android.server.wifi.scanner; 18 19 import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder; 20 import static com.android.server.wifi.ScanTestUtil.setupMockChannels; 21 22 import static org.junit.Assert.*; 23 import static org.mockito.Mockito.*; 24 25 import android.app.test.TestAlarmManager; 26 import android.content.Context; 27 import android.net.wifi.WifiScanner; 28 import android.os.SystemClock; 29 import android.os.test.TestLooper; 30 import android.support.test.filters.SmallTest; 31 32 import com.android.internal.R; 33 import com.android.server.wifi.Clock; 34 import com.android.server.wifi.MockResources; 35 import com.android.server.wifi.MockWifiMonitor; 36 import com.android.server.wifi.ScanResults; 37 import com.android.server.wifi.WifiMonitor; 38 import com.android.server.wifi.WifiNative; 39 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.mockito.InOrder; 44 import org.mockito.Mock; 45 import org.mockito.MockitoAnnotations; 46 47 import java.util.Set; 48 49 /** 50 * Unit tests for {@link com.android.server.wifi.scanner.WificondScannerImpl.setPnoList}. 51 */ 52 @SmallTest 53 public class WificondPnoScannerTest { 54 private static final String IFACE_NAME = "a_test_interface_name"; 55 56 @Mock Context mContext; 57 TestAlarmManager mAlarmManager; 58 MockWifiMonitor mWifiMonitor; 59 TestLooper mLooper; 60 @Mock WifiNative mWifiNative; 61 MockResources mResources; 62 @Mock Clock mClock; 63 WificondScannerImpl mScanner; 64 65 @Before 66 public void setup() throws Exception { 67 MockitoAnnotations.initMocks(this); 68 69 mLooper = new TestLooper(); 70 mAlarmManager = new TestAlarmManager(); 71 mWifiMonitor = new MockWifiMonitor(); 72 mResources = new MockResources(); 73 74 setupMockChannels(mWifiNative, 75 new int[]{2400, 2450}, 76 new int[]{5150, 5175}, 77 new int[]{5600, 5650}); 78 79 when(mWifiNative.getClientInterfaceName()).thenReturn(IFACE_NAME); 80 when(mContext.getSystemService(Context.ALARM_SERVICE)) 81 .thenReturn(mAlarmManager.getAlarmManager()); 82 when(mContext.getResources()).thenReturn(mResources); 83 when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()); 84 } 85 86 /** 87 * Verify that the HW disconnected PNO scan triggers a wificond PNO scan and invokes the 88 * OnPnoNetworkFound callback when the scan results are received. 89 */ 90 @Test 91 public void startHwDisconnectedPnoScan() { 92 createScannerWithHwPnoScanSupport(); 93 94 WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); 95 WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); 96 ScanResults scanResults = createDummyScanResults(false); 97 98 InOrder order = inOrder(pnoEventHandler, mWifiNative); 99 // Start PNO scan 100 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 101 expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults); 102 verifyNoMoreInteractions(pnoEventHandler); 103 } 104 105 /** 106 * Verify that the HW PNO scan stop failure still resets the PNO scan state. 107 * 1. Start Hw PNO. 108 * 2. Stop Hw PNO scan which raises a stop command to WifiNative which is failed. 109 * 3. Now restart a new PNO scan to ensure that the failure was cleanly handled. 110 */ 111 @Test 112 public void ignoreHwDisconnectedPnoScanStopFailure() { 113 createScannerWithHwPnoScanSupport(); 114 115 WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class); 116 WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false); 117 118 // Start PNO scan 119 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 120 121 // Fail the PNO stop. 122 when(mWifiNative.stopPnoScan(IFACE_NAME)).thenReturn(false); 123 assertTrue(mScanner.resetHwPnoList()); 124 mLooper.dispatchAll(); 125 verify(mWifiNative).stopPnoScan(IFACE_NAME); 126 127 // Add a new PNO scan request and ensure it runs successfully. 128 startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler); 129 mLooper.dispatchAll(); 130 InOrder order = inOrder(pnoEventHandler, mWifiNative); 131 ScanResults scanResults = createDummyScanResults(false); 132 expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults); 133 verifyNoMoreInteractions(pnoEventHandler); 134 } 135 136 private void createScannerWithHwPnoScanSupport() { 137 mResources.setBoolean(R.bool.config_wifi_background_scan_support, true); 138 mScanner = new WificondScannerImpl(mContext, IFACE_NAME, mWifiNative, mWifiMonitor, 139 new WificondChannelHelper(mWifiNative), mLooper.getLooper(), mClock); 140 } 141 142 private WifiNative.PnoNetwork createDummyPnoNetwork(String ssid) { 143 WifiNative.PnoNetwork pnoNetwork = new WifiNative.PnoNetwork(); 144 pnoNetwork.ssid = ssid; 145 return pnoNetwork; 146 } 147 148 private WifiNative.PnoSettings createDummyPnoSettings(boolean isConnected) { 149 WifiNative.PnoSettings pnoSettings = new WifiNative.PnoSettings(); 150 pnoSettings.isConnected = isConnected; 151 pnoSettings.networkList = new WifiNative.PnoNetwork[2]; 152 pnoSettings.networkList[0] = createDummyPnoNetwork("ssid_pno_1"); 153 pnoSettings.networkList[1] = createDummyPnoNetwork("ssid_pno_2"); 154 return pnoSettings; 155 } 156 157 private WifiNative.ScanSettings createDummyScanSettings(boolean allChannelsScanned) { 158 WifiNative.ScanSettings settings = new NativeScanSettingsBuilder() 159 .withBasePeriod(10000) 160 .withMaxApPerScan(10) 161 .addBucketWithBand( 162 10000, 163 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 164 allChannelsScanned 165 ? WifiScanner.WIFI_BAND_BOTH_WITH_DFS : WifiScanner.WIFI_BAND_24_GHZ) 166 .build(); 167 return settings; 168 } 169 170 private ScanResults createDummyScanResults(boolean allChannelsScanned) { 171 return ScanResults.create(0, allChannelsScanned, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 172 2450, 2450); 173 } 174 175 private void startSuccessfulPnoScan(WifiNative.ScanSettings scanSettings, 176 WifiNative.PnoSettings pnoSettings, WifiNative.ScanEventHandler scanEventHandler, 177 WifiNative.PnoEventHandler pnoEventHandler) { 178 // Scans succeed 179 when(mWifiNative.scan(eq(IFACE_NAME), anyInt(), any(), any(Set.class))).thenReturn(true); 180 when(mWifiNative.startPnoScan(eq(IFACE_NAME), any(WifiNative.PnoSettings.class))) 181 .thenReturn(true); 182 when(mWifiNative.stopPnoScan(IFACE_NAME)).thenReturn(true); 183 184 assertTrue(mScanner.setHwPnoList(pnoSettings, pnoEventHandler)); 185 } 186 187 private Set<Integer> expectedBandScanFreqs(int band) { 188 ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection(); 189 collection.addBand(band); 190 return collection.getScanFreqs(); 191 } 192 193 /** 194 * Verify that the PNO scan was successfully started. 195 */ 196 private void expectHwDisconnectedPnoScanStart(InOrder order, 197 WifiNative.PnoSettings pnoSettings) { 198 // Verify HW PNO scan started 199 order.verify(mWifiNative).startPnoScan(any(), any(WifiNative.PnoSettings.class)); 200 } 201 202 /** 203 * 204 * 1. Verify that the PNO scan was successfully started. 205 * 2. Send scan results and ensure that the |onPnoNetworkFound| callback was called. 206 */ 207 private void expectSuccessfulHwDisconnectedPnoScan(InOrder order, 208 WifiNative.PnoSettings pnoSettings, WifiNative.PnoEventHandler eventHandler, 209 ScanResults scanResults) { 210 expectHwDisconnectedPnoScanStart(order, pnoSettings); 211 212 // Setup scan results 213 when(mWifiNative.getPnoScanResults(IFACE_NAME)) 214 .thenReturn(scanResults.getScanDetailArrayList()); 215 when(mWifiNative.getScanResults(IFACE_NAME)) 216 .thenReturn(scanResults.getScanDetailArrayList()); 217 218 // Notify scan has finished 219 mWifiMonitor.sendMessage(IFACE_NAME, WifiMonitor.PNO_SCAN_RESULTS_EVENT); 220 assertEquals("dispatch message after results event", 1, mLooper.dispatchAll()); 221 222 order.verify(eventHandler).onPnoNetworkFound(scanResults.getRawScanResults()); 223 } 224 225 } 226