/* * Copyright (C) 2018 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; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; import static android.net.NetworkFactory.CMD_REQUEST_NETWORK; import static com.android.server.wifi.WifiNetworkFactory.PERIODIC_SCAN_INTERVAL_MS; import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; import android.app.AppOpsManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.MacAddress; import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.INetworkRequestUserSelectionCallback; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.net.wifi.WifiNetworkSpecifier; import android.net.wifi.WifiScanner; import android.net.wifi.WifiScanner.ScanListener; import android.net.wifi.WifiScanner.ScanSettings; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.PatternMatcher; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.WorkSource; import android.os.test.TestLooper; import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import com.android.internal.util.AsyncChannel; import com.android.server.wifi.WifiNetworkFactory.AccessPoint; import com.android.server.wifi.nano.WifiMetricsProto; import com.android.server.wifi.util.ScanResultUtil; 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 java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Unit tests for {@link com.android.server.wifi.WifiNetworkFactory}. */ @SmallTest public class WifiNetworkFactoryTest { private static final int TEST_NETWORK_ID_1 = 104; private static final int TEST_UID_1 = 10423; private static final int TEST_UID_2 = 10424; private static final int TEST_CALLBACK_IDENTIFIER = 123; private static final String TEST_PACKAGE_NAME_1 = "com.test.networkrequest.1"; private static final String TEST_PACKAGE_NAME_2 = "com.test.networkrequest.2"; private static final String TEST_APP_NAME = "app"; private static final String TEST_SSID_1 = "test1234"; private static final String TEST_SSID_2 = "test12345678"; private static final String TEST_SSID_3 = "abc1234"; private static final String TEST_SSID_4 = "abc12345678"; private static final String TEST_BSSID_1 = "12:34:23:23:45:ac"; private static final String TEST_BSSID_2 = "12:34:23:32:12:67"; private static final String TEST_BSSID_3 = "45:34:34:12:bb:dd"; private static final String TEST_BSSID_4 = "45:34:34:56:ee:ff"; private static final String TEST_BSSID_1_2_OUI = "12:34:23:00:00:00"; private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00"; private static final String TEST_WPA_PRESHARED_KEY = "\"password123\""; @Mock Context mContext; @Mock ActivityManager mActivityManager; @Mock AlarmManager mAlarmManager; @Mock AppOpsManager mAppOpsManager; @Mock Clock mClock; @Mock WifiInjector mWifiInjector; @Mock WifiConnectivityManager mWifiConnectivityManager; @Mock WifiConfigManager mWifiConfigManager; @Mock WifiConfigStore mWifiConfigStore; @Mock WifiPermissionsUtil mWifiPermissionsUtil; @Mock WifiScanner mWifiScanner; @Mock PackageManager mPackageManager; @Mock IBinder mAppBinder; @Mock INetworkRequestMatchCallback mNetworkRequestMatchCallback; @Mock ClientModeImpl mClientModeImpl; @Mock ConnectivityManager mConnectivityManager; @Mock WifiMetrics mWifiMetrics; @Mock Messenger mConnectivityMessenger; NetworkCapabilities mNetworkCapabilities; TestLooper mLooper; NetworkRequest mNetworkRequest; WifiScanner.ScanData[] mTestScanDatas; WifiConfiguration mSelectedNetwork; ArgumentCaptor mScanSettingsArgumentCaptor = ArgumentCaptor.forClass(ScanSettings.class); ArgumentCaptor mWorkSourceArgumentCaptor = ArgumentCaptor.forClass(WorkSource.class); ArgumentCaptor mNetworkRequestUserSelectionCallback = ArgumentCaptor.forClass(INetworkRequestUserSelectionCallback.class); ArgumentCaptor mPeriodicScanListenerArgumentCaptor = ArgumentCaptor.forClass(OnAlarmListener.class); ArgumentCaptor mConnectionTimeoutAlarmListenerArgumentCaptor = ArgumentCaptor.forClass(OnAlarmListener.class); ArgumentCaptor mScanListenerArgumentCaptor = ArgumentCaptor.forClass(ScanListener.class); InOrder mInOrder; private WifiNetworkFactory mWifiNetworkFactory; private NetworkRequestStoreData.DataSource mDataSource; /** * Setup the mocks. */ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mLooper = new TestLooper(); mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); mTestScanDatas = ScanTestUtil.createScanDatas(new int[][]{ { 2417, 2427, 5180, 5170 } }); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE))) .thenReturn(mConnectivityManager); when(mPackageManager.getNameForUid(TEST_UID_1)).thenReturn(TEST_PACKAGE_NAME_1); when(mPackageManager.getNameForUid(TEST_UID_2)).thenReturn(TEST_PACKAGE_NAME_2); when(mPackageManager.getApplicationInfo(any(), anyInt())).thenReturn(new ApplicationInfo()); when(mPackageManager.getApplicationLabel(any())).thenReturn(TEST_APP_NAME); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner); when(mWifiInjector.getClientModeImpl()).thenReturn(mClientModeImpl); when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), anyString())) .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID_1)); mWifiNetworkFactory = new WifiNetworkFactory(mLooper.getLooper(), mContext, mNetworkCapabilities, mActivityManager, mAlarmManager, mAppOpsManager, mClock, mWifiInjector, mWifiConnectivityManager, mWifiConfigManager, mWifiConfigStore, mWifiPermissionsUtil, mWifiMetrics); ArgumentCaptor dataSourceArgumentCaptor = ArgumentCaptor.forClass(NetworkRequestStoreData.DataSource.class); verify(mWifiInjector).makeNetworkRequestStoreData(dataSourceArgumentCaptor.capture()); mDataSource = dataSourceArgumentCaptor.getValue(); assertNotNull(mDataSource); // Register and establish full connection to connectivity manager. mWifiNetworkFactory.register(); ArgumentCaptor messengerArgumentCaptor = ArgumentCaptor.forClass(Messenger.class); verify(mConnectivityManager).registerNetworkFactory( messengerArgumentCaptor.capture(), anyString()); assertNotNull(messengerArgumentCaptor.getValue()); Message fullConnectionMsg = Message.obtain(); fullConnectionMsg.what = AsyncChannel.CMD_CHANNEL_FULL_CONNECTION; fullConnectionMsg.replyTo = mConnectivityMessenger; messengerArgumentCaptor.getValue().send(fullConnectionMsg); mLooper.dispatchAll(); mNetworkRequest = new NetworkRequest.Builder() .setCapabilities(mNetworkCapabilities) .build(); // Setup with wifi on. mWifiNetworkFactory.setWifiState(true); mWifiNetworkFactory.enableVerboseLogging(1); } /** * Called after each test */ @After public void cleanup() { validateMockitoUsage(); } /** * Validates handling of needNetworkFor. */ @Test public void testHandleNetworkRequestWithNoSpecifier() { assertFalse(mWifiNetworkFactory.hasConnectionRequests()); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // First network request should turn on auto-join. verify(mWifiConnectivityManager).setTrustedConnectionAllowed(true); assertTrue(mWifiNetworkFactory.hasConnectionRequests()); // Subsequent ones should do nothing. mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verifyNoMoreInteractions(mWifiConnectivityManager); } /** * Validates handling of releaseNetwork. */ @Test public void testHandleNetworkReleaseWithNoSpecifier() { // Release network with out a corresponding request should be ignored. mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); assertFalse(mWifiNetworkFactory.hasConnectionRequests()); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); assertTrue(mWifiNetworkFactory.hasConnectionRequests()); verify(mWifiConnectivityManager).setTrustedConnectionAllowed(true); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); assertFalse(mWifiNetworkFactory.hasConnectionRequests()); verify(mWifiConnectivityManager).setTrustedConnectionAllowed(false); } /** * Validates handling of acceptNetwork for requests with no network specifier. */ @Test public void testHandleAcceptNetworkRequestWithNoSpecifier() { assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier with invalid uid/package name. */ @Test public void testHandleAcceptNetworkRequestFromWithInvalidSpecifier() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_GONE); when(mWifiPermissionsUtil.checkNetworkSettingsPermission(TEST_UID_1)) .thenReturn(true); doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString()); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); mLooper.dispatchAll(); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Validates handling of acceptNetwork with a network specifier with internet capability. */ @Test public void testHandleAcceptNetworkRequestFromWithInternetCapability() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mNetworkRequest.networkCapabilities.addCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET); assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); mLooper.dispatchAll(); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Validates handling of acceptNetwork with a network specifier from a non foreground * app/service. */ @Test public void testHandleAcceptNetworkRequestFromNonFgAppOrSvcWithSpecifier() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE + 1); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); mLooper.dispatchAll(); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * app. */ @Test public void testHandleAcceptNetworkRequestFromFgAppWithSpecifier() { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier from apps holding * NETWORK_SETTINGS. */ @Test public void testHandleAcceptNetworkRequestFromNetworkSettingAppWithSpecifier() { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_GONE); when(mWifiPermissionsUtil.checkNetworkSettingsPermission(TEST_UID_1)) .thenReturn(true); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * app. */ @Test public void testHandleAcceptNetworkRequestFromFgAppWithSpecifierWithPendingRequestFromFgSvc() { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND); // Handle request 1. WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Make request 2 which will be accepted because a fg app request can // override a fg service request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * app. */ @Test public void testHandleAcceptNetworkRequestFromFgSvcWithSpecifierWithPendingRequestFromFgSvc() { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); // Handle request 1. WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Make request 2 which will be accepted because a fg service request can // override an existing fg service request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * app. */ @Test public void testHandleAcceptNetworkRequestFromFgAppWithSpecifierWithPendingRequestFromFgApp() { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND); // Handle request 1. WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Make request 2 which will be accepted because a fg app request can // override an existing fg app request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * service when we're in the midst of processing a request from a foreground app. */ @Test public void testHandleAcceptNetworkRequestFromFgSvcWithSpecifierWithPendingRequestFromFgApp() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); // Handle request 1. WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Make request 2 which will be rejected because a fg service request cannot // override a fg app request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); mLooper.dispatchAll(); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * app when we're connected to a request from a foreground app. */ @Test public void testHandleAcceptNetworkRequestFromFgAppWithSpecifierWithConnectedRequestFromFgApp() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND); // Connect to request 1 sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Make request 2 which will be accepted because a fg app request can // override an existing fg app request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Validates handling of acceptNetwork with a network specifier from a foreground * service when we're connected to a request from a foreground app. */ @Test public void testHandleAcceptNetworkRequestFromFgSvcWithSpecifierWithConnectedRequestFromFgApp() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2)) .thenReturn(IMPORTANCE_FOREGROUND_SERVICE); // Connect to request 1 sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Make request 2 which will be rejected because a fg service request cannot // override a fg app request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); mLooper.dispatchAll(); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Verify handling of new network request with network specifier. */ @Test public void testHandleNetworkRequestWithSpecifier() { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Verify UI start. validateUiStartParams(true); // Verify scan settings. verify(mWifiScanner).startScan(mScanSettingsArgumentCaptor.capture(), any(), mWorkSourceArgumentCaptor.capture()); validateScanSettings(null); verify(mWifiMetrics).incrementNetworkRequestApiNumRequest(); } /** * Validates handling of new network request with network specifier with internet capability. */ @Test public void testHandleNetworkRequestWithSpecifierAndInternetCapability() throws Exception { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mNetworkRequest.networkCapabilities.addCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mLooper.dispatchAll(); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Verify handling of new network request with network specifier for a hidden network. */ @Test public void testHandleNetworkRequestWithSpecifierForHiddenNetwork() { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, true); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Verify UI start. validateUiStartParams(true); // Verify scan settings. verify(mWifiScanner).startScan(mScanSettingsArgumentCaptor.capture(), any(), mWorkSourceArgumentCaptor.capture()); validateScanSettings(specifier.ssidPatternMatcher.getPath()); verify(mWifiMetrics).incrementNetworkRequestApiNumRequest(); } /** * Verify handling of new network request with network specifier for a non-hidden network * after processing a previous hidden network requst. * Validates that the scan settings was properly reset between the 2 request * {@link ScanSettings#hiddenNetworks} */ @Test public void testHandleNetworkRequestWithSpecifierAfterPreviousHiddenNetworkRequest() { // Hidden request 1. WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, true); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Verify scan settings. verify(mWifiScanner, times(1)).startScan(mScanSettingsArgumentCaptor.capture(), any(), mWorkSourceArgumentCaptor.capture()); validateScanSettings(specifier.ssidPatternMatcher.getPath()); // Release request 1. mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); // Regular request 2. specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Verify scan settings. verify(mWifiScanner, times(2)).startScan(mScanSettingsArgumentCaptor.capture(), any(), mWorkSourceArgumentCaptor.capture()); validateScanSettings(null); verify(mWifiMetrics, times(2)).incrementNetworkRequestApiNumRequest(); } /** * Verify handling of release of the active network request with network specifier. */ @Test public void testHandleNetworkReleaseWithSpecifier() { // Make a generic request first to ensure that we re-enable auto-join after release. mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); // Make the network request with specifier. mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verify(mWifiScanner).startScan(any(), any(), any()); // Release the network request. mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); // Verify that we did not trigger a disconnect because we've not yet connected. verify(mClientModeImpl, never()).disconnectCommand(); // Re-enable connectivity manager . verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verify(mWifiMetrics).incrementNetworkRequestApiNumRequest(); } /** * Verify the periodic scan to find a network matching the network specifier. * Simulates the case where the network is not found in any of the scan results. */ @Test public void testPeriodicScanNetworkRequestWithSpecifier() { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS, // 10s PERIODIC_SCAN_INTERVAL_MS, // 10s PERIODIC_SCAN_INTERVAL_MS, // 10s PERIODIC_SCAN_INTERVAL_MS); // 10s } /** * Verify the periodic scan back off to find a network matching the network specifier * is cancelled when the active network request is released. */ @Test public void testPeriodicScanCancelOnReleaseNetworkRequestWithSpecifier() { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS, // 10s PERIODIC_SCAN_INTERVAL_MS); // 10s mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); // Cancel the alarm set for the next scan. verify(mAlarmManager).cancel(any(OnAlarmListener.class)); } /** * Verify callback registration/unregistration. */ @Test public void testHandleCallbackRegistrationAndUnregistration() throws Exception { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); //Ensure that we register the user selection callback using the newly registered callback. verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration( any(INetworkRequestUserSelectionCallback.class)); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); verifyNoMoreInteractions(mNetworkRequestMatchCallback); } /** * Verify callback registration when the active request has already been released.. */ @Test public void testHandleCallbackRegistrationWithNoActiveRequest() throws Exception { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); //Ensure that we trigger the onAbort callback & nothing else. verify(mNetworkRequestMatchCallback).onAbort(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); verifyNoMoreInteractions(mNetworkRequestMatchCallback); } /** * Verify network specifier matching for a specifier containing a specific SSID match using * 4 WPA_PSK scan results, each with unique SSID. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidMatch() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(true); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We only expect 1 network match in this case. validateScanResults(matchedScanResultsCaptor.getValue(), mTestScanDatas[0].getResults()[0]); verify(mWifiMetrics).incrementNetworkRequestApiMatchSizeHistogram( matchedScanResultsCaptor.getValue().size()); } /** * Verify network specifier matching for a specifier containing a Prefix SSID match using * 4 open scan results, each with unique SSID. */ @Test public void testNetworkSpecifierMatchSuccessUsingPrefixSsidMatch() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_OPEN, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_PREFIX); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(false); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We expect 2 scan result matches in this case. validateScanResults(matchedScanResultsCaptor.getValue(), mTestScanDatas[0].getResults()[0], mTestScanDatas[0].getResults()[1]); verify(mWifiMetrics).incrementNetworkRequestApiMatchSizeHistogram( matchedScanResultsCaptor.getValue().size()); } /** * Verify network specifier matching for a specifier containing a specific BSSID match using * 4 WPA_PSK scan results, each with unique SSID. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralBssidMatch() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(TEST_BSSID_1), MacAddress.BROADCAST_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(true); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We only expect 1 scan result match in this case. validateScanResults(matchedScanResultsCaptor.getValue(), mTestScanDatas[0].getResults()[0]); verify(mWifiMetrics).incrementNetworkRequestApiMatchSizeHistogram( matchedScanResultsCaptor.getValue().size()); } /** * Verify network specifier matching for a specifier containing a prefix BSSID match using * 4 WPA_EAP scan results, each with unique SSID. */ @Test public void testNetworkSpecifierMatchSuccessUsingOuiPrefixBssidMatch() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_WPA_EAP, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(TEST_BSSID_1_2_OUI), MacAddress.fromString(TEST_BSSID_OUI_MASK)); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(false); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We expect 2 scan result matches in this case. validateScanResults(matchedScanResultsCaptor.getValue(), mTestScanDatas[0].getResults()[0], mTestScanDatas[0].getResults()[1]); verify(mWifiMetrics).incrementNetworkRequestApiMatchSizeHistogram( matchedScanResultsCaptor.getValue().size()); } /** * Verify network specifier matching for a specifier containing a specific SSID match using * 4 WPA_PSK scan results, 3 of which have the same SSID. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidMatchWithMultipleBssidMatches() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_1, TEST_SSID_1, TEST_SSID_2); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(true); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We expect 3 scan result matches in this case. validateScanResults(matchedScanResultsCaptor.getValue(), mTestScanDatas[0].getResults()[0], mTestScanDatas[0].getResults()[1], mTestScanDatas[0].getResults()[2]); verify(mWifiMetrics).incrementNetworkRequestApiMatchSizeHistogram( matchedScanResultsCaptor.getValue().size()); } /** * Verify network specifier match failure for a specifier containing a specific SSID match using * 4 WPA_PSK scan results, 2 of which SSID_1 and the other 2 SSID_2. But, none of the scan * results' SSID match the one requested in the specifier. */ @Test public void testNetworkSpecifierMatchFailUsingLiteralSsidMatchWhenSsidNotFound() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_1, TEST_SSID_2, TEST_SSID_2); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_3, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(true); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We expect no network match in this case. assertEquals(0, matchedScanResultsCaptor.getValue().size()); verify(mWifiMetrics).incrementNetworkRequestApiMatchSizeHistogram( matchedScanResultsCaptor.getValue().size()); } /** * Verify network specifier match failure for a specifier containing a specific SSID match using * 4 open scan results, each with unique SSID. But, none of the scan * results' key mgmt match the one requested in the specifier. */ @Test public void testNetworkSpecifierMatchFailUsingLiteralSsidMatchWhenKeyMgmtDiffers() throws Exception { // Setup scan data for open networks. setupScanData(SCAN_RESULT_TYPE_OPEN, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Setup network specifier for open networks. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); validateUiStartParams(true); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); // We expect no network match in this case. assertEquals(0, matchedScanResultsCaptor.getValue().size()); } /** * Verify handling of stale user selection (previous request released). */ @Test public void testNetworkSpecifierHandleUserSelectionConnectToNetworkWithoutActiveRequest() throws Exception { sendNetworkRequestAndSetupForUserSelection(); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); // Now release the active network request. mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); // Re-enable connectivity manager (if it was disabled). verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); // Now trigger user selection to some network. WifiConfiguration selectedNetwork = WifiConfigurationTestUtil.createOpenNetwork(); networkRequestUserSelectionCallback.select(selectedNetwork); mLooper.dispatchAll(); // Verify we did not attempt to trigger a connection or disable connectivity manager. verifyNoMoreInteractions(mClientModeImpl, mWifiConnectivityManager); } /** * Verify handling of stale user selection (new request replacing the previous request). */ @Test public void testNetworkSpecifierHandleUserSelectionConnectToNetworkWithDifferentActiveRequest() throws Exception { sendNetworkRequestAndSetupForUserSelection(); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); // Now send another network request. mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Now trigger user selection to some network. WifiConfiguration selectedNetwork = WifiConfigurationTestUtil.createOpenNetwork(); networkRequestUserSelectionCallback.select(selectedNetwork); mLooper.dispatchAll(); // Verify we did not attempt to trigger a connection or disable connectivity manager. verifyNoMoreInteractions(mClientModeImpl, mWifiConnectivityManager, mWifiConfigManager); } /** * Verify handling of user selection to trigger connection to a network. */ @Test public void testNetworkSpecifierHandleUserSelectionConnectToNetwork() throws Exception { sendNetworkRequestAndSetupForUserSelection(); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); // Now trigger user selection to one of the network. ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; mSelectedNetwork = WifiConfigurationTestUtil.createPskNetwork(); mSelectedNetwork.SSID = "\"" + mTestScanDatas[0].getResults()[0].SSID + "\""; networkRequestUserSelectionCallback.select(mSelectedNetwork); mLooper.dispatchAll(); // Cancel periodic scans. verify(mAlarmManager).cancel(any(OnAlarmListener.class)); // Disable connectivity manager verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(true); validateConnectParams(mSelectedNetwork.SSID, matchingScanResult.BSSID); verify(mWifiMetrics).setNominatorForNetwork(anyInt(), eq(WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER)); verify(mClientModeImpl).disconnectCommand(); ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mClientModeImpl).sendMessage(messageCaptor.capture()); Message message = messageCaptor.getValue(); assertNotNull(message); assertEquals(WifiManager.CONNECT_NETWORK, message.what); assertEquals(TEST_NETWORK_ID_1, message.arg1); } /** * Verify handling of user selection to trigger connection to an existing saved network. */ @Test public void testNetworkSpecifierHandleUserSelectionConnectToExistingSavedNetwork() throws Exception { sendNetworkRequestAndSetupForUserSelection(); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); mSelectedNetwork = WifiConfigurationTestUtil.createPskNetwork(); mSelectedNetwork.SSID = "\"" + mTestScanDatas[0].getResults()[0].SSID + "\""; // Have a saved network with the same configuration. WifiConfiguration matchingSavedNetwork = new WifiConfiguration(mSelectedNetwork); matchingSavedNetwork.networkId = TEST_NETWORK_ID_1; when(mWifiConfigManager.getConfiguredNetwork(mSelectedNetwork.configKey())) .thenReturn(matchingSavedNetwork); // Now trigger user selection to one of the network. networkRequestUserSelectionCallback.select(mSelectedNetwork); mLooper.dispatchAll(); // Cancel periodic scans. verify(mAlarmManager).cancel(any(OnAlarmListener.class)); // Disable connectivity manager verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(true); // verify we don't try to add the network to WifiConfigManager. verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt(), anyString()); verify(mClientModeImpl).disconnectCommand(); ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mClientModeImpl).sendMessage(messageCaptor.capture()); Message message = messageCaptor.getValue(); assertNotNull(message); assertEquals(WifiManager.CONNECT_NETWORK, message.what); assertEquals(TEST_NETWORK_ID_1, message.arg1); } /** * Verify handling of user selection to trigger connection to a network. Ensure we fill * up the BSSID field. */ @Test public void testNetworkSpecifierHandleUserSelectionConnectToNetworkUsingLiteralSsidAndBssidMatch() throws Exception { setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Make a specific AP request. ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.BROADCAST_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); wifiConfiguration.preSharedKey = TEST_WPA_PRESHARED_KEY; WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration( mNetworkRequestUserSelectionCallback.capture()); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); // Now trigger user selection to the network. mSelectedNetwork = ScanResultUtil.createNetworkFromScanResult(matchingScanResult); mSelectedNetwork.SSID = "\"" + matchingScanResult.SSID + "\""; INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); networkRequestUserSelectionCallback.select(mSelectedNetwork); mLooper.dispatchAll(); // Verify WifiConfiguration params. validateConnectParams(mSelectedNetwork.SSID, matchingScanResult.BSSID); verify(mWifiMetrics).setNominatorForNetwork(anyInt(), eq(WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER)); verify(mClientModeImpl).disconnectCommand(); // Verify connection message. ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mClientModeImpl).sendMessage(messageCaptor.capture()); Message message = messageCaptor.getValue(); assertNotNull(message); assertEquals(WifiManager.CONNECT_NETWORK, message.what); assertEquals(TEST_NETWORK_ID_1, message.arg1); } /** * Verify handling of user selection to trigger connection to a network. Ensure we fill * up the BSSID field with scan result for highest RSSI. */ @Test public void testNetworkSpecifierHandleUserSelectionConnectToNetworkMultipleBssidMatches() throws Exception { setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_1, TEST_SSID_1, TEST_SSID_4); // Make a ssid pattern request which matches 3 scan results - 0, 1, 2. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); wifiConfiguration.preSharedKey = TEST_WPA_PRESHARED_KEY; WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration( mNetworkRequestUserSelectionCallback.capture()); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); // Scan result 2 has the highest RSSI, so that should be picked. ScanResult matchingScanResult = mTestScanDatas[0].getResults()[2]; // Now trigger user selection to the network. mSelectedNetwork = ScanResultUtil.createNetworkFromScanResult(matchingScanResult); mSelectedNetwork.SSID = "\"" + matchingScanResult.SSID + "\""; INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); networkRequestUserSelectionCallback.select(mSelectedNetwork); mLooper.dispatchAll(); // Verify WifiConfiguration params. validateConnectParams(mSelectedNetwork.SSID, matchingScanResult.BSSID); verify(mWifiMetrics).setNominatorForNetwork(anyInt(), eq(WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER)); verify(mClientModeImpl).disconnectCommand(); // Verify connection message. ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mClientModeImpl).sendMessage(messageCaptor.capture()); Message message = messageCaptor.getValue(); assertNotNull(message); assertEquals(WifiManager.CONNECT_NETWORK, message.what); assertEquals(TEST_NETWORK_ID_1, message.arg1); } /** * Verify handling of user selection to reject the request. */ @Test public void testNetworkSpecifierHandleUserSelectionReject() throws Exception { sendNetworkRequestAndSetupForUserSelection(); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); // Now trigger user rejection. networkRequestUserSelectionCallback.reject(); mLooper.dispatchAll(); // Cancel periodic scans. verify(mAlarmManager).cancel(any(OnAlarmListener.class)); // Verify we reset the network request handling. verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyUnfullfillableDispatched(mConnectivityMessenger); verify(mWifiMetrics).incrementNetworkRequestApiNumUserReject(); // Verify we did not attempt to trigger a connection. verifyNoMoreInteractions(mClientModeImpl, mWifiConfigManager); } /** * Verify handling of connection timeout. * The timeouts should trigger connection retries until we hit the max. */ @Test public void testNetworkSpecifierHandleConnectionTimeout() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Simulate connection timeout beyond the retry limit to trigger the failure handling. for (int i = 0; i <= WifiNetworkFactory.USER_SELECTED_NETWORK_CONNECT_RETRY_MAX; i++) { mConnectionTimeoutAlarmListenerArgumentCaptor.getValue().onAlarm(); mLooper.dispatchAll(); } mInOrder = inOrder(mAlarmManager, mClientModeImpl); validateConnectionRetryAttempts(); // Fail the request after all the retries are exhausted. verify(mNetworkRequestMatchCallback).onAbort(); // Verify that we sent the connection failure callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure( argThat(new WifiConfigMatcher(mSelectedNetwork))); // Verify we reset the network request handling. verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Verify handling of connection trigger failure. * The trigger failures should trigger connection retries until we hit the max. */ @Test public void testNetworkSpecifierHandleConnectionTriggerFailure() throws Exception { Messenger replyToMsgr = sendNetworkRequestAndSetupForConnectionStatus(); // Send failure message beyond the retry limit to trigger the failure handling. for (int i = 0; i <= WifiNetworkFactory.USER_SELECTED_NETWORK_CONNECT_RETRY_MAX; i++) { Message failureMsg = Message.obtain(); failureMsg.what = WifiManager.CONNECT_NETWORK_FAILED; replyToMsgr.send(failureMsg); mLooper.dispatchAll(); } mInOrder = inOrder(mAlarmManager, mClientModeImpl); validateConnectionRetryAttempts(); // Fail the request after all the retries are exhausted. verify(mNetworkRequestMatchCallback).onAbort(); // Verify that we sent the connection failure callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. mInOrder.verify(mAlarmManager).cancel( mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Verify we reset the network request handling. verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Verify handling of connection failure. * The connection failures should trigger connection retries until we hit the max. */ @Test public void testNetworkSpecifierHandleConnectionFailure() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); assertNotNull(mSelectedNetwork); // Send network connection failure indication beyond the retry limit to trigger the failure // handling. for (int i = 0; i <= WifiNetworkFactory.USER_SELECTED_NETWORK_CONNECT_RETRY_MAX; i++) { mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_DHCP, mSelectedNetwork); mLooper.dispatchAll(); } mInOrder = inOrder(mAlarmManager, mClientModeImpl); validateConnectionRetryAttempts(); verify(mNetworkRequestMatchCallback).onAbort(); // Verify that we sent the connection failure callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. mInOrder.verify(mAlarmManager).cancel( mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Verify we reset the network request handling. verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Verify handling of connection failure to a different network. */ @Test public void testNetworkSpecifierHandleConnectionFailureToWrongNetwork() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Send network connection failure to a different network indication. assertNotNull(mSelectedNetwork); WifiConfiguration connectedNetwork = new WifiConfiguration(mSelectedNetwork); connectedNetwork.SSID += "test"; mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_DHCP, connectedNetwork); // Verify that we did not send the connection failure callback. verify(mNetworkRequestMatchCallback, never()).onUserSelectionConnectFailure(any()); // verify we canceled the timeout alarm. verify(mAlarmManager, never()) .cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Verify we don't reset the network request handling. verify(mWifiConnectivityManager, never()) .setSpecificNetworkRequestInProgress(false); // Send network connection failure indication beyond the retry limit to trigger the failure // handling. for (int i = 0; i <= WifiNetworkFactory.USER_SELECTED_NETWORK_CONNECT_RETRY_MAX; i++) { mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_DHCP, mSelectedNetwork); mLooper.dispatchAll(); } mInOrder = inOrder(mAlarmManager, mClientModeImpl); validateConnectionRetryAttempts(); // Verify that we sent the connection failure callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. mInOrder.verify(mAlarmManager).cancel( mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Verify we reset the network request handling. verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyUnfullfillableDispatched(mConnectivityMessenger); } /** * Verify handling of connection success. */ @Test public void testNetworkSpecifierHandleConnectionSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Verify that we sent the connection success callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); verify(mWifiMetrics).incrementNetworkRequestApiNumConnectSuccess(); } /** * Verify that we ignore connection success events after the first one (may be triggered by a * roam event) */ @Test public void testNetworkSpecifierDuplicateHandleConnectionSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Verify that we sent the connection success callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); verify(mWifiMetrics).incrementNetworkRequestApiNumConnectSuccess(); // Send second network connection success indication which should be ignored. mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); verifyNoMoreInteractions(mNetworkRequestMatchCallback); } /** * Verify that we ignore any connection failure events after the first connection success (may * be triggered by a disconnect). * Note: The disconnect handling will be done via the NetworkAgent. */ @Test public void testNetworkSpecifierHandleConnectionFailureAfterSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Verify that we sent the connection success callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); verify(mWifiMetrics).incrementNetworkRequestApiNumConnectSuccess(); // Send a network connection failure indication which should be ignored (beyond the retry // limit to trigger the failure handling). for (int i = 0; i <= WifiNetworkFactory.USER_SELECTED_NETWORK_CONNECT_RETRY_MAX; i++) { mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_DHCP, mSelectedNetwork); mLooper.dispatchAll(); } // Verify that we ignore the second connection failure callback. verifyNoMoreInteractions(mNetworkRequestMatchCallback); } /** * Verify handling of connection success to a different network. */ @Test public void testNetworkSpecifierHandleConnectionSuccessToWrongNetwork() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Send network connection success to a different network indication. assertNotNull(mSelectedNetwork); WifiConfiguration connectedNetwork = new WifiConfiguration(mSelectedNetwork); connectedNetwork.SSID += "test"; mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, connectedNetwork); // verify that we did not send out the success callback and did not stop the alarm timeout. verify(mNetworkRequestMatchCallback, never()).onUserSelectionConnectSuccess(any()); verify(mAlarmManager, never()) .cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Send network connection success to the correct network indication. mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Verify that we sent the connection success callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); } /** * Verify handling of request release after connecting to the network. */ @Test public void testHandleNetworkReleaseWithSpecifierAfterConnectionSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Verify that we sent the connection success callback. verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess( argThat(new WifiConfigMatcher(mSelectedNetwork))); // verify we canceled the timeout alarm. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Now release the network request. mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); // Verify that we triggered a disconnect. verify(mClientModeImpl, times(2)).disconnectCommand(); // Re-enable connectivity manager . verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); } /** * Verify we return the correct UID when processing network request with network specifier. */ @Test public void testHandleNetworkRequestWithSpecifierGetUid() throws Exception { assertEquals(Integer.valueOf(Process.INVALID_UID), mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName( new WifiConfiguration()).first); assertTrue(mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName( new WifiConfiguration()).second.isEmpty()); sendNetworkRequestAndSetupForConnectionStatus(); assertNotNull(mSelectedNetwork); // connected to a different network. WifiConfiguration connectedNetwork = new WifiConfiguration(mSelectedNetwork); connectedNetwork.SSID += "test"; assertEquals(Integer.valueOf(Process.INVALID_UID), mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName( new WifiConfiguration()).first); assertTrue(mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName( new WifiConfiguration()).second.isEmpty()); // connected to the correct network. connectedNetwork = new WifiConfiguration(mSelectedNetwork); assertEquals(Integer.valueOf(TEST_UID_1), mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName( connectedNetwork).first); assertEquals(TEST_PACKAGE_NAME_1, mWifiNetworkFactory.getSpecificNetworkRequestUidAndPackageName( connectedNetwork).second); } /** * Verify handling for new network request while processing another one. */ @Test public void testHandleNewNetworkRequestWithSpecifierWhenScanning() throws Exception { WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Register callback. mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(any()); // Send second request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mLooper.dispatchAll(); verify(mNetworkRequestMatchCallback).onAbort(); verify(mWifiScanner, times(2)).startScan(any(), any(), any()); verifyUnfullfillableDispatched(mConnectivityMessenger); // Remove the stale request1 & ensure nothing happens. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager, mNetworkRequestMatchCallback); // Remove the active request2 & ensure auto-join is re-enabled. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); } /** * Verify handling for new network request while processing another one. */ @Test public void testHandleNewNetworkRequestWithSpecifierAfterMatch() throws Exception { sendNetworkRequestAndSetupForUserSelection(); WifiNetworkSpecifier specifier1 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); // Send second request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Ignore stale callbacks. WifiConfiguration selectedNetwork = WifiConfigurationTestUtil.createOpenNetwork(); networkRequestUserSelectionCallback.select(selectedNetwork); mLooper.dispatchAll(); verify(mNetworkRequestMatchCallback).onAbort(); verify(mWifiScanner, times(2)).startScan(any(), any(), any()); verify(mAlarmManager).cancel(mPeriodicScanListenerArgumentCaptor.getValue()); verifyUnfullfillableDispatched(mConnectivityMessenger); // Remove the stale request1 & ensure nothing happens. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager, mNetworkRequestMatchCallback); // Remove the active request2 & ensure auto-join is re-enabled. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); } /** * Verify handling for new network request while processing another one. */ @Test public void testHandleNewNetworkRequestWithSpecifierAfterConnect() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); WifiNetworkSpecifier specifier1 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); // Send second request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verify(mNetworkRequestMatchCallback).onAbort(); verify(mWifiConnectivityManager, times(1)).setSpecificNetworkRequestInProgress(true); verify(mWifiScanner, times(2)).startScan(any(), any(), any()); verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Remove the stale request1 & ensure nothing happens. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager, mNetworkRequestMatchCallback); // Remove the active request2 & ensure auto-join is re-enabled. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); } /** * Verify handling for new network request while processing another one. */ @Test public void testHandleNewNetworkRequestWithSpecifierAfterConnectionSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); WifiNetworkSpecifier specifier1 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Cancel the connection timeout. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Send second request. WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verify(mWifiConnectivityManager, times(1)).setSpecificNetworkRequestInProgress(true); verify(mWifiScanner, times(2)).startScan(any(), any(), any()); // we shouldn't disconnect until the user accepts the next request. verify(mClientModeImpl, times(1)).disconnectCommand(); // Remove the connected request1 & ensure we disconnect. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mClientModeImpl, times(2)).disconnectCommand(); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager); // Now remove the active request2 & ensure auto-join is re-enabled. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager); } /** * Verify handling for new network request while processing another one. */ @Test public void testHandleNewNetworkRequestWithSpecifierWhichUserSelectedAfterConnectionSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1); WifiNetworkSpecifier specifier1 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Cancel the connection timeout. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Send second request & we simulate the user selecting the request & connecting to it. reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager); sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_2); WifiNetworkSpecifier specifier2 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Cancel the connection timeout. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // We shouldn't explicitly disconnect, the new connection attempt will implicitly disconnect // from the connected network. verify(mClientModeImpl, times(2)).disconnectCommand(); // Remove the stale request1 & ensure nothing happens (because it was replaced by the // second request) mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager); // Now remove the rejected request2, ensure we disconnect & re-enable auto-join. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mClientModeImpl, times(3)).disconnectCommand(); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager); } /** * Verify handling for new network request while processing another one. */ @Test public void testHandleNewNetworkRequestWithSpecifierWhichUserRejectedAfterConnectionSuccess() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1); WifiNetworkSpecifier specifier1 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); // Send network connection success indication. assertNotNull(mSelectedNetwork); mWifiNetworkFactory.handleConnectionAttemptEnded( WifiMetrics.ConnectionEvent.FAILURE_NONE, mSelectedNetwork); // Cancel the connection timeout. verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Send second request & we simulate the user rejecting the request. reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager); sendNetworkRequestAndSetupForUserSelection(TEST_SSID_2); WifiNetworkSpecifier specifier2 = (WifiNetworkSpecifier) mNetworkRequest.networkCapabilities.getNetworkSpecifier(); mNetworkRequestUserSelectionCallback.getValue().reject(); mLooper.dispatchAll(); // cancel periodic scans. verify(mAlarmManager).cancel(mPeriodicScanListenerArgumentCaptor.getValue()); // we shouldn't disconnect/re-enable auto-join until the connected request is released. verify(mWifiConnectivityManager, never()).setSpecificNetworkRequestInProgress(false); verify(mClientModeImpl, times(1)).disconnectCommand(); // Remove the connected request1 & ensure we disconnect & ensure auto-join is re-enabled. mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verify(mClientModeImpl, times(2)).disconnectCommand(); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager); // Now remove the rejected request2 & ensure nothing happens mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2); mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); verifyNoMoreInteractions(mWifiConnectivityManager, mWifiScanner, mClientModeImpl, mAlarmManager); } /** * Verify handling of screen state changes while triggering periodic scans to find matching * networks. */ @Test public void testNetworkSpecifierHandleScreenStateChangedWhileScanning() throws Exception { sendNetworkRequestAndSetupForUserSelection(); // Turn off screen. mWifiNetworkFactory.handleScreenStateChanged(false); // 1. Cancel the scan timer. mInOrder.verify(mAlarmManager).cancel( mPeriodicScanListenerArgumentCaptor.getValue()); // 2. Simulate the scan results from an ongoing scan, ensure no more scans are scheduled. mScanListenerArgumentCaptor.getValue().onResults(mTestScanDatas); // Ensure no more interactions. mInOrder.verifyNoMoreInteractions(); // Now, turn the screen on. mWifiNetworkFactory.handleScreenStateChanged(true); // Verify that we resumed periodic scanning. mInOrder.verify(mWifiScanner).startScan(any(), any(), any()); } /** * Verify handling of screen state changes after the active network request was released. */ @Test public void testNetworkSpecifierHandleScreenStateChangedWithoutActiveRequest() throws Exception { sendNetworkRequestAndSetupForUserSelection(); // Now release the active network request. mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest); // Cancel the scan timer on release. mInOrder.verify(mAlarmManager).cancel( mPeriodicScanListenerArgumentCaptor.getValue()); // Turn off screen. mWifiNetworkFactory.handleScreenStateChanged(false); // Now, turn the screen on. mWifiNetworkFactory.handleScreenStateChanged(true); // Ensure that we did not pause or resume scanning. mInOrder.verifyNoMoreInteractions(); } /** * Verify handling of screen state changes after user selected a network to connect to. */ @Test public void testNetworkSpecifierHandleScreenStateChangedAfterUserSelection() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // Turn off screen. mWifiNetworkFactory.handleScreenStateChanged(false); // Now, turn the screen on. mWifiNetworkFactory.handleScreenStateChanged(true); // Ensure that we did not pause or resume scanning. mInOrder.verifyNoMoreInteractions(); } /** * Verify we don't accept specific network request when wifi is off. */ @Test public void testHandleAcceptNetworkRequestWithSpecifierWhenWifiOff() throws Exception { when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1)) .thenReturn(IMPORTANCE_FOREGROUND); WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); // set wifi off. mWifiNetworkFactory.setWifiState(false); assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); // set wifi on. mWifiNetworkFactory.setWifiState(true); assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0)); } /** * Verify handling of new network request with network specifier when wifi is off. */ @Test public void testHandleNetworkRequestWithSpecifierWhenWifiOff() { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); // set wifi off mWifiNetworkFactory.setWifiState(false); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verify(mWifiScanner, never()).startScan(any(), any(), any()); // set wifi on mWifiNetworkFactory.setWifiState(true); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); verify(mWifiScanner).startScan(any(), any(), any()); } /** * Verify wifi toggle off when scanning. */ @Test public void testHandleNetworkRequestWithSpecifierWifiOffWhenScanning() throws Exception { WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); // Register callback. mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(any()); verify(mWifiScanner).startScan(any(), any(), any()); // toggle wifi off & verify we aborted ongoing request. mWifiNetworkFactory.setWifiState(false); verify(mNetworkRequestMatchCallback).onAbort(); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); } /** * Verify wifi toggle off after connection attempt is started. */ @Test public void testHandleNetworkRequestWithSpecifierWifiOffAfterConnect() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(); // toggle wifi off & verify we aborted ongoing request. mWifiNetworkFactory.setWifiState(false); verify(mAlarmManager).cancel(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); verify(mNetworkRequestMatchCallback).onAbort(); verify(mWifiConnectivityManager).setSpecificNetworkRequestInProgress(false); } /** * Verify handling of new network request with network specifier when wifi is off & then on. * Note: Unlike the other unit tests, this test invokes the top level * {@link NetworkFactory#CMD_REQUEST_NETWORK} to simulate the full flow. */ @Test public void testFullHandleNetworkRequestWithSpecifierWhenWifiOff() { WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); // set wifi off mWifiNetworkFactory.setWifiState(false); // Add the request, should do nothing. Message message = Message.obtain(); message.what = CMD_REQUEST_NETWORK; message.obj = mNetworkRequest; mWifiNetworkFactory.sendMessage(message); mLooper.dispatchAll(); verify(mWifiScanner, never()).startScan(any(), any(), any()); // set wifi on mWifiNetworkFactory.setWifiState(true); mLooper.dispatchAll(); // Should trigger a re-evaluation of existing requests and the pending request will be // processed now. verify(mWifiScanner).startScan(any(), any(), any()); } /** * Verify the user approval bypass for a specific request for an access point that was already * approved previously. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchPreviouslyApproved() throws Exception { // 1. First request (no user approval bypass) sendNetworkRequestAndSetupForConnectionStatus(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl); // 2. Second request for the same access point (user approval bypass). ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.BROADCAST_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); // Trigger scan results & ensure we triggered a connect. verify(mWifiScanner).startScan(any(), mScanListenerArgumentCaptor.capture(), any()); ScanListener scanListener = mScanListenerArgumentCaptor.getValue(); assertNotNull(scanListener); scanListener.onResults(mTestScanDatas); // Verify we did not trigger the match callback. verify(mNetworkRequestMatchCallback, never()).onMatch(anyList()); // Verify that we sent a connection attempt to ClientModeImpl verify(mClientModeImpl).sendMessage(any()); verify(mWifiMetrics).incrementNetworkRequestApiNumUserApprovalBypass(); } /** * Verify that we don't bypass user approval for a specific request for an access point that was * approved previously, but then the user forgot it sometime after. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchPreviouslyApprovedNForgot() throws Exception { // 1. First request (no user approval bypass) sendNetworkRequestAndSetupForConnectionStatus(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl); // 2. Simulate user forgeting the network. when(mWifiConfigManager.wasEphemeralNetworkDeleted( ScanResultUtil.createQuotedSSID(mTestScanDatas[0].getResults()[0].SSID))) .thenReturn(true); // 3. Second request for the same access point (user approval bypass). ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.BROADCAST_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); // Verify we triggered the match callback. matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeImpl. verify(mClientModeImpl, never()).sendMessage(any()); } /** * Verify that we don't bypass user approval for a specific request for an access point that was * not approved previously. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchNotPreviouslyApproved() throws Exception { // 1. First request (no user approval bypass) sendNetworkRequestAndSetupForConnectionStatus(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl); // 2. Second request for a different access point (but same network). setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_1, TEST_SSID_3, TEST_SSID_4); ScanResult matchingScanResult = mTestScanDatas[0].getResults()[1]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.BROADCAST_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); // Verify we triggered the match callback. matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeImpl. verify(mClientModeImpl, never()).sendMessage(any()); } /** * Verify that we don't bypass user approval for a specific request for a network * (not access point) that was approved previously. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidMatchPreviouslyApproved() throws Exception { // 1. First request (no user approval bypass) sendNetworkRequestAndSetupForConnectionStatus(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl); // 2. Second request for the same network (but not specific access point) ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); // match-all. Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); // Verify we triggered the match callback. matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeImpl. verify(mClientModeImpl, never()).sendMessage(any()); } /** * Verify the we don't bypass user approval for a specific request for an access point that was * already approved previously, but was then removed (app uninstalled, user deleted it from * notification, from tests, etc). */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchAfterApprovalsRemove() throws Exception { // 1. First request (no user approval bypass) sendNetworkRequestAndSetupForConnectionStatus(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl); // 2. Remove all approvals for the app. mWifiNetworkFactory.removeUserApprovedAccessPointsForApp(TEST_PACKAGE_NAME_1); // 3. Second request for the same access point ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.ALL_ZEROS_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); // Verify we triggered the match callback. matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeImpl. verify(mClientModeImpl, never()).sendMessage(any()); } /** * Verify the we don't bypass user approval for a specific request for an access point that was * already approved previously, but then the user perform network settings reset. */ @Test public void testNetworkSpecifierMatchSuccessUsingLiteralSsidAndBssidMatchAfterClear() throws Exception { // 1. First request (no user approval bypass) sendNetworkRequestAndSetupForConnectionStatus(); mWifiNetworkFactory.removeCallback(TEST_CALLBACK_IDENTIFIER); reset(mNetworkRequestMatchCallback, mWifiScanner, mAlarmManager, mClientModeImpl); // 2. Remove all approvals. mWifiNetworkFactory.clear(); // 3. Second request for the same access point ScanResult matchingScanResult = mTestScanDatas[0].getResults()[0]; PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(matchingScanResult.BSSID), MacAddress.ALL_ZEROS_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); ArgumentCaptor> matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); // Verify we triggered the match callback. matchedScanResultsCaptor = ArgumentCaptor.forClass(List.class); verify(mNetworkRequestMatchCallback).onMatch(matchedScanResultsCaptor.capture()); assertNotNull(matchedScanResultsCaptor.getValue()); validateScanResults(matchedScanResultsCaptor.getValue(), matchingScanResult); // Verify that we did not send a connection attempt to ClientModeImpl. verify(mClientModeImpl, never()).sendMessage(any()); } /** * Verify the config store save for store user approval. */ @Test public void testNetworkSpecifierUserApprovalConfigStoreSave() throws Exception { sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1); // Verify config store interactions. verify(mWifiConfigManager).saveToStore(true); assertTrue(mDataSource.hasNewDataToSerialize()); Map> approvedAccessPointsMapToWrite = mDataSource.toSerialize(); assertEquals(1, approvedAccessPointsMapToWrite.size()); assertTrue(approvedAccessPointsMapToWrite.keySet().contains(TEST_PACKAGE_NAME_1)); Set approvedAccessPointsToWrite = approvedAccessPointsMapToWrite.get(TEST_PACKAGE_NAME_1); Set expectedApprovedAccessPoints = new HashSet() {{ add(new AccessPoint(TEST_SSID_1, MacAddress.fromString(TEST_BSSID_1), WifiConfiguration.SECURITY_TYPE_PSK)); }}; assertEquals(expectedApprovedAccessPoints, approvedAccessPointsToWrite); // Ensure that the new data flag has been reset after read. assertFalse(mDataSource.hasNewDataToSerialize()); } /** * Verify the config store load for store user approval. */ @Test public void testNetworkSpecifierUserApprovalConfigStoreLoad() throws Exception { Map> approvedAccessPointsMapToRead = new HashMap<>(); Set approvedAccessPoints = new HashSet() {{ add(new AccessPoint(TEST_SSID_1, MacAddress.fromString(TEST_BSSID_1), WifiConfiguration.SECURITY_TYPE_PSK)); }}; approvedAccessPointsMapToRead.put(TEST_PACKAGE_NAME_1, approvedAccessPoints); mDataSource.fromDeserialized(approvedAccessPointsMapToRead); // The new network request should bypass user approval for the same access point. PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.fromString(TEST_BSSID_1), MacAddress.BROADCAST_ADDRESS); WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, WifiConfigurationTestUtil.createPskNetwork(), TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); // Trigger scan results & ensure we triggered a connect. setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); verify(mWifiScanner).startScan(any(), mScanListenerArgumentCaptor.capture(), any()); ScanListener scanListener = mScanListenerArgumentCaptor.getValue(); assertNotNull(scanListener); scanListener.onResults(mTestScanDatas); // Verify we did not trigger the match callback. verify(mNetworkRequestMatchCallback, never()).onMatch(anyList()); // Verify that we sent a connection attempt to ClientModeImpl verify(mClientModeImpl).sendMessage(any()); } private Messenger sendNetworkRequestAndSetupForConnectionStatus() throws RemoteException { return sendNetworkRequestAndSetupForConnectionStatus(TEST_SSID_1); } // Helper method to setup the necessary pre-requisite steps for tracking connection status. private Messenger sendNetworkRequestAndSetupForConnectionStatus(String targetSsid) throws RemoteException { when(mClock.getElapsedSinceBootMillis()).thenReturn(0L); sendNetworkRequestAndSetupForUserSelection(targetSsid); INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback = mNetworkRequestUserSelectionCallback.getValue(); assertNotNull(networkRequestUserSelectionCallback); // Now trigger user selection to one of the network. mSelectedNetwork = WifiConfigurationTestUtil.createPskNetwork(); mSelectedNetwork.SSID = "\"" + targetSsid + "\""; networkRequestUserSelectionCallback.select(mSelectedNetwork); mLooper.dispatchAll(); // Cancel the periodic scan timer. mInOrder.verify(mAlarmManager).cancel(mPeriodicScanListenerArgumentCaptor.getValue()); // Disable connectivity manager verify(mWifiConnectivityManager, atLeastOnce()).setSpecificNetworkRequestInProgress(true); // Increment the number of unique apps. verify(mWifiMetrics).incrementNetworkRequestApiNumApps(); verify(mClientModeImpl, atLeastOnce()).disconnectCommand(); ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mClientModeImpl, atLeastOnce()).sendMessage(messageCaptor.capture()); Message message = messageCaptor.getValue(); assertNotNull(message); // Start the connection timeout alarm. mInOrder.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq((long) WifiNetworkFactory.NETWORK_CONNECTION_TIMEOUT_MS), any(), mConnectionTimeoutAlarmListenerArgumentCaptor.capture(), any()); assertNotNull(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); return message.replyTo; } private void sendNetworkRequestAndSetupForUserSelection() throws RemoteException { sendNetworkRequestAndSetupForUserSelection(TEST_SSID_1); } // Helper method to setup the necessary pre-requisite steps for user selection. private void sendNetworkRequestAndSetupForUserSelection(String targetSsid) throws RemoteException { // Setup scan data for WPA-PSK networks. setupScanData(SCAN_RESULT_TYPE_WPA_PSK, TEST_SSID_1, TEST_SSID_2, TEST_SSID_3, TEST_SSID_4); // Setup network specifier for WPA-PSK networks. PatternMatcher ssidPatternMatch = new PatternMatcher(targetSsid, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration = WifiConfigurationTestUtil.createPskNetwork(); wifiConfiguration.preSharedKey = TEST_WPA_PRESHARED_KEY; WifiNetworkSpecifier specifier = new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, TEST_UID_1, TEST_PACKAGE_NAME_1); mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier); mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0); mWifiNetworkFactory.addCallback(mAppBinder, mNetworkRequestMatchCallback, TEST_CALLBACK_IDENTIFIER); verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration( mNetworkRequestUserSelectionCallback.capture()); verifyPeriodicScans(0, PERIODIC_SCAN_INTERVAL_MS); verify(mNetworkRequestMatchCallback).onMatch(anyList()); } // Simulates the periodic scans performed to find a matching network. // a) Start scan // b) Scan results received. // c) Set alarm for next scan at the expected interval. // d) Alarm fires, go to step a) again and repeat. private void verifyPeriodicScans(long...expectedIntervalsInSeconds) { when(mClock.getElapsedSinceBootMillis()).thenReturn(0L); OnAlarmListener alarmListener = null; ScanListener scanListener = null; mInOrder = inOrder(mWifiScanner, mAlarmManager); for (int i = 0; i < expectedIntervalsInSeconds.length - 1; i++) { long expectedCurrentIntervalInMs = expectedIntervalsInSeconds[i]; long expectedNextIntervalInMs = expectedIntervalsInSeconds[i + 1]; // First scan is immediately fired, so need for the alarm to fire. if (expectedCurrentIntervalInMs != 0) { // Fire the alarm and ensure that we started the next scan. alarmListener.onAlarm(); } mInOrder.verify(mWifiScanner).startScan( any(), mScanListenerArgumentCaptor.capture(), any()); scanListener = mScanListenerArgumentCaptor.getValue(); assertNotNull(scanListener); // Now trigger the scan results callback and verify the alarm set for the next scan. scanListener.onResults(mTestScanDatas); mInOrder.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(expectedNextIntervalInMs), any(), mPeriodicScanListenerArgumentCaptor.capture(), any()); alarmListener = mPeriodicScanListenerArgumentCaptor.getValue(); assertNotNull(alarmListener); } mInOrder.verifyNoMoreInteractions(); } private WifiNetworkSpecifier createWifiNetworkSpecifier(int uid, boolean isHidden) { PatternMatcher ssidPatternMatch = new PatternMatcher(TEST_SSID_1, PatternMatcher.PATTERN_LITERAL); Pair bssidPatternMatch = Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); WifiConfiguration wifiConfiguration; if (isHidden) { wifiConfiguration = WifiConfigurationTestUtil.createPskHiddenNetwork(); } else { wifiConfiguration = WifiConfigurationTestUtil.createPskNetwork(); } String packageName = null; if (uid == TEST_UID_1) { packageName = TEST_PACKAGE_NAME_1; } else if (uid == TEST_UID_2) { packageName = TEST_PACKAGE_NAME_2; } else { fail(); } return new WifiNetworkSpecifier( ssidPatternMatch, bssidPatternMatch, wifiConfiguration, uid, packageName); } private static final int SCAN_RESULT_TYPE_OPEN = 0; private static final int SCAN_RESULT_TYPE_WPA_PSK = 1; private static final int SCAN_RESULT_TYPE_WPA_EAP = 2; private String getScanResultCapsForType(int scanResultType) { switch (scanResultType) { case SCAN_RESULT_TYPE_OPEN: return WifiConfigurationTestUtil.getScanResultCapsForNetwork( WifiConfigurationTestUtil.createOpenNetwork()); case SCAN_RESULT_TYPE_WPA_PSK: return WifiConfigurationTestUtil.getScanResultCapsForNetwork( WifiConfigurationTestUtil.createPskNetwork()); case SCAN_RESULT_TYPE_WPA_EAP: return WifiConfigurationTestUtil.getScanResultCapsForNetwork( WifiConfigurationTestUtil.createEapNetwork()); } fail("Invalid scan result type " + scanResultType); return ""; } // Helper method to setup the scan data for verifying the matching algo. private void setupScanData(int scanResultType, String ssid1, String ssid2, String ssid3, String ssid4) { // 4 scan results, assertEquals(1, mTestScanDatas.length); ScanResult[] scanResults = mTestScanDatas[0].getResults(); assertEquals(4, scanResults.length); String caps = getScanResultCapsForType(scanResultType); // Scan results have increasing RSSI. scanResults[0].SSID = ssid1; scanResults[0].BSSID = TEST_BSSID_1; scanResults[0].capabilities = caps; scanResults[0].level = -45; scanResults[1].SSID = ssid2; scanResults[1].BSSID = TEST_BSSID_2; scanResults[1].capabilities = caps; scanResults[1].level = -35; scanResults[2].SSID = ssid3; scanResults[2].BSSID = TEST_BSSID_3; scanResults[2].capabilities = caps; scanResults[2].level = -25; scanResults[3].SSID = ssid4; scanResults[3].BSSID = TEST_BSSID_4; scanResults[3].capabilities = caps; scanResults[3].level = -15; } private void validateScanResults( List actualScanResults, ScanResult...expectedScanResults) { assertEquals(expectedScanResults.length, actualScanResults.size()); for (int i = 0; i < expectedScanResults.length; i++) { ScanResult expectedScanResult = expectedScanResults[i]; ScanResult actualScanResult = actualScanResults.stream() .filter(x -> x.BSSID.equals(expectedScanResult.BSSID)) .findFirst() .orElse(null); ScanTestUtil.assertScanResultEquals(expectedScanResult, actualScanResult); } } private void validateConnectionRetryAttempts() { for (int i = 0; i < WifiNetworkFactory.USER_SELECTED_NETWORK_CONNECT_RETRY_MAX; i++) { // Cancel the existing connection timeout. mInOrder.verify(mAlarmManager).cancel( mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); // Trigger new connection. ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); mInOrder.verify(mClientModeImpl).sendMessage(messageCaptor.capture()); Message message = messageCaptor.getValue(); assertNotNull(message); assertEquals(WifiManager.CONNECT_NETWORK, message.what); // Start the new connection timeout alarm. mInOrder.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq((long) WifiNetworkFactory.NETWORK_CONNECTION_TIMEOUT_MS), any(), mConnectionTimeoutAlarmListenerArgumentCaptor.capture(), any()); assertNotNull(mConnectionTimeoutAlarmListenerArgumentCaptor.getValue()); } } private void validateScanSettings(@Nullable String hiddenSsid) { ScanSettings scanSettings = mScanSettingsArgumentCaptor.getValue(); assertNotNull(scanSettings); assertEquals(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, scanSettings.band); assertEquals(WifiScanner.TYPE_HIGH_ACCURACY, scanSettings.type); assertEquals(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, scanSettings.reportEvents); if (hiddenSsid == null) { assertNull(scanSettings.hiddenNetworks); } else { assertNotNull(scanSettings.hiddenNetworks); assertNotNull(scanSettings.hiddenNetworks[0]); assertEquals(scanSettings.hiddenNetworks[0].ssid, addEnclosingQuotes(hiddenSsid)); } WorkSource workSource = mWorkSourceArgumentCaptor.getValue(); assertNotNull(workSource); assertEquals(TEST_UID_1, workSource.get(0)); } class WifiConfigMatcher implements ArgumentMatcher { private final WifiConfiguration mConfig; WifiConfigMatcher(WifiConfiguration config) { assertNotNull(config); mConfig = config; } @Override public boolean matches(WifiConfiguration otherConfig) { if (otherConfig == null) return false; return mConfig.configKey().equals(otherConfig.configKey()); } } /** * Verify that an EVENT_UNFULFILLABLE_REQUEST was dispatched on the (mock) messenger. */ private void verifyUnfullfillableDispatched(Messenger messenger) throws Exception { ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); verify(messenger, atLeastOnce()).send(messageCaptor.capture()); assertEquals(NetworkFactory.EVENT_UNFULFILLABLE_REQUEST, messageCaptor.getValue().what); } private void validateUiStartParams(boolean expectedIsReqForSingeNetwork) { ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).startActivityAsUser( intentArgumentCaptor.capture(), eq(UserHandle.getUserHandleForUid(TEST_UID_1))); Intent intent = intentArgumentCaptor.getValue(); assertNotNull(intent); assertEquals(intent.getAction(), WifiNetworkFactory.UI_START_INTENT_ACTION); assertTrue(intent.getCategories().contains(WifiNetworkFactory.UI_START_INTENT_CATEGORY)); assertEquals(intent.getStringExtra(WifiNetworkFactory.UI_START_INTENT_EXTRA_APP_NAME), TEST_APP_NAME); assertEquals(expectedIsReqForSingeNetwork, intent.getBooleanExtra( WifiNetworkFactory.UI_START_INTENT_EXTRA_REQUEST_IS_FOR_SINGLE_NETWORK, false)); assertTrue((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0); assertTrue((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0); } private void validateConnectParams(String ssid, String bssid) { ArgumentCaptor wifiConfigurationCaptor = ArgumentCaptor.forClass(WifiConfiguration.class); verify(mWifiConfigManager).addOrUpdateNetwork( wifiConfigurationCaptor.capture(), eq(TEST_UID_1), eq(TEST_PACKAGE_NAME_1)); WifiConfiguration network = wifiConfigurationCaptor.getValue(); assertNotNull(network); WifiConfiguration expectedWifiConfiguration = new WifiConfiguration(((WifiNetworkSpecifier) mNetworkRequest.networkCapabilities .getNetworkSpecifier()).wifiConfiguration); expectedWifiConfiguration.SSID = ssid; expectedWifiConfiguration.preSharedKey = TEST_WPA_PRESHARED_KEY; expectedWifiConfiguration.BSSID = bssid; expectedWifiConfiguration.ephemeral = true; expectedWifiConfiguration.fromWifiNetworkSpecifier = true; WifiConfigurationTestUtil.assertConfigurationEqual(expectedWifiConfiguration, network); } }