summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java4
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkFactory.java190
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java228
3 files changed, 403 insertions, 19 deletions
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 2da06fd4b..4c4008718 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -18,6 +18,7 @@ package com.android.server.wifi;
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 @@ public class WifiInjector {
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 936b85dbb..a75b80f8c 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 @@ import java.io.PrintWriter;
*/
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 @@ public class WifiNetworkFactory extends NetworkFactory {
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 @@ public class WifiNetworkFactory extends NetworkFactory {
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 @@ public class WifiNetworkFactory extends NetworkFactory {
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 @@ public class WifiNetworkFactory extends NetworkFactory {
}
// 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 @@ public class WifiNetworkFactory extends NetworkFactory {
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/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
index 1a7cce780..da4c32994 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
@@ -19,10 +19,15 @@ package com.android.server.wifi;
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.NetworkCapabilities;
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 android.util.Pair;
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 @@ public class WifiNetworkFactoryTest {
@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 @@ public class WifiNetworkFactoryTest {
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 @@ public class WifiNetworkFactoryTest {
.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 @@ public class WifiNetworkFactoryTest {
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 @@ public class WifiNetworkFactoryTest {
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 @@ public class WifiNetworkFactoryTest {
.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 @@ public class WifiNetworkFactoryTest {
.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 @@ public class WifiNetworkFactoryTest {
.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 @@ public class WifiNetworkFactoryTest {
.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);
}