| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wifi.scanner; |
| |
| import static android.content.pm.PackageManager.PERMISSION_DENIED; |
| import static android.content.pm.PackageManager.PERMISSION_GRANTED; |
| import static android.net.wifi.WifiScanner.GET_AVAILABLE_CHANNELS_EXTRA; |
| |
| import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder; |
| import static com.android.server.wifi.ScanTestUtil.assertNativePnoSettingsEquals; |
| import static com.android.server.wifi.ScanTestUtil.assertNativeScanSettingsEquals; |
| import static com.android.server.wifi.ScanTestUtil.assertScanDatasEquals; |
| import static com.android.server.wifi.ScanTestUtil.assertScanResultsEquals; |
| import static com.android.server.wifi.ScanTestUtil.channelsToSpec; |
| import static com.android.server.wifi.ScanTestUtil.computeSingleScanNativeSettings; |
| import static com.android.server.wifi.ScanTestUtil.computeSingleScanNativeSettingsWithChannelHelper; |
| import static com.android.server.wifi.ScanTestUtil.createRequest; |
| import static com.android.server.wifi.ScanTestUtil.createSingleScanNativeSettingsForChannels; |
| import static com.android.server.wifi.scanner.WifiScanningServiceImpl.WifiSingleScanStateMachine.CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS; |
| import static com.android.server.wifi.scanner.WifiScanningServiceImpl.WifiSingleScanStateMachine.EMERGENCY_SCAN_END_INDICATION_ALARM_TAG; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.junit.Assume.assumeTrue; |
| import static org.mockito.Mockito.any; |
| import static org.mockito.Mockito.anyBoolean; |
| import static org.mockito.Mockito.anyInt; |
| import static org.mockito.Mockito.anyString; |
| import static org.mockito.Mockito.argThat; |
| import static org.mockito.Mockito.atLeastOnce; |
| import static org.mockito.Mockito.clearInvocations; |
| import static org.mockito.Mockito.doNothing; |
| import static org.mockito.Mockito.doThrow; |
| import static org.mockito.Mockito.eq; |
| import static org.mockito.Mockito.inOrder; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.validateMockitoUsage; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.when; |
| |
| import android.Manifest; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.test.MockAnswerUtil.AnswerWithArguments; |
| import android.app.test.TestAlarmManager; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.WifiScanner; |
| import android.os.BatteryStatsManager; |
| import android.os.Binder; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.os.WorkSource; |
| import android.os.test.TestLooper; |
| import android.util.ArraySet; |
| import android.util.Pair; |
| |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.internal.util.AsyncChannel; |
| import com.android.internal.util.Protocol; |
| import com.android.internal.util.test.BidirectionalAsyncChannel; |
| import com.android.modules.utils.build.SdkLevel; |
| import com.android.server.wifi.Clock; |
| import com.android.server.wifi.FakeWifiLog; |
| import com.android.server.wifi.FrameworkFacade; |
| import com.android.server.wifi.MockResources; |
| import com.android.server.wifi.ScanResults; |
| import com.android.server.wifi.WifiBaseTest; |
| import com.android.server.wifi.WifiInjector; |
| import com.android.server.wifi.WifiMetrics; |
| import com.android.server.wifi.WifiNative; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto; |
| import com.android.server.wifi.util.LastCallerInfoManager; |
| import com.android.server.wifi.util.WifiAsyncChannel; |
| import com.android.server.wifi.util.WifiPermissionsUtil; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.ArgumentMatcher; |
| import org.mockito.InOrder; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| import org.mockito.Spy; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.regex.Pattern; |
| |
| /** |
| * Unit tests for {@link com.android.server.wifi.scanner.WifiScanningServiceImpl}. |
| */ |
| @SmallTest |
| public class WifiScanningServiceTest extends WifiBaseTest { |
| public static final String TAG = "WifiScanningServiceTest"; |
| |
| private static final int TEST_MAX_SCAN_BUCKETS_IN_CAPABILITIES = 8; |
| private static final String TEST_PACKAGE_NAME = "com.test.123"; |
| private static final String TEST_FEATURE_ID = "test.feature"; |
| private static final String TEST_IFACE_NAME_0 = "wlan0"; |
| private static final String TEST_IFACE_NAME_1 = "wlan1"; |
| private static final int TEST_PSC_CHANNEL = ScanResult.BAND_6_GHZ_PSC_START_MHZ; |
| private static final int TEST_NON_PSC_CHANNEL = 5985; |
| private static final WifiScanner.ScanData PLACEHOLDER_SCAN_DATA = |
| new WifiScanner.ScanData(0, 0, new ScanResult[0]); |
| |
| @Mock Context mContext; |
| TestAlarmManager mAlarmManager; |
| @Mock WifiScannerImpl mWifiScannerImpl0; |
| @Mock WifiScannerImpl mWifiScannerImpl1; |
| @Mock WifiScannerImpl.WifiScannerImplFactory mWifiScannerImplFactory; |
| @Mock BatteryStatsManager mBatteryStats; |
| @Mock WifiInjector mWifiInjector; |
| @Mock FrameworkFacade mFrameworkFacade; |
| @Mock Clock mClock; |
| @Spy FakeWifiLog mLog; |
| @Mock WifiPermissionsUtil mWifiPermissionsUtil; |
| @Mock WifiNative mWifiNative; |
| @Mock WifiMetrics mWifiMetrics; |
| @Mock WifiMetrics.ScanMetrics mScanMetrics; |
| @Mock WifiManager mWifiManager; |
| @Mock LastCallerInfoManager mLastCallerInfoManager; |
| ChannelHelper mChannelHelper0; |
| ChannelHelper mChannelHelper1; |
| TestLooper mLooper; |
| WifiScanningServiceImpl mWifiScanningServiceImpl; |
| |
| @Before |
| public void setUp() throws Exception { |
| MockitoAnnotations.initMocks(this); |
| |
| mAlarmManager = new TestAlarmManager(); |
| when(mContext.getSystemService(Context.ALARM_SERVICE)) |
| .thenReturn(mAlarmManager.getAlarmManager()); |
| when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager); |
| when(mContext.getResources()).thenReturn(new MockResources()); |
| when(mWifiInjector.getWifiPermissionsUtil()) |
| .thenReturn(mWifiPermissionsUtil); |
| |
| mChannelHelper0 = new PresetKnownBandsChannelHelper( |
| new int[]{2412, 2450}, |
| new int[]{5160, 5175}, |
| new int[]{5600, 5650, 5660}, |
| new int[]{TEST_PSC_CHANNEL, TEST_NON_PSC_CHANNEL}, |
| new int[]{58320, 60480}); |
| mChannelHelper1 = new PresetKnownBandsChannelHelper( |
| new int[]{2412, 2450}, |
| new int[]{5160, 5175}, |
| new int[]{5600, 5660, 5680}, // 5650 is missing from channelHelper0 |
| new int[]{5945, 5985}, |
| new int[]{58320, 60480}); |
| mLooper = new TestLooper(); |
| when(mWifiScannerImplFactory |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_0))) |
| .thenReturn(mWifiScannerImpl0); |
| when(mWifiScannerImpl0.getChannelHelper()).thenReturn(mChannelHelper0); |
| when(mWifiScannerImpl0.getIfaceName()).thenReturn(TEST_IFACE_NAME_0); |
| when(mWifiScannerImplFactory |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_1))) |
| .thenReturn(mWifiScannerImpl1); |
| when(mWifiScannerImpl1.getChannelHelper()).thenReturn(mChannelHelper1); |
| when(mWifiScannerImpl1.getIfaceName()).thenReturn(TEST_IFACE_NAME_1); |
| when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics); |
| when(mWifiMetrics.getScanMetrics()).thenReturn(mScanMetrics); |
| when(mWifiInjector.makeLog(anyString())).thenReturn(mLog); |
| WifiAsyncChannel mWifiAsyncChannel = new WifiAsyncChannel("ScanningServiceTest"); |
| mWifiAsyncChannel.setWifiLog(mLog); |
| when(mFrameworkFacade.makeWifiAsyncChannel(anyString())).thenReturn(mWifiAsyncChannel); |
| when(mWifiInjector.getFrameworkFacade()).thenReturn(mFrameworkFacade); |
| when(mWifiInjector.getClock()).thenReturn(mClock); |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0))); |
| when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative); |
| when(mContext.checkPermission(eq(Manifest.permission.NETWORK_STACK), |
| anyInt(), eq(Binder.getCallingUid()))) |
| .thenReturn(PERMISSION_GRANTED); |
| when(mWifiInjector.getLastCallerInfoManager()).thenReturn(mLastCallerInfoManager); |
| mWifiScanningServiceImpl = new WifiScanningServiceImpl(mContext, mLooper.getLooper(), |
| mWifiScannerImplFactory, mBatteryStats, mWifiInjector); |
| } |
| |
| @After |
| public void cleanup() { |
| validateMockitoUsage(); |
| } |
| |
| /** |
| * Internal BroadcastReceiver that WifiScanningServiceImpl uses to listen for broadcasts |
| * this is initialized by calling startServiceAndLoadDriver |
| */ |
| BroadcastReceiver mBroadcastReceiver; |
| |
| private WifiScanner.ScanSettings generateValidScanSettings() { |
| return createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| } |
| |
| private BidirectionalAsyncChannel connectChannel(Handler handler) { |
| BidirectionalAsyncChannel controlChannel = new BidirectionalAsyncChannel(); |
| controlChannel.connect(mLooper.getLooper(), mWifiScanningServiceImpl.getMessenger(), |
| handler); |
| mLooper.dispatchAll(); |
| controlChannel.assertConnected(); |
| return controlChannel; |
| } |
| |
| private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler) { |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| order.verify(handler).handleMessage(messageCaptor.capture()); |
| return messageCaptor.getValue(); |
| } |
| |
| private static class ConditionalMessageCaptor implements ArgumentMatcher<Message> { |
| private Message mLastValue; |
| private final int mWhat; |
| |
| private ConditionalMessageCaptor(int what) { |
| mWhat = what; |
| } |
| |
| public Message getLastValue() { |
| assertNotNull("Nothing captured yet", mLastValue); |
| |
| return mLastValue; |
| } |
| |
| public boolean matches(Message message) { |
| boolean isMatch = message.what == mWhat; |
| |
| if (isMatch) { |
| mLastValue = message; |
| } |
| |
| return isMatch; |
| } |
| } |
| |
| private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler, |
| final int what) { |
| ConditionalMessageCaptor messageMatcher = new ConditionalMessageCaptor(what); |
| |
| order.verify(handler).handleMessage(argThat(messageMatcher)); |
| return messageMatcher.getLastValue(); |
| } |
| |
| private static void verifyScanResultsReceived(InOrder order, Handler handler, int listenerId, |
| WifiScanner.ScanData... expected) { |
| Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler, |
| WifiScanner.CMD_SCAN_RESULT); |
| assertScanResultsMessage(listenerId, expected, scanResultMessage); |
| } |
| |
| private static void assertScanResultsMessage(int listenerId, WifiScanner.ScanData[] expected, |
| Message scanResultMessage) { |
| assertEquals("what", WifiScanner.CMD_SCAN_RESULT, scanResultMessage.what); |
| assertEquals("listenerId", listenerId, scanResultMessage.arg2); |
| assertScanDatasEquals(expected, |
| ((WifiScanner.ParcelableScanData) scanResultMessage.obj).getResults()); |
| } |
| |
| private static void verifySingleScanCompletedReceived(InOrder order, Handler handler, |
| int listenerId) { |
| Message completedMessage = verifyHandleMessageAndGetMessage(order, handler, |
| WifiScanner.CMD_SINGLE_SCAN_COMPLETED); |
| assertSingleScanCompletedMessage(listenerId, completedMessage); |
| } |
| |
| private static void assertSingleScanCompletedMessage(int listenerId, Message completedMessage) { |
| assertEquals("what", WifiScanner.CMD_SINGLE_SCAN_COMPLETED, completedMessage.what); |
| assertEquals("listenerId", listenerId, completedMessage.arg2); |
| } |
| |
| private static void sendBackgroundScanRequest(BidirectionalAsyncChannel controlChannel, |
| int scanRequestId, WifiScanner.ScanSettings settings, WorkSource workSource) { |
| Bundle scanParams = new Bundle(); |
| scanParams.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); |
| scanParams.putParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY, workSource); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_BACKGROUND_SCAN, 0, |
| scanRequestId, scanParams)); |
| } |
| |
| private static void sendSingleScanRequest(BidirectionalAsyncChannel controlChannel, |
| int scanRequestId, WifiScanner.ScanSettings settings, WorkSource workSource) { |
| Bundle scanParams = new Bundle(); |
| scanParams.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); |
| scanParams.putParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY, workSource); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_SINGLE_SCAN, 0, |
| scanRequestId, scanParams)); |
| } |
| |
| private static void registerScanListener(BidirectionalAsyncChannel controlChannel, |
| int listenerRequestId) { |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_REGISTER_SCAN_LISTENER, 0, |
| listenerRequestId, null)); |
| } |
| |
| private static void deregisterScanListener(BidirectionalAsyncChannel controlChannel, |
| int listenerRequestId) { |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DEREGISTER_SCAN_LISTENER, 0, |
| listenerRequestId, null)); |
| } |
| |
| private static void verifySuccessfulResponse(InOrder order, Handler handler, int arg2) { |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| assertSuccessfulResponse(arg2, response); |
| } |
| |
| private static void assertSuccessfulResponse(int arg2, Message response) { |
| if (response.what == WifiScanner.CMD_OP_FAILED) { |
| WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj; |
| fail("response indicates failure, reason=" + result.reason |
| + ", description=" + result.description); |
| } else { |
| assertEquals("response.what", WifiScanner.CMD_OP_SUCCEEDED, response.what); |
| assertEquals("response.arg2", arg2, response.arg2); |
| } |
| } |
| |
| /** |
| * If multiple results are expected for a single hardware scan then the order that they are |
| * dispatched is dependant on the order which they are iterated through internally. This |
| * function validates that the order is either one way or the other. A scan listener can |
| * optionally be provided as well and will be checked after the after the single scan requests. |
| */ |
| private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler, |
| int requestId1, ScanResults results1, int requestId2, ScanResults results2, |
| int listenerRequestId, ScanResults listenerResults) { |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| handlerOrder.verify(handler, times(listenerResults == null ? 4 : 5)) |
| .handleMessage(messageCaptor.capture()); |
| int firstListenerId = messageCaptor.getAllValues().get(0).arg2; |
| assertTrue(firstListenerId + " was neither " + requestId2 + " nor " + requestId1, |
| firstListenerId == requestId2 || firstListenerId == requestId1); |
| if (firstListenerId == requestId2) { |
| assertScanResultsMessage(requestId2, |
| new WifiScanner.ScanData[] {results2.getScanData()}, |
| messageCaptor.getAllValues().get(0)); |
| assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(1)); |
| assertScanResultsMessage(requestId1, |
| new WifiScanner.ScanData[] {results1.getScanData()}, |
| messageCaptor.getAllValues().get(2)); |
| assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(3)); |
| if (listenerResults != null) { |
| assertScanResultsMessage(listenerRequestId, |
| new WifiScanner.ScanData[] {listenerResults.getScanData()}, |
| messageCaptor.getAllValues().get(4)); |
| } |
| } else { |
| assertScanResultsMessage(requestId1, |
| new WifiScanner.ScanData[] {results1.getScanData()}, |
| messageCaptor.getAllValues().get(0)); |
| assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(1)); |
| assertScanResultsMessage(requestId2, |
| new WifiScanner.ScanData[] {results2.getScanData()}, |
| messageCaptor.getAllValues().get(2)); |
| assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(3)); |
| if (listenerResults != null) { |
| assertScanResultsMessage(listenerRequestId, |
| new WifiScanner.ScanData[] {listenerResults.getScanData()}, |
| messageCaptor.getAllValues().get(4)); |
| } |
| } |
| } |
| |
| private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler, |
| int requestId1, ScanResults results1, int requestId2, ScanResults results2) { |
| verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2, |
| results2, -1, null); |
| } |
| |
| private static void verifyFailedResponse(InOrder order, Handler handler, int arg2, |
| int expectedErrorReason, String expectedErrorDescription) { |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| assertFailedResponse(arg2, expectedErrorReason, expectedErrorDescription, response); |
| } |
| |
| private static void assertFailedResponse(int arg2, int expectedErrorReason, |
| String expectedErrorDescription, Message response) { |
| if (response.what == WifiScanner.CMD_OP_SUCCEEDED) { |
| fail("response indicates success"); |
| } else { |
| assertEquals("response.what", WifiScanner.CMD_OP_FAILED, response.what); |
| assertEquals("response.arg2", arg2, response.arg2); |
| WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj; |
| assertEquals("response.obj.reason", |
| expectedErrorReason, result.reason); |
| assertEquals("response.obj.description", |
| expectedErrorDescription, result.description); |
| } |
| } |
| |
| private WifiNative.ScanEventHandler verifyStartSingleScan(InOrder order, |
| WifiNative.ScanSettings expected) { |
| return verifyStartSingleScanForImpl(mWifiScannerImpl0, order, expected); |
| } |
| |
| private WifiNative.ScanEventHandler verifyStartSingleScanForImpl( |
| WifiScannerImpl wifiScannerImpl, InOrder order, WifiNative.ScanSettings expected) { |
| ArgumentCaptor<WifiNative.ScanSettings> scanSettingsCaptor = |
| ArgumentCaptor.forClass(WifiNative.ScanSettings.class); |
| ArgumentCaptor<WifiNative.ScanEventHandler> scanEventHandlerCaptor = |
| ArgumentCaptor.forClass(WifiNative.ScanEventHandler.class); |
| order.verify(wifiScannerImpl).startSingleScan(scanSettingsCaptor.capture(), |
| scanEventHandlerCaptor.capture()); |
| assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue()); |
| return scanEventHandlerCaptor.getValue(); |
| } |
| |
| private WifiNative.ScanEventHandler verifyStartBackgroundScan(InOrder order, |
| WifiNative.ScanSettings expected) { |
| ArgumentCaptor<WifiNative.ScanSettings> scanSettingsCaptor = |
| ArgumentCaptor.forClass(WifiNative.ScanSettings.class); |
| ArgumentCaptor<WifiNative.ScanEventHandler> scanEventHandlerCaptor = |
| ArgumentCaptor.forClass(WifiNative.ScanEventHandler.class); |
| order.verify(mWifiScannerImpl0).startBatchedScan(scanSettingsCaptor.capture(), |
| scanEventHandlerCaptor.capture()); |
| assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue()); |
| return scanEventHandlerCaptor.getValue(); |
| } |
| |
| private static final int MAX_AP_PER_SCAN = 16; |
| private void startServiceAndLoadDriver() { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| setupAndLoadDriver(TEST_MAX_SCAN_BUCKETS_IN_CAPABILITIES); |
| } |
| |
| private void setupAndLoadDriver( |
| BidirectionalAsyncChannel controlChannel, int maxScanBuckets) { |
| when(mWifiScannerImpl0.getScanCapabilities(any(WifiNative.ScanCapabilities.class))) |
| .thenAnswer(new AnswerWithArguments() { |
| public boolean answer(WifiNative.ScanCapabilities capabilities) { |
| capabilities.max_scan_cache_size = Integer.MAX_VALUE; |
| capabilities.max_scan_buckets = maxScanBuckets; |
| capabilities.max_ap_cache_per_scan = MAX_AP_PER_SCAN; |
| capabilities.max_rssi_sample_size = 8; |
| capabilities.max_scan_reporting_threshold = 10; |
| return true; |
| } |
| }); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| } |
| |
| private void setupAndLoadDriver(int maxScanBuckets) { |
| BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class)); |
| setupAndLoadDriver(controlChannel, maxScanBuckets); |
| } |
| |
| private String dumpService() { |
| StringWriter stringWriter = new StringWriter(); |
| mWifiScanningServiceImpl.dump(new FileDescriptor(), new PrintWriter(stringWriter), |
| new String[0]); |
| return stringWriter.toString(); |
| } |
| |
| private void assertDumpContainsRequestLog(String type, int id) { |
| String serviceDump = dumpService(); |
| Pattern logLineRegex = Pattern.compile("^.+" + type |
| + ": ClientInfo\\[uid=\\d+,android\\.os\\.Messenger@[a-f0-9]+\\],Id=" + id |
| + ".*$", Pattern.MULTILINE); |
| assertTrue("dump did not contain log with type=" + type + ", id=" + id + |
| ": " + serviceDump + "\n", |
| logLineRegex.matcher(serviceDump).find()); |
| } |
| |
| private void assertDumpContainsCallbackLog(String callback, int id, String extra) { |
| String serviceDump = dumpService(); |
| String extraPattern = extra == null ? "" : "," + extra; |
| Pattern logLineRegex = Pattern.compile("^.+" + callback |
| + ": ClientInfo\\[uid=\\d+,android\\.os\\.Messenger@[a-f0-9]+\\],Id=" + id |
| + extraPattern + "$", Pattern.MULTILINE); |
| assertTrue("dump did not contain callback log with callback=" + callback + ", id=" + id + |
| ", extra=" + extra + ": " + serviceDump + "\n", |
| logLineRegex.matcher(serviceDump).find()); |
| } |
| |
| @Test |
| public void construct() throws Exception { |
| verifyNoMoreInteractions(mWifiScannerImpl0, mWifiScannerImpl0, |
| mWifiScannerImplFactory, mBatteryStats); |
| dumpService(); // make sure this succeeds |
| } |
| |
| @Test |
| public void startServiceAndTriggerSingleScanWithoutDriverLoaded() throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| verifyNoMoreInteractions(mWifiScannerImplFactory); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| sendSingleScanRequest(controlChannel, 122, createRequest(WifiScanner.WIFI_BAND_ALL, |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN), new WorkSource(2292)); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available"); |
| } |
| |
| @Test |
| public void disconnectClientBeforeWifiEnabled() throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.disconnect(); |
| mLooper.dispatchAll(); |
| } |
| |
| @Test |
| public void loadDriver() throws Exception { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_0)); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| when(mWifiScannerImpl0.startBatchedScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| sendBackgroundScanRequest(controlChannel, 192, generateValidScanSettings(), null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, 192); |
| assertDumpContainsRequestLog("addBackgroundScanRequest", 192); |
| } |
| |
| /** |
| * Verifies that duplicate scan enable is ignored. |
| */ |
| @Test |
| public void duplicateScanEnableIsIgnored() throws RemoteException { |
| startServiceAndLoadDriver(); |
| |
| // Send scan enable again. |
| BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class)); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // Ensure we didn't create scanner instance twice. |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), any()); |
| } |
| |
| @Test |
| public void disconnectClientAfterStartingWifi() throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class)); |
| mLooper.dispatchAll(); |
| |
| setupAndLoadDriver(TEST_MAX_SCAN_BUCKETS_IN_CAPABILITIES); |
| |
| controlChannel.disconnect(); |
| mLooper.dispatchAll(); |
| } |
| |
| @Test |
| public void connectAndDisconnectClientAfterStartingWifi() throws Exception { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class)); |
| mLooper.dispatchAll(); |
| controlChannel.disconnect(); |
| mLooper.dispatchAll(); |
| } |
| |
| @Test |
| public void sendInvalidCommand() throws Exception { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| controlChannel.sendMessage(Message.obtain(null, Protocol.BASE_WIFI_MANAGER)); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 0, WifiScanner.REASON_INVALID_REQUEST, |
| "Invalid request"); |
| } |
| |
| @Test |
| public void rejectBackgroundScanRequestWhenHalReturnsInvalidCapabilities() throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| setupAndLoadDriver(0); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| sendBackgroundScanRequest(controlChannel, 122, generateValidScanSettings(), null); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available"); |
| } |
| |
| @Test |
| public void rejectBackgroundScanRequestWhenScannerImplCreateFails() throws Exception { |
| // Fail scanner impl creation. |
| when(mWifiScannerImplFactory.create(any(), any(), any(), any())).thenReturn(null); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| sendBackgroundScanRequest(controlChannel, 122, generateValidScanSettings(), null); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available"); |
| } |
| |
| private void doSuccessfulSingleScan(WifiScanner.ScanSettings requestSettings, |
| WifiNative.ScanSettings nativeSettings, @NonNull ScanResults resultsForImpl0) |
| throws RemoteException { |
| doSuccessfulSingleScanOnImpls(requestSettings, nativeSettings, resultsForImpl0, null); |
| } |
| |
| private void doSuccessfulSingleScanOnImpls(WifiScanner.ScanSettings requestSettings, |
| WifiNative.ScanSettings nativeSettings, @NonNull ScanResults resultsForImpl0, |
| @Nullable ScanResults resultsForImpl1) throws RemoteException { |
| int requestId = 12; |
| WorkSource workSource = new WorkSource(2292); |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| if (resultsForImpl1 != null) { |
| when(mWifiScannerImpl1.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| } |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, workSource); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler0 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl0, order, nativeSettings); |
| WifiNative.ScanEventHandler eventHandler1 = null; |
| if (resultsForImpl1 != null) { |
| eventHandler1 = verifyStartSingleScanForImpl(mWifiScannerImpl1, order, nativeSettings); |
| } |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource)); |
| |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(resultsForImpl0.getScanData()); |
| eventHandler0.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| if (resultsForImpl1 != null) { |
| when(mWifiScannerImpl1.getLatestSingleScanResults()) |
| .thenReturn(resultsForImpl1.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| } |
| |
| mLooper.dispatchAll(); |
| ScanResults expectedResults = resultsForImpl0; |
| if (resultsForImpl1 != null) { |
| expectedResults = ScanResults.merge( |
| resultsForImpl0.getScanData().getScannedBandsInternal(), |
| resultsForImpl0, resultsForImpl1); |
| } |
| verifyScanResultsReceived(order, handler, requestId, expectedResults.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource)); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId); |
| assertDumpContainsCallbackLog("singleScanResults", requestId, |
| "results=" + expectedResults.getScanData().getResults().length); |
| } |
| |
| /** |
| * Do a single scan for a band and verify that it is successful. |
| */ |
| @Test |
| public void sendSingleScanBandRequest() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_ALL, |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 2412, 5160, 5175)); |
| } |
| |
| /** |
| * Do a single scan for a list of channels and verify that it is successful. |
| */ |
| @Test |
| public void sendSingleScanChannelsRequest() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2412, 5160, 5175), |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412, 5160, 5175)); |
| } |
| |
| /** |
| * Do a single scan for a list of all channels and verify that it is successful. |
| */ |
| @Test |
| public void sendSingleScanAllChannelsRequest() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest( |
| channelsToSpec(2412, 2450, 5160, 5175, 5600, 5650, 5660), |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412, 5160, 5175)); |
| } |
| |
| /** |
| * Do a single scan with no results and verify that it is successful. |
| */ |
| @Test |
| public void sendSingleScanRequestWithNoResults() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Verify that PSC channels not added when a channel list is explicitly specified for scanning. |
| */ |
| @Test |
| public void testPscIsIgnoredForPartialScan() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| WifiScanner.ScanSettings requestSettings = createRequest( |
| channelsToSpec(2412, 5160, 5955), |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int expectedChannelListSize = requestSettings.channels.length; |
| requestSettings.set6GhzPscOnlyEnabled(true); |
| WifiNative.ScanSettings fromChannelList = computeSingleScanNativeSettings(requestSettings); |
| assertEquals(expectedChannelListSize, fromChannelList.buckets[0].channels.length); |
| WifiNative.ScanSettings fromChannelHelper = |
| computeSingleScanNativeSettingsWithChannelHelper(requestSettings, mChannelHelper0); |
| assertNativeScanSettingsEquals(fromChannelList, fromChannelHelper); |
| doSuccessfulSingleScan(requestSettings, fromChannelList, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Verify that when set6GhzPscOnlyEnabled(true) is used, only 6Ghz PSC channels get added |
| * when the 6Ghz band is being scanned. |
| */ |
| @Test |
| public void testPscChannelAddedWhenScanning6GhzBand() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_ALL, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings.set6GhzPscOnlyEnabled(true); |
| |
| // The expectedChannels should match with all supported channels configured for |
| // mChannelHelper0, less the TEST_NON_PSC_CHANNEL |
| Set<Integer> expectedChannels = new ArraySet<Integer>( |
| new Integer[]{2412, 2450, 5160, 5175, 5600, 5650, 5660, 5600, 5650, 5660, |
| TEST_PSC_CHANNEL, 58320, 60480}); |
| |
| // Compute the expected nativeSettings |
| WifiNative.ScanSettings nativeSettings = |
| computeSingleScanNativeSettingsWithChannelHelper(requestSettings, mChannelHelper0); |
| assertEquals("The scan band should be WIFI_BAND_UNSPECIFIED since only a subset of 6Ghz " |
| + "channels need to be scanned", WifiScanner.WIFI_BAND_UNSPECIFIED, |
| nativeSettings.buckets[0].band); |
| Set<Integer> scanTestUtilcomputedExpectedChannels = new ArraySet<>(); |
| for (WifiNative.ChannelSettings channelSettings : nativeSettings.buckets[0].channels) { |
| scanTestUtilcomputedExpectedChannels.add(channelSettings.frequency); |
| } |
| |
| assertEquals("Computed native settings does not match with expected value", |
| expectedChannels, scanTestUtilcomputedExpectedChannels); |
| doSuccessfulSingleScan(requestSettings, nativeSettings, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Verify that when set6GhzPscOnlyEnabled(true) is used but the 6Ghz band not being scanned, |
| * we ignore the flag. |
| */ |
| @Test |
| public void testPscChannelNotAddedWhenNotScanning6GhzBand() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings.set6GhzPscOnlyEnabled(true); |
| WifiNative.ScanSettings fromChannelList = computeSingleScanNativeSettings(requestSettings); |
| assertNull("channel list should be null", fromChannelList.buckets[0].channels); |
| WifiNative.ScanSettings fromChannelHelper = |
| computeSingleScanNativeSettingsWithChannelHelper(requestSettings, mChannelHelper0); |
| assertNativeScanSettingsEquals(fromChannelList, fromChannelHelper); |
| doSuccessfulSingleScan(requestSettings, fromChannelList, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Verify WifiNative.ScanSettings#enable6GhzRnr is set appropriatly according to |
| * WifiScanner.ScanSettings#band and WifiScanner.ScanSettings#getRnrSetting(). |
| */ |
| @Test |
| public void testRnrIsDisabledIf6GhzBandIsNotScanned() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| // Verify RNR is disabled by default since WIFI_BAND_BOTH doesn't include the 6Ghz band. |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| assertEquals(WifiScanner.WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED, |
| requestSettings.getRnrSetting()); |
| assertEquals(false, nativeSettings.enable6GhzRnr); |
| doSuccessfulSingleScan(requestSettings, nativeSettings, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Verify that when WIFI_BAND_ALL is scanned, RNR is automatically enabled when |
| * getRnrSetting() returns WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED. |
| */ |
| @Test |
| public void testRnrIsEnabledIf6GhzBandIsScanned() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_ALL, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| assertEquals(WifiScanner.WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED, |
| requestSettings.getRnrSetting()); |
| assertEquals(true, nativeSettings.enable6GhzRnr); |
| doSuccessfulSingleScan(requestSettings, nativeSettings, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, new int[0])); |
| } |
| |
| /** |
| * Verify RNR is enabled even though only 2.4 and 5Ghz channels are being scanned because of |
| * getRnrSetting() returns WIFI_RNR_ENABLED. |
| */ |
| @Test |
| public void testForceEnableRnr() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings.setRnrSetting(WifiScanner.WIFI_RNR_ENABLED); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| assertEquals(WifiScanner.WIFI_RNR_ENABLED, |
| requestSettings.getRnrSetting()); |
| assertEquals(true, nativeSettings.enable6GhzRnr); |
| doSuccessfulSingleScan(requestSettings, nativeSettings, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Verify that when WIFI_BAND_ALL is scanned, RNR is disabled when |
| * getRnrSetting() returns WIFI_RNR_NOT_NEEDED. |
| */ |
| @Test |
| public void testRnrIsExplicitlyDisabled() throws Exception { |
| assumeTrue(SdkLevel.isAtLeastS()); |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_ALL, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings.setRnrSetting(WifiScanner.WIFI_RNR_NOT_NEEDED); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| assertEquals(WifiScanner.WIFI_RNR_NOT_NEEDED, |
| requestSettings.getRnrSetting()); |
| assertEquals(false, nativeSettings.enable6GhzRnr); |
| doSuccessfulSingleScan(requestSettings, nativeSettings, |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, new int[0])); |
| } |
| |
| /** |
| * Do a single scan with results that do not match the requested scan and verify that it is |
| * still successful (and returns no results). |
| */ |
| @Test |
| public void sendSingleScanRequestWithBadRawResults() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_24_GHZ, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| // Create a set of scan results that has results not matching the request settings, but is |
| // limited to zero results for the expected results. |
| ScanResults results = ScanResults.createOverflowing(0, WifiScanner.WIFI_BAND_24_GHZ, 0, |
| ScanResults.generateNativeResults(0, 5160, 5171)); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| results); |
| } |
| |
| /** |
| * Do a single scan from a non-privileged app with some privileged params set. |
| * Expect a scan failure. |
| */ |
| @Test |
| public void sendSingleScanRequestWithPrivilegedTypeParamsSetFromNonPrivilegedApp() |
| throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| requestSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| when(mContext.checkPermission( |
| Manifest.permission.NETWORK_STACK, -1, Binder.getCallingUid())) |
| .thenReturn(PERMISSION_DENIED); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| // Scan is successfully queued |
| mLooper.dispatchAll(); |
| |
| // but then fails to execute |
| verifyFailedResponse(order, handler, requestId, |
| WifiScanner.REASON_INVALID_REQUEST, "bad request"); |
| assertDumpContainsCallbackLog("singleScanInvalidRequest", requestId, |
| "bad request"); |
| |
| verify(mWifiMetrics, never()).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); |
| |
| // Ensure that no scan was triggered to the lower layers. |
| verify(mBatteryStats, never()).reportWifiScanStoppedFromSource(eq(workSource)); |
| verify(mWifiScannerImpl0, never()).startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class)); |
| } |
| |
| /** |
| * Do a single scan from a non-privileged app with some privileged params set. |
| * Expect a scan failure. |
| */ |
| @Test |
| public void sendSingleScanRequestWithPrivilegedHiddenNetworkParamsSetFromNonPrivilegedApp() |
| throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| requestSettings.hiddenNetworks.clear(); |
| requestSettings.hiddenNetworks.add( |
| new WifiScanner.ScanSettings.HiddenNetwork("Test1")); |
| requestSettings.hiddenNetworks.add( |
| new WifiScanner.ScanSettings.HiddenNetwork("Test2")); |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| when(mContext.checkPermission( |
| Manifest.permission.NETWORK_STACK, -1, Binder.getCallingUid())) |
| .thenReturn(PERMISSION_DENIED); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| // Scan is successfully queued |
| mLooper.dispatchAll(); |
| |
| // but then fails to execute |
| verifyFailedResponse(order, handler, requestId, |
| WifiScanner.REASON_INVALID_REQUEST, "bad request"); |
| assertDumpContainsCallbackLog("singleScanInvalidRequest", requestId, |
| "bad request"); |
| |
| verify(mWifiMetrics, never()).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); |
| |
| // Ensure that no scan was triggered to the lower layers. |
| verify(mBatteryStats, never()).reportWifiScanStoppedFromSource(eq(workSource)); |
| verify(mWifiScannerImpl0, never()).startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class)); |
| } |
| |
| /** |
| * Do a single scan with invalid scan type set. |
| * Expect a scan failure. |
| */ |
| @Test |
| public void sendSingleScanRequestWithInvalidScanType() |
| throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| requestSettings.type = 100; // invalid scan type |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| // Scan is successfully queued |
| mLooper.dispatchAll(); |
| |
| // but then fails to execute |
| verifyFailedResponse(order, handler, requestId, |
| WifiScanner.REASON_INVALID_REQUEST, "bad request"); |
| assertDumpContainsCallbackLog("singleScanInvalidRequest", requestId, |
| "bad request"); |
| |
| verify(mWifiMetrics, never()).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); |
| |
| // Ensure that no scan was triggered to the lower layers. |
| verify(mBatteryStats, never()).reportWifiScanStoppedFromSource(eq(workSource)); |
| verify(mWifiScannerImpl0, never()).startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class)); |
| } |
| |
| /** |
| * Do a single scan from a non-privileged app with no privileged params set. |
| */ |
| @Test |
| public void sendSingleScanRequestWithNoPrivilegedParamsSetFromNonPrivilegedApp() |
| throws Exception { |
| when(mContext.checkPermission( |
| Manifest.permission.NETWORK_STACK, -1, Binder.getCallingUid())) |
| .thenReturn(PERMISSION_DENIED); |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2412, 5160, 5175), |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, 2412, 5160, 5175)); |
| } |
| |
| /** |
| * Do a single scan, which the hardware fails to start, and verify that a failure response is |
| * delivered. |
| */ |
| @Test |
| public void sendSingleScanRequestWhichFailsToStart() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // scan fails |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(false); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| mLooper.dispatchAll(); |
| // Scan is successfully queue, but then fails to execute |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| order.verify(handler, times(2)).handleMessage(messageCaptor.capture()); |
| assertSuccessfulResponse(requestId, messageCaptor.getAllValues().get(0)); |
| assertFailedResponse(requestId, WifiScanner.REASON_UNSPECIFIED, |
| "Failed to start single scan", messageCaptor.getAllValues().get(1)); |
| verifyNoMoreInteractions(mBatteryStats); |
| |
| verify(mWifiMetrics).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 1); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId); |
| } |
| |
| /** |
| * Do a single scan, which successfully starts, but fails partway through and verify that a |
| * failure response is delivered. |
| */ |
| @Test |
| public void sendSingleScanRequestWhichFailsAfterStart() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| // Scan is successfully queue |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = |
| verifyStartSingleScan(order, computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource)); |
| |
| // but then fails to execute |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, requestId, |
| WifiScanner.REASON_UNSPECIFIED, "Scan failed"); |
| assertDumpContainsCallbackLog("singleScanFailed", requestId, |
| "reason=" + WifiScanner.REASON_UNSPECIFIED + ", Scan failed"); |
| verify(mWifiMetrics).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 1); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource)); |
| } |
| |
| /** |
| * Do a single scan that includes DFS channels and verify that both oneshot scan count and |
| * oneshot scan count with dfs are incremented. |
| */ |
| @Test |
| public void testMetricsForOneshotScanWithDFSIsIncremented() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest( |
| WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| verify(mWifiMetrics, never()).incrementOneshotScanCount(); |
| verify(mWifiMetrics, never()).incrementOneshotScanWithDfsCount(); |
| // Scan is successfully queue |
| mLooper.dispatchAll(); |
| verify(mWifiMetrics).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementOneshotScanWithDfsCount(); |
| } |
| |
| /** |
| * Do a single scan that excludes DFS channels and verify that only oneshot scan count is |
| * incremented. |
| */ |
| @Test |
| public void testMetricsForOneshotScanWithDFSIsNotIncremented() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest( |
| WifiScanner.WIFI_BAND_5_GHZ, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| verify(mWifiMetrics, never()).incrementOneshotScanCount(); |
| verify(mWifiMetrics, never()).incrementOneshotScanWithDfsCount(); |
| // Scan is successfully queue |
| mLooper.dispatchAll(); |
| verify(mWifiMetrics).incrementOneshotScanCount(); |
| verify(mWifiMetrics, never()).incrementOneshotScanWithDfsCount(); |
| } |
| |
| /** |
| * Send a single scan request and then disable Wi-Fi before it completes |
| */ |
| @Test |
| public void sendSingleScanRequestThenDisableWifi() { |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 2293; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| // disable wifi |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| |
| // validate failed response |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, requestId, WifiScanner.REASON_UNSPECIFIED, |
| "Scan was interrupted"); |
| verifyNoMoreInteractions(handler); |
| } |
| |
| /** |
| * Send a single scan request and then disable Wi-Fi before it completes |
| */ |
| @Test |
| public void sendSingleScanRequestThenDisableWifiAfterScanCompleteButBeforeReportingResults() { |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults results = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| int requestId = 2293; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| // disable wifi |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| // scan results complete event |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results.getScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, requestId, WifiScanner.REASON_UNSPECIFIED, |
| "Scan was interrupted"); |
| verifyNoMoreInteractions(handler); |
| } |
| |
| /** |
| * Send a single scan request, schedule a second pending scan and disable Wi-Fi before the first |
| * scan completes. |
| */ |
| @Test |
| public void sendSingleScanAndPendingScanAndListenerThenDisableWifi() { |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId1 = 2293; |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId2 = 2294; |
| |
| int listenerRequestId = 2295; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| // Request scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, requestId1); |
| |
| // Request scan 2 |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, requestId2); |
| |
| // Setup scan listener |
| registerScanListener(controlChannel, listenerRequestId); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, listenerRequestId); |
| |
| // disable wifi |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| |
| // validate failed response |
| mLooper.dispatchAll(); |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| order.verify(handler, times(2)).handleMessage(messageCaptor.capture()); |
| assertFailedResponse(requestId1, WifiScanner.REASON_UNSPECIFIED, |
| "Scan was interrupted", messageCaptor.getAllValues().get(0)); |
| assertFailedResponse(requestId2, WifiScanner.REASON_UNSPECIFIED, |
| "Scan was interrupted", messageCaptor.getAllValues().get(1)); |
| // No additional callbacks for scan listener |
| verifyNoMoreInteractions(handler); |
| } |
| |
| /** |
| * Send a single scan request and then a second one after the first completes. |
| */ |
| @Test |
| public void sendSingleScanRequestAfterPreviousCompletes() { |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId1 = 12; |
| ScanResults results1 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId2 = 13; |
| ScanResults results2 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2450); |
| |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mContext); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(order, handler, requestId1); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results1.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| // Note: The order of the following verification calls looks out of order if you compare to |
| // the source code of WifiScanningServiceImpl WifiSingleScanStateMachine.reportScanResults. |
| // This is due to the fact that verifyScanResultsReceived and |
| // verifySingleScanCompletedReceived require an additional call to handle the message that |
| // is created in reportScanResults. This handling is done in the two verify*Received calls |
| // that is run AFTER the reportScanResults method in WifiScanningServiceImpl completes. |
| verifyScanResultsReceived(order, handler, requestId1, results1.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId1); |
| |
| // Run scan 2 |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(requestSettings2)); |
| verifySuccessfulResponse(order, handler, requestId2); |
| |
| // dispatch scan 2 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results2.getScanData()); |
| eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId2, results2.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId2); |
| } |
| |
| /** |
| * Send a single scan request and then a second one not satisfied by the first before the first |
| * completes. Verify that both are scheduled and succeed. |
| */ |
| @Test |
| public void sendSingleScanRequestWhilePreviousScanRunning() { |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId1 = 12; |
| ScanResults results1 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId2 = 13; |
| ScanResults results2 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2450); |
| |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder handlerOrder = inOrder(handler); |
| InOrder nativeOrder = inOrder(mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(handlerOrder, handler, requestId1); |
| |
| // Queue scan 2 (will not run because previous is in progress) |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId2); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results1.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(handlerOrder, handler, requestId1, results1.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId1); |
| |
| // now that the first scan completed we expect the second one to start |
| WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings2)); |
| |
| // dispatch scan 2 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results2.getScanData()); |
| eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(handlerOrder, handler, requestId2, results2.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId2); |
| verify(mWifiMetrics, times(2)).incrementOneshotScanCount(); |
| verify(mWifiMetrics, times(2)).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 1); |
| } |
| |
| /** |
| * Send a single scan request and then a second one not satisfied by the first before the first |
| * completes. Verify that both are scheduled and succeed. |
| * Validates that a high accuracy scan request is not satisfied by an ongoing low latency scan, |
| * while any other low latency/low power scan request is satisfied. |
| */ |
| @Test |
| public void sendSingleScanRequestWhilePreviousScanRunningWithTypesThatDoesNotSatisfy() { |
| // Create identitical scan requests other than the types being different. |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings1.type = WifiScanner.SCAN_TYPE_LOW_LATENCY; |
| int requestId1 = 12; |
| ScanResults results1 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings2.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; |
| int requestId2 = 13; |
| ScanResults results2 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder handlerOrder = inOrder(handler); |
| InOrder nativeOrder = inOrder(mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(handlerOrder, handler, requestId1); |
| |
| // Queue scan 2 (will not run because previous is in progress) |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId2); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results1.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(handlerOrder, handler, requestId1, results1.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId1); |
| |
| // now that the first scan completed we expect the second one to start |
| WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings2)); |
| |
| // dispatch scan 2 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results2.getScanData()); |
| eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(handlerOrder, handler, requestId2, results2.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId2); |
| verify(mWifiMetrics, times(2)).incrementOneshotScanCount(); |
| verify(mWifiMetrics, times(2)).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 1); |
| } |
| |
| |
| /** |
| * Send a single scan request and then two more before the first completes. Neither are |
| * satisfied by the first scan. Verify that the first completes and the second two are merged. |
| * Validates that a high accuracy scan is always preferred over the other types while merging. |
| */ |
| @Test |
| public void sendMultipleSingleScanRequestWhilePreviousScanRunning() throws RemoteException { |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings1.type = WifiScanner.SCAN_TYPE_LOW_LATENCY; |
| int requestId1 = 12; |
| WorkSource workSource1 = new WorkSource(1121); |
| ScanResults results1 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings2.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; |
| int requestId2 = 13; |
| WorkSource workSource2 = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| ScanResults results2 = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2450, 5175, 2450); |
| |
| WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5160), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings3.type = WifiScanner.SCAN_TYPE_LOW_POWER; |
| int requestId3 = 15; |
| // Let one of the WorkSources be a chained workSource. |
| WorkSource workSource3 = new WorkSource(); |
| workSource3.createWorkChain() |
| .addNode(2292, "tag1"); |
| ScanResults results3 = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 5160, 5160, 5160, 5160); |
| |
| WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels( |
| WifiScanner.SCAN_TYPE_HIGH_ACCURACY, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, |
| channelsToSpec(2450, 5175, 5160)); |
| ScanResults results2and3 = |
| ScanResults.merge(WifiScanner.WIFI_BAND_UNSPECIFIED, results2, results3); |
| WorkSource workSource2and3 = new WorkSource(); |
| workSource2and3.add(workSource2); |
| workSource2and3.add(workSource3); |
| |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder handlerOrder = inOrder(handler); |
| InOrder nativeOrder = inOrder(mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, workSource1); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(handlerOrder, handler, requestId1); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource1)); |
| |
| |
| // Queue scan 2 (will not run because previous is in progress) |
| // uses uid of calling process |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId2); |
| |
| // Queue scan 3 (will not run because previous is in progress) |
| sendSingleScanRequest(controlChannel, requestId3, requestSettings3, workSource3); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId3); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results1.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(handlerOrder, handler, requestId1, results1.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId1); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource1)); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource2and3)); |
| |
| // now that the first scan completed we expect the second and third ones to start |
| WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder, |
| nativeSettings2and3); |
| |
| // dispatch scan 2 and 3 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results2and3.getScanData()); |
| eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| |
| verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3, |
| results3); |
| verify(mWifiMetrics, times(3)).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 1); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 2); |
| |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource2and3)); |
| |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId1); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId2); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId3); |
| assertDumpContainsCallbackLog("singleScanResults", requestId1, |
| "results=" + results1.getRawScanResults().length); |
| assertDumpContainsCallbackLog("singleScanResults", requestId2, |
| "results=" + results2.getRawScanResults().length); |
| assertDumpContainsCallbackLog("singleScanResults", requestId3, |
| "results=" + results3.getRawScanResults().length); |
| } |
| |
| /** |
| * Send a single scan request and then a second one satisfied by the first before the first |
| * completes. Verify that only one scan is scheduled. |
| * Validates that a low latency scan type request is satisfied by an ongoing high accuracy |
| * scan. |
| */ |
| @Test |
| public void sendSingleScanRequestWhilePreviousScanRunningAndMergeIntoFirstScan() { |
| // Split by frequency to make it easier to determine which results each request is expecting |
| ScanResults results24GHz = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, 2412, 2412, 2412, 2450); |
| ScanResults results5GHz = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, 5160, 5160, 5175); |
| ScanResults resultsBoth = |
| ScanResults.merge(WifiScanner.WIFI_BAND_BOTH, results24GHz, results5GHz); |
| |
| WifiScanner.ScanSettings requestSettings1 = createRequest( |
| WifiScanner.SCAN_TYPE_HIGH_ACCURACY, WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId1 = 12; |
| ScanResults results1 = resultsBoth; |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest( |
| WifiScanner.SCAN_TYPE_LOW_LATENCY, WifiScanner.WIFI_BAND_24_GHZ, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId2 = 13; |
| ScanResults results2 = results24GHz; |
| |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder handlerOrder = inOrder(handler); |
| InOrder nativeOrder = inOrder(mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(handlerOrder, handler, requestId1); |
| |
| // Queue scan 2 (will be folded into ongoing scan) |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId2); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(resultsBoth.getScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2, |
| results2); |
| |
| verify(mWifiMetrics, times(2)).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 2); |
| } |
| |
| /** |
| * Send a single scan request and then two more before the first completes, one of which is |
| * satisfied by the first scan. Verify that the first two complete together the second scan is |
| * just for the other scan. |
| * Validates that a high accuracy scan request is not satisfied by an ongoing low latency scan, |
| * while any other low latency/low power scan request is satisfied. |
| */ |
| @Test |
| public void sendMultipleSingleScanRequestWhilePreviousScanRunningAndMergeOneIntoFirstScan() |
| throws RemoteException { |
| // Split by frequency to make it easier to determine which results each request is expecting |
| ScanResults results2412 = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412, 2412, 2412); |
| ScanResults results2450 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2450); |
| ScanResults results1and3 = |
| ScanResults.merge(WifiScanner.WIFI_BAND_UNSPECIFIED, results2412, results2450); |
| |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412, 2450), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings1.type = WifiScanner.SCAN_TYPE_LOW_LATENCY; |
| int requestId1 = 12; |
| WorkSource workSource1 = new WorkSource(1121); |
| ScanResults results1 = results1and3; |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings2.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; |
| int requestId2 = 13; |
| WorkSource workSource2 = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450); |
| |
| WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings3.type = WifiScanner.SCAN_TYPE_LOW_POWER; |
| int requestId3 = 15; |
| WorkSource workSource3 = new WorkSource(2292); |
| ScanResults results3 = results2412; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder handlerOrder = inOrder(handler); |
| InOrder nativeOrder = inOrder(mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, workSource1); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(handlerOrder, handler, requestId1); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource1)); |
| |
| |
| // Queue scan 2 (will not run because previous is in progress) |
| // uses uid of calling process |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId2); |
| |
| // Queue scan 3 (will be merged into the active scan) |
| sendSingleScanRequest(controlChannel, requestId3, requestSettings3, workSource3); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId3); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results1and3.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId3, |
| results3); |
| // only the requests know at the beginning of the scan get blamed |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource1)); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource2)); |
| |
| // now that the first scan completed we expect the second and third ones to start |
| WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings2)); |
| |
| // dispatch scan 2 and 3 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results2.getScanData()); |
| eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| |
| verifyScanResultsReceived(handlerOrder, handler, requestId2, results2.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId2); |
| verify(mWifiMetrics, times(3)).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 2); |
| verify(mWifiMetrics).incrementScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS, 1); |
| |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource2)); |
| |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId1); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId2); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId3); |
| assertDumpContainsCallbackLog("singleScanResults", requestId1, |
| "results=" + results1.getRawScanResults().length); |
| assertDumpContainsCallbackLog("singleScanResults", requestId2, |
| "results=" + results2.getRawScanResults().length); |
| assertDumpContainsCallbackLog("singleScanResults", requestId3, |
| "results=" + results3.getRawScanResults().length); |
| } |
| |
| /** |
| * Verify that WifiService provides a way to get the most recent SingleScan results. |
| */ |
| @Test |
| public void retrieveSingleScanResults() throws Exception { |
| WifiScanner.ScanSettings requestSettings = |
| createRequest(WifiScanner.WIFI_BAND_ALL, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults expectedResults = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 2412, 5160, 5175); |
| doSuccessfulSingleScan(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), |
| expectedResults); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertEquals(results.size(), expectedResults.getRawScanResults().length); |
| |
| // Make sure that we logged the scan results in the dump method. |
| String serviceDump = dumpService(); |
| Pattern logLineRegex = Pattern.compile("Latest scan results:"); |
| assertTrue("dump did not contain Latest scan results: " + serviceDump + "\n", |
| logLineRegex.matcher(serviceDump).find()); |
| } |
| |
| /** |
| * Verify that WifiService provides a way to get the most recent SingleScan results even when |
| * they are empty. |
| */ |
| @Test |
| public void retrieveSingleScanResultsEmpty() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertEquals(results.size(), 0); |
| } |
| |
| /** |
| * Verify that WifiService will return empty SingleScan results if a scan has not been |
| * performed. |
| */ |
| @Test |
| public void retrieveSingleScanResultsBeforeAnySingleScans() throws Exception { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertEquals(results.size(), 0); |
| } |
| |
| /** |
| * Verify that the newest full scan results are returned by WifiService.getSingleScanResults. |
| */ |
| @Test |
| public void retrieveMostRecentFullSingleScanResults() throws Exception { |
| int scanBand = WifiScanner.WIFI_BAND_ALL & ~WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY; |
| WifiScanner.ScanSettings requestSettings = createRequest(scanBand, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults expectedResults = ScanResults.create(0, scanBand, 2412, 5160, 5175); |
| doSuccessfulSingleScan(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), |
| expectedResults); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertEquals(results.size(), expectedResults.getRawScanResults().length); |
| |
| // now update with a new scan that only has one result |
| int secondScanRequestId = 35; |
| ScanResults expectedSingleResult = ScanResults.create(0, scanBand, 5160); |
| sendSingleScanRequest(controlChannel, secondScanRequestId, requestSettings, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, secondScanRequestId); |
| |
| // dispatch scan 2 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(expectedSingleResult.getScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, secondScanRequestId, |
| expectedSingleResult.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, secondScanRequestId); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response2 = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results2 = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response2.obj).getResults()); |
| assertEquals(results2.size(), expectedSingleResult.getRawScanResults().length); |
| } |
| |
| /** |
| * Verify that the newest partial scan results are not returned by |
| * WifiService.getSingleScanResults. |
| */ |
| @Test |
| public void doesNotRetrieveMostRecentPartialSingleScanResults() throws Exception { |
| int scanBand = WifiScanner.WIFI_BAND_ALL & ~WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY; |
| WifiScanner.ScanSettings fullRequestSettings = createRequest(scanBand, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults expectedFullResults = |
| ScanResults.create(0, scanBand, 2412, 5160, 5175); |
| doSuccessfulSingleScan(fullRequestSettings, |
| computeSingleScanNativeSettings(fullRequestSettings), |
| expectedFullResults); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertEquals(results.size(), expectedFullResults.getRawScanResults().length); |
| |
| // now update with a new scan that only has one result |
| int secondScanRequestId = 35; |
| WifiScanner.ScanSettings partialRequestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults expectedPartialResults = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_5_GHZ, 5160); |
| sendSingleScanRequest(controlChannel, secondScanRequestId, partialRequestSettings, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(partialRequestSettings)); |
| verifySuccessfulResponse(order, handler, secondScanRequestId); |
| |
| // dispatch scan 2 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(expectedPartialResults.getScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, secondScanRequestId, |
| expectedPartialResults.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, secondScanRequestId); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response2 = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results2 = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response2.obj).getResults()); |
| assertEquals(results2.size(), expectedFullResults.getRawScanResults().length); |
| } |
| |
| /** |
| * Verify that the scan results returned by WifiService.getSingleScanResults are not older |
| * than {@link com.android.server.wifi.scanner.WifiScanningServiceImpl |
| * .WifiSingleScanStateMachine#CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}. |
| */ |
| @Test |
| public void doesNotRetrieveStaleScanResultsFromLastFullSingleScan() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_ALL, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults scanResults = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 2412, 5160, 5175); |
| |
| // Out of the 3 scan results, modify the timestamp of 2 of them to be within the expiration |
| // age and 1 out of it. |
| long currentTimeInMillis = CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS * 2; |
| when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeInMillis); |
| scanResults.getRawScanResults()[0].timestamp = (currentTimeInMillis - 1) * 1000; |
| scanResults.getRawScanResults()[1].timestamp = (currentTimeInMillis - 2) * 1000; |
| scanResults.getRawScanResults()[2].timestamp = |
| (currentTimeInMillis - CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS) * 1000; |
| List<ScanResult> expectedResults = new ArrayList<ScanResult>() {{ |
| add(scanResults.getRawScanResults()[0]); |
| add(scanResults.getRawScanResults()[1]); |
| }}; |
| |
| doSuccessfulSingleScan(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), scanResults); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertScanResultsEquals(expectedResults.toArray(new ScanResult[expectedResults.size()]), |
| results.toArray(new ScanResult[results.size()])); |
| } |
| |
| /** |
| * Cached scan results should be cleared after the driver is unloaded. |
| */ |
| @Test |
| public void validateScanResultsClearedAfterDriverUnloaded() throws Exception { |
| WifiScanner.ScanSettings requestSettings = |
| createRequest(WifiScanner.WIFI_BAND_ALL, |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults expectedResults = ScanResults.create( |
| 0, WifiScanner.WIFI_BAND_ALL, 2412, 5160, 5175); |
| doSuccessfulSingleScan(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), |
| expectedResults); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response = verifyHandleMessageAndGetMessage(order, handler); |
| List<ScanResult> results = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response.obj).getResults()); |
| assertEquals(results.size(), expectedResults.getRawScanResults().length); |
| |
| // disable wifi |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| // Now get scan results again. The returned list should be empty since we |
| // clear the cache when exiting the DriverLoaded state. |
| controlChannel.sendMessage( |
| Message.obtain(null, WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS, 0)); |
| mLooper.dispatchAll(); |
| Message response2 = verifyHandleMessageAndGetMessage(order, handler); |
| List<ScanResult> results2 = Arrays.asList( |
| ((WifiScanner.ParcelableScanResults) response2.obj).getResults()); |
| assertEquals(results2.size(), 0); |
| } |
| |
| /** |
| * Register a single scan listener and do a single scan |
| */ |
| @Test |
| public void registerScanListener() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| ScanResults results = ScanResults.create(0, 2412, 5160, 5175); |
| |
| int requestId = 12; |
| int listenerRequestId = 13; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| registerScanListener(controlChannel, listenerRequestId); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, listenerRequestId); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings); |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results.getRawScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyScanResultsReceived(order, handler, listenerRequestId, results.getScanData()); |
| verifyNoMoreInteractions(handler); |
| |
| assertDumpContainsRequestLog("registerScanListener", listenerRequestId); |
| assertDumpContainsCallbackLog("singleScanResults", listenerRequestId, |
| "results=" + results.getScanData().getResults().length); |
| } |
| |
| /** |
| * Register a single scan listener and do a single scan |
| */ |
| @Test |
| public void deregisterScanListener() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| ScanResults results = ScanResults.create(0, 2412, 5160, 5175); |
| |
| int requestId = 12; |
| int listenerRequestId = 13; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| registerScanListener(controlChannel, listenerRequestId); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, listenerRequestId); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings); |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| deregisterScanListener(controlChannel, listenerRequestId); |
| mLooper.dispatchAll(); |
| |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results.getRawScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| |
| assertDumpContainsRequestLog("registerScanListener", listenerRequestId); |
| assertDumpContainsRequestLog("deregisterScanListener", listenerRequestId); |
| } |
| |
| /** |
| * Send a single scan request and then two more before the first completes. Neither are |
| * satisfied by the first scan. Verify that the first completes and the second two are merged. |
| */ |
| @Test |
| public void scanListenerReceivesAllResults() throws RemoteException { |
| WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2412), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId1 = 12; |
| ScanResults results1 = ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412); |
| |
| WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId2 = 13; |
| ScanResults results2 = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2450, 5175, 2450); |
| |
| WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5160), 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId3 = 15; |
| ScanResults results3 = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 5160, 5160, 5160, 5160); |
| |
| WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels( |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channelsToSpec(2450, 5175, 5160)); |
| ScanResults results2and3 = |
| ScanResults.merge(WifiScanner.WIFI_BAND_UNSPECIFIED, results2, results3); |
| |
| int listenerRequestId = 13; |
| |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder handlerOrder = inOrder(handler); |
| InOrder nativeOrder = inOrder(mWifiScannerImpl0); |
| |
| // Run scan 1 |
| sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder, |
| computeSingleScanNativeSettings(requestSettings1)); |
| verifySuccessfulResponse(handlerOrder, handler, requestId1); |
| |
| |
| // Queue scan 2 (will not run because previous is in progress) |
| sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId2); |
| |
| // Queue scan 3 (will not run because previous is in progress) |
| sendSingleScanRequest(controlChannel, requestId3, requestSettings3, null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, requestId3); |
| |
| // Register scan listener |
| registerScanListener(controlChannel, listenerRequestId); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(handlerOrder, handler, listenerRequestId); |
| |
| // dispatch scan 1 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results1.getScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(handlerOrder, handler, requestId1, results1.getScanData()); |
| verifySingleScanCompletedReceived(handlerOrder, handler, requestId1); |
| verifyScanResultsReceived(handlerOrder, handler, listenerRequestId, results1.getScanData()); |
| |
| // now that the first scan completed we expect the second and third ones to start |
| WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder, |
| nativeSettings2and3); |
| |
| // dispatch scan 2 and 3 results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results2and3.getScanData()); |
| eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| |
| verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3, |
| results3, listenerRequestId, results2and3); |
| |
| assertDumpContainsRequestLog("registerScanListener", listenerRequestId); |
| assertDumpContainsCallbackLog("singleScanResults", listenerRequestId, |
| "results=" + results1.getRawScanResults().length); |
| assertDumpContainsCallbackLog("singleScanResults", listenerRequestId, |
| "results=" + results2and3.getRawScanResults().length); |
| } |
| |
| @Test |
| public void rejectSingleScanRequestWhenScannerGetIfaceNameFails() throws Exception { |
| // Failed to get client interface name. |
| when(mWifiNative.getClientInterfaceNames()).thenReturn(new ArraySet<>()); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| sendSingleScanRequest(controlChannel, 122, generateValidScanSettings(), null); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available"); |
| } |
| |
| @Test |
| public void rejectSingleScanRequestWhenScannerImplCreateFails() throws Exception { |
| // Fail scanner impl creation. |
| when(mWifiScannerImplFactory.create(any(), any(), any(), any())).thenReturn(null); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| sendSingleScanRequest(controlChannel, 122, generateValidScanSettings(), null); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available"); |
| } |
| |
| private void doSuccessfulBackgroundScan(WifiScanner.ScanSettings requestSettings, |
| WifiNative.ScanSettings nativeSettings) { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| when(mWifiScannerImpl0.startBatchedScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendBackgroundScanRequest(controlChannel, 12, requestSettings, null); |
| mLooper.dispatchAll(); |
| verifyStartBackgroundScan(order, nativeSettings); |
| verifySuccessfulResponse(order, handler, 12); |
| verifyNoMoreInteractions(handler); |
| assertDumpContainsRequestLog("addBackgroundScanRequest", 12); |
| } |
| |
| /** |
| * Do a background scan for a band and verify that it is successful. |
| */ |
| @Test |
| public void sendBackgroundScanBandRequest() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder() |
| .withBasePeriod(30000) |
| .withMaxApPerScan(MAX_AP_PER_SCAN) |
| .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH) |
| .addBucketWithBand(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, |
| WifiScanner.WIFI_BAND_BOTH) |
| .build(); |
| doSuccessfulBackgroundScan(requestSettings, nativeSettings); |
| verify(mWifiMetrics).incrementBackgroundScanCount(); |
| } |
| |
| /** |
| * Do a background scan for a list of channels and verify that it is successful. |
| */ |
| @Test |
| public void sendBackgroundScanChannelsRequest() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(5160), 30000, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder() |
| .withBasePeriod(30000) |
| .withMaxApPerScan(MAX_AP_PER_SCAN) |
| .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH) |
| .addBucketWithChannels(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5160) |
| .build(); |
| doSuccessfulBackgroundScan(requestSettings, nativeSettings); |
| } |
| |
| private Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> createScanSettingsForHwPno() |
| throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest( |
| channelsToSpec(0, 2412, 5160, 5175), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder() |
| .withBasePeriod(30000) |
| .withMaxApPerScan(MAX_AP_PER_SCAN) |
| .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH) |
| .addBucketWithChannels(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, |
| 0, 2412, 5160, 5175) |
| .build(); |
| return Pair.create(requestSettings, nativeSettings); |
| } |
| |
| private Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> createPnoSettings( |
| ScanResults results) |
| throws Exception { |
| WifiScanner.PnoSettings requestPnoSettings = new WifiScanner.PnoSettings(); |
| requestPnoSettings.networkList = |
| new WifiScanner.PnoSettings.PnoNetwork[results.getRawScanResults().length]; |
| int i = 0; |
| for (ScanResult scanResult : results.getRawScanResults()) { |
| requestPnoSettings.networkList[i++] = |
| new WifiScanner.PnoSettings.PnoNetwork(scanResult.SSID); |
| } |
| |
| WifiNative.PnoSettings nativePnoSettings = new WifiNative.PnoSettings(); |
| nativePnoSettings.min5GHzRssi = requestPnoSettings.min5GHzRssi; |
| nativePnoSettings.min24GHzRssi = requestPnoSettings.min24GHzRssi; |
| nativePnoSettings.min6GHzRssi = requestPnoSettings.min6GHzRssi; |
| nativePnoSettings.isConnected = requestPnoSettings.isConnected; |
| nativePnoSettings.networkList = |
| new WifiNative.PnoNetwork[requestPnoSettings.networkList.length]; |
| for (i = 0; i < requestPnoSettings.networkList.length; i++) { |
| nativePnoSettings.networkList[i] = new WifiNative.PnoNetwork(); |
| nativePnoSettings.networkList[i].ssid = requestPnoSettings.networkList[i].ssid; |
| nativePnoSettings.networkList[i].flags = requestPnoSettings.networkList[i].flags; |
| nativePnoSettings.networkList[i].auth_bit_field = |
| requestPnoSettings.networkList[i].authBitField; |
| } |
| return Pair.create(requestPnoSettings, nativePnoSettings); |
| } |
| |
| private ScanResults createScanResultsForPno() { |
| return ScanResults.create(0, 2412, 5160, 5175); |
| } |
| |
| private WifiNative.PnoEventHandler verifyHwPnoForImpl(WifiScannerImpl impl, InOrder order, |
| WifiNative.PnoSettings expected) { |
| ArgumentCaptor<WifiNative.PnoSettings> pnoSettingsCaptor = |
| ArgumentCaptor.forClass(WifiNative.PnoSettings.class); |
| ArgumentCaptor<WifiNative.PnoEventHandler> pnoEventHandlerCaptor = |
| ArgumentCaptor.forClass(WifiNative.PnoEventHandler.class); |
| order.verify(impl).setHwPnoList(pnoSettingsCaptor.capture(), |
| pnoEventHandlerCaptor.capture()); |
| assertNativePnoSettingsEquals(expected, pnoSettingsCaptor.getValue()); |
| return pnoEventHandlerCaptor.getValue(); |
| } |
| |
| private void sendPnoScanRequest(BidirectionalAsyncChannel controlChannel, |
| int scanRequestId, WifiScanner.ScanSettings scanSettings, |
| WifiScanner.PnoSettings pnoSettings) { |
| Bundle pnoParams = new Bundle(); |
| scanSettings.isPnoScan = true; |
| pnoParams.putParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| pnoParams.putParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_PNO_SCAN, 0, |
| scanRequestId, pnoParams)); |
| } |
| |
| private void assertPnoNetworkFoundMessage(int listenerId, ScanResult[] expected, |
| Message networkFoundMessage) { |
| assertEquals("what", WifiScanner.CMD_PNO_NETWORK_FOUND, networkFoundMessage.what); |
| assertEquals("listenerId", listenerId, networkFoundMessage.arg2); |
| assertScanResultsEquals(expected, |
| ((WifiScanner.ParcelableScanResults) networkFoundMessage.obj).getResults()); |
| } |
| |
| private void verifyPnoNetworkFoundReceived(InOrder order, Handler handler, int listenerId, |
| ScanResult[] expected) { |
| Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler, |
| WifiScanner.CMD_PNO_NETWORK_FOUND); |
| assertPnoNetworkFoundMessage(listenerId, expected, scanResultMessage); |
| } |
| |
| private void expectSuccessfulBackgroundScan(InOrder order, |
| WifiNative.ScanSettings nativeSettings, ScanResults results) { |
| when(mWifiScannerImpl0.startBatchedScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = verifyStartBackgroundScan(order, nativeSettings); |
| WifiScanner.ScanData[] scanDatas = new WifiScanner.ScanData[1]; |
| scanDatas[0] = results.getScanData(); |
| for (ScanResult fullScanResult : results.getRawScanResults()) { |
| eventHandler.onFullScanResult(fullScanResult, 0); |
| } |
| when(mWifiScannerImpl0.getLatestBatchedScanResults(anyBoolean())).thenReturn(scanDatas); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| mLooper.dispatchAll(); |
| } |
| |
| private void expectHwPnoScan(InOrder order, Handler handler, int requestId, |
| WifiNative.PnoSettings nativeSettings, ScanResults results) { |
| when(mWifiScannerImpl0.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| |
| when(mWifiScannerImpl0.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| mLooper.dispatchAll(); |
| WifiNative.PnoEventHandler eventHandler = |
| verifyHwPnoForImpl(mWifiScannerImpl0, order, nativeSettings); |
| verifySuccessfulResponse(order, handler, requestId); |
| eventHandler.onPnoNetworkFound(results.getRawScanResults()); |
| mLooper.dispatchAll(); |
| } |
| |
| private void expectHwPnoScanOnImpls(InOrder order, Handler handler, |
| int requestId, WifiNative.PnoSettings nativeSettings, |
| @Nullable ScanResults resultsForImpl0, @Nullable ScanResults resultsForImpl1) { |
| when(mWifiScannerImpl0.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| when(mWifiScannerImpl1.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| |
| when(mWifiScannerImpl0.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| when(mWifiScannerImpl1.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| mLooper.dispatchAll(); |
| WifiNative.PnoEventHandler eventHandler0 = |
| verifyHwPnoForImpl(mWifiScannerImpl0, order, nativeSettings); |
| WifiNative.PnoEventHandler eventHandler1 = |
| verifyHwPnoForImpl(mWifiScannerImpl1, order, nativeSettings); |
| verifySuccessfulResponse(order, handler, requestId); |
| if (resultsForImpl0 != null) { |
| eventHandler0.onPnoNetworkFound(resultsForImpl0.getRawScanResults()); |
| } else if (resultsForImpl1 != null) { |
| eventHandler1.onPnoNetworkFound(resultsForImpl1.getRawScanResults()); |
| } |
| mLooper.dispatchAll(); |
| } |
| |
| /** |
| * Tests wificond PNO scan. This ensures that the PNO scan results are plumbed back to the |
| * client as a PNO network found event. |
| */ |
| @Test |
| public void testSuccessfulHwPnoScanWithNoBackgroundScan() throws Exception { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| expectHwPnoScan(order, handler, requestId, pnoSettings.second, scanResults); |
| verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults()); |
| } |
| |
| @Test |
| public void rejectHwPnoScanRequestWhenScannerImplCreateFails() throws Exception { |
| // Fail scanner impl creation. |
| when(mWifiScannerImplFactory.create(any(), any(), any(), any())).thenReturn(null); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| sendPnoScanRequest(controlChannel, 122, scanSettings.first, pnoSettings.first); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available"); |
| } |
| |
| /** |
| * Tries to simulate the race scenario where a client is disconnected immediately after single |
| * scan request is sent to |SingleScanStateMachine|. |
| */ |
| @Test |
| public void processSingleScanRequestAfterDisconnect() throws Exception { |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class)); |
| mLooper.dispatchAll(); |
| |
| // Send the single scan request and then send the disconnect immediately after. |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 10; |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| // Can't call |disconnect| here because that sends |CMD_CHANNEL_DISCONNECT| followed by |
| // |CMD_CHANNEL_DISCONNECTED|. |
| controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED, |
| AsyncChannel.STATUS_REMOTE_DISCONNECTION, 0, null)); |
| |
| // Now process the above 2 actions. This should result in first processing the single scan |
| // request (which forwards the request to SingleScanStateMachine) and then processing the |
| // disconnect after. |
| mLooper.dispatchAll(); |
| |
| // Now check that we logged the invalid request. |
| String serviceDump = dumpService(); |
| Pattern logLineRegex = Pattern.compile("^.+" + "singleScanInvalidRequest: " |
| + "ClientInfo\\[unknown\\],Id=" + requestId + ",bad request$", Pattern.MULTILINE); |
| assertTrue("dump did not contain log with ClientInfo[unknown]: " + serviceDump + "\n", |
| logLineRegex.matcher(serviceDump).find()); |
| } |
| |
| /** |
| * Tries to simulate the race scenario where a client is disconnected immediately after single |
| * scan request is sent to |SingleScanStateMachine|. |
| */ |
| @Test |
| public void sendScanRequestAfterUnsuccessfulSend() throws Exception { |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 9; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| mLooper.dispatchAll(); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| ScanResults results = ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, 2412); |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results.getRawScanData()); |
| |
| InOrder order = inOrder(mWifiScannerImpl0, handler); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| |
| controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED, |
| AsyncChannel.STATUS_SEND_UNSUCCESSFUL, 0, null)); |
| mLooper.dispatchAll(); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(order, |
| computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| } |
| |
| /** |
| * Verifies that background scan works after duplicate scan enable. |
| */ |
| @Test |
| public void backgroundScanAfterDuplicateScanEnable() throws RemoteException { |
| startServiceAndLoadDriver(); |
| |
| // Send scan enable again. |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // Ensure we didn't create scanner instance twice. |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), any()); |
| |
| InOrder order = inOrder(handler); |
| when(mWifiScannerImpl0.startBatchedScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| sendBackgroundScanRequest(controlChannel, 192, generateValidScanSettings(), null); |
| mLooper.dispatchAll(); |
| verifySuccessfulResponse(order, handler, 192); |
| assertDumpContainsRequestLog("addBackgroundScanRequest", 192); |
| verify(mLastCallerInfoManager, atLeastOnce()).put( |
| eq(LastCallerInfoManager.SCANNING_ENABLED), anyInt(), anyInt(), anyInt(), any(), |
| eq(true)); |
| } |
| |
| /** |
| * Verifies that single scan works after duplicate scan enable. |
| */ |
| @Test |
| public void singleScanScanAfterDuplicateScanEnable() throws RemoteException { |
| startServiceAndLoadDriver(); |
| |
| // Send scan enable again. |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // Ensure we didn't create scanner instance twice. |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), any()); |
| |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| |
| int requestId = 12; |
| WorkSource workSource = new WorkSource(2292); |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2412, 5160, 5175), |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| ScanResults results = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412, 5160, 5175); |
| |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, workSource); |
| |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler = |
| verifyStartSingleScan(order, computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource)); |
| |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(results.getRawScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource)); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId); |
| assertDumpContainsCallbackLog("singleScanResults", requestId, |
| "results=" + results.getScanData().getResults().length); |
| verify(mLastCallerInfoManager, atLeastOnce()).put( |
| eq(LastCallerInfoManager.SCANNING_ENABLED), anyInt(), anyInt(), anyInt(), any(), |
| eq(true)); |
| } |
| |
| /** |
| * Verifies that pno scan works after duplicate scan enable. |
| */ |
| @Test |
| public void hwPnoScanScanAfterDuplicateScanEnable() throws Exception { |
| startServiceAndLoadDriver(); |
| |
| // Send scan enable again. |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // Ensure we didn't create scanner instance twice. |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), any()); |
| |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| expectHwPnoScan(order, handler, requestId, pnoSettings.second, scanResults); |
| verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults()); |
| } |
| |
| /** |
| * Verifies that only clients with NETWORK_STACK permission can issues restricted messages |
| * (from API's). |
| */ |
| @Test |
| public void rejectRestrictedMessagesFromNonPrivilegedApps() throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_PNO_SCAN)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_STOP_PNO_SCAN)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_REGISTER_SCAN_LISTENER)); |
| mLooper.dispatchAll(); |
| |
| // All 4 of the above messages should have been rejected because the app doesn't have |
| // the required permissions. |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(handler, times(5)).handleMessage(messageCaptor.capture()); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(0)); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(1)); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(2)); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(3)); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(4)); |
| |
| // Ensure we didn't create scanner instance. |
| verify(mWifiScannerImplFactory, never()).create(any(), any(), any(), any()); |
| |
| } |
| |
| /** |
| * Verifies that clients without NETWORK_STACK permission cannot issue any messages when they |
| * don't have the necessary location permissions & location is enabled. |
| */ |
| @Test |
| public void rejectAllMessagesFromNonPrivilegedAppsWithoutLocationPermission() throws Exception { |
| // Start service & initialize it. |
| startServiceAndLoadDriver(); |
| |
| // Location permission or mode check fail. |
| doThrow(new SecurityException()).when(mWifiPermissionsUtil) |
| .enforceCanAccessScanResultsForWifiScanner(any(), any(), eq(Binder.getCallingUid()), |
| eq(false), eq(false)); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_SINGLE_SCAN)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_GET_SCAN_RESULTS)); |
| mLooper.dispatchAll(); |
| |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_BACKGROUND_SCAN)); |
| mLooper.dispatchAll(); |
| |
| // All the above messages should have been rejected because the app doesn't have |
| // the privileged permissions & location is turned off. |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(handler, times(3)).handleMessage(messageCaptor.capture()); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(0)); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(1)); |
| assertFailedResponse(0, WifiScanner.REASON_NOT_AUTHORIZED, |
| "Not authorized", messageCaptor.getAllValues().get(2)); |
| |
| // Validate the initialization sequence. |
| verify(mWifiScannerImpl0).getChannelHelper(); |
| verify(mWifiScannerImpl0).getScanCapabilities(any()); |
| |
| // Ensure we didn't start any scans after. |
| verifyNoMoreInteractions(mWifiScannerImpl0); |
| } |
| |
| /** |
| * Verifies that we ignore location settings when the single scan request settings sets |
| * {@link WifiScanner.ScanSettings#ignoreLocationSettings} |
| */ |
| @Test |
| public void verifyIgnoreLocationSettingsFromNonPrivilegedAppsForSingleScan() throws Exception { |
| // Start service & initialize it. |
| startServiceAndLoadDriver(); |
| |
| Handler handler = mock(Handler.class); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| int requestId = 122; |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| Bundle bundle = new Bundle(); |
| bundle.putString(WifiScanner.REQUEST_PACKAGE_NAME_KEY, TEST_PACKAGE_NAME); |
| bundle.putString(WifiScanner.REQUEST_FEATURE_ID_KEY, TEST_FEATURE_ID); |
| WifiScanner.ScanSettings scanSettings = |
| createRequest(WifiScanner.WIFI_BAND_ALL, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| |
| // send single scan request (ignoreLocationSettings == true). |
| scanSettings.ignoreLocationSettings = true; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| Message message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_SINGLE_SCAN; |
| message.obj = bundle; |
| message.arg2 = requestId; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify the permission check params (ignoreLocationSettings == true). |
| verify(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), eq(true), |
| eq(false)); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mWifiManager).setEmergencyScanRequestInProgress(true); |
| |
| // send single scan request (ignoreLocationSettings == false). |
| scanSettings.ignoreLocationSettings = false; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_SINGLE_SCAN; |
| message.obj = bundle; |
| message.arg2 = requestId; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify the permission check params (ignoreLocationSettings == true). |
| verify(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), eq(false), |
| eq(false)); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mWifiManager, times(1)).setEmergencyScanRequestInProgress(true); |
| |
| // send background scan request (ignoreLocationSettings == true). |
| scanSettings.ignoreLocationSettings = true; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_BACKGROUND_SCAN; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify the permission check params (ignoreLocationSettings == false), the field |
| // is ignored for any requests other than single scan. |
| verify(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), eq(false), |
| eq(false)); |
| } |
| |
| /** |
| * Verifies that we hide from app-ops when the single scan request settings sets |
| * {@link WifiScanner.ScanSettings#hideFromAppOps} |
| */ |
| @Test |
| public void verifyHideFromAppOpsFromNonPrivilegedAppsForSingleScan() throws Exception { |
| // Start service & initialize it. |
| startServiceAndLoadDriver(); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| Bundle bundle = new Bundle(); |
| bundle.putString(WifiScanner.REQUEST_PACKAGE_NAME_KEY, TEST_PACKAGE_NAME); |
| bundle.putString(WifiScanner.REQUEST_FEATURE_ID_KEY, TEST_FEATURE_ID); |
| WifiScanner.ScanSettings scanSettings = new WifiScanner.ScanSettings(); |
| |
| // send single scan request (hideFromAppOps == true). |
| scanSettings.hideFromAppOps = true; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| Message message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_SINGLE_SCAN; |
| message.obj = bundle; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify the permission check params (hideFromAppOps == true). |
| verify(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), eq(false), |
| eq(true)); |
| |
| // send single scan request (hideFromAppOps == false). |
| scanSettings.hideFromAppOps = false; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_SINGLE_SCAN; |
| message.obj = bundle; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify the permission check params (hideFromAppOps == false). |
| verify(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), eq(false), |
| eq(false)); |
| |
| // send background scan request (hideFromAppOps == true). |
| scanSettings.hideFromAppOps = true; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_BACKGROUND_SCAN; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify the permission check params (hideFromAppOps == false), the field |
| // is ignored for any requests other than single scan. |
| verify(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), eq(false), |
| eq(false)); |
| } |
| |
| /** |
| * Verifies that we don't invoke {@link WifiPermissionsUtil# |
| * enforceCanAccessScanResultsForWifiScanner(String, int, boolean, boolean)} for requests |
| * from privileged clients (i.e wifi service). |
| */ |
| @Test |
| public void verifyLocationPermissionCheckIsSkippedFromPrivilegedClientsForSingleScan() |
| throws Exception { |
| // Start service & initialize it. |
| startServiceAndLoadDriver(); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| |
| // Client does have NETWORK_STACK permission. |
| doNothing().when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| Bundle bundle = new Bundle(); |
| bundle.putString(WifiScanner.REQUEST_PACKAGE_NAME_KEY, TEST_PACKAGE_NAME); |
| bundle.putString(WifiScanner.REQUEST_FEATURE_ID_KEY, TEST_FEATURE_ID); |
| WifiScanner.ScanSettings scanSettings = new WifiScanner.ScanSettings(); |
| |
| // send single scan request (hideFromAppOps == true, ignoreLocationSettings = true). |
| scanSettings.hideFromAppOps = true; |
| scanSettings.ignoreLocationSettings = true; |
| bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, scanSettings); |
| Message message = Message.obtain(); |
| message.what = WifiScanner.CMD_START_SINGLE_SCAN; |
| message.obj = bundle; |
| controlChannel.sendMessage(message); |
| mLooper.dispatchAll(); |
| |
| // Verify that we didn't invoke the location permission check. |
| verify(mWifiPermissionsUtil, never()).enforceCanAccessScanResultsForWifiScanner( |
| eq(TEST_PACKAGE_NAME), eq(TEST_FEATURE_ID), eq(Binder.getCallingUid()), |
| anyBoolean(), anyBoolean()); |
| } |
| |
| /** |
| * Setup/teardown a second scanner impl dynamically. |
| */ |
| @Test |
| public void setupAndTeardownSecondImpl() throws Exception { |
| // start up service with a single impl. |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_0)); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| |
| // Now setup an impl for second iface. |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_1)); |
| |
| // Now teardown the impl for second iface. |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0))); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiScannerImpl1).cleanup(); |
| |
| // Now teardown everything. |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| mLooper.dispatchAll(); |
| |
| verify(mLastCallerInfoManager).put(eq(LastCallerInfoManager.SCANNING_ENABLED), anyInt(), |
| anyInt(), anyInt(), any(), eq(false)); |
| verify(mWifiScannerImpl0).cleanup(); |
| } |
| |
| /** |
| * Setup/teardown a second scanner impl dynamically which satisfies the same set of channels |
| * as the existing one. |
| */ |
| @Test |
| public void setupAndTeardownSecondImplWhichSatisfiesExistingImpl() throws Exception { |
| // start up service with a single impl. |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_0)); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| |
| // Now setup an impl for second iface. |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| // Setup the second impl to contain the same set of channels as the first one. |
| when(mWifiScannerImpl1.getChannelHelper()).thenReturn(mChannelHelper0); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // Verify that we created the new impl and immediately tore it down because it was |
| // satisfied by an existing impl. |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_1)); |
| verify(mWifiScannerImpl1, times(1)).getChannelHelper(); |
| verify(mWifiScannerImpl1, times(1)).cleanup(); |
| |
| // Now teardown the second iface. |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0))); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // do nothing, since impl1 was never added to the active impl list. |
| verifyNoMoreInteractions(mWifiScannerImpl1); |
| |
| // Now teardown everything. |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiScannerImpl0).cleanup(); |
| } |
| |
| /** |
| * Setup a second scanner impl and tearddown a existing scanning impl dynamically which |
| * satisfies the same set of channels as the existing one. |
| */ |
| @Test |
| public void setupSecondImplAndTeardownFirstImplWhichSatisfiesExistingImpl() throws Exception { |
| // start up service with a single impl. |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_0)); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler); |
| |
| |
| // Now setup an impl for second iface and teardown the first one. |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_1))); |
| // Setup the second impl to contain the same set of channels as the first one. |
| when(mWifiScannerImpl1.getChannelHelper()).thenReturn(mChannelHelper0); |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_ENABLE)); |
| mLooper.dispatchAll(); |
| |
| // tear down the first one because corresponding iface was brought down. |
| verify(mWifiScannerImpl0).cleanup(); |
| |
| // Verify that we created the new impl. |
| verify(mWifiScannerImplFactory, times(1)) |
| .create(any(), any(), any(), eq(TEST_IFACE_NAME_1)); |
| verify(mWifiScannerImpl1, never()).getChannelHelper(); |
| |
| // Now teardown everything. |
| controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DISABLE)); |
| mLooper.dispatchAll(); |
| |
| verify(mWifiScannerImpl1).cleanup(); |
| } |
| |
| /** |
| * Do a single scan for a band and verify that it is successful across multiple impls. |
| */ |
| @Test |
| public void sendSingleScanBandRequestOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| WifiScanner.ScanSettings requestSettings = createRequest( |
| WifiScanner.WIFI_BAND_ALL, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScanOnImpls(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 2412), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 5160)); |
| } |
| |
| /** |
| * Do a single scan for a list of channels and verify that it is successful across multiple |
| * impls. |
| */ |
| @Test |
| public void sendSingleScanChannelsRequestOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2412, 5160, 5175), |
| 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScanOnImpls(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 5175)); |
| } |
| |
| /** |
| * Do a single scan with no results and verify that it is successful across multiple |
| * impls. |
| */ |
| @Test |
| public void sendSingleScanRequestWithNoResultsOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| doSuccessfulSingleScanOnImpls(requestSettings, |
| computeSingleScanNativeSettings(requestSettings), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0]), |
| ScanResults.create(0, WifiScanner.WIFI_BAND_BOTH, new int[0])); |
| } |
| |
| /** |
| * Do a single scan, which the hardware fails to start across multiple impls, and verify that a |
| * failure response is delivered. |
| */ |
| @Test |
| public void sendSingleScanRequestWhichFailsToStartOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| |
| // scan fails |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(false); |
| when(mWifiScannerImpl1.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(false); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| mLooper.dispatchAll(); |
| // Scan is successfully queue, but then fails to execute |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| order.verify(handler, times(2)).handleMessage(messageCaptor.capture()); |
| assertSuccessfulResponse(requestId, messageCaptor.getAllValues().get(0)); |
| assertFailedResponse(requestId, WifiScanner.REASON_UNSPECIFIED, |
| "Failed to start single scan", messageCaptor.getAllValues().get(1)); |
| verifyNoMoreInteractions(mBatteryStats); |
| |
| verify(mWifiMetrics).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 1); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId); |
| } |
| |
| /** |
| * Do a single scan, which the hardware fails to start on one of the impl, and verify that a |
| * successful response is delivered when other impls succeed. |
| */ |
| @Test |
| public void sendSingleScanRequestWhichFailsToStartOnOneImpl() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| ScanResults results = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412, 5160, 5175); |
| int requestId = 33; |
| WorkSource workSource = new WorkSource(2292); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| |
| // scan fails on impl0 |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(false); |
| // scan succeeds on impl1 |
| when(mWifiScannerImpl1.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, workSource); |
| |
| mLooper.dispatchAll(); |
| |
| WifiNative.ScanEventHandler eventHandler0 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl0, order, nativeSettings); |
| WifiNative.ScanEventHandler eventHandler1 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl1, order, nativeSettings); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource)); |
| |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(new WifiScanner.ScanData(PLACEHOLDER_SCAN_DATA)); |
| // Send scan success on impl1 |
| when(mWifiScannerImpl1.getLatestSingleScanResults()) |
| .thenReturn(results.getRawScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource)); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId); |
| assertDumpContainsCallbackLog("singleScanResults", requestId, |
| "results=" + results.getScanData().getResults().length); |
| } |
| |
| /** |
| * Do a single scan, which successfully starts, but fails across multiple impls partway through |
| * and verify that a failure response is delivered. |
| */ |
| @Test |
| public void sendSingleScanRequestWhichFailsAfterStartOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| int requestId = 33; |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| when(mWifiScannerImpl1.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| // Scan is successfully queue |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler0 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl0, order, |
| computeSingleScanNativeSettings(requestSettings)); |
| WifiNative.ScanEventHandler eventHandler1 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl1, order, |
| computeSingleScanNativeSettings(requestSettings)); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource)); |
| |
| // but then fails to execute |
| eventHandler0.onScanStatus(WifiNative.WIFI_SCAN_FAILED); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_FAILED); |
| mLooper.dispatchAll(); |
| verifyFailedResponse(order, handler, requestId, |
| WifiScanner.REASON_UNSPECIFIED, "Scan failed"); |
| assertDumpContainsCallbackLog("singleScanFailed", requestId, |
| "reason=" + WifiScanner.REASON_UNSPECIFIED + ", Scan failed"); |
| verify(mWifiMetrics).incrementOneshotScanCount(); |
| verify(mWifiMetrics).incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 1); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource)); |
| } |
| |
| /** |
| * Do a single scan, which successfully starts, but fails partway through on one of the impls |
| * and verify that a successful response is delivered. |
| */ |
| @Test |
| public void sendSingleScanRequestWhichFailsAfterStartOnOneImpl() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0, |
| 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings); |
| ScanResults results = |
| ScanResults.create(0, WifiScanner.WIFI_BAND_UNSPECIFIED, 2412, 5160, 5175); |
| int requestId = 33; |
| WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| when(mWifiScannerImpl1.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, null); |
| |
| // Scan is successfully queued |
| mLooper.dispatchAll(); |
| WifiNative.ScanEventHandler eventHandler0 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl0, order, nativeSettings); |
| WifiNative.ScanEventHandler eventHandler1 = |
| verifyStartSingleScanForImpl(mWifiScannerImpl1, order, nativeSettings); |
| verifySuccessfulResponse(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(workSource)); |
| |
| // then fails to execute on impl0 |
| when(mWifiScannerImpl0.getLatestSingleScanResults()) |
| .thenReturn(new WifiScanner.ScanData(PLACEHOLDER_SCAN_DATA)); |
| eventHandler0.onScanStatus(WifiNative.WIFI_SCAN_FAILED); |
| // but succeeds on impl1 |
| when(mWifiScannerImpl1.getLatestSingleScanResults()) |
| .thenReturn(results.getRawScanData()); |
| eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| |
| mLooper.dispatchAll(); |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verifyNoMoreInteractions(handler); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(workSource)); |
| assertDumpContainsRequestLog("addSingleScanRequest", requestId); |
| assertDumpContainsCallbackLog("singleScanResults", requestId, |
| "results=" + results.getScanData().getResults().length); |
| } |
| |
| /** |
| * Tests wificond PNO scan across multiple impls. This ensures that the |
| * PNO scan results are plumbed back to the client as a PNO network found event. |
| */ |
| @Test |
| public void testSuccessfulHwPnoScanOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| // Results received on impl 0 |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| expectHwPnoScanOnImpls(order, handler, requestId, pnoSettings.second, scanResults, null); |
| verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults()); |
| } |
| |
| /** |
| * Tests wificond PNO scan that fails to start on all impls. |
| */ |
| @Test |
| public void testFailedHwPnoScanWhichFailsToStartOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| when(mWifiScannerImpl0.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| when(mWifiScannerImpl1.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| // pno scan fails on both impls |
| when(mWifiScannerImpl0.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(false); |
| when(mWifiScannerImpl1.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(false); |
| |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| mLooper.dispatchAll(); |
| |
| verifyFailedResponse(order, handler, requestId, WifiScanner.REASON_INVALID_REQUEST, |
| "bad request"); |
| } |
| |
| /** |
| * Tests wificond PNO scan that fails to start on one of the impls. |
| */ |
| @Test |
| public void testSuccessfulHwPnoScanWhichFailsToStartOnOneImpl() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| when(mWifiScannerImpl0.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| when(mWifiScannerImpl1.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| // pno scan fails on impl0 |
| when(mWifiScannerImpl0.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(false); |
| // pno scan succeeds on impl1 |
| when(mWifiScannerImpl1.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| mLooper.dispatchAll(); |
| |
| WifiNative.PnoEventHandler eventHandler0 = |
| verifyHwPnoForImpl(mWifiScannerImpl0, order, pnoSettings.second); |
| WifiNative.PnoEventHandler eventHandler1 = |
| verifyHwPnoForImpl(mWifiScannerImpl1, order, pnoSettings.second); |
| |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| eventHandler1.onPnoNetworkFound(scanResults.getRawScanResults()); |
| mLooper.dispatchAll(); |
| |
| verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults()); |
| } |
| |
| /** |
| * Tests wificond PNO scan that fails after start on all impls. |
| */ |
| @Test |
| public void testFailedHwPnoScanWhichFailsAfterStartOnMultipleImpls() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| when(mWifiScannerImpl0.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| when(mWifiScannerImpl1.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| // pno scan succeeds |
| when(mWifiScannerImpl0.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| when(mWifiScannerImpl1.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| mLooper.dispatchAll(); |
| |
| WifiNative.PnoEventHandler eventHandler0 = |
| verifyHwPnoForImpl(mWifiScannerImpl0, order, pnoSettings.second); |
| WifiNative.PnoEventHandler eventHandler1 = |
| verifyHwPnoForImpl(mWifiScannerImpl1, order, pnoSettings.second); |
| |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| // fails afterwards. |
| eventHandler0.onPnoScanFailed(); |
| eventHandler1.onPnoScanFailed(); |
| mLooper.dispatchAll(); |
| |
| // Scan is successfully queue, but then fails to execute |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| order.verify(handler).handleMessage(messageCaptor.capture()); |
| assertFailedResponse(requestId, WifiScanner.REASON_UNSPECIFIED, |
| "pno scan failed", messageCaptor.getValue()); |
| } |
| |
| /** |
| * Tests wificond PNO scan that fails after start on one impls. |
| */ |
| @Test |
| public void testSuccessfulHwPnoScanWhichFailsAfterStartOnOneImpl() throws Exception { |
| when(mWifiNative.getClientInterfaceNames()) |
| .thenReturn(new ArraySet<>(Arrays.asList(TEST_IFACE_NAME_0, TEST_IFACE_NAME_1))); |
| |
| startServiceAndLoadDriver(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0, mWifiScannerImpl1); |
| int requestId = 12; |
| |
| ScanResults scanResults = createScanResultsForPno(); |
| Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings = |
| createScanSettingsForHwPno(); |
| Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings = |
| createPnoSettings(scanResults); |
| |
| when(mWifiScannerImpl0.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| when(mWifiScannerImpl1.isHwPnoSupported(anyBoolean())).thenReturn(true); |
| // pno scan succeeds |
| when(mWifiScannerImpl0.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| when(mWifiScannerImpl1.setHwPnoList(any(WifiNative.PnoSettings.class), |
| any(WifiNative.PnoEventHandler.class))).thenReturn(true); |
| |
| sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first); |
| mLooper.dispatchAll(); |
| |
| WifiNative.PnoEventHandler eventHandler0 = |
| verifyHwPnoForImpl(mWifiScannerImpl0, order, pnoSettings.second); |
| WifiNative.PnoEventHandler eventHandler1 = |
| verifyHwPnoForImpl(mWifiScannerImpl1, order, pnoSettings.second); |
| |
| verifySuccessfulResponse(order, handler, requestId); |
| |
| // fails afterwards on impl0. |
| eventHandler0.onPnoScanFailed(); |
| // pno match on impl1. |
| eventHandler1.onPnoNetworkFound(scanResults.getRawScanResults()); |
| mLooper.dispatchAll(); |
| |
| verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults()); |
| } |
| |
| /** |
| * Tests that {@link WifiScanningServiceImpl#getAvailableChannels(int, String)} throws a |
| * {@link SecurityException} if the caller doesn't hold the required permissions. |
| */ |
| @Test(expected = SecurityException.class) |
| public void getAvailableChannels_noPermission_throwsException() throws Exception { |
| startServiceAndLoadDriver(); |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| // Location permission or mode check fail. |
| doThrow(new SecurityException()) |
| .when(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| TEST_PACKAGE_NAME, TEST_FEATURE_ID, Binder.getCallingUid(), false, false); |
| |
| mWifiScanningServiceImpl.getAvailableChannels(WifiScanner.WIFI_BAND_24_GHZ, |
| TEST_PACKAGE_NAME, TEST_FEATURE_ID); |
| } |
| |
| /** |
| * Tests that {@link WifiScanningServiceImpl#getAvailableChannels(int, String)} returns |
| * the expected result if the caller does hold the required permissions. |
| */ |
| @Test |
| public void getAvailableChannels_hasPermission_returnsSuccessfully() throws Exception { |
| startServiceAndLoadDriver(); |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| // has access scan results permission |
| doNothing().when(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| TEST_PACKAGE_NAME, TEST_FEATURE_ID, Binder.getCallingUid(), false, false); |
| |
| mLooper.startAutoDispatch(); |
| Bundle bundle = mWifiScanningServiceImpl.getAvailableChannels( |
| WifiScanner.WIFI_BAND_24_GHZ, TEST_PACKAGE_NAME, TEST_FEATURE_ID); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| List<Integer> actual = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA); |
| |
| List<Integer> expected = Arrays.asList(2412, 2450); |
| assertEquals(expected, actual); |
| } |
| |
| /** |
| * Tests that {@link WifiScanningServiceImpl#getAvailableChannels(int, String)} returns |
| * an empty array when wifi is off. |
| */ |
| @Test |
| public void getAvailableChannels_DoesNotCrashWhenWifiDisabled() throws Exception { |
| // Don't enable wifi. |
| |
| // Client doesn't have NETWORK_STACK permission. |
| doThrow(new SecurityException()).when(mContext).enforcePermission( |
| eq(Manifest.permission.NETWORK_STACK), anyInt(), eq(Binder.getCallingUid()), any()); |
| |
| // has access scan results permission |
| doNothing().when(mWifiPermissionsUtil).enforceCanAccessScanResultsForWifiScanner( |
| TEST_PACKAGE_NAME, TEST_FEATURE_ID, Binder.getCallingUid(), false, false); |
| |
| mLooper.startAutoDispatch(); |
| Bundle bundle = mWifiScanningServiceImpl.getAvailableChannels( |
| WifiScanner.WIFI_BAND_24_GHZ, TEST_PACKAGE_NAME, TEST_FEATURE_ID); |
| mLooper.stopAutoDispatchAndIgnoreExceptions(); |
| List<Integer> actual = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA); |
| |
| assertTrue(actual.isEmpty()); |
| } |
| |
| private WifiScanner.ScanSettings triggerEmergencySingleScanAndVerify(WorkSource ws, |
| int requestId, InOrder order, BidirectionalAsyncChannel controlChannel, Handler handler) |
| throws Exception { |
| WifiScanner.ScanSettings requestSettings = |
| createRequest(WifiScanner.WIFI_BAND_ALL, 0, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| requestSettings.ignoreLocationSettings = true; // set emergency scan flag. |
| sendSingleScanRequest(controlChannel, requestId, requestSettings, ws); |
| mLooper.dispatchAll(); |
| |
| // Scan is successfully queued |
| verifySuccessfulResponse(order, handler, requestId); |
| return requestSettings; |
| } |
| |
| private void sendEmergencySingleScanResultsAndVerify( |
| WorkSource ws, int requestId, WifiScanner.ScanSettings requestSettings, |
| ScanResults results, InOrder order, Handler handler) throws Exception { |
| // verify scan start |
| WifiNative.ScanEventHandler eventHandler = |
| verifyStartSingleScan(order, computeSingleScanNativeSettings(requestSettings)); |
| verify(mBatteryStats).reportWifiScanStartedFromSource(eq(ws)); |
| |
| // dispatch scan results |
| when(mWifiScannerImpl0.getLatestSingleScanResults()).thenReturn(results.getScanData()); |
| eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); |
| mLooper.dispatchAll(); |
| |
| verifyScanResultsReceived(order, handler, requestId, results.getScanData()); |
| verifySingleScanCompletedReceived(order, handler, requestId); |
| verify(mBatteryStats).reportWifiScanStoppedFromSource(eq(ws)); |
| } |
| |
| @Test |
| public void startServiceAndTriggerEmergencySingleScanWithoutDriverLoaded() throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| int requestId = 122; |
| WorkSource ws = new WorkSource(2292); |
| ScanResults results = ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 2412); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| // emergency scan request |
| WifiScanner.ScanSettings requestSettings = |
| triggerEmergencySingleScanAndVerify(ws, requestId, order, controlChannel, handler); |
| |
| // Indicate start of emergency scan. |
| verify(mWifiManager).setEmergencyScanRequestInProgress(true); |
| |
| // Now simulate WifiManager enabling scanning. |
| setupAndLoadDriver(controlChannel, TEST_MAX_SCAN_BUCKETS_IN_CAPABILITIES); |
| |
| // Send native results & verify |
| sendEmergencySingleScanResultsAndVerify( |
| ws, requestId, requestSettings, results, order, handler); |
| |
| // Ensure that we indicate the end of emergency scan processing after the timeout. |
| mAlarmManager.dispatch(EMERGENCY_SCAN_END_INDICATION_ALARM_TAG); |
| mLooper.dispatchAll(); |
| verify(mWifiManager).setEmergencyScanRequestInProgress(false); |
| } |
| |
| @Test |
| public void startServiceAndTriggerEmergencySuccessiveSingleScanWithoutDriverLoaded() |
| throws Exception { |
| mWifiScanningServiceImpl.startService(); |
| mLooper.dispatchAll(); |
| mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog); |
| |
| Handler handler = mock(Handler.class); |
| BidirectionalAsyncChannel controlChannel = connectChannel(handler); |
| InOrder order = inOrder(handler, mWifiScannerImpl0); |
| int requestId = 122; |
| WorkSource ws = new WorkSource(2292); |
| ScanResults results = ScanResults.create(0, WifiScanner.WIFI_BAND_ALL, 2412); |
| |
| // successful start |
| when(mWifiScannerImpl0.startSingleScan(any(WifiNative.ScanSettings.class), |
| any(WifiNative.ScanEventHandler.class))).thenReturn(true); |
| |
| // emergency scan request 1 |
| WifiScanner.ScanSettings requestSettings1 = |
| triggerEmergencySingleScanAndVerify(ws, requestId, order, controlChannel, handler); |
| |
| // Indicate start of emergency scan. |
| verify(mWifiManager).setEmergencyScanRequestInProgress(true); |
| |
| // Now simulate WifiManager enabling scanning. |
| setupAndLoadDriver(controlChannel, TEST_MAX_SCAN_BUCKETS_IN_CAPABILITIES); |
| |
| // Send native results & verify |
| sendEmergencySingleScanResultsAndVerify( |
| ws, requestId, requestSettings1, results, order, handler); |
| |
| // emergency scan request 2 |
| clearInvocations(mBatteryStats); |
| order = inOrder(handler, mWifiScannerImpl0); |
| |
| WifiScanner.ScanSettings requestSettings2 = |
| triggerEmergencySingleScanAndVerify(ws, requestId, order, controlChannel, handler); |
| |
| // Indicate start of emergency scan. |
| verify(mWifiManager, times(2)).setEmergencyScanRequestInProgress(true); |
| |
| // Send native results 2 & verify |
| sendEmergencySingleScanResultsAndVerify( |
| ws, requestId, requestSettings2, results, order, handler); |
| |
| // Ensure that we indicate only 1 end of emergency scan processing after the timeout. |
| mAlarmManager.dispatch(EMERGENCY_SCAN_END_INDICATION_ALARM_TAG); |
| mLooper.dispatchAll(); |
| verify(mWifiManager, times(1)).setEmergencyScanRequestInProgress(false); |
| } |
| } |