blob: 38d2e8275e888e415d2743a24967222683961f31 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import static com.android.server.wifi.ClientModeImpl.WIFI_WORK_SOURCE;
import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.argThat;
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.app.test.TestAlarmManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.MacAddress;
import android.net.NetworkScoreManager;
import android.net.wifi.ScanResult;
import android.net.wifi.ScanResult.InformationElement;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSuggestion;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiScanner.PnoScanListener;
import android.net.wifi.WifiScanner.PnoSettings;
import android.net.wifi.WifiScanner.ScanData;
import android.net.wifi.WifiScanner.ScanListener;
import android.net.wifi.WifiScanner.ScanSettings;
import android.net.wifi.WifiSsid;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Handler;
import android.os.Process;
import android.os.SystemClock;
import android.os.WorkSource;
import android.os.test.TestLooper;
import android.util.LocalLog;
import androidx.test.filters.SmallTest;
import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.util.LruConnectionTracker;
import com.android.server.wifi.util.ScanResultUtil;
import com.android.wifi.resources.R;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
/**
* Unit tests for {@link com.android.server.wifi.WifiConnectivityManager}.
*/
@SmallTest
public class WifiConnectivityManagerTest extends WifiBaseTest {
/**
* Called before each test
*/
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mResources = new MockResources();
setUpResources(mResources);
mAlarmManager = new TestAlarmManager();
mContext = mockContext();
mLocalLog = new LocalLog(512);
mClientModeImpl = mockClientModeImpl();
mWifiConfigManager = mockWifiConfigManager();
mWifiInfo = getWifiInfo();
mScanData = mockScanData();
mWifiScanner = mockWifiScanner();
mWifiConnectivityHelper = mockWifiConnectivityHelper();
mWifiNS = mockWifiNetworkSelector();
when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
when(mWifiNetworkSuggestionsManager.retrieveHiddenNetworkList())
.thenReturn(new ArrayList<>());
when(mWifiNetworkSuggestionsManager.getAllApprovedNetworkSuggestions())
.thenReturn(new HashSet<>());
when(mWifiInjector.getBssidBlocklistMonitor()).thenReturn(mBssidBlocklistMonitor);
when(mWifiInjector.getWifiChannelUtilizationScan()).thenReturn(mWifiChannelUtilization);
when(mWifiInjector.getWifiScoreCard()).thenReturn(mWifiScoreCard);
when(mWifiInjector.getWifiNetworkSuggestionsManager())
.thenReturn(mWifiNetworkSuggestionsManager);
when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
when(mPasspointManager.getProviderConfigs(anyInt(), anyBoolean()))
.thenReturn(new ArrayList<>());
mWifiConnectivityManager = createConnectivityManager();
verify(mWifiConfigManager).addOnNetworkUpdateListener(
mNetworkUpdateListenerCaptor.capture());
verify(mWifiNetworkSuggestionsManager).addOnSuggestionUpdateListener(
mSuggestionUpdateListenerCaptor.capture());
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
mWifiConnectivityManager.setWifiEnabled(true);
when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
mMinPacketRateActiveTraffic = mResources.getInteger(
R.integer.config_wifiFrameworkMinPacketPerSecondActiveTraffic);
when(mWifiLastResortWatchdog.shouldIgnoreBssidUpdate(anyString())).thenReturn(false);
mLruConnectionTracker = new LruConnectionTracker(100, mContext);
Comparator<WifiConfiguration> comparator =
Comparator.comparingInt(mLruConnectionTracker::getAgeIndexOfNetwork);
when(mWifiConfigManager.getScanListComparator()).thenReturn(comparator);
}
private void setUpResources(MockResources resources) {
resources.setBoolean(
R.bool.config_wifi_framework_enable_associated_network_selection, true);
resources.setInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz, -60);
resources.setInteger(
R.integer.config_wifiFrameworkMinPacketPerSecondActiveTraffic, 16);
resources.setIntArray(
R.array.config_wifiConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC);
resources.setIntArray(
R.array.config_wifiDisconnectedScanIntervalScheduleSec,
VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC);
resources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
SCHEDULE_EMPTY_SEC);
resources.setInteger(
R.integer.config_wifiHighMovementNetworkSelectionOptimizationScanDelayMs,
HIGH_MVMT_SCAN_DELAY_MS);
resources.setInteger(
R.integer.config_wifiHighMovementNetworkSelectionOptimizationRssiDelta,
HIGH_MVMT_RSSI_DELTA);
resources.setInteger(R.integer.config_wifiInitialPartialScanChannelCacheAgeMins,
CHANNEL_CACHE_AGE_MINS);
resources.setInteger(R.integer.config_wifiMovingPnoScanIntervalMillis,
MOVING_PNO_SCAN_INTERVAL_MILLIS);
resources.setInteger(R.integer.config_wifiStationaryPnoScanIntervalMillis,
STATIONARY_PNO_SCAN_INTERVAL_MILLIS);
}
/**
* Called after each test
*/
@After
public void cleanup() {
verify(mScoringParams, atLeast(0)).getEntryRssi(anyInt());
verifyNoMoreInteractions(mScoringParams);
validateMockitoUsage();
}
private Context mContext;
private TestAlarmManager mAlarmManager;
private TestLooper mLooper = new TestLooper();
private WifiConnectivityManager mWifiConnectivityManager;
private WifiNetworkSelector mWifiNS;
private ClientModeImpl mClientModeImpl;
private WifiScanner mWifiScanner;
private WifiConnectivityHelper mWifiConnectivityHelper;
private ScanData mScanData;
private WifiConfigManager mWifiConfigManager;
private WifiInfo mWifiInfo;
private LocalLog mLocalLog;
private LruConnectionTracker mLruConnectionTracker;
@Mock private WifiInjector mWifiInjector;
@Mock private NetworkScoreManager mNetworkScoreManager;
@Mock private Clock mClock;
@Mock private WifiLastResortWatchdog mWifiLastResortWatchdog;
@Mock private OpenNetworkNotifier mOpenNetworkNotifier;
@Mock private WifiMetrics mWifiMetrics;
@Mock private WifiNetworkScoreCache mScoreCache;
@Mock private WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
@Mock private BssidBlocklistMonitor mBssidBlocklistMonitor;
@Mock private WifiChannelUtilization mWifiChannelUtilization;
@Mock private ScoringParams mScoringParams;
@Mock private WifiScoreCard mWifiScoreCard;
@Mock private PasspointManager mPasspointManager;
@Mock private WifiScoreCard.PerNetwork mPerNetwork;
@Mock private WifiScoreCard.PerNetwork mPerNetwork1;
@Mock private PasspointConfiguration mPasspointConfiguration;
@Mock private WifiConfiguration mSuggestionConfig;
@Mock private WifiNetworkSuggestion mWifiNetworkSuggestion;
@Mock WifiCandidates.Candidate mCandidate1;
@Mock WifiCandidates.Candidate mCandidate2;
private List<WifiCandidates.Candidate> mCandidateList;
@Captor ArgumentCaptor<ScanResult> mCandidateScanResultCaptor;
@Captor ArgumentCaptor<ArrayList<String>> mBssidBlacklistCaptor;
@Captor ArgumentCaptor<ArrayList<String>> mSsidWhitelistCaptor;
@Captor ArgumentCaptor<WifiConfigManager.OnNetworkUpdateListener>
mNetworkUpdateListenerCaptor;
@Captor ArgumentCaptor<WifiNetworkSuggestionsManager.OnSuggestionUpdateListener>
mSuggestionUpdateListenerCaptor;
private MockResources mResources;
private int mMinPacketRateActiveTraffic;
private static final int CANDIDATE_NETWORK_ID = 0;
private static final String CANDIDATE_SSID = "\"AnSsid\"";
private static final String CANDIDATE_BSSID = "6c:f3:7f:ae:8c:f3";
private static final String CANDIDATE_BSSID_2 = "6c:f3:7f:ae:8d:f3";
private static final String INVALID_SCAN_RESULT_BSSID = "6c:f3:7f:ae:8c:f4";
private static final int TEST_FREQUENCY = 2420;
private static final long CURRENT_SYSTEM_TIME_MS = 1000;
private static final int MAX_BSSID_BLACKLIST_SIZE = 16;
private static final int[] VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC = {10, 30, 50};
private static final int[] VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC = {15, 35, 55};
private static final int[] VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC = {25, 40, 60};
private static final int[] SCHEDULE_EMPTY_SEC = {};
private static final int[] INVALID_SCHEDULE_NEGATIVE_VALUES_SEC = {10, -10, 20};
private static final int[] INVALID_SCHEDULE_ZERO_VALUES_SEC = {10, 0, 20};
private static final int MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC = 60;
private static final int[] DEFAULT_SINGLE_SCAN_SCHEDULE_SEC = {20, 40, 80, 160};
private static final int MAX_SCAN_INTERVAL_IN_DEFAULT_SCHEDULE_SEC = 160;
private static final int TEST_FREQUENCY_1 = 2412;
private static final int TEST_FREQUENCY_2 = 5180;
private static final int TEST_FREQUENCY_3 = 5240;
private static final int TEST_CURRENT_CONNECTED_FREQUENCY = 2427;
private static final int HIGH_MVMT_SCAN_DELAY_MS = 10000;
private static final int HIGH_MVMT_RSSI_DELTA = 10;
private static final String TEST_FQDN = "FQDN";
private static final String TEST_SSID = "SSID";
private static final int TEMP_BSSID_BLOCK_DURATION_MS = 10 * 1000; // 10 seconds
private static final int TEST_CONNECTED_NETWORK_ID = 55;
private static final int CHANNEL_CACHE_AGE_MINS = 14400;
private static final int MOVING_PNO_SCAN_INTERVAL_MILLIS = 20_000;
private static final int STATIONARY_PNO_SCAN_INTERVAL_MILLIS = 60_000;
Context mockContext() {
Context context = mock(Context.class);
when(context.getResources()).thenReturn(mResources);
when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
mAlarmManager.getAlarmManager());
when(context.getPackageManager()).thenReturn(mock(PackageManager.class));
return context;
}
ScanData mockScanData() {
ScanData scanData = mock(ScanData.class);
when(scanData.getBandScanned()).thenReturn(WifiScanner.WIFI_BAND_ALL);
return scanData;
}
WifiScanner mockWifiScanner() {
WifiScanner scanner = mock(WifiScanner.class);
ArgumentCaptor<ScanListener> allSingleScanListenerCaptor =
ArgumentCaptor.forClass(ScanListener.class);
doNothing().when(scanner).registerScanListener(
any(), allSingleScanListenerCaptor.capture());
ScanData[] scanDatas = new ScanData[1];
scanDatas[0] = mScanData;
// do a synchronous answer for the ScanListener callbacks
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onResults(scanDatas);
}}).when(scanner).startBackgroundScan(anyObject(), anyObject(), anyObject());
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onResults(scanDatas);
// WCM processes scan results received via onFullResult (even though they're the
// same as onResult for single scans).
if (mScanData != null && mScanData.getResults() != null) {
for (int i = 0; i < mScanData.getResults().length; i++) {
allSingleScanListenerCaptor.getValue().onFullResult(
mScanData.getResults()[i]);
}
}
allSingleScanListenerCaptor.getValue().onResults(scanDatas);
}}).when(scanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
// This unfortunately needs to be a somewhat valid scan result, otherwise
// |ScanDetailUtil.toScanDetail| raises exceptions.
final ScanResult[] scanResults = new ScanResult[1];
scanResults[0] = new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID),
CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps",
-78, 2450, 1025, 22, 33, 20, 0, 0, true);
scanResults[0].informationElements = new InformationElement[1];
scanResults[0].informationElements[0] = new InformationElement();
scanResults[0].informationElements[0].id = InformationElement.EID_SSID;
scanResults[0].informationElements[0].bytes =
CANDIDATE_SSID.getBytes(StandardCharsets.UTF_8);
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, PnoSettings pnoSettings,
Executor executor, PnoScanListener listener) throws Exception {
listener.onPnoNetworkFound(scanResults);
}}).when(scanner).startDisconnectedPnoScan(
anyObject(), anyObject(), anyObject(), anyObject());
return scanner;
}
WifiConnectivityHelper mockWifiConnectivityHelper() {
WifiConnectivityHelper connectivityHelper = mock(WifiConnectivityHelper.class);
when(connectivityHelper.isFirmwareRoamingSupported()).thenReturn(false);
when(connectivityHelper.getMaxNumBlacklistBssid()).thenReturn(MAX_BSSID_BLACKLIST_SIZE);
return connectivityHelper;
}
ClientModeImpl mockClientModeImpl() {
ClientModeImpl stateMachine = mock(ClientModeImpl.class);
when(stateMachine.isConnected()).thenReturn(false);
when(stateMachine.isDisconnected()).thenReturn(true);
when(stateMachine.isSupplicantTransientState()).thenReturn(false);
return stateMachine;
}
WifiNetworkSelector mockWifiNetworkSelector() {
WifiNetworkSelector ns = mock(WifiNetworkSelector.class);
WifiConfiguration candidate = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
candidate.BSSID = ClientModeImpl.SUPPLICANT_BSSID_ANY;
ScanResult candidateScanResult = new ScanResult();
candidateScanResult.SSID = CANDIDATE_SSID;
candidateScanResult.BSSID = CANDIDATE_BSSID;
candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
when(mWifiConfigManager.getConfiguredNetwork(CANDIDATE_NETWORK_ID)).thenReturn(candidate);
MacAddress macAddress = MacAddress.fromString(CANDIDATE_BSSID);
WifiCandidates.Key key = new WifiCandidates.Key(mock(ScanResultMatchInfo.class),
macAddress, 0);
when(mCandidate1.getKey()).thenReturn(key);
when(mCandidate1.getScanRssi()).thenReturn(-40);
when(mCandidate1.getFrequency()).thenReturn(TEST_FREQUENCY);
when(mCandidate2.getKey()).thenReturn(key);
when(mCandidate2.getScanRssi()).thenReturn(-60);
mCandidateList = new ArrayList<WifiCandidates.Candidate>();
mCandidateList.add(mCandidate1);
when(ns.getCandidatesFromScan(any(), any(), any(), anyBoolean(), anyBoolean(),
anyBoolean())).thenReturn(mCandidateList);
when(ns.selectNetwork(any()))
.then(new AnswerWithArguments() {
public WifiConfiguration answer(List<WifiCandidates.Candidate> candidateList) {
if (candidateList == null || candidateList.size() == 0) {
return null;
}
return candidate;
}
});
return ns;
}
WifiInfo getWifiInfo() {
WifiInfo wifiInfo = new WifiInfo();
wifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
wifiInfo.setBSSID(null);
wifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
return wifiInfo;
}
WifiConfigManager mockWifiConfigManager() {
WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
List<WifiConfiguration> networkList = new ArrayList<>();
networkList.add(config);
when(wifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(null);
when(wifiConfigManager.getSavedNetworks(anyInt())).thenReturn(networkList);
return wifiConfigManager;
}
WifiConnectivityManager createConnectivityManager() {
return new WifiConnectivityManager(mContext,
mScoringParams,
mClientModeImpl, mWifiInjector, mWifiConfigManager, mWifiNetworkSuggestionsManager,
mWifiInfo, mWifiNS, mWifiConnectivityHelper,
mWifiLastResortWatchdog, mOpenNetworkNotifier,
mWifiMetrics, new Handler(mLooper.getLooper()), mClock,
mLocalLog, mWifiScoreCard);
}
void setWifiStateConnected() {
// Prep for setting WiFi to connected state
WifiConfiguration connectedWifiConfiguration = new WifiConfiguration();
connectedWifiConfiguration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mClientModeImpl.getCurrentWifiConfiguration()).thenReturn(connectedWifiConfiguration);
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
}
/**
* Wifi enters disconnected state while screen is on.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID and BSSID.
*/
@Test
public void enterWifiDisconnectedStateWhenScreenOn() {
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Wifi enters connected state while screen is on.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID and BSSID.
*/
@Test
public void enterWifiConnectedStateWhenScreenOn() {
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state
setWifiStateConnected();
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Screen turned on while WiFi in disconnected state.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID and BSSID.
*/
@Test
public void turnScreenOnWhenWifiInDisconnectedState() {
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mClientModeImpl, atLeastOnce()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Screen turned on while WiFi in connected state.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID and BSSID.
*/
@Test
public void turnScreenOnWhenWifiInConnectedState() {
// Set WiFi to connected state
setWifiStateConnected();
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mClientModeImpl, atLeastOnce()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Screen turned on while WiFi in connected state but
* auto roaming is disabled.
*
* Expected behavior: WifiConnectivityManager doesn't invoke
* ClientModeImpl.startConnectToNetwork() because roaming
* is turned off.
*/
@Test
public void turnScreenOnWhenWifiInConnectedStateRoamingDisabled() {
// Turn off auto roaming
mResources.setBoolean(
R.bool.config_wifi_framework_enable_associated_network_selection, false);
mWifiConnectivityManager = createConnectivityManager();
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
// Set WiFi to connected state
setWifiStateConnected();
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mClientModeImpl, times(0)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Multiple back to back connection attempts within the rate interval should be rate limited.
*
* Expected behavior: WifiConnectivityManager calls ClientModeImpl.startConnectToNetwork()
* with the expected candidate network ID and BSSID for only the expected number of times within
* the given interval.
*/
@Test
public void connectionAttemptRateLimitedWhenScreenOff() {
int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
int numAttempts = 0;
int connectionAttemptIntervals = timeInterval / maxAttemptRate;
mWifiConnectivityManager.handleScreenStateChanged(false);
// First attempt the max rate number of connections within the rate interval.
long currentTimeStamp = 0;
for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
currentTimeStamp += connectionAttemptIntervals;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
}
// Now trigger another connection attempt before the rate interval, this should be
// skipped because we've crossed rate limit.
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Verify that we attempt to connect upto the rate.
verify(mClientModeImpl, times(numAttempts)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Multiple back to back connection attempts outside the rate interval should not be rate
* limited.
*
* Expected behavior: WifiConnectivityManager calls ClientModeImpl.startConnectToNetwork()
* with the expected candidate network ID and BSSID for only the expected number of times within
* the given interval.
*/
@Test
public void connectionAttemptNotRateLimitedWhenScreenOff() {
int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
int numAttempts = 0;
int connectionAttemptIntervals = timeInterval / maxAttemptRate;
mWifiConnectivityManager.handleScreenStateChanged(false);
// First attempt the max rate number of connections within the rate interval.
long currentTimeStamp = 0;
for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
currentTimeStamp += connectionAttemptIntervals;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
}
// Now trigger another connection attempt after the rate interval, this should not be
// skipped because we should've evicted the older attempt.
when(mClock.getElapsedSinceBootMillis()).thenReturn(
currentTimeStamp + connectionAttemptIntervals * 2);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
// Verify that all the connection attempts went through
verify(mClientModeImpl, times(numAttempts)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Multiple back to back connection attempts after a force connectivity scan should not be rate
* limited.
*
* Expected behavior: WifiConnectivityManager calls ClientModeImpl.startConnectToNetwork()
* with the expected candidate network ID and BSSID for only the expected number of times within
* the given interval.
*/
@Test
public void connectionAttemptNotRateLimitedWhenScreenOffForceConnectivityScan() {
int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
int numAttempts = 0;
int connectionAttemptIntervals = timeInterval / maxAttemptRate;
mWifiConnectivityManager.handleScreenStateChanged(false);
// First attempt the max rate number of connections within the rate interval.
long currentTimeStamp = 0;
for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
currentTimeStamp += connectionAttemptIntervals;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
}
mWifiConnectivityManager.forceConnectivityScan(new WorkSource());
for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
currentTimeStamp += connectionAttemptIntervals;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
}
// Verify that all the connection attempts went through
verify(mClientModeImpl, times(numAttempts)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Multiple back to back connection attempts after a user selection should not be rate limited.
*
* Expected behavior: WifiConnectivityManager calls ClientModeImpl.startConnectToNetwork()
* with the expected candidate network ID and BSSID for only the expected number of times within
* the given interval.
*/
@Test
public void connectionAttemptNotRateLimitedWhenScreenOffAfterUserSelection() {
int maxAttemptRate = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_RATE;
int timeInterval = WifiConnectivityManager.MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS;
int numAttempts = 0;
int connectionAttemptIntervals = timeInterval / maxAttemptRate;
mWifiConnectivityManager.handleScreenStateChanged(false);
// First attempt the max rate number of connections within the rate interval.
long currentTimeStamp = 0;
for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
currentTimeStamp += connectionAttemptIntervals;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
}
mWifiConnectivityManager.setUserConnectChoice(CANDIDATE_NETWORK_ID);
mWifiConnectivityManager.prepareForForcedConnection(CANDIDATE_NETWORK_ID);
for (int attempt = 0; attempt < maxAttemptRate; attempt++) {
currentTimeStamp += connectionAttemptIntervals;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
numAttempts++;
}
// Verify that all the connection attempts went through
verify(mClientModeImpl, times(numAttempts)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* PNO retry for low RSSI networks.
*
* Expected behavior: WifiConnectivityManager doubles the low RSSI
* network retry delay value after QNS skips the PNO scan results
* because of their low RSSI values.
*/
@Test
public void pnoRetryForLowRssiNetwork() {
when(mWifiNS.selectNetwork(any())).thenReturn(null);
// Set screen to off
mWifiConnectivityManager.handleScreenStateChanged(false);
// Get the current retry delay value
int lowRssiNetworkRetryDelayStartValue = mWifiConnectivityManager
.getLowRssiNetworkRetryDelay();
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Get the retry delay value after QNS didn't select a
// network candicate from the PNO scan results.
int lowRssiNetworkRetryDelayAfterPnoValue = mWifiConnectivityManager
.getLowRssiNetworkRetryDelay();
assertEquals(lowRssiNetworkRetryDelayStartValue * 2,
lowRssiNetworkRetryDelayAfterPnoValue);
}
/**
* Ensure that the watchdog bite increments the "Pno bad" metric.
*
* Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find
* a candidate while watchdog single scan did.
*/
@Test
public void watchdogBitePnoBadIncrementsMetrics() {
// Set screen to off
mWifiConnectivityManager.handleScreenStateChanged(false);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Now fire the watchdog alarm and verify the metrics were incremented.
mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG);
mLooper.dispatchAll();
verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoBad();
verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoGood();
}
/**
* Ensure that the watchdog bite increments the "Pno good" metric.
*
* Expected behavior: WifiConnectivityManager detects that the PNO scan failed to find
* a candidate which was the same with watchdog single scan.
*/
@Test
public void watchdogBitePnoGoodIncrementsMetrics() {
// Qns returns no candidate after watchdog single scan.
when(mWifiNS.selectNetwork(any())).thenReturn(null);
// Set screen to off
mWifiConnectivityManager.handleScreenStateChanged(false);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Now fire the watchdog alarm and verify the metrics were incremented.
mAlarmManager.dispatch(WifiConnectivityManager.WATCHDOG_TIMER_TAG);
mLooper.dispatchAll();
verify(mWifiMetrics).incrementNumConnectivityWatchdogPnoGood();
verify(mWifiMetrics, never()).incrementNumConnectivityWatchdogPnoBad();
}
/**
* Verify that 2 scans that are sufficiently far apart are required to initiate a connection
* when the high mobility scanning optimization is enabled.
*/
@Test
public void testHighMovementNetworkSelection() {
when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
// Enable high movement optimization
mResources.setBoolean(R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled,
true);
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify there is no connection due to currently having no cached candidates.
verify(mClientModeImpl, never()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
// Move time forward but do not cross HIGH_MVMT_SCAN_DELAY_MS yet.
when(mClock.getElapsedSinceBootMillis()).thenReturn(HIGH_MVMT_SCAN_DELAY_MS - 1L);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify we still don't connect because not enough time have passed since the candidates
// were cached.
verify(mClientModeImpl, never()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
// Move time past HIGH_MVMT_SCAN_DELAY_MS.
when(mClock.getElapsedSinceBootMillis()).thenReturn((long) HIGH_MVMT_SCAN_DELAY_MS);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify a candidate if found this time.
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
verify(mWifiMetrics, times(2)).incrementNumHighMovementConnectionSkipped();
verify(mWifiMetrics).incrementNumHighMovementConnectionStarted();
}
/**
* Verify that the device is initiating partial scans to verify AP stability in the high
* movement mobility state.
*/
@Test
public void testHighMovementTriggerPartialScan() {
when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
// Enable high movement optimization
mResources.setBoolean(R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled,
true);
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify there is no connection due to currently having no cached candidates.
verify(mClientModeImpl, never()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
// Move time forward and verify that a delayed partial scan is scheduled.
when(mClock.getElapsedSinceBootMillis()).thenReturn(HIGH_MVMT_SCAN_DELAY_MS + 1L);
mAlarmManager.dispatch(WifiConnectivityManager.DELAYED_PARTIAL_SCAN_TIMER_TAG);
mLooper.dispatchAll();
verify(mWifiScanner).startScan((ScanSettings) argThat(new WifiPartialScanSettingMatcher()),
any(), any(), any());
}
private class WifiPartialScanSettingMatcher implements ArgumentMatcher<ScanSettings> {
@Override
public boolean matches(ScanSettings scanSettings) {
return scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED
&& scanSettings.channels[0].frequency == TEST_FREQUENCY;
}
}
/**
* Verify that when there are we obtain more than one valid candidates from scan results and
* network connection fails, connection is immediately retried on the remaining candidates.
*/
@Test
public void testRetryConnectionOnFailure() {
// Setup WifiNetworkSelector to return 2 valid candidates from scan results
MacAddress macAddress = MacAddress.fromString(CANDIDATE_BSSID_2);
WifiCandidates.Key key = new WifiCandidates.Key(mock(ScanResultMatchInfo.class),
macAddress, 0);
WifiCandidates.Candidate otherCandidate = mock(WifiCandidates.Candidate.class);
when(otherCandidate.getKey()).thenReturn(key);
List<WifiCandidates.Candidate> candidateList = new ArrayList<>();
candidateList.add(mCandidate1);
candidateList.add(otherCandidate);
when(mWifiNS.getCandidatesFromScan(any(), any(), any(), anyBoolean(), anyBoolean(),
anyBoolean())).thenReturn(candidateList);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify a connection starting
verify(mWifiNS).selectNetwork((List<WifiCandidates.Candidate>)
argThat(new WifiCandidatesListSizeMatcher(2)));
verify(mClientModeImpl).startConnectToNetwork(anyInt(), anyInt(), any());
// Simulate the connection failing
mWifiConnectivityManager.handleConnectionAttemptEnded(
WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, CANDIDATE_BSSID,
CANDIDATE_SSID);
// Verify the failed BSSID is added to blocklist
verify(mBssidBlocklistMonitor).blockBssidForDurationMs(eq(CANDIDATE_BSSID),
eq(CANDIDATE_SSID), anyLong(), anyInt(), anyInt());
// Verify another connection starting
verify(mWifiNS).selectNetwork((List<WifiCandidates.Candidate>)
argThat(new WifiCandidatesListSizeMatcher(1)));
verify(mClientModeImpl, times(2)).startConnectToNetwork(anyInt(), anyInt(), any());
// Simulate the second connection also failing
mWifiConnectivityManager.handleConnectionAttemptEnded(
WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, CANDIDATE_BSSID_2,
CANDIDATE_SSID);
// Verify there are no more connections
verify(mWifiNS).selectNetwork((List<WifiCandidates.Candidate>)
argThat(new WifiCandidatesListSizeMatcher(0)));
verify(mClientModeImpl, times(2)).startConnectToNetwork(anyInt(), anyInt(), any());
}
private class WifiCandidatesListSizeMatcher implements
ArgumentMatcher<List<WifiCandidates.Candidate>> {
int mSize;
WifiCandidatesListSizeMatcher(int size) {
mSize = size;
}
@Override
public boolean matches(List<WifiCandidates.Candidate> candidateList) {
return candidateList.size() == mSize;
}
}
/**
* Verify that the cached candidates become cleared after a period of time.
*/
@Test
public void testRetryConnectionOnFailureCacheTimeout() {
// Setup WifiNetworkSelector to return 2 valid candidates from scan results
when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
MacAddress macAddress = MacAddress.fromString(CANDIDATE_BSSID_2);
WifiCandidates.Key key = new WifiCandidates.Key(mock(ScanResultMatchInfo.class),
macAddress, 0);
WifiCandidates.Candidate otherCandidate = mock(WifiCandidates.Candidate.class);
when(otherCandidate.getKey()).thenReturn(key);
List<WifiCandidates.Candidate> candidateList = new ArrayList<>();
candidateList.add(mCandidate1);
candidateList.add(otherCandidate);
when(mWifiNS.getCandidatesFromScan(any(), any(), any(), anyBoolean(), anyBoolean(),
anyBoolean())).thenReturn(candidateList);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify a connection starting
verify(mWifiNS).selectNetwork((List<WifiCandidates.Candidate>)
argThat(new WifiCandidatesListSizeMatcher(2)));
verify(mClientModeImpl).startConnectToNetwork(anyInt(), anyInt(), any());
// Simulate the connection failing after the cache timeout period.
when(mClock.getElapsedSinceBootMillis()).thenReturn(TEMP_BSSID_BLOCK_DURATION_MS + 1L);
mWifiConnectivityManager.handleConnectionAttemptEnded(
WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, CANDIDATE_BSSID,
CANDIDATE_SSID);
// verify there are no additional connections.
verify(mClientModeImpl).startConnectToNetwork(anyInt(), anyInt(), any());
}
/**
* Verify that in the high movement mobility state, when the RSSI delta of a BSSID from
* 2 consecutive scans becomes greater than a threshold, the candidate get ignored from
* network selection.
*/
@Test
public void testHighMovementRssiFilter() {
when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
// Enable high movement optimization
mResources.setBoolean(R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled,
true);
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify there is no connection due to currently having no cached candidates.
verify(mClientModeImpl, never()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
// Move time past HIGH_MVMT_SCAN_DELAY_MS.
when(mClock.getElapsedSinceBootMillis()).thenReturn((long) HIGH_MVMT_SCAN_DELAY_MS);
// Mock the current Candidate to have RSSI over the filter threshold
mCandidateList.clear();
mCandidateList.add(mCandidate2);
// Set WiFi to disconnected state to trigger scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mLooper.dispatchAll();
// Verify connect is not started.
verify(mClientModeImpl, never()).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
verify(mWifiMetrics, times(2)).incrementNumHighMovementConnectionSkipped();
}
/**
* {@link OpenNetworkNotifier} handles scan results on network selection.
*
* Expected behavior: ONA handles scan results
*/
@Test
public void wifiDisconnected_noConnectionCandidate_openNetworkNotifierScanResultsHandled() {
// no connection candidate selected
when(mWifiNS.selectNetwork(any())).thenReturn(null);
List<ScanDetail> expectedOpenNetworks = new ArrayList<>();
expectedOpenNetworks.add(
new ScanDetail(
new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID),
CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", -78, 2450,
1025, 22, 33, 20, 0, 0, true), null));
when(mWifiNS.getFilteredScanDetailsForOpenUnsavedNetworks())
.thenReturn(expectedOpenNetworks);
// Set WiFi to disconnected state to trigger PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mOpenNetworkNotifier).handleScanResults(expectedOpenNetworks);
}
/**
* When wifi is connected, {@link OpenNetworkNotifier} handles the Wi-Fi connected behavior.
*
* Expected behavior: ONA handles connected behavior
*/
@Test
public void wifiConnected_openNetworkNotifierHandlesConnection() {
// Set WiFi to connected state
mWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID));
mWifiConnectivityManager.handleConnectionAttemptEnded(
WifiMetrics.ConnectionEvent.FAILURE_NONE, CANDIDATE_BSSID, CANDIDATE_SSID);
verify(mOpenNetworkNotifier).handleWifiConnected(CANDIDATE_SSID);
}
/**
* When wifi is connected, {@link OpenNetworkNotifier} handles connection state
* change.
*
* Expected behavior: ONA does not clear pending notification.
*/
@Test
public void wifiDisconnected_openNetworkNotifierDoesNotClearPendingNotification() {
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mOpenNetworkNotifier, never()).clearPendingNotification(anyBoolean());
}
/**
* When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} handles the connection
* failure. A failure code that is not {@link WifiMetrics.ConnectionEvent#FAILURE_NONE}
* represents a connection failure.
*
* Expected behavior: ONA handles connection failure.
*/
@Test
public void wifiConnectionEndsWithFailure_openNetworkNotifierHandlesConnectionFailure() {
mWifiConnectivityManager.handleConnectionAttemptEnded(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED, CANDIDATE_BSSID,
CANDIDATE_SSID);
verify(mOpenNetworkNotifier).handleConnectionFailure();
}
/**
* When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} does not handle connection
* failure after a successful connection. {@link WifiMetrics.ConnectionEvent#FAILURE_NONE}
* represents a successful connection.
*
* Expected behavior: ONA does nothing.
*/
@Test
public void wifiConnectionEndsWithSuccess_openNetworkNotifierDoesNotHandleConnectionFailure() {
mWifiConnectivityManager.handleConnectionAttemptEnded(
WifiMetrics.ConnectionEvent.FAILURE_NONE, CANDIDATE_BSSID, CANDIDATE_SSID);
verify(mOpenNetworkNotifier, never()).handleConnectionFailure();
}
/**
* When Wi-Fi is disabled, clear the pending notification and reset notification repeat delay.
*
* Expected behavior: clear pending notification and reset notification repeat delay
* */
@Test
public void openNetworkNotifierClearsPendingNotificationOnWifiDisabled() {
mWifiConnectivityManager.setWifiEnabled(false);
verify(mOpenNetworkNotifier).clearPendingNotification(true /* resetRepeatDelay */);
}
/**
* Verify that the ONA controller tracks screen state changes.
*/
@Test
public void openNetworkNotifierTracksScreenStateChanges() {
mWifiConnectivityManager.handleScreenStateChanged(false);
verify(mOpenNetworkNotifier).handleScreenStateChanged(false);
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mOpenNetworkNotifier).handleScreenStateChanged(true);
}
/**
* Verify that if configuration for single scan schedule is empty, default
* schedule is being used.
*/
@Test
public void checkPeriodicScanIntervalWhenDisconnectedWithEmptySchedule() throws Exception {
mResources.setIntArray(R.array.config_wifiDisconnectedScanIntervalScheduleSec,
SCHEDULE_EMPTY_SEC);
checkWorkingWithDefaultSchedule();
}
/**
* Verify that if configuration for single scan schedule has zero values, default
* schedule is being used.
*/
@Test
public void checkPeriodicScanIntervalWhenDisconnectedWithZeroValuesSchedule() {
mResources.setIntArray(
R.array.config_wifiDisconnectedScanIntervalScheduleSec,
INVALID_SCHEDULE_ZERO_VALUES_SEC);
checkWorkingWithDefaultSchedule();
}
/**
* Verify that if configuration for single scan schedule has negative values, default
* schedule is being used.
*/
@Test
public void checkPeriodicScanIntervalWhenDisconnectedWithNegativeValuesSchedule() {
mResources.setIntArray(
R.array.config_wifiDisconnectedScanIntervalScheduleSec,
INVALID_SCHEDULE_NEGATIVE_VALUES_SEC);
checkWorkingWithDefaultSchedule();
}
private void checkWorkingWithDefaultSchedule() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mWifiConnectivityManager = createConnectivityManager();
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
mWifiConnectivityManager.setWifiEnabled(true);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max periodic scan interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_DEFAULT_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(DEFAULT_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
currentTimeStamp += firstIntervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Now fire the first periodic scan alarm timer
mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
mLooper.dispatchAll();
// Get the second periodic scan interval
long secondIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
// Verify the intervals are exponential back off
assertEquals(DEFAULT_SINGLE_SCAN_SCHEDULE_SEC[1] * 1000, secondIntervalMs);
currentTimeStamp += secondIntervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Make sure we eventually stay at the maximum scan interval.
long intervalMs = 0;
for (int i = 0; i < 5; i++) {
mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
mLooper.dispatchAll();
intervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
currentTimeStamp += intervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
}
assertEquals(DEFAULT_SINGLE_SCAN_SCHEDULE_SEC[DEFAULT_SINGLE_SCAN_SCHEDULE_SEC.length - 1]
* 1000, intervalMs);
}
/**
* Verify that scan interval for screen on and wifi disconnected scenario
* is in the exponential backoff fashion.
*
* Expected behavior: WifiConnectivityManager doubles periodic
* scan interval.
*/
@Test
public void checkPeriodicScanIntervalWhenDisconnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max periodic scan interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
currentTimeStamp += firstIntervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Now fire the first periodic scan alarm timer
mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
mLooper.dispatchAll();
// Get the second periodic scan interval
long secondIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
// Verify the intervals are exponential back off
assertEquals(VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC[1] * 1000, secondIntervalMs);
currentTimeStamp += secondIntervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Make sure we eventually stay at the maximum scan interval.
long intervalMs = 0;
for (int i = 0; i < 5; i++) {
mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
mLooper.dispatchAll();
intervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
currentTimeStamp += intervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
}
assertEquals(VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC[
VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC.length - 1] * 1000, intervalMs);
}
/**
* Verify that scan interval for screen on and wifi connected scenario
* is in the exponential backoff fashion.
*
* Expected behavior: WifiConnectivityManager doubles periodic
* scan interval.
*/
@Test
public void checkPeriodicScanIntervalWhenConnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to connected state to trigger periodic scan
setWifiStateConnected();
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
currentTimeStamp += firstIntervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Now fire the first periodic scan alarm timer
mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
mLooper.dispatchAll();
// Get the second periodic scan interval
long secondIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
// Verify the intervals are exponential back off
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[1] * 1000, secondIntervalMs);
currentTimeStamp += secondIntervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Make sure we eventually stay at the maximum scan interval.
long intervalMs = 0;
for (int i = 0; i < 5; i++) {
mAlarmManager.dispatch(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
mLooper.dispatchAll();
intervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
currentTimeStamp += intervalMs;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
}
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[
VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC.length - 1] * 1000, intervalMs);
}
/**
* When screen on and single saved network schedule is set
* If we have multiple saved networks, the regular connected state scan schedule is used
*/
@Test
public void checkScanScheduleForMultipleSavedNetwork() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
WifiConfiguration wifiConfiguration1 = new WifiConfiguration();
WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
wifiConfiguration1.status = WifiConfiguration.Status.CURRENT;
List<WifiConfiguration> wifiConfigurationList = new ArrayList<WifiConfiguration>();
wifiConfigurationList.add(wifiConfiguration1);
wifiConfigurationList.add(wifiConfiguration2);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(wifiConfigurationList);
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* When screen on and single saved network schedule is set
* If we have a single saved network (connected network),
* no passpoint or suggestion networks.
* the single-saved-network connected state scan schedule is used
*/
@Test
public void checkScanScheduleForSingleSavedNetworkConnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.networkId = TEST_CONNECTED_NETWORK_ID;
List<WifiConfiguration> wifiConfigurationList = new ArrayList<WifiConfiguration>();
wifiConfigurationList.add(wifiConfiguration);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(wifiConfigurationList);
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set WiFi to connected state to trigger periodic scan
setWifiStateConnected();
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* When screen on and single saved network schedule is set
* If we have a single saved network (not connected network),
* no passpoint or suggestion networks.
* the regular connected state scan schedule is used
*/
@Test
public void checkScanScheduleForSingleSavedNetwork() {
int testSavedNetworkId = TEST_CONNECTED_NETWORK_ID + 1;
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.status = WifiConfiguration.Status.ENABLED;
wifiConfiguration.networkId = testSavedNetworkId;
List<WifiConfiguration> wifiConfigurationList = new ArrayList<WifiConfiguration>();
wifiConfigurationList.add(wifiConfiguration);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(wifiConfigurationList);
// Set WiFi to connected state to trigger periodic scan
setWifiStateConnected();
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* When screen on and single saved network schedule is set
* If we have a single passpoint network (connected network),
* and no saved or suggestion networks the single-saved-network
* connected state scan schedule is used.
*/
@Test
public void checkScanScheduleForSinglePasspointNetworkConnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
// Prepare for a single passpoint network
WifiConfiguration config = new WifiConfiguration();
config.networkId = TEST_CONNECTED_NETWORK_ID;
String passpointKey = "PASSPOINT_KEY";
when(mWifiConfigManager.getConfiguredNetwork(passpointKey)).thenReturn(config);
List<PasspointConfiguration> passpointNetworks = new ArrayList<PasspointConfiguration>();
passpointNetworks.add(mPasspointConfiguration);
when(mPasspointConfiguration.getUniqueId()).thenReturn(passpointKey);
when(mPasspointManager.getProviderConfigs(anyInt(), anyBoolean()))
.thenReturn(passpointNetworks);
// Prepare for no saved networks
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(new ArrayList<>());
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set WiFi to connected state to trigger periodic scan
setWifiStateConnected();
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* When screen on and single saved network schedule is set
* If we have a single suggestion network (connected network),
* and no saved network or passpoint networks the single-saved-network
* connected state scan schedule is used
*/
@Test
public void checkScanScheduleForSingleSuggestionsNetworkConnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
// Prepare for a single suggestions network
WifiConfiguration config = new WifiConfiguration();
config.networkId = TEST_CONNECTED_NETWORK_ID;
String networkKey = "NETWORK_KEY";
when(mWifiConfigManager.getConfiguredNetwork(networkKey)).thenReturn(config);
when(mSuggestionConfig.getKey()).thenReturn(networkKey);
when(mWifiNetworkSuggestion.getWifiConfiguration()).thenReturn(mSuggestionConfig);
Set<WifiNetworkSuggestion> suggestionNetworks = new HashSet<WifiNetworkSuggestion>();
suggestionNetworks.add(mWifiNetworkSuggestion);
when(mWifiNetworkSuggestionsManager.getAllApprovedNetworkSuggestions())
.thenReturn(suggestionNetworks);
// Prepare for no saved networks
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(new ArrayList<>());
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set WiFi to connected state to trigger periodic scan
setWifiStateConnected();
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* When screen on and single saved network schedule is set
* If we have a single suggestion network (connected network),
* and saved network/passpoint networks the regular
* connected state scan schedule is used
*/
@Test
public void checkScanScheduleForSavedPasspointSuggestionNetworkConnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
// Prepare for a single suggestions network
WifiConfiguration config = new WifiConfiguration();
config.networkId = TEST_CONNECTED_NETWORK_ID;
String networkKey = "NETWORK_KEY";
when(mWifiConfigManager.getConfiguredNetwork(networkKey)).thenReturn(config);
when(mSuggestionConfig.getKey()).thenReturn(networkKey);
when(mWifiNetworkSuggestion.getWifiConfiguration()).thenReturn(mSuggestionConfig);
Set<WifiNetworkSuggestion> suggestionNetworks = new HashSet<WifiNetworkSuggestion>();
suggestionNetworks.add(mWifiNetworkSuggestion);
when(mWifiNetworkSuggestionsManager.getAllApprovedNetworkSuggestions())
.thenReturn(suggestionNetworks);
// Prepare for a single passpoint network
WifiConfiguration passpointConfig = new WifiConfiguration();
String passpointKey = "PASSPOINT_KEY";
when(mWifiConfigManager.getConfiguredNetwork(passpointKey)).thenReturn(passpointConfig);
List<PasspointConfiguration> passpointNetworks = new ArrayList<PasspointConfiguration>();
passpointNetworks.add(mPasspointConfiguration);
when(mPasspointConfiguration.getUniqueId()).thenReturn(passpointKey);
when(mPasspointManager.getProviderConfigs(anyInt(), anyBoolean()))
.thenReturn(passpointNetworks);
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set WiFi to connected state to trigger periodic scan
setWifiStateConnected();
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* Remove network will trigger update scan and meet single network requirement.
* Verify before disconnect finished, will not trigger single network scan schedule.
*/
@Test
public void checkScanScheduleForCurrentConnectedNetworkIsNull() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
mResources.setIntArray(
R.array.config_wifiSingleSavedNetworkConnectedScanIntervalScheduleSec,
VALID_CONNECTED_SINGLE_SAVED_NETWORK_SCHEDULE_SEC);
// Set firmware roaming to enabled
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set up single saved network
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.networkId = TEST_CONNECTED_NETWORK_ID;
List<WifiConfiguration> wifiConfigurationList = new ArrayList<WifiConfiguration>();
wifiConfigurationList.add(wifiConfiguration);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(wifiConfigurationList);
// Set WiFi to connected state.
setWifiStateConnected();
// Simulate remove network, disconnect not finished.
when(mClientModeImpl.getCurrentWifiConfiguration()).thenReturn(null);
mNetworkUpdateListenerCaptor.getValue().onNetworkRemoved(null);
// Get the first periodic scan interval
long firstIntervalMs = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
- currentTimeStamp;
assertEquals(VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000, firstIntervalMs);
}
/**
* When screen on trigger a disconnected state change event then a connected state
* change event back to back to verify that the minium scan interval is enforced.
*
* Expected behavior: WifiConnectivityManager start the second periodic single
* scan after the first one by first interval in connected scanning schedule.
*/
@Test
public void checkMinimumPeriodicScanIntervalWhenScreenOnAndConnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for max scanning interval in schedule so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
long scanForDisconnectedTimeStamp = currentTimeStamp;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state which triggers a scan immediately
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mWifiScanner, times(1)).startScan(
anyObject(), anyObject(), anyObject(), anyObject());
// Set up time stamp for when entering CONNECTED state
currentTimeStamp += 2000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to connected state to trigger its periodic scan
setWifiStateConnected();
// The very first scan triggered for connected state is actually via the alarm timer
// and it obeys the minimum scan interval
long firstScanForConnectedTimeStamp = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
// Verify that the first scan for connected state is scheduled after the scan for
// disconnected state by first interval in connected scanning schedule.
assertEquals(scanForDisconnectedTimeStamp + VALID_CONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0]
* 1000, firstScanForConnectedTimeStamp);
}
/**
* When screen on trigger a connected state change event then a disconnected state
* change event back to back to verify that a scan is fired immediately for the
* disconnected state change event.
*
* Expected behavior: WifiConnectivityManager directly starts the periodic immediately
* for the disconnected state change event. The second scan for disconnected state is
* via alarm timer.
*/
@Test
public void scanImmediatelyWhenScreenOnAndDisconnected() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for maximum scanning interval in schedule so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
long scanForConnectedTimeStamp = currentTimeStamp;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to connected state to trigger the periodic scan
setWifiStateConnected();
verify(mWifiScanner, times(1)).startScan(
anyObject(), anyObject(), anyObject(), anyObject());
// Set up the time stamp for when entering DISCONNECTED state
currentTimeStamp += 2000;
long enteringDisconnectedStateTimeStamp = currentTimeStamp;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to disconnected state to trigger its periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Verify the very first scan for DISCONNECTED state is fired immediately
verify(mWifiScanner, times(2)).startScan(
anyObject(), anyObject(), anyObject(), anyObject());
long secondScanForDisconnectedTimeStamp = mAlarmManager
.getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG);
// Verify that the second scan is scheduled after entering DISCONNECTED state by first
// interval in disconnected scanning schedule.
assertEquals(enteringDisconnectedStateTimeStamp
+ VALID_DISCONNECTED_SINGLE_SCAN_SCHEDULE_SEC[0] * 1000,
secondScanForDisconnectedTimeStamp);
}
/**
* When screen on trigger a connection state change event and a forced connectivity
* scan event back to back to verify that the minimum scan interval is not applied
* in this scenario.
*
* Expected behavior: WifiConnectivityManager starts the second periodic single
* scan immediately.
*/
@Test
public void checkMinimumPeriodicScanIntervalNotEnforced() {
long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Wait for maximum interval in scanning schedule so that any impact triggered
// by screen state change can settle
currentTimeStamp += MAX_SCAN_INTERVAL_IN_SCHEDULE_SEC * 1000;
long firstScanTimeStamp = currentTimeStamp;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Set WiFi to connected state to trigger the periodic scan
setWifiStateConnected();
// Set the second scan attempt time stamp
currentTimeStamp += 2000;
when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
// Allow untrusted networks so WifiConnectivityManager starts a periodic scan
// immediately.
mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
// Get the second periodic scan actual time stamp. Note, this scan is not
// started from the AlarmManager.
long secondScanTimeStamp = mWifiConnectivityManager.getLastPeriodicSingleScanTimeStamp();
// Verify that the second scan is fired immediately
assertEquals(secondScanTimeStamp, currentTimeStamp);
}
/**
* Verify that we perform full band scan in the following two cases
* 1) Current RSSI is low, no active stream, network is insufficient
* 2) Current RSSI is high, no active stream, and a long time since last network selection
* 3) Current RSSI is high, no active stream, and a short time since last network selection,
* internet status is not acceptable
*
* Expected behavior: WifiConnectivityManager does full band scan in both cases
*/
@Test
public void verifyFullBandScanWhenConnected() {
mResources.setInteger(
R.integer.config_wifiConnectedHighRssiScanMinimumWindowSizeSec, 600);
// Verify case 1
when(mWifiNS.isNetworkSufficient(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasActiveStream(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasSufficientLinkQuality(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasInternetOrExpectNoInternet(eq(mWifiInfo))).thenReturn(true);
final List<Integer> channelList = new ArrayList<>();
channelList.add(TEST_FREQUENCY_1);
channelList.add(TEST_FREQUENCY_2);
channelList.add(TEST_FREQUENCY_3);
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
when(mClientModeImpl.getCurrentWifiConfiguration())
.thenReturn(configuration);
when(mWifiScoreCard.lookupNetwork(configuration.SSID)).thenReturn(mPerNetwork);
when(mPerNetwork.getFrequencies(anyLong())).thenReturn(new ArrayList<>());
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, ScanListener listener,
WorkSource workSource) throws Exception {
assertEquals(settings.band, WifiScanner.WIFI_BAND_ALL);
assertNull(settings.channels);
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject());
when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
// Verify case 2
when(mWifiNS.isNetworkSufficient(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasActiveStream(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasSufficientLinkQuality(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasInternetOrExpectNoInternet(eq(mWifiInfo))).thenReturn(true);
when(mClock.getElapsedSinceBootMillis()).thenReturn(600_000L + 1L);
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mWifiScanner, times(2)).startScan(anyObject(), anyObject(), anyObject(),
anyObject());
// Verify case 3
when(mWifiNS.isNetworkSufficient(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasActiveStream(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasSufficientLinkQuality(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasInternetOrExpectNoInternet(eq(mWifiInfo))).thenReturn(false);
when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mWifiScanner, times(2)).startScan(anyObject(), anyObject(), anyObject(),
anyObject());
}
/**
* Verify that we perform partial scan when the current RSSI is low,
* Tx/Rx success rates are high, and when the currently connected network is present
* in scan cache in WifiConfigManager.
* WifiConnectivityManager does partial scan only when firmware roaming is not supported.
*
* Expected behavior: WifiConnectivityManager does partial scan.
*/
@Test
public void checkPartialScanRequestedWithLowRssiAndActiveStreamWithoutFwRoaming() {
when(mWifiNS.isNetworkSufficient(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasActiveStream(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasSufficientLinkQuality(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasInternetOrExpectNoInternet(eq(mWifiInfo))).thenReturn(true);
mResources.setInteger(
R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels,
10);
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
List<Integer> channelList = linkScoreCardFreqsToNetwork(configuration).get(0);
when(mClientModeImpl.getCurrentWifiConfiguration())
.thenReturn(configuration);
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(false);
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
assertEquals(settings.band, WifiScanner.WIFI_BAND_UNSPECIFIED);
assertEquals(settings.channels.length, channelList.size());
for (int chanIdx = 0; chanIdx < settings.channels.length; chanIdx++) {
assertTrue(channelList.contains(settings.channels[chanIdx].frequency));
}
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
}
/**
* Verify that we perform partial scan when the current RSSI is high,
* Tx/Rx success rates are low, and when the currently connected network is present
* in scan cache in WifiConfigManager.
* WifiConnectivityManager does partial scan only when firmware roaming is not supported.
*
* Expected behavior: WifiConnectivityManager does partial scan.
*/
@Test
public void checkPartialScanRequestedWithHighRssiNoActiveStreamWithoutFwRoaming() {
when(mWifiNS.isNetworkSufficient(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasActiveStream(eq(mWifiInfo))).thenReturn(false);
when(mWifiNS.hasSufficientLinkQuality(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasInternetOrExpectNoInternet(eq(mWifiInfo))).thenReturn(true);
mResources.setInteger(
R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels,
10);
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
List<Integer> channelList = linkScoreCardFreqsToNetwork(configuration).get(0);
when(mClientModeImpl.getCurrentWifiConfiguration())
.thenReturn(configuration);
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(false);
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
assertEquals(settings.band, WifiScanner.WIFI_BAND_UNSPECIFIED);
assertEquals(settings.channels.length, channelList.size());
for (int chanIdx = 0; chanIdx < settings.channels.length; chanIdx++) {
assertTrue(channelList.contains(settings.channels[chanIdx].frequency));
}
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
}
/**
* Verify that we fall back to full band scan when the currently connected network's tx/rx
* success rate is high, RSSI is also high but the currently connected network
* is not present in scan cache in WifiConfigManager.
* This is simulated by returning an empty hashset in |makeChannelList|.
*
* Expected behavior: WifiConnectivityManager does full band scan.
*/
@Test
public void checkSingleScanSettingsWhenConnectedWithHighDataRateNotInCache() {
when(mWifiNS.isNetworkSufficient(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasActiveStream(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasSufficientLinkQuality(eq(mWifiInfo))).thenReturn(true);
when(mWifiNS.hasInternetOrExpectNoInternet(eq(mWifiInfo))).thenReturn(true);
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
List<Integer> channelList = linkScoreCardFreqsToNetwork(configuration).get(0);
when(mClientModeImpl.getCurrentWifiConfiguration())
.thenReturn(new WifiConfiguration());
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
assertEquals(settings.band, WifiScanner.WIFI_BAND_ALL);
assertNull(settings.channels);
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to connected state to trigger periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
verify(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
}
/**
* Verify that we retry connectivity scan up to MAX_SCAN_RESTART_ALLOWED times
* when Wifi somehow gets into a bad state and fails to scan.
*
* Expected behavior: WifiConnectivityManager schedules connectivity scan
* MAX_SCAN_RESTART_ALLOWED times.
*/
@Test
public void checkMaximumScanRetry() {
// Set screen to ON
mWifiConnectivityManager.handleScreenStateChanged(true);
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onFailure(-1, "ScanFailure");
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
// Set WiFi to disconnected state to trigger the single scan based periodic scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Fire the alarm timer 2x timers
for (int i = 0; i < (WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED * 2); i++) {
mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG);
mLooper.dispatchAll();
}
// Verify that the connectivity scan has been retried for MAX_SCAN_RESTART_ALLOWED
// times. Note, WifiScanner.startScan() is invoked MAX_SCAN_RESTART_ALLOWED + 1 times.
// The very first scan is the initial one, and the other MAX_SCAN_RESTART_ALLOWED
// are the retrial ones.
verify(mWifiScanner, times(WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED + 1)).startScan(
anyObject(), anyObject(), anyObject(), anyObject());
}
/**
* Verify that a successful scan result resets scan retry counter
*
* Steps
* 1. Trigger a scan that fails
* 2. Let the retry succeed
* 3. Trigger a scan again and have it and all subsequent retries fail
* 4. Verify that there are MAX_SCAN_RESTART_ALLOWED + 3 startScan calls. (2 are from the
* original scans, and MAX_SCAN_RESTART_ALLOWED + 1 from retries)
*/
@Test
public void verifyScanFailureCountIsResetAfterOnResult() {
// Setup WifiScanner to fail
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onFailure(-1, "ScanFailure");
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
mWifiConnectivityManager.forceConnectivityScan(null);
// make the retry succeed
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onResults(null);
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG);
mLooper.dispatchAll();
// Verify that startScan is called once for the original scan, plus once for the retry.
// The successful retry should have now cleared the restart count
verify(mWifiScanner, times(2)).startScan(
anyObject(), anyObject(), anyObject(), anyObject());
// Now force a new scan and verify we retry MAX_SCAN_RESTART_ALLOWED times
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, Executor executor, ScanListener listener,
WorkSource workSource) throws Exception {
listener.onFailure(-1, "ScanFailure");
}}).when(mWifiScanner).startScan(anyObject(), anyObject(), anyObject(), anyObject());
mWifiConnectivityManager.forceConnectivityScan(null);
// Fire the alarm timer 2x timers
for (int i = 0; i < (WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED * 2); i++) {
mAlarmManager.dispatch(WifiConnectivityManager.RESTART_SINGLE_SCAN_TIMER_TAG);
mLooper.dispatchAll();
}
// Verify that the connectivity scan has been retried for MAX_SCAN_RESTART_ALLOWED + 3
// times. Note, WifiScanner.startScan() is invoked 2 times by the first part of this test,
// and additionally MAX_SCAN_RESTART_ALLOWED + 1 times from forceConnectivityScan and
// subsequent retries.
verify(mWifiScanner, times(WifiConnectivityManager.MAX_SCAN_RESTART_ALLOWED + 3)).startScan(
anyObject(), anyObject(), anyObject(), anyObject());
}
/**
* Listen to scan results not requested by WifiConnectivityManager and
* act on them.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID and BSSID.
*/
@Test
public void listenToAllSingleScanResults() {
ScanSettings settings = new ScanSettings();
ScanListener scanListener = mock(ScanListener.class);
// Request a single scan outside of WifiConnectivityManager.
mWifiScanner.startScan(settings, mock(Executor.class), scanListener, WIFI_WORK_SOURCE);
// Verify that WCM receives the scan results and initiates a connection
// to the network.
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Verify that a forced connectivity scan waits for full band scan
* results.
*
* Expected behavior: WifiConnectivityManager doesn't invoke
* ClientModeImpl.startConnectToNetwork() when full band scan
* results are not available.
*/
@Test
public void waitForFullBandScanResults() {
// Set WiFi to connected state.
setWifiStateConnected();
// Set up as partial scan results.
when(mScanData.getBandScanned()).thenReturn(WifiScanner.WIFI_BAND_5_GHZ);
// Force a connectivity scan which enables WifiConnectivityManager
// to wait for full band scan results.
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
// No roaming because no full band scan results.
verify(mClientModeImpl, times(0)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
// Set up as full band scan results.
when(mScanData.getBandScanned()).thenReturn(WifiScanner.WIFI_BAND_ALL);
// Force a connectivity scan which enables WifiConnectivityManager
// to wait for full band scan results.
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
// Roaming attempt because full band scan results are available.
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Verify when new scanResults are available, UserDisabledList will be updated.
*/
@Test
public void verifyUserDisabledListUpdated() {
mResources.setBoolean(
R.bool.config_wifi_framework_use_single_radio_chain_scan_results_network_selection,
true);
verify(mWifiConfigManager, never()).updateUserDisabledList(anyList());
Set<String> updateNetworks = new HashSet<>();
mScanData = createScanDataWithDifferentRadioChainInfos();
int i = 0;
for (ScanResult scanResult : mScanData.getResults()) {
scanResult.SSID = TEST_SSID + i;
updateNetworks.add(ScanResultUtil.createQuotedSSID(scanResult.SSID));
i++;
}
updateNetworks.add(TEST_FQDN);
mScanData.getResults()[0].setFlag(ScanResult.FLAG_PASSPOINT_NETWORK);
HashMap<String, Map<Integer, List<ScanResult>>> passpointNetworks = new HashMap<>();
passpointNetworks.put(TEST_FQDN, new HashMap<>());
when(mPasspointManager.getAllMatchingPasspointProfilesForScanResults(any()))
.thenReturn(passpointNetworks);
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
ArgumentCaptor<ArrayList<String>> listArgumentCaptor =
ArgumentCaptor.forClass(ArrayList.class);
verify(mWifiConfigManager).updateUserDisabledList(listArgumentCaptor.capture());
assertEquals(updateNetworks, new HashSet<>(listArgumentCaptor.getValue()));
}
/**
* Verify that a blacklisted BSSID becomes available only after
* BSSID_BLACKLIST_EXPIRE_TIME_MS.
*/
@Test
public void verifyBlacklistRefreshedAfterScanResults() {
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
InOrder inOrder = inOrder(mBssidBlocklistMonitor);
// Force a connectivity scan
inOrder.verify(mBssidBlocklistMonitor, never())
.updateAndGetBssidBlocklistForSsid(anyString());
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
inOrder.verify(mBssidBlocklistMonitor).tryEnablingBlockedBssids(any());
inOrder.verify(mBssidBlocklistMonitor).updateAndGetBssidBlocklistForSsid(anyString());
}
/**
* Verify that BSSID blacklist gets cleared when exiting Wifi client mode.
*/
@Test
public void clearBssidBlocklistWhenExitingWifiClientMode() {
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Verify the BSSID blacklist is cleared at start up.
verify(mBssidBlocklistMonitor).clearBssidBlocklist();
// Exit Wifi client mode.
mWifiConnectivityManager.setWifiEnabled(false);
// Verify the BSSID blacklist is cleared again.
verify(mBssidBlocklistMonitor, times(2)).clearBssidBlocklist();
// Verify WifiNetworkSelector is informed of the disable.
verify(mWifiNS).resetOnDisable();
}
/**
* Verify that BSSID blacklist gets cleared when preparing for a forced connection
* initiated by user/app.
*/
@Test
public void clearBssidBlocklistWhenPreparingForForcedConnection() {
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Prepare for a forced connection attempt.
WifiConfiguration currentNetwork = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork);
mWifiConnectivityManager.prepareForForcedConnection(1);
verify(mBssidBlocklistMonitor).clearBssidBlocklistForSsid(CANDIDATE_SSID);
}
/**
* When WifiConnectivityManager is on and Wifi client mode is enabled, framework
* queries firmware via WifiConnectivityHelper to check if firmware roaming is
* supported and its capability.
*
* Expected behavior: WifiConnectivityManager#setWifiEnabled calls into
* WifiConnectivityHelper#getFirmwareRoamingInfo
*/
@Test
public void verifyGetFirmwareRoamingInfoIsCalledWhenEnableWiFiAndWcmOn() {
// WifiConnectivityManager is on by default
mWifiConnectivityManager.setWifiEnabled(true);
verify(mWifiConnectivityHelper).getFirmwareRoamingInfo();
}
/**
* When WifiConnectivityManager is off, verify that framework does not
* query firmware via WifiConnectivityHelper to check if firmware roaming is
* supported and its capability when enabling Wifi client mode.
*
* Expected behavior: WifiConnectivityManager#setWifiEnabled does not call into
* WifiConnectivityHelper#getFirmwareRoamingInfo
*/
@Test
public void verifyGetFirmwareRoamingInfoIsNotCalledWhenEnableWiFiAndWcmOff() {
reset(mWifiConnectivityHelper);
mWifiConnectivityManager.setAutoJoinEnabledExternal(false);
mWifiConnectivityManager.setWifiEnabled(true);
verify(mWifiConnectivityHelper, times(0)).getFirmwareRoamingInfo();
}
/*
* Firmware supports controlled roaming.
* Connect to a network which doesn't have a config specified BSSID.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID, and the BSSID value should be
* 'any' since firmware controls the roaming.
*/
@Test
public void useAnyBssidToConnectWhenFirmwareRoamingOnAndConfigHasNoBssidSpecified() {
// Firmware controls roaming
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, ClientModeImpl.SUPPLICANT_BSSID_ANY);
}
/*
* Firmware supports controlled roaming.
* Connect to a network which has a config specified BSSID.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the
* expected candidate network ID, and the BSSID value should be
* the config specified one.
*/
@Test
public void useConfigSpecifiedBssidToConnectWhenFirmwareRoamingOn() {
// Firmware controls roaming
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set up the candidate configuration such that it has a BSSID specified.
WifiConfiguration candidate = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
candidate.BSSID = CANDIDATE_BSSID; // config specified
ScanResult candidateScanResult = new ScanResult();
candidateScanResult.SSID = CANDIDATE_SSID;
candidateScanResult.BSSID = CANDIDATE_BSSID;
candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
when(mWifiNS.selectNetwork(any())).thenReturn(candidate);
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/*
* Firmware does not support controlled roaming.
* Connect to a network which doesn't have a config specified BSSID.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the expected candidate network ID,
* and the BSSID value should be the candidate scan result specified.
*/
@Test
public void useScanResultBssidToConnectWhenFirmwareRoamingOffAndConfigHasNoBssidSpecified() {
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/*
* Firmware does not support controlled roaming.
* Connect to a network which has a config specified BSSID.
*
* Expected behavior: WifiConnectivityManager calls
* ClientModeImpl.startConnectToNetwork() with the expected candidate network ID,
* and the BSSID value should be the config specified one.
*/
@Test
public void useConfigSpecifiedBssidToConnectionWhenFirmwareRoamingOff() {
// Set up the candidate configuration such that it has a BSSID specified.
WifiConfiguration candidate = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
candidate.BSSID = CANDIDATE_BSSID; // config specified
ScanResult candidateScanResult = new ScanResult();
candidateScanResult.SSID = CANDIDATE_SSID;
candidateScanResult.BSSID = CANDIDATE_BSSID;
candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
when(mWifiNS.selectNetwork(any())).thenReturn(candidate);
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mClientModeImpl).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/**
* Firmware does not support controlled roaming.
* WiFi in connected state, framework triggers roaming.
*
* Expected behavior: WifiConnectivityManager invokes
* ClientModeImpl.startRoamToNetwork().
*/
@Test
public void frameworkInitiatedRoaming() {
// Mock the currently connected network which has the same networkID and
// SSID as the one to be selected.
WifiConfiguration currentNetwork = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork);
// Set WiFi to connected state
setWifiStateConnected();
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mClientModeImpl).startRoamToNetwork(eq(CANDIDATE_NETWORK_ID),
mCandidateScanResultCaptor.capture());
assertEquals(mCandidateScanResultCaptor.getValue().BSSID, CANDIDATE_BSSID);
}
/**
* Firmware supports controlled roaming.
* WiFi in connected state, framework does not trigger roaming
* as it's handed off to the firmware.
*
* Expected behavior: WifiConnectivityManager doesn't invoke
* ClientModeImpl.startRoamToNetwork().
*/
@Test
public void noFrameworkRoamingIfConnectedAndFirmwareRoamingSupported() {
// Mock the currently connected network which has the same networkID and
// SSID as the one to be selected.
WifiConfiguration currentNetwork = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork);
// Firmware controls roaming
when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
// Set WiFi to connected state
setWifiStateConnected();
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mClientModeImpl, times(0)).startRoamToNetwork(anyInt(), anyObject());
}
/*
* Wifi in disconnected state. Drop the connection attempt if the recommended
* network configuration has a BSSID specified but the scan result BSSID doesn't
* match it.
*
* Expected behavior: WifiConnectivityManager doesn't invoke
* ClientModeImpl.startConnectToNetwork().
*/
@Test
public void dropConnectAttemptIfConfigSpecifiedBssidDifferentFromScanResultBssid() {
// Set up the candidate configuration such that it has a BSSID specified.
WifiConfiguration candidate = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
candidate.BSSID = CANDIDATE_BSSID; // config specified
ScanResult candidateScanResult = new ScanResult();
candidateScanResult.SSID = CANDIDATE_SSID;
// Set up the scan result BSSID to be different from the config specified one.
candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID;
candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
when(mWifiNS.selectNetwork(any())).thenReturn(candidate);
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
// Set WiFi to disconnected state
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
verify(mClientModeImpl, times(0)).startConnectToNetwork(
CANDIDATE_NETWORK_ID, Process.WIFI_UID, CANDIDATE_BSSID);
}
/*
* Wifi in connected state. Drop the roaming attempt if the recommended
* network configuration has a BSSID specified but the scan result BSSID doesn't
* match it.
*
* Expected behavior: WifiConnectivityManager doesn't invoke
* ClientModeImpl.startRoamToNetwork().
*/
@Test
public void dropRoamingAttemptIfConfigSpecifiedBssidDifferentFromScanResultBssid() {
// Mock the currently connected network which has the same networkID and
// SSID as the one to be selected.
WifiConfiguration currentNetwork = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
when(mWifiConfigManager.getConfiguredNetwork(anyInt())).thenReturn(currentNetwork);
// Set up the candidate configuration such that it has a BSSID specified.
WifiConfiguration candidate = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
candidate.BSSID = CANDIDATE_BSSID; // config specified
ScanResult candidateScanResult = new ScanResult();
candidateScanResult.SSID = CANDIDATE_SSID;
// Set up the scan result BSSID to be different from the config specified one.
candidateScanResult.BSSID = INVALID_SCAN_RESULT_BSSID;
candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
when(mWifiNS.selectNetwork(any())).thenReturn(candidate);
// Set WiFi to connected state
setWifiStateConnected();
// Set screen to on
mWifiConnectivityManager.handleScreenStateChanged(true);
verify(mClientModeImpl, times(0)).startRoamToNetwork(anyInt(), anyObject());
}
/**
* Dump local log buffer.
*
* Expected behavior: Logs dumped from WifiConnectivityManager.dump()
* contain the message we put in mLocalLog.
*/
@Test
public void dumpLocalLog() {
final String localLogMessage = "This is a message from the test";
mLocalLog.log(localLogMessage);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{});
assertTrue(sw.toString().contains(localLogMessage));
}
/**
* Dump ONA controller.
*
* Expected behavior: {@link OpenNetworkNotifier#dump(FileDescriptor, PrintWriter,
* String[])} is invoked.
*/
@Test
public void dumpNotificationController() {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{});
verify(mOpenNetworkNotifier).dump(any(), any(), any());
}
/**
* Create scan data with different radio chain infos:
* First scan result has null radio chain info (No DBS support).
* Second scan result has empty radio chain info (No DBS support).
* Third scan result has 1 radio chain info (DBS scan).
* Fourth scan result has 2 radio chain info (non-DBS scan).
*/
private ScanData createScanDataWithDifferentRadioChainInfos() {
// Create 4 scan results.
ScanData[] scanDatas =
ScanTestUtil.createScanDatas(new int[][]{{5150, 5175, 2412, 2400}}, new int[]{0});
// WCM barfs if the scan result does not have an IE.
scanDatas[0].getResults()[0].informationElements = new InformationElement[0];
scanDatas[0].getResults()[1].informationElements = new InformationElement[0];
scanDatas[0].getResults()[2].informationElements = new InformationElement[0];
scanDatas[0].getResults()[3].informationElements = new InformationElement[0];
scanDatas[0].getResults()[0].radioChainInfos = null;
scanDatas[0].getResults()[1].radioChainInfos = new ScanResult.RadioChainInfo[0];
scanDatas[0].getResults()[2].radioChainInfos = new ScanResult.RadioChainInfo[1];
scanDatas[0].getResults()[3].radioChainInfos = new ScanResult.RadioChainInfo[2];
return scanDatas[0];
}
/**
* If |config_wifi_framework_use_single_radio_chain_scan_results_network_selection| flag is
* false, WifiConnectivityManager should filter scan results which contain scans from a single
* radio chain (i.e DBS scan).
* Note:
* a) ScanResult with no radio chain indicates a lack of DBS support on the device.
* b) ScanResult with 2 radio chain info indicates a scan done using both the radio chains
* on a DBS supported device.
*
* Expected behavior: WifiConnectivityManager invokes
* {@link WifiNetworkSelector#selectNetwork(List, HashSet, WifiInfo, boolean, boolean, boolean)}
* after filtering out the scan results obtained via DBS scan.
*/
@Test
public void filterScanResultsWithOneRadioChainInfoForNetworkSelectionIfConfigDisabled() {
mResources.setBoolean(
R.bool.config_wifi_framework_use_single_radio_chain_scan_results_network_selection,
false);
when(mWifiNS.selectNetwork(any())).thenReturn(null);
mWifiConnectivityManager = createConnectivityManager();
mScanData = createScanDataWithDifferentRadioChainInfos();
// Capture scan details which were sent to network selector.
final List<ScanDetail> capturedScanDetails = new ArrayList<>();
doAnswer(new AnswerWithArguments() {
public List<WifiCandidates.Candidate> answer(
List<ScanDetail> scanDetails, Set<String> bssidBlacklist, WifiInfo wifiInfo,
boolean connected, boolean disconnected, boolean untrustedNetworkAllowed)
throws Exception {
capturedScanDetails.addAll(scanDetails);
return null;
}}).when(mWifiNS).getCandidatesFromScan(
any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean());
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
// Set WiFi to disconnected state with screen on which triggers a scan immediately.
mWifiConnectivityManager.setWifiEnabled(true);
mWifiConnectivityManager.handleScreenStateChanged(true);
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// We should have filtered out the 3rd scan result.
assertEquals(3, capturedScanDetails.size());
List<ScanResult> capturedScanResults =
capturedScanDetails.stream().map(ScanDetail::getScanResult)
.collect(Collectors.toList());
assertEquals(3, capturedScanResults.size());
assertTrue(capturedScanResults.contains(mScanData.getResults()[0]));
assertTrue(capturedScanResults.contains(mScanData.getResults()[1]));
assertFalse(capturedScanResults.contains(mScanData.getResults()[2]));
assertTrue(capturedScanResults.contains(mScanData.getResults()[3]));
}
/**
* If |config_wifi_framework_use_single_radio_chain_scan_results_network_selection| flag is
* true, WifiConnectivityManager should not filter scan results which contain scans from a
* single radio chain (i.e DBS scan).
* Note:
* a) ScanResult with no radio chain indicates a lack of DBS support on the device.
* b) ScanResult with 2 radio chain info indicates a scan done using both the radio chains
* on a DBS supported device.
*
* Expected behavior: WifiConnectivityManager invokes
* {@link WifiNetworkSelector#selectNetwork(List, HashSet, WifiInfo, boolean, boolean, boolean)}
* after filtering out the scan results obtained via DBS scan.
*/
@Test
public void dontFilterScanResultsWithOneRadioChainInfoForNetworkSelectionIfConfigEnabled() {
mResources.setBoolean(
R.bool.config_wifi_framework_use_single_radio_chain_scan_results_network_selection,
true);
when(mWifiNS.selectNetwork(any())).thenReturn(null);
mWifiConnectivityManager = createConnectivityManager();
mScanData = createScanDataWithDifferentRadioChainInfos();
// Capture scan details which were sent to network selector.
final List<ScanDetail> capturedScanDetails = new ArrayList<>();
doAnswer(new AnswerWithArguments() {
public List<WifiCandidates.Candidate> answer(
List<ScanDetail> scanDetails, Set<String> bssidBlacklist, WifiInfo wifiInfo,
boolean connected, boolean disconnected, boolean untrustedNetworkAllowed)
throws Exception {
capturedScanDetails.addAll(scanDetails);
return null;
}}).when(mWifiNS).getCandidatesFromScan(
any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean());
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
// Set WiFi to disconnected state with screen on which triggers a scan immediately.
mWifiConnectivityManager.setWifiEnabled(true);
mWifiConnectivityManager.handleScreenStateChanged(true);
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// We should not filter any of the scan results.
assertEquals(4, capturedScanDetails.size());
List<ScanResult> capturedScanResults =
capturedScanDetails.stream().map(ScanDetail::getScanResult)
.collect(Collectors.toList());
assertEquals(4, capturedScanResults.size());
assertTrue(capturedScanResults.contains(mScanData.getResults()[0]));
assertTrue(capturedScanResults.contains(mScanData.getResults()[1]));
assertTrue(capturedScanResults.contains(mScanData.getResults()[2]));
assertTrue(capturedScanResults.contains(mScanData.getResults()[3]));
}
/**
* Verify the various auto join enable/disable sequences when auto join is disabled externally.
*
* Expected behavior: Autojoin is turned on as a long as there is
* - Auto join is enabled externally
* And
* - No specific network request being processed.
* And
* - Pending generic Network request for trusted wifi connection.
* OR
* - Pending generic Network request for untrused wifi connection.
*/
@Test
public void verifyEnableAndDisableAutoJoinWhenExternalAutoJoinIsDisabled() {
mWifiConnectivityManager = createConnectivityManager();
// set wifi on & disconnected to trigger pno scans when auto-join is enabled.
mWifiConnectivityManager.setWifiEnabled(true);
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Disable externally.
mWifiConnectivityManager.setAutoJoinEnabledExternal(false);
// Enable trusted connection. This should NOT trigger a pno scan for auto-join.
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
verify(mWifiScanner, never()).startDisconnectedPnoScan(any(), any(), any(), any());
// End of processing a specific request. This should NOT trigger a new pno scan for
// auto-join.
mWifiConnectivityManager.setSpecificNetworkRequestInProgress(false);
verify(mWifiScanner, never()).startDisconnectedPnoScan(any(), any(), any(), any());
// Enable untrusted connection. This should NOT trigger a pno scan for auto-join.
mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
verify(mWifiScanner, never()).startDisconnectedPnoScan(any(), any(), any(), any());
}
/**
* Verify the various auto join enable/disable sequences when auto join is enabled externally.
*
* Expected behavior: Autojoin is turned on as a long as there is
* - Auto join is enabled externally
* And
* - No specific network request being processed.
* And
* - Pending generic Network request for trusted wifi connection.
* OR
* - Pending generic Network request for untrused wifi connection.
*/
@Test
public void verifyEnableAndDisableAutoJoin() {
mWifiConnectivityManager = createConnectivityManager();
// set wifi on & disconnected to trigger pno scans when auto-join is enabled.
mWifiConnectivityManager.setWifiEnabled(true);
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
// Enable trusted connection. This should trigger a pno scan for auto-join.
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
verify(mWifiScanner).startDisconnectedPnoScan(any(), any(), any(), any());
// Start of processing a specific request. This should stop any pno scan for auto-join.
mWifiConnectivityManager.setSpecificNetworkRequestInProgress(true);
verify(mWifiScanner).stopPnoScan(any());
// End of processing a specific request. This should now trigger a new pno scan for
// auto-join.
mWifiConnectivityManager.setSpecificNetworkRequestInProgress(false);
verify(mWifiScanner, times(2)).startDisconnectedPnoScan(any(), any(), any(), any());
// Disable trusted connection. This should stop any pno scan for auto-join.
mWifiConnectivityManager.setTrustedConnectionAllowed(false);
verify(mWifiScanner, times(2)).stopPnoScan(any());
// Enable untrusted connection. This should trigger a pno scan for auto-join.
mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
verify(mWifiScanner, times(3)).startDisconnectedPnoScan(any(), any(), any(), any());
}
/**
* Change device mobility state in the middle of a PNO scan. PNO scan should stop, then restart
* with the updated scan period.
*/
@Test
public void changeDeviceMobilityStateDuringScan() {
mWifiConnectivityManager.setWifiEnabled(true);
// starts a PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
ArgumentCaptor<ScanSettings> scanSettingsCaptor = ArgumentCaptor.forClass(
ScanSettings.class);
InOrder inOrder = inOrder(mWifiScanner);
inOrder.verify(mWifiScanner).startDisconnectedPnoScan(
scanSettingsCaptor.capture(), any(), any(), any());
assertEquals(scanSettingsCaptor.getValue().periodInMs, MOVING_PNO_SCAN_INTERVAL_MILLIS);
// initial connectivity state uses moving PNO scan interval, now set it to stationary
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_STATIONARY);
inOrder.verify(mWifiScanner).stopPnoScan(any());
inOrder.verify(mWifiScanner).startDisconnectedPnoScan(
scanSettingsCaptor.capture(), any(), any(), any());
assertEquals(scanSettingsCaptor.getValue().periodInMs, STATIONARY_PNO_SCAN_INTERVAL_MILLIS);
verify(mScoringParams, times(2)).getEntryRssi(ScanResult.BAND_6_GHZ_START_FREQ_MHZ);
verify(mScoringParams, times(2)).getEntryRssi(ScanResult.BAND_5_GHZ_START_FREQ_MHZ);
verify(mScoringParams, times(2)).getEntryRssi(ScanResult.BAND_24_GHZ_START_FREQ_MHZ);
}
/**
* Change device mobility state in the middle of a PNO scan, but it is changed to another
* mobility state with the same scan period. Original PNO scan should continue.
*/
@Test
public void changeDeviceMobilityStateDuringScanWithSameScanPeriod() {
mWifiConnectivityManager.setWifiEnabled(true);
// starts a PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
ArgumentCaptor<ScanSettings> scanSettingsCaptor = ArgumentCaptor.forClass(
ScanSettings.class);
InOrder inOrder = inOrder(mWifiScanner);
inOrder.verify(mWifiScanner, never()).stopPnoScan(any());
inOrder.verify(mWifiScanner).startDisconnectedPnoScan(
scanSettingsCaptor.capture(), any(), any(), any());
assertEquals(scanSettingsCaptor.getValue().periodInMs, MOVING_PNO_SCAN_INTERVAL_MILLIS);
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_LOW_MVMT);
inOrder.verifyNoMoreInteractions();
}
/**
* Device is already connected, setting device mobility state should do nothing since no PNO
* scans are running. Then, when PNO scan is started afterwards, should use the new scan period.
*/
@Test
public void setDeviceMobilityStateBeforePnoScan() {
// ensure no PNO scan running
mWifiConnectivityManager.setWifiEnabled(true);
setWifiStateConnected();
// initial connectivity state uses moving PNO scan interval, now set it to stationary
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_STATIONARY);
// no scans should start or stop because no PNO scan is running
verify(mWifiScanner, never()).startDisconnectedPnoScan(any(), any(), any(), any());
verify(mWifiScanner, never()).stopPnoScan(any());
// starts a PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
ArgumentCaptor<ScanSettings> scanSettingsCaptor = ArgumentCaptor.forClass(
ScanSettings.class);
verify(mWifiScanner).startDisconnectedPnoScan(
scanSettingsCaptor.capture(), any(), any(), any());
// check that now the PNO scan uses the stationary interval, even though it was set before
// the PNO scan started
assertEquals(scanSettingsCaptor.getValue().periodInMs, STATIONARY_PNO_SCAN_INTERVAL_MILLIS);
}
/**
* Tests the metrics collection of PNO scans through changes to device mobility state and
* starting and stopping of PNO scans.
*/
@Test
public void deviceMobilityStateMetricsChangeStateAndStopStart() {
InOrder inOrder = inOrder(mWifiMetrics);
mWifiConnectivityManager = createConnectivityManager();
mWifiConnectivityManager.setWifiEnabled(true);
// change mobility state while no PNO scans running
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_LOW_MVMT);
inOrder.verify(mWifiMetrics).enterDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_LOW_MVMT);
// starts a PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
inOrder.verify(mWifiMetrics).logPnoScanStart();
// change to High Movement, which has the same scan interval as Low Movement
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
inOrder.verify(mWifiMetrics).logPnoScanStop();
inOrder.verify(mWifiMetrics).enterDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
inOrder.verify(mWifiMetrics).logPnoScanStart();
// change to Stationary, which has a different scan interval from High Movement
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_STATIONARY);
inOrder.verify(mWifiMetrics).logPnoScanStop();
inOrder.verify(mWifiMetrics).enterDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_STATIONARY);
inOrder.verify(mWifiMetrics).logPnoScanStart();
// stops PNO scan
mWifiConnectivityManager.setTrustedConnectionAllowed(false);
inOrder.verify(mWifiMetrics).logPnoScanStop();
// change mobility state while no PNO scans running
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
inOrder.verify(mWifiMetrics).enterDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
inOrder.verifyNoMoreInteractions();
}
/**
* Verify that WifiChannelUtilization is updated
*/
@Test
public void verifyWifiChannelUtilizationRefreshedAfterScanResults() {
WifiLinkLayerStats llstats = new WifiLinkLayerStats();
when(mClientModeImpl.getWifiLinkLayerStats()).thenReturn(llstats);
// Force a connectivity scan
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
verify(mWifiChannelUtilization).refreshChannelStatsAndChannelUtilization(
llstats, WifiChannelUtilization.UNKNOWN_FREQ);
}
/**
* Verify that WifiChannelUtilization is initialized properly
*/
@Test
public void verifyWifiChannelUtilizationInitAfterWifiToggle() {
verify(mWifiChannelUtilization, times(1)).init(null);
WifiLinkLayerStats llstats = new WifiLinkLayerStats();
when(mClientModeImpl.getWifiLinkLayerStats()).thenReturn(llstats);
mWifiConnectivityManager.setWifiEnabled(false);
mWifiConnectivityManager.setWifiEnabled(true);
verify(mWifiChannelUtilization, times(1)).init(llstats);
}
/**
* Verify that WifiChannelUtilization sets mobility state correctly
*/
@Test
public void verifyWifiChannelUtilizationSetMobilityState() {
WifiLinkLayerStats llstats = new WifiLinkLayerStats();
when(mClientModeImpl.getWifiLinkLayerStats()).thenReturn(llstats);
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
verify(mWifiChannelUtilization).setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT);
mWifiConnectivityManager.setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_STATIONARY);
verify(mWifiChannelUtilization).setDeviceMobilityState(
WifiManager.DEVICE_MOBILITY_STATE_STATIONARY);
}
/**
* Verify that WifiNetworkSelector sets bluetoothConnected correctly
*/
@Test
public void verifyWifiNetworkSelectorSetBluetoothConnected() {
mWifiConnectivityManager.setBluetoothConnected(true);
verify(mWifiNS).setBluetoothConnected(true);
mWifiConnectivityManager.setBluetoothConnected(false);
verify(mWifiNS).setBluetoothConnected(false);
}
/**
* Verify that WifiChannelUtilization is updated
*/
@Test
public void verifyForceConnectivityScan() {
// Auto-join enabled
mWifiConnectivityManager.setAutoJoinEnabledExternal(true);
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
verify(mWifiScanner).startScan(any(), any(), any(), any());
// Auto-join disabled
mWifiConnectivityManager.setAutoJoinEnabledExternal(false);
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
verify(mWifiScanner, times(2)).startScan(any(), any(), any(), any());
// Wifi disabled, no new scans
mWifiConnectivityManager.setWifiEnabled(false);
mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
verify(mWifiScanner, times(2)).startScan(any(), any(), any(), any());
}
/**
* Verify no network is network selection disabled, auto-join disabled using.
* {@link WifiConnectivityManager#retrievePnoNetworkList()}.
*/
@Test
public void testRetrievePnoList() {
// Create and add 3 networks.
WifiConfiguration network1 = WifiConfigurationTestUtil.createEapNetwork();
WifiConfiguration network2 = WifiConfigurationTestUtil.createPskNetwork();
WifiConfiguration network3 = WifiConfigurationTestUtil.createOpenHiddenNetwork();
List<WifiConfiguration> networkList = new ArrayList<>();
networkList.add(network1);
networkList.add(network2);
networkList.add(network3);
mLruConnectionTracker.addNetwork(network3);
mLruConnectionTracker.addNetwork(network2);
mLruConnectionTracker.addNetwork(network1);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(networkList);
// Retrieve the Pno network list & verify.
List<WifiScanner.PnoSettings.PnoNetwork> pnoNetworks =
mWifiConnectivityManager.retrievePnoNetworkList();
verify(mWifiNetworkSuggestionsManager).getAllScanOptimizationSuggestionNetworks();
assertEquals(3, pnoNetworks.size());
assertEquals(network1.SSID, pnoNetworks.get(0).ssid);
assertEquals(network2.SSID, pnoNetworks.get(1).ssid);
assertEquals(network3.SSID, pnoNetworks.get(2).ssid);
// Now permanently disable |network3|. This should remove network 3 from the list.
network3.getNetworkSelectionStatus().setNetworkSelectionStatus(
WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED);
// Retrieve the Pno network list & verify.
pnoNetworks = mWifiConnectivityManager.retrievePnoNetworkList();
assertEquals(2, pnoNetworks.size());
assertEquals(network1.SSID, pnoNetworks.get(0).ssid);
assertEquals(network2.SSID, pnoNetworks.get(1).ssid);
// Now set network1 autojoin disabled. This should remove network 1 from the list.
network1.allowAutojoin = false;
// Retrieve the Pno network list & verify.
pnoNetworks = mWifiConnectivityManager.retrievePnoNetworkList();
assertEquals(1, pnoNetworks.size());
assertEquals(network2.SSID, pnoNetworks.get(0).ssid);
}
/**
* Verifies frequencies are populated correctly for pno networks.
* {@link WifiConnectivityManager#retrievePnoNetworkList()}.
*/
@Test
public void testRetrievePnoListFrequencies() {
// Create 2 networks.
WifiConfiguration network1 = WifiConfigurationTestUtil.createEapNetwork();
WifiConfiguration network2 = WifiConfigurationTestUtil.createPskNetwork();
List<WifiConfiguration> networkList = new ArrayList<>();
networkList.add(network1);
networkList.add(network2);
mLruConnectionTracker.addNetwork(network2);
mLruConnectionTracker.addNetwork(network1);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(networkList);
// Retrieve the Pno network list and verify.
// Frequencies should be empty since no scan results have been received yet.
List<WifiScanner.PnoSettings.PnoNetwork> pnoNetworks =
mWifiConnectivityManager.retrievePnoNetworkList();
assertEquals(2, pnoNetworks.size());
assertEquals(network1.SSID, pnoNetworks.get(0).ssid);
assertEquals(network2.SSID, pnoNetworks.get(1).ssid);
assertEquals("frequencies should be empty", 0, pnoNetworks.get(0).frequencies.length);
assertEquals("frequencies should be empty", 0, pnoNetworks.get(1).frequencies.length);
//Set up wifiScoreCard to get frequency.
List<Integer> channelList = Arrays
.asList(TEST_FREQUENCY_1, TEST_FREQUENCY_2, TEST_FREQUENCY_3);
when(mWifiScoreCard.lookupNetwork(network1.SSID)).thenReturn(mPerNetwork);
when(mWifiScoreCard.lookupNetwork(network2.SSID)).thenReturn(mPerNetwork1);
when(mPerNetwork.getFrequencies(anyLong())).thenReturn(channelList);
when(mPerNetwork1.getFrequencies(anyLong())).thenReturn(new ArrayList<>());
//Set config_wifiPnoFrequencyCullingEnabled false, should ignore get frequency.
mResources.setBoolean(R.bool.config_wifiPnoFrequencyCullingEnabled, false);
pnoNetworks = mWifiConnectivityManager.retrievePnoNetworkList();
assertEquals(2, pnoNetworks.size());
assertEquals(network1.SSID, pnoNetworks.get(0).ssid);
assertEquals(network2.SSID, pnoNetworks.get(1).ssid);
assertEquals("frequencies should be empty", 0, pnoNetworks.get(0).frequencies.length);
assertEquals("frequencies should be empty", 0, pnoNetworks.get(1).frequencies.length);
// Set config_wifiPnoFrequencyCullingEnabled false, should get the right frequency.
mResources.setBoolean(R.bool.config_wifiPnoFrequencyCullingEnabled, true);
pnoNetworks = mWifiConnectivityManager.retrievePnoNetworkList();
assertEquals(2, pnoNetworks.size());
assertEquals(network1.SSID, pnoNetworks.get(0).ssid);
assertEquals(network2.SSID, pnoNetworks.get(1).ssid);
assertEquals(3, pnoNetworks.get(0).frequencies.length);
Arrays.sort(pnoNetworks.get(0).frequencies);
assertEquals(TEST_FREQUENCY_1, pnoNetworks.get(0).frequencies[0]);
assertEquals(TEST_FREQUENCY_2, pnoNetworks.get(0).frequencies[1]);
assertEquals(TEST_FREQUENCY_3, pnoNetworks.get(0).frequencies[2]);
assertEquals("frequencies should be empty", 0, pnoNetworks.get(1).frequencies.length);
}
/**
* Verifies the ordering of network list generated using
* {@link WifiConnectivityManager#retrievePnoNetworkList()}.
*/
@Test
public void testRetrievePnoListOrder() {
//Create 3 networks.
WifiConfiguration network1 = WifiConfigurationTestUtil.createEapNetwork();
WifiConfiguration network2 = WifiConfigurationTestUtil.createPskNetwork();
WifiConfiguration network3 = WifiConfigurationTestUtil.createOpenHiddenNetwork();
mLruConnectionTracker.addNetwork(network1);
mLruConnectionTracker.addNetwork(network2);
mLruConnectionTracker.addNetwork(network3);
List<WifiConfiguration> networkList = new ArrayList<>();
networkList.add(network1);
networkList.add(network2);
networkList.add(network3);
when(mWifiConfigManager.getSavedNetworks(anyInt())).thenReturn(networkList);
List<WifiScanner.PnoSettings.PnoNetwork> pnoNetworks =
mWifiConnectivityManager.retrievePnoNetworkList();
assertEquals(3, pnoNetworks.size());
assertEquals(network3.SSID, pnoNetworks.get(0).ssid);
assertEquals(network2.SSID, pnoNetworks.get(1).ssid);
assertEquals(network1.SSID, pnoNetworks.get(2).ssid);
}
private List<List<Integer>> linkScoreCardFreqsToNetwork(WifiConfiguration... configs) {
List<List<Integer>> results = new ArrayList<>();
int i = 0;
for (WifiConfiguration config : configs) {
List<Integer> channelList = Arrays.asList(TEST_FREQUENCY_1 + i, TEST_FREQUENCY_2 + i,
TEST_FREQUENCY_3 + i);
WifiScoreCard.PerNetwork perNetwork = mock(WifiScoreCard.PerNetwork.class);
when(mWifiScoreCard.lookupNetwork(config.SSID)).thenReturn(perNetwork);
when(perNetwork.getFrequencies(anyLong())).thenReturn(channelList);
results.add(channelList);
i++;
}
return results;
}
/**
* Verify that the length of frequency set will not exceed the provided max value
*/
@Test
public void testFetchChannelSetForPartialScanMaxCount() {
WifiConfiguration configuration1 = WifiConfigurationTestUtil.createOpenNetwork();
WifiConfiguration configuration2 = WifiConfigurationTestUtil.createOpenNetwork();
when(mWifiConfigManager.getSavedNetworks(anyInt()))
.thenReturn(Arrays.asList(configuration1, configuration2));
List<List<Integer>> freqs = linkScoreCardFreqsToNetwork(configuration1, configuration2);
mLruConnectionTracker.addNetwork(configuration2);
mLruConnectionTracker.addNetwork(configuration1);
assertEquals(new HashSet<>(freqs.get(0)), mWifiConnectivityManager
.fetchChannelSetForPartialScan(3, CHANNEL_CACHE_AGE_MINS));
}
/**
* Verifies the creation of channel list using
* {@link WifiConnectivityManager#fetchChannelSetForNetworkForPartialScan(int)}.
*/
@Test
public void testFetchChannelSetForNetwork() {
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
List<List<Integer>> freqs = linkScoreCardFreqsToNetwork(configuration);
assertEquals(new HashSet<>(freqs.get(0)), mWifiConnectivityManager
.fetchChannelSetForNetworkForPartialScan(configuration.networkId));
}
/**
* Verifies the creation of channel list using
* {@link WifiConnectivityManager#fetchChannelSetForNetworkForPartialScan(int)} and
* ensures that the frequenecy of the currently connected network is in the returned
* channel set.
*/
@Test
public void testFetchChannelSetForNetworkIncludeCurrentNetwork() {
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
linkScoreCardFreqsToNetwork(configuration);
mWifiInfo.setFrequency(TEST_CURRENT_CONNECTED_FREQUENCY);
// Currently connected network frequency 2427 is not in the TEST_FREQ_LIST
Set<Integer> freqs = mWifiConnectivityManager.fetchChannelSetForNetworkForPartialScan(
configuration.networkId);
assertTrue(freqs.contains(2427));
}
/**
* Verifies the creation of channel list using
* {@link WifiConnectivityManager#fetchChannelSetForNetworkForPartialScan(int)} and
* ensures that the list size does not exceed the max configured for the device.
*/
@Test
public void testFetchChannelSetForNetworkIsLimitedToConfiguredSize() {
// Need to recreate the WifiConfigManager instance for this test to modify the config
// value which is read only in the constructor.
int maxListSize = 2;
mResources.setInteger(
R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels,
maxListSize);
WifiConfiguration configuration = WifiConfigurationTestUtil.createOpenNetwork();
configuration.networkId = TEST_CONNECTED_NETWORK_ID;
when(mWifiConfigManager.getConfiguredNetwork(TEST_CONNECTED_NETWORK_ID))
.thenReturn(configuration);
List<List<Integer>> freqs = linkScoreCardFreqsToNetwork(configuration);
// Ensure that the fetched list size is limited.
Set<Integer> results = mWifiConnectivityManager.fetchChannelSetForNetworkForPartialScan(
configuration.networkId);
assertEquals(maxListSize, results.size());
assertFalse(results.contains(freqs.get(0).get(2)));
}
@Test
public void restartPnoScanForNetworkChanges() {
mWifiConnectivityManager.setWifiEnabled(true);
// starts a PNO scan
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
mWifiConnectivityManager.setTrustedConnectionAllowed(true);
InOrder inOrder = inOrder(mWifiScanner);
inOrder.verify(mWifiScanner).startDisconnectedPnoScan(any(), any(), any(), any());
// Add or update suggestions.
mSuggestionUpdateListenerCaptor.getValue().onSuggestionsAddedOrUpdated(
Arrays.asList(mWifiNetworkSuggestion));
// Ensure that we restarted PNO.
inOrder.verify(mWifiScanner).stopPnoScan(any());
inOrder.verify(mWifiScanner).startDisconnectedPnoScan(any(), any(), any(), any());
// Add saved network
mNetworkUpdateListenerCaptor.getValue().onNetworkAdded(new WifiConfiguration());
// Ensure that we restarted PNO.
inOrder.verify(mWifiScanner).stopPnoScan(any());
inOrder.verify(mWifiScanner).startDisconnectedPnoScan(any(), any(), any(), any());
}
}