WifiNetworkFactory: Trigger periodic scans
Trigger periodic scans to find networks matching the active network request.
This CL only adds the scan interval management. The actual processing of
the scan results to find the match will be added in a follow up CL.
Bug: 113878056
Test: Unit tests
Change-Id: I406fa2de5527064134ce7d41f6b48f28464c7261
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 2da06fd..4c40087 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.hardware.SystemSensorManager;
@@ -548,7 +549,8 @@
return new WifiNetworkFactory(
mWifiCoreHandlerThread.getLooper(), mContext, nc,
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE),
- wifiConnectivityManager);
+ (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE),
+ mClock, this, wifiConnectivityManager);
}
/**
diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java
index 936b85d..a75b80f 100644
--- a/service/java/com/android/server/wifi/WifiNetworkFactory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java
@@ -16,16 +16,27 @@
package com.android.server.wifi;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes;
+
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.content.Context;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiNetworkSpecifier;
+import android.net.wifi.WifiScanner;
+import android.os.Handler;
import android.os.Looper;
+import android.os.WorkSource;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -34,23 +45,107 @@
*/
public class WifiNetworkFactory extends NetworkFactory {
private static final String TAG = "WifiNetworkFactory";
+ @VisibleForTesting
private static final int SCORE_FILTER = 60;
- private final WifiConnectivityManager mWifiConnectivityManager;
+ @VisibleForTesting
+ public static final int PERIODIC_SCAN_INTERVAL_MS = 10 * 1000; // 10 seconds
+
private final Context mContext;
private final ActivityManager mActivityManager;
+ private final AlarmManager mAlarmManager;
+ private final Clock mClock;
+ private final Handler mHandler;
+ private final WifiInjector mWifiInjector;
+ private final WifiConnectivityManager mWifiConnectivityManager;
+ private final WifiScanner.ScanSettings mScanSettings;
+ private final NetworkFactoryScanListener mScanListener;
+ private final NetworkFactoryAlarmListener mPeriodicScanTimerListener;
private int mGenericConnectionReqCount = 0;
- NetworkRequest mActiveSpecificNetworkRequest;
+ private NetworkRequest mActiveSpecificNetworkRequest;
+ private WifiNetworkSpecifier mActiveSpecificNetworkRequestSpecifier;
+ private WifiScanner mWifiScanner;
// Verbose logging flag.
private boolean mVerboseLoggingEnabled = false;
+ private boolean mPeriodicScanTimerSet = false;
+
+ // Scan listener for scan requests.
+ private class NetworkFactoryScanListener implements WifiScanner.ScanListener {
+ @Override
+ public void onSuccess() {
+ // Scan request succeeded, wait for results to report to external clients.
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Scan request succeeded");
+ }
+ }
+
+ @Override
+ public void onFailure(int reason, String description) {
+ Log.e(TAG, "Scan failure received. reason: " + reason
+ + ", description: " + description);
+ // TODO(b/113878056): Retry scan to workaround any transient scan failures.
+ scheduleNextPeriodicScan();
+ }
+
+ @Override
+ public void onResults(WifiScanner.ScanData[] scanDatas) {
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Scan results received");
+ }
+ // For single scans, the array size should always be 1.
+ if (scanDatas.length != 1) {
+ Log.wtf(TAG, "Found more than 1 batch of scan results, Ignoring...");
+ return;
+ }
+ WifiScanner.ScanData scanData = scanDatas[0];
+ ScanResult[] scanResults = scanData.getResults();
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Received " + scanResults.length + " scan results");
+ }
+ // TODO(b/113878056): Find network match in scan results
+
+ // Didn't find a match, schedule the next scan.
+ scheduleNextPeriodicScan();
+ }
+
+ @Override
+ public void onFullResult(ScanResult fullScanResult) {
+ // Ignore for single scans.
+ }
+
+ @Override
+ public void onPeriodChanged(int periodInMs) {
+ // Ignore for single scans.
+ }
+ };
+
+ private class NetworkFactoryAlarmListener implements AlarmManager.OnAlarmListener {
+ @Override
+ public void onAlarm() {
+ // Trigger the next scan.
+ startScan();
+ }
+ }
public WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc,
- ActivityManager activityManager,
+ ActivityManager activityManager, AlarmManager alarmManager,
+ Clock clock, WifiInjector wifiInjector,
WifiConnectivityManager connectivityManager) {
super(looper, context, TAG, nc);
mContext = context;
mActivityManager = activityManager;
+ mAlarmManager = alarmManager;
+ mClock = clock;
+ mHandler = new Handler(looper);
+ mWifiInjector = wifiInjector;
mWifiConnectivityManager = connectivityManager;
+ // Create the scan settings.
+ mScanSettings = new WifiScanner.ScanSettings();
+ mScanSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
+ mScanSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
+ mScanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ mScanListener = new NetworkFactoryScanListener();
+ mPeriodicScanTimerListener = new NetworkFactoryAlarmListener();
setScoreFilter(SCORE_FILTER);
}
@@ -62,6 +157,11 @@
mVerboseLoggingEnabled = (verbose > 0);
}
+ /**
+ * Check whether to accept the new network connection request.
+ *
+ * All the validation of the incoming request is done in this method.
+ */
@Override
public boolean acceptRequest(NetworkRequest networkRequest, int score) {
NetworkSpecifier ns = networkRequest.networkCapabilities.getNetworkSpecifier();
@@ -112,6 +212,12 @@
return true;
}
+ /**
+ * Handle new network connection requests.
+ *
+ * The assumption here is that {@link #acceptRequest(NetworkRequest, int)} has already sanitized
+ * the incoming request.
+ */
@Override
protected void needNetworkFor(NetworkRequest networkRequest, int score) {
NetworkSpecifier ns = networkRequest.networkCapabilities.getNetworkSpecifier();
@@ -126,9 +232,20 @@
Log.e(TAG, "Invalid network specifier mentioned. Rejecting");
return;
}
+ retrieveWifiScanner();
+
// Store the active network request.
mActiveSpecificNetworkRequest = new NetworkRequest(networkRequest);
- // TODO (b/113878056): Complete handling.
+ WifiNetworkSpecifier wns = (WifiNetworkSpecifier) ns;
+ mActiveSpecificNetworkRequestSpecifier = new WifiNetworkSpecifier(
+ wns.ssidPatternMatcher, wns.bssidPatternMatcher, wns.wifiConfiguration,
+ wns.requestorUid);
+
+ // Trigger periodic scans for finding a network in the request.
+ startPeriodicScans();
+ // Disable Auto-join so that NetworkFactory can take control of the network selection.
+ // TODO(b/117979585): Defer turning off auto-join.
+ mWifiConnectivityManager.enable(false);
}
}
@@ -156,7 +273,13 @@
}
// Release the active network request.
mActiveSpecificNetworkRequest = null;
- // TODO (b/113878056): Complete handling.
+ mActiveSpecificNetworkRequestSpecifier = null;
+ // Cancel the periodic scans.
+ cancelPeriodicScans();
+ // Re-enable Auto-join (if there is a generic request pending).
+ if (mGenericConnectionReqCount > 0) {
+ mWifiConnectivityManager.enable(true);
+ }
}
}
@@ -201,5 +324,62 @@
return false;
}
}
+
+ /**
+ * Helper method to populate WifiScanner handle. This is done lazily because
+ * WifiScanningService is started after WifiService.
+ */
+ private void retrieveWifiScanner() {
+ if (mWifiScanner != null) return;
+ mWifiScanner = mWifiInjector.getWifiScanner();
+ checkNotNull(mWifiScanner);
+ }
+
+ private void startPeriodicScans() {
+ if (mActiveSpecificNetworkRequestSpecifier == null) {
+ Log.e(TAG, "Periodic scan triggered when there is no active network request. "
+ + "Ignoring...");
+ return;
+ }
+ WifiNetworkSpecifier wns = mActiveSpecificNetworkRequestSpecifier;
+ WifiConfiguration wifiConfiguration = wns.wifiConfiguration;
+ if (wifiConfiguration.hiddenSSID) {
+ mScanSettings.hiddenNetworks = new WifiScanner.ScanSettings.HiddenNetwork[1];
+ // Can't search for SSID pattern in hidden networks.
+ mScanSettings.hiddenNetworks[0] =
+ new WifiScanner.ScanSettings.HiddenNetwork(
+ addEnclosingQuotes(wns.ssidPatternMatcher.getPath()));
+ }
+ startScan();
+ }
+
+ private void cancelPeriodicScans() {
+ if (mPeriodicScanTimerSet) {
+ mAlarmManager.cancel(mPeriodicScanTimerListener);
+ mPeriodicScanTimerSet = false;
+ }
+ // Clear the hidden networks field after each request.
+ mScanSettings.hiddenNetworks = null;
+ }
+
+ private void scheduleNextPeriodicScan() {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mClock.getElapsedSinceBootMillis() + PERIODIC_SCAN_INTERVAL_MS,
+ TAG, mPeriodicScanTimerListener, mHandler);
+ mPeriodicScanTimerSet = true;
+ }
+
+ private void startScan() {
+ if (mActiveSpecificNetworkRequestSpecifier == null) {
+ Log.e(TAG, "Scan triggered when there is no active network request. Ignoring...");
+ return;
+ }
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Starting the next scan for " + mActiveSpecificNetworkRequestSpecifier);
+ }
+ // Create a worksource using the caller's UID.
+ WorkSource workSource = new WorkSource(mActiveSpecificNetworkRequestSpecifier.requestorUid);
+ mWifiScanner.startScan(mScanSettings, mScanListener, workSource);
+ }
}
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
index 1a7cce7..da4c329 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
@@ -19,10 +19,15 @@
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static com.android.server.wifi.WifiNetworkFactory.PERIODIC_SCAN_INTERVAL_MS;
+import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes;
+
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.MacAddress;
@@ -30,7 +35,11 @@
import android.net.NetworkRequest;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiNetworkSpecifier;
+import android.net.wifi.WifiScanner;
+import android.net.wifi.WifiScanner.ScanListener;
+import android.net.wifi.WifiScanner.ScanSettings;
import android.os.PatternMatcher;
+import android.os.WorkSource;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
@@ -38,6 +47,8 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -55,10 +66,19 @@
@Mock WifiConnectivityManager mWifiConnectivityManager;
@Mock Context mContext;
@Mock ActivityManager mActivityManager;
+ @Mock AlarmManager mAlarmManager;
+ @Mock Clock mClock;
+ @Mock WifiInjector mWifiInjector;
+ @Mock WifiScanner mWifiScanner;
@Mock PackageManager mPackageManager;
NetworkCapabilities mNetworkCapabilities;
TestLooper mLooper;
NetworkRequest mNetworkRequest;
+ WifiScanner.ScanData[] mTestScanDatas;
+ ArgumentCaptor<ScanSettings> mScanSettingsArgumentCaptor =
+ ArgumentCaptor.forClass(ScanSettings.class);
+ ArgumentCaptor<WorkSource> mWorkSourceArgumentCaptor =
+ ArgumentCaptor.forClass(WorkSource.class);
private WifiNetworkFactory mWifiNetworkFactory;
@@ -72,6 +92,7 @@
mLooper = new TestLooper();
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ mTestScanDatas = ScanTestUtil.createScanDatas(new int[][]{ { 2417, 2427, 5180, 5170 } });
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getNameForUid(TEST_UID_1)).thenReturn(TEST_PACKAGE_NAME_1);
@@ -80,9 +101,11 @@
.thenReturn(IMPORTANCE_FOREGROUND_SERVICE);
when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_2))
.thenReturn(IMPORTANCE_FOREGROUND_SERVICE);
+ when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
mWifiNetworkFactory = new WifiNetworkFactory(mLooper.getLooper(), mContext,
- mNetworkCapabilities, mActivityManager, mWifiConnectivityManager);
+ mNetworkCapabilities, mActivityManager, mAlarmManager, mClock, mWifiInjector,
+ mWifiConnectivityManager);
mNetworkRequest = new NetworkRequest.Builder()
.setCapabilities(mNetworkCapabilities)
@@ -149,7 +172,7 @@
when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1))
.thenReturn(IMPORTANCE_FOREGROUND_SERVICE + 1);
- WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1);
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0));
@@ -164,7 +187,7 @@
when(mActivityManager.getPackageImportance(TEST_PACKAGE_NAME_1))
.thenReturn(IMPORTANCE_FOREGROUND);
- WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1);
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0));
@@ -182,13 +205,13 @@
.thenReturn(IMPORTANCE_FOREGROUND);
// Handle request 1.
- WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1);
+ WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1);
mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
// Make request 2 which will be accepted because a fg app request can
// override a fg service request.
- WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2);
+ WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2);
assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0));
}
@@ -205,13 +228,13 @@
.thenReturn(IMPORTANCE_FOREGROUND_SERVICE);
// Handle request 1.
- WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1);
+ WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1);
mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
// Make request 2 which will be accepted because a fg service request can
// override an existing fg service request.
- WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2);
+ WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2);
assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0));
}
@@ -228,13 +251,13 @@
.thenReturn(IMPORTANCE_FOREGROUND);
// Handle request 1.
- WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1);
+ WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1);
mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
// Make request 2 which will be accepted because a fg app request can
// override an existing fg app request.
- WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2);
+ WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2);
assertTrue(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0));
}
@@ -251,23 +274,202 @@
.thenReturn(IMPORTANCE_FOREGROUND_SERVICE);
// Handle request 1.
- WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1);
+ WifiNetworkSpecifier specifier1 = createWifiNetworkSpecifier(TEST_UID_1, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier1);
mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
// Make request 2 which will be rejected because a fg service request cannot
// override a fg app request.
- WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2);
+ WifiNetworkSpecifier specifier2 = createWifiNetworkSpecifier(TEST_UID_2, false);
mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier2);
assertFalse(mWifiNetworkFactory.acceptRequest(mNetworkRequest, 0));
}
- private WifiNetworkSpecifier createWifiNetworkSpecifier(int uid) {
+ /**
+ * Verify handling of new network request with network specifier.
+ */
+ @Test
+ public void testHandleNetworkRequestWithSpecifier() {
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+
+ // Disable connectivity manager .
+ verify(mWifiConnectivityManager).enable(false);
+ verify(mWifiScanner).startScan(mScanSettingsArgumentCaptor.capture(), any(),
+ mWorkSourceArgumentCaptor.capture());
+
+ // Verify scan settings.
+ ScanSettings scanSettings = mScanSettingsArgumentCaptor.getValue();
+ assertNotNull(scanSettings);
+ assertEquals(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, scanSettings.band);
+ assertEquals(WifiScanner.TYPE_HIGH_ACCURACY, scanSettings.type);
+ assertEquals(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, scanSettings.reportEvents);
+ assertNull(scanSettings.hiddenNetworks);
+ WorkSource workSource = mWorkSourceArgumentCaptor.getValue();
+ assertNotNull(workSource);
+ assertEquals(TEST_UID_1, workSource.get(0));
+ }
+
+ /**
+ * Verify handling of new network request with network specifier for a hidden network.
+ */
+ @Test
+ public void testHandleNetworkRequestWithSpecifierForHiddenNetwork() {
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, true);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+
+ // Disable connectivity manager .
+ verify(mWifiConnectivityManager).enable(false);
+ verify(mWifiScanner).startScan(mScanSettingsArgumentCaptor.capture(), any(),
+ mWorkSourceArgumentCaptor.capture());
+
+ // Verify scan settings.
+ ScanSettings scanSettings = mScanSettingsArgumentCaptor.getValue();
+ assertNotNull(scanSettings);
+ assertEquals(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, scanSettings.band);
+ assertEquals(WifiScanner.TYPE_HIGH_ACCURACY, scanSettings.type);
+ assertEquals(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, scanSettings.reportEvents);
+ assertNotNull(scanSettings.hiddenNetworks);
+ assertNotNull(scanSettings.hiddenNetworks[0]);
+ assertEquals(scanSettings.hiddenNetworks[0].ssid,
+ addEnclosingQuotes(specifier.ssidPatternMatcher.getPath()));
+ WorkSource workSource = mWorkSourceArgumentCaptor.getValue();
+ assertNotNull(workSource);
+ assertEquals(TEST_UID_1, workSource.get(0));
+ }
+
+ /**
+ * Verify handling of new network request with network specifier for a non-hidden network
+ * after processing a previous hidden network requst.
+ * Validates that the scan settings was properly reset between the 2 request
+ * {@link ScanSettings#hiddenNetworks}
+ */
+ @Test
+ public void testHandleNetworkRequestWithSpecifierAfterPreviousHiddenNetworkRequest() {
+ testHandleNetworkRequestWithSpecifierForHiddenNetwork();
+ mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest);
+ reset(mWifiScanner, mWifiConnectivityManager);
+ testHandleNetworkRequestWithSpecifier();
+ }
+
+ /**
+ * Verify handling of release of the active network request with network specifier.
+ */
+ @Test
+ public void testHandleNetworkReleaseWithSpecifier() {
+ // Make a generic request first to ensure that we re-enable auto-join after release.
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+
+ // Make the network request with specifier.
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+ // Disable connectivity manager .
+ verify(mWifiConnectivityManager).enable(false);
+ verify(mWifiScanner).startScan(any(), any(), any());
+
+ // Release the network request.
+ mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest);
+ // Re-enable connectivity manager .
+ verify(mWifiConnectivityManager).enable(true);
+ }
+
+ /**
+ * Verify the periodic scan to find a network matching the network specifier.
+ * Simulates the case where the network is not found in any of the scan results.
+ */
+ @Test
+ public void testPeriodicScanNetworkRequestWithSpecifier() {
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+
+ verify(mWifiConnectivityManager).enable(false);
+ verifyPeriodicScans(0,
+ PERIODIC_SCAN_INTERVAL_MS, // 10s
+ PERIODIC_SCAN_INTERVAL_MS, // 10s
+ PERIODIC_SCAN_INTERVAL_MS, // 10s
+ PERIODIC_SCAN_INTERVAL_MS); // 10s
+ }
+
+ /**
+ * Verify the periodic scan back off to find a network matching the network specifier
+ * is cancelled when the active network request is released.
+ */
+ @Test
+ public void testPeriodicScanCancelOnReleaseNetworkRequestWithSpecifier() {
+ WifiNetworkSpecifier specifier = createWifiNetworkSpecifier(TEST_UID_1, false);
+ mNetworkRequest.networkCapabilities.setNetworkSpecifier(specifier);
+ mWifiNetworkFactory.needNetworkFor(mNetworkRequest, 0);
+
+ verify(mWifiConnectivityManager).enable(false);
+ verifyPeriodicScans(0,
+ PERIODIC_SCAN_INTERVAL_MS, // 10s
+ PERIODIC_SCAN_INTERVAL_MS); // 10s
+
+ mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest);
+ // Cancel the alarm set for the next scan.
+ verify(mAlarmManager).cancel(any(OnAlarmListener.class));
+ }
+
+ // Simulates the periodic scans performed to find a matching network.
+ // a) Start scan
+ // b) Scan results received.
+ // c) Set alarm for next scan at the expected interval.
+ // d) Alarm fires, go to step a) again and repeat.
+ private void verifyPeriodicScans(long...expectedIntervalsInSeconds) {
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
+
+ ArgumentCaptor<OnAlarmListener> alarmListenerArgumentCaptor =
+ ArgumentCaptor.forClass(OnAlarmListener.class);
+ OnAlarmListener alarmListener = null;
+ ArgumentCaptor<ScanListener> scanListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ScanListener.class);
+ ScanListener scanListener = null;
+
+ InOrder inOrder = inOrder(mWifiScanner, mAlarmManager);
+
+ for (int i = 0; i < expectedIntervalsInSeconds.length - 1; i++) {
+ long expectedCurrentIntervalInMs = expectedIntervalsInSeconds[i];
+ long expectedNextIntervalInMs = expectedIntervalsInSeconds[i + 1];
+
+ // First scan is immediately fired, so need for the alarm to fire.
+ if (expectedCurrentIntervalInMs != 0) {
+ // Fire the alarm and ensure that we started the next scan.
+ alarmListener.onAlarm();
+ }
+ inOrder.verify(mWifiScanner).startScan(
+ any(), scanListenerArgumentCaptor.capture(), any());
+ scanListener = scanListenerArgumentCaptor.getValue();
+ assertNotNull(scanListener);
+
+ // Now trigger the scan results callback and verify the alarm set for the next scan.
+ scanListener.onResults(mTestScanDatas);
+
+ inOrder.verify(mAlarmManager).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ eq(expectedNextIntervalInMs), any(),
+ alarmListenerArgumentCaptor.capture(), any());
+ alarmListener = alarmListenerArgumentCaptor.getValue();
+ assertNotNull(alarmListener);
+ }
+
+ verifyNoMoreInteractions(mWifiScanner, mAlarmManager);
+ }
+
+ private WifiNetworkSpecifier createWifiNetworkSpecifier(int uid, boolean isHidden) {
PatternMatcher ssidPatternMatch =
new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_LITERAL);
Pair<MacAddress, MacAddress> bssidPatternMatch =
Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
- WifiConfiguration wifiConfiguration = WifiConfigurationTestUtil.createPskNetwork();
+ WifiConfiguration wifiConfiguration;
+ if (isHidden) {
+ wifiConfiguration = WifiConfigurationTestUtil.createPskHiddenNetwork();
+ } else {
+ wifiConfiguration = WifiConfigurationTestUtil.createPskNetwork();
+ }
return new WifiNetworkSpecifier(
ssidPatternMatch, bssidPatternMatch, wifiConfiguration, uid);
}