summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/HalWifiScannerImpl.java12
-rw-r--r--service/java/com/android/server/wifi/ScanDetail.java1
-rw-r--r--service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java12
-rw-r--r--service/java/com/android/server/wifi/WifiScanningScheduler.java16
-rw-r--r--service/java/com/android/server/wifi/WifiScanningServiceImpl.java566
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java69
-rw-r--r--tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java1
-rw-r--r--tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java12
-rw-r--r--tests/wifitests/src/com/android/server/wifi/MultiClientSchedulerTest.java43
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanResults.java27
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java36
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java11
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java460
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java62
14 files changed, 1100 insertions, 228 deletions
diff --git a/service/java/com/android/server/wifi/HalWifiScannerImpl.java b/service/java/com/android/server/wifi/HalWifiScannerImpl.java
index b86e4c6d8..246100b59 100644
--- a/service/java/com/android/server/wifi/HalWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/HalWifiScannerImpl.java
@@ -58,14 +58,10 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
mChannelHelper = new HalChannelHelper(wifiNative);
- // We can't enable these until WifiStateMachine switches to using WifiScanner because
- // WifiMonitor only supports sending results to one listener
- // TODO Enable these
- // Also need to fix tests again when this is enabled
- // WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- // WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
- // WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- // WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
+ WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
+ WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
+ WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
+ WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
}
@Override
diff --git a/service/java/com/android/server/wifi/ScanDetail.java b/service/java/com/android/server/wifi/ScanDetail.java
index 1f4024a2a..1dea556c1 100644
--- a/service/java/com/android/server/wifi/ScanDetail.java
+++ b/service/java/com/android/server/wifi/ScanDetail.java
@@ -80,6 +80,7 @@ public class ScanDetail {
mScanResult = scanResult;
mNetworkDetail = networkDetail;
mMatches = matches;
+ mSeen = mScanResult.seen;
}
/**
diff --git a/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java b/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java
index b51317157..c1043f065 100644
--- a/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java
@@ -108,14 +108,10 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
// TODO figure out how to get channel information from supplicant
mChannelHelper = new NoBandChannelHelper();
- // We can't enable these until WifiStateMachine switches to using WifiScanner because
- // WifiMonitor only supports sending results to one listener
- // TODO Enable these
- // Also need to fix tests again when this is enabled
- // WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- // WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
- // WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- // WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
+ WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
+ WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
+ WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
+ WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
}
@Override
diff --git a/service/java/com/android/server/wifi/WifiScanningScheduler.java b/service/java/com/android/server/wifi/WifiScanningScheduler.java
index 7b36b9918..744afd55c 100644
--- a/service/java/com/android/server/wifi/WifiScanningScheduler.java
+++ b/service/java/com/android/server/wifi/WifiScanningScheduler.java
@@ -28,17 +28,17 @@ import java.util.Collection;
*/
public abstract class WifiScanningScheduler {
- private static final int DEFAULT_MAX_BUCKETS = 8;
- private static final int DEFAULT_MAX_CHANNELS = 32;
+ static final int DEFAULT_MAX_BUCKETS = 8;
+ static final int DEFAULT_MAX_CHANNELS = 32;
// anecdotally, some chipsets will fail without explanation with a higher batch size, and
// there is apparently no way to retrieve the maximum batch size
- private static final int DEFAULT_MAX_SCANS_TO_BATCH = 10;
- private static final int DEFAULT_MAX_AP_PER_SCAN = 32;
+ static final int DEFAULT_MAX_SCANS_TO_BATCH = 10;
+ static final int DEFAULT_MAX_AP_PER_SCAN = 32;
- private static int mMaxBuckets = DEFAULT_MAX_BUCKETS;
- private static int mMaxChannels = DEFAULT_MAX_CHANNELS;
- private static int mMaxBatch = DEFAULT_MAX_SCANS_TO_BATCH;
- private static int mMaxApPerScan = DEFAULT_MAX_AP_PER_SCAN;
+ private int mMaxBuckets = DEFAULT_MAX_BUCKETS;
+ private int mMaxChannels = DEFAULT_MAX_CHANNELS;
+ private int mMaxBatch = DEFAULT_MAX_SCANS_TO_BATCH;
+ private int mMaxApPerScan = DEFAULT_MAX_AP_PER_SCAN;
int getMaxBuckets() {
return mMaxBuckets;
diff --git a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
index 6263a9af3..9c8895440 100644
--- a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
@@ -40,18 +40,23 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.WorkSource;
import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Log;
+import android.util.Pair;
+import android.util.SparseIntArray;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
import com.android.server.wifi.scanner.ChannelHelper;
+import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -175,7 +180,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
if (msg.what == WifiScanner.CMD_GET_SCAN_RESULTS) {
- mStateMachine.sendMessage(Message.obtain(msg));
+ mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
return;
}
ClientInfo ci = mClients.get(msg.replyTo);
@@ -195,13 +200,15 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE:
case WifiScanner.CMD_START_TRACKING_CHANGE:
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
+ mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
+ break;
case WifiScanner.CMD_START_SINGLE_SCAN:
case WifiScanner.CMD_STOP_SINGLE_SCAN:
- mStateMachine.sendMessage(Message.obtain(msg));
- return;
+ mSingleScanStateMachine.sendMessage(Message.obtain(msg));
+ break;
default:
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request");
- return;
+ break;
}
}
}
@@ -218,8 +225,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private static final int CMD_DRIVER_UNLOADED = BASE + 7;
private static final int CMD_SCAN_PAUSED = BASE + 8;
private static final int CMD_SCAN_RESTARTED = BASE + 9;
- private static final int CMD_STOP_SCAN_INTERNAL = BASE + 10;
- private static final int CMD_SCAN_FAILED = BASE + 11;
+ private static final int CMD_SCAN_FAILED = BASE + 10;
+ private static final int CMD_SCAN_TIMEOUT = BASE + 11;
private static final int CMD_PNO_NETWORK_FOUND = BASE + 12;
private final Context mContext;
@@ -231,9 +238,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private WifiScanningScheduler mScheduler;
private WifiNative.ScanSettings mPreviousSchedule;
- private WifiScanningStateMachine mStateMachine;
+ private WifiBackgroundScanStateMachine mBackgroundScanStateMachine;
+ private WifiSingleScanStateMachine mSingleScanStateMachine;
private ClientHandler mClientHandler;
private final IBatteryStats mBatteryStats;
+ private final AlarmManager mAlarmManager;
WifiScanningServiceImpl(Context context, Looper looper,
WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, IBatteryStats batteryStats) {
@@ -242,14 +251,16 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mScannerImplFactory = scannerImplFactory;
mBatteryStats = batteryStats;
mClients = new ArrayMap<>();
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mPreviousSchedule = null;
}
public void startService() {
mClientHandler = new ClientHandler(mLooper);
- mStateMachine = new WifiScanningStateMachine(mLooper);
+ mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper);
mWifiChangeStateMachine = new WifiChangeStateMachine(mLooper);
+ mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
mContext.registerReceiver(
new BroadcastReceiver() {
@@ -259,34 +270,392 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
if (DBG) localLog("SCAN_AVAILABLE : " + state);
if (state == WifiManager.WIFI_STATE_ENABLED) {
- mStateMachine.sendMessage(CMD_DRIVER_LOADED);
+ mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
+ mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
- mStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
+ mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
+ mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
}
}
}, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));
- mStateMachine.start();
+ mBackgroundScanStateMachine.start();
mWifiChangeStateMachine.start();
+ mSingleScanStateMachine.start();
}
- class WifiScanningStateMachine extends StateMachine implements WifiNative.ScanEventHandler,
- WifiNative.PnoEventHandler, WifiNative.HotlistEventHandler,
- WifiNative.SignificantWifiChangeEventHandler {
+ /**
+ * A map of objects of a WifiScanner client and handler id to an object of type T
+ */
+ private static class ClientHandlerMap<T> extends HashMap<Pair<ClientInfo, Integer>, T> {
+ public T put(ClientInfo ci, int handler, T value) {
+ return put(Pair.create(ci, handler), value);
+ }
+
+ public T get(ClientInfo ci, int handler) {
+ return get(Pair.create(ci, handler));
+ }
+
+ public T remove(ClientInfo ci, int handler) {
+ return remove(Pair.create(ci, handler));
+ }
+ }
+
+ /**
+ * State machine that holds the state of single scans. Scans should only be active in the
+ * ScanningState. The pending scans and active scans maps are swaped when entering
+ * ScanningState. Any requests queued while scanning will be placed in the pending queue and
+ * executed after transitioning back to IdleState.
+ */
+ class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler {
+ private final DefaultState mDefaultState = new DefaultState();
+ private final DriverStartedState mDriverStartedState = new DriverStartedState();
+ private final IdleState mIdleState = new IdleState();
+ private final ScanningState mScanningState = new ScanningState();
+
+ private ClientHandlerMap<ScanSettings> mActiveScans = new ClientHandlerMap<>();
+ private ClientHandlerMap<ScanSettings> mPendingScans = new ClientHandlerMap<>();
+
+ WifiSingleScanStateMachine(Looper looper) {
+ super("WifiSingleScanStateMachine", looper);
+
+ setLogRecSize(128);
+ setLogOnlyTransitions(false);
+
+ // CHECKSTYLE:OFF IndentationCheck
+ addState(mDefaultState);
+ addState(mDriverStartedState, mDefaultState);
+ addState(mIdleState, mDriverStartedState);
+ addState(mScanningState, mDriverStartedState);
+ // CHECKSTYLE:ON IndentationCheck
+
+ setInitialState(mDefaultState);
+ }
+
+ /**
+ * Called to indicate a change in state for the current scan.
+ * Will dispatch a coresponding event to the state machine
+ */
+ @Override
+ public void onScanStatus(int event) {
+ if (DBG) localLog("onScanStatus event received, event=" + event);
+ switch(event) {
+ case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE:
+ case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS:
+ case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT:
+ sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
+ break;
+ case WifiNative.WIFI_SCAN_FAILED:
+ sendMessage(CMD_SCAN_FAILED);
+ break;
+ default:
+ Log.e(TAG, "Unknown scan status event: " + event);
+ break;
+ }
+ }
+
+ /**
+ * Called for each full scan result if requested
+ */
+ @Override
+ public void onFullScanResult(ScanResult fullScanResult) {
+ if (DBG) localLog("onFullScanResult received");
+ sendMessage(CMD_FULL_SCAN_RESULTS, 0, 0, fullScanResult);
+ }
+
+ @Override
+ public void onScanPaused(ScanData[] scanData) {
+ // should not happen for single scan
+ Log.e(TAG, "Got scan paused for single scan");
+ }
+
+ @Override
+ public void onScanRestarted() {
+ // should not happen for single scan
+ Log.e(TAG, "Got scan restarted for single scan");
+ }
+
+ class DefaultState extends State {
+ @Override
+ public void enter() {
+ mActiveScans.clear();
+ mPendingScans.clear();
+ }
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_DRIVER_LOADED:
+ transitionTo(mIdleState);
+ return HANDLED;
+ case CMD_DRIVER_UNLOADED:
+ transitionTo(mDefaultState);
+ return HANDLED;
+ case WifiScanner.CMD_START_SINGLE_SCAN:
+ case WifiScanner.CMD_STOP_SINGLE_SCAN:
+ replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available");
+ return HANDLED;
+ case CMD_SCAN_RESULTS_AVAILABLE:
+ if (DBG) localLog("ignored scan results available event");
+ return HANDLED;
+ case CMD_FULL_SCAN_RESULTS:
+ if (DBG) localLog("ignored full scan result event");
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+
+ }
+ }
+
+ /**
+ * State representing when the driver is running. This state is not meant to be transitioned
+ * directly, but is instead indented as a parent state of ScanningState and IdleState
+ * to hold common functionality and handle cleaning up scans when the driver is shut down.
+ */
+ class DriverStartedState extends State {
+ @Override
+ public void exit() {
+ sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ ClientInfo ci = mClients.get(msg.replyTo);
+
+ switch (msg.what) {
+ case WifiScanner.CMD_START_SINGLE_SCAN:
+ if (validateAndAddToScanQueue(ci, msg.arg2, (ScanSettings) msg.obj)) {
+ replySucceeded(msg);
+ // If were not currently scanning then try to start a scan. Otherwise
+ // this scan will be scheduled when transitioning back to IdleState
+ // after finishing the current scan.
+ if (getCurrentState() != mScanningState) {
+ tryToStartNewScan();
+ }
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ }
+ return HANDLED;
+ case WifiScanner.CMD_STOP_SINGLE_SCAN:
+ removeSingleScanRequest(ci, msg.arg2);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class IdleState extends State {
+ @Override
+ public void enter() {
+ tryToStartNewScan();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ return NOT_HANDLED;
+ }
+ }
+
+ class ScanningState extends State {
+ /**
+ * Duration to wait before timing out a scan.
+ *
+ * The expected behavior is that the hardware will return a failed scan if it does not
+ * complete, but timeout just in case it does not.
+ * It is possible that there may already be a scan in progress when the scan is
+ * scheduled, so make sure that there is time for two scans to complete.
+ */
+ private static final long SINGLE_SCAN_TIMEOUT_MS = 20000;
+ private WakeupMessage mTimeoutMessage = new WakeupMessage(mContext, getHandler(),
+ "WifiScanner Single Scan Timeout", CMD_SCAN_TIMEOUT);
+
+ @Override
+ public void enter() {
+ mTimeoutMessage.schedule(
+ SystemClock.elapsedRealtime() + SINGLE_SCAN_TIMEOUT_MS);
+ }
+
+ @Override
+ public void exit() {
+ mTimeoutMessage.cancel();
+ // if any scans are still active (never got results available then indicate failure)
+ sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ }
+
+ // TODO(b/27247460) correctly handle battery blaming
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_SCAN_RESULTS_AVAILABLE:
+ reportScanResults(mScannerImpl.getLatestSingleScanResults());
+ mActiveScans.clear();
+ transitionTo(mIdleState);
+ return HANDLED;
+ case CMD_FULL_SCAN_RESULTS:
+ reportFullScanResult((ScanResult) msg.obj);
+ return HANDLED;
+ case CMD_SCAN_FAILED:
+ sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
+ "Scan failed");
+ transitionTo(mIdleState);
+ return HANDLED;
+ case CMD_SCAN_TIMEOUT:
+ sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
+ "Timed out waiting for a scan result");
+ loge("Timed out waiting for single scan result/failure");
+ transitionTo(mIdleState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ boolean validateAndAddToScanQueue(ClientInfo ci, int handler, ScanSettings settings) {
+ if (ci == null) {
+ Log.d(TAG, "Failing single scan request ClientInfo not found " + handler);
+ return false;
+ }
+ if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
+ if (settings.channels == null || settings.channels.length == 0) {
+ Log.d(TAG, "Failing single scan because channel list was empty");
+ return false;
+ }
+ }
+ logScanRequest("validateSingleScanAndAddToScanQueue", ci, handler, settings);
+ mPendingScans.put(ci, handler, settings);
+ return true;
+ }
+
+ void removeSingleScanRequest(ClientInfo ci, int handler) {
+ if (ci != null) {
+ logScanRequest("removeSingleScanRequest", ci, handler, null);
+ mPendingScans.remove(ci, handler);
+ mActiveScans.remove(ci, handler);
+ }
+ }
+
+ void tryToStartNewScan() {
+ if (mPendingScans.size() == 0) { // no pending requests
+ return;
+ }
+ mChannelHelper.updateChannels();
+ // TODO move merging logic to a scheduler
+ WifiNative.ScanSettings settings = new WifiNative.ScanSettings();
+ settings.num_buckets = 1;
+ WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
+ bucketSettings.bucket = 0;
+ bucketSettings.period_ms = 0;
+
+ ChannelCollection channels = mChannelHelper.createChannelCollection();
+ HashSet<Integer> hiddenNetworkIdSet = new HashSet<>();
+ for (WifiScanner.ScanSettings scanSettings : mPendingScans.values()) {
+ channels.addChannels(scanSettings);
+ if (scanSettings.hiddenNetworkIds != null) {
+ for (int i = 0; i < scanSettings.hiddenNetworkIds.length; i++) {
+ hiddenNetworkIdSet.add(scanSettings.hiddenNetworkIds[i]);
+ }
+ }
+ }
+ if (hiddenNetworkIdSet.size() > 0) {
+ settings.hiddenNetworkIds = new int[hiddenNetworkIdSet.size()];
+ int numHiddenNetworks = 0;
+ for (Integer hiddenNetworkId : hiddenNetworkIdSet) {
+ settings.hiddenNetworkIds[numHiddenNetworks++] = hiddenNetworkId;
+ }
+ }
+
+ channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
+ bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ for (ScanSettings pendingRequest : mPendingScans.values()) {
+ if ((pendingRequest.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)
+ != 0) {
+ bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
+ }
+ }
+
+ settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};
+ if (mScannerImpl.startSingleScan(settings, this)) {
+ // swap pending and active scan requests
+ ClientHandlerMap<ScanSettings> tmp = mActiveScans;
+ mActiveScans = mPendingScans;
+ mPendingScans = tmp;
+ // make sure that the pending list is clear
+ mPendingScans.clear();
+ transitionTo(mScanningState);
+ } else {
+ // notify and cancel failed scans
+ sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
+ "Failed to start single scan");
+ }
+ }
+
+ void sendOpFailedToAllAndClear(ClientHandlerMap<?> clientHandlers, int reason,
+ String description) {
+ for (Pair<ClientInfo, Integer> key : clientHandlers.keySet()) {
+ ClientInfo ci = key.first;
+ int handler = key.second;
+ ci.sendMessage(WifiScanner.CMD_OP_FAILED, 0, handler,
+ new WifiScanner.OperationResult(reason, description));
+ }
+ clientHandlers.clear();
+ }
+
+ // TODO fix shouldReport checks
+ // currently these checks work because the shouldReport methods don't yet rely on the
+ // internal state of the scheduler.
+ void reportFullScanResult(ScanResult result) {
+ for (Map.Entry<Pair<ClientInfo, Integer>, ScanSettings> entry
+ : mActiveScans.entrySet()) {
+ ClientInfo ci = entry.getKey().first;
+ int handler = entry.getKey().second;
+ ScanSettings settings = entry.getValue();
+ if (mScheduler.shouldReportFullScanResultForSettings(result, settings)) {
+ ci.sendMessage(WifiScanner.CMD_FULL_SCAN_RESULT, 0, handler, result);
+ }
+ }
+ }
+
+ void reportScanResults(ScanData results) {
+ for (Map.Entry<Pair<ClientInfo, Integer>, ScanSettings> entry
+ : mActiveScans.entrySet()) {
+ ClientInfo ci = entry.getKey().first;
+ int handler = entry.getKey().second;
+ ScanSettings settings = entry.getValue();
+ ScanData[] resultsArray = new ScanData[] {results};
+ ScanData[] resultsToDeliver =
+ mScheduler.filterResultsForSettings(resultsArray, settings);
+ WifiScanner.ParcelableScanData parcelableScanData =
+ new WifiScanner.ParcelableScanData(resultsToDeliver);
+ ci.sendMessage(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData);
+ // make sure the handler is removed
+ ci.sendMessage(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, handler);
+ }
+ }
+ }
+
+ class WifiBackgroundScanStateMachine extends StateMachine
+ implements WifiNative.ScanEventHandler, WifiNative.HotlistEventHandler,
+ WifiNative.PnoEventHandler, WifiNative.SignificantWifiChangeEventHandler {
private final DefaultState mDefaultState = new DefaultState();
private final StartedState mStartedState = new StartedState();
private final PausedState mPausedState = new PausedState();
- public WifiScanningStateMachine(Looper looper) {
+ WifiBackgroundScanStateMachine(Looper looper) {
super(TAG, looper);
setLogRecSize(512);
setLogOnlyTransitions(false);
+ // CHECKSTYLE:OFF IndentationCheck
addState(mDefaultState);
addState(mStartedState, mDefaultState);
addState(mPausedState, mDefaultState);
+ // CHECKSTYLE:ON IndentationCheck
setInitialState(mDefaultState);
}
@@ -360,6 +729,9 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_DRIVER_LOADED:
+ // TODO this should be moved to a common location since it is used outside
+ // of this state machine. It is ok right now becuase the driver loaded event
+ // is sent to this state machine first.
if (mScannerImpl == null) {
mScannerImpl = mScannerImplFactory.create(mContext, mLooper);
}
@@ -432,14 +804,14 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case CMD_DRIVER_UNLOADED:
return NOT_HANDLED;
case WifiScanner.CMD_START_BACKGROUND_SCAN:
- if (addScanRequest(ci, msg.arg2, (ScanSettings) msg.obj)) {
+ if (addBackgroundScanRequest(ci, msg.arg2, (ScanSettings) msg.obj)) {
replySucceeded(msg);
} else {
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
}
break;
case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
- removeScanRequest(ci, msg.arg2);
+ removeBackgroundScanRequest(ci, msg.arg2);
break;
case WifiScanner.CMD_START_PNO_SCAN:
Bundle pnoParams = (Bundle) msg.obj;
@@ -460,20 +832,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
reportScanResults(mScannerImpl.getLatestBatchedScanResults(true));
replySucceeded(msg);
break;
- case WifiScanner.CMD_START_SINGLE_SCAN:
- if (addSingleScanRequest(ci, msg.arg2, (ScanSettings) msg.obj)) {
- replySucceeded(msg);
- } else {
- replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
- }
- break;
- case WifiScanner.CMD_STOP_SINGLE_SCAN:
- removeScanRequest(ci, msg.arg2);
- break;
- case CMD_STOP_SCAN_INTERNAL:
- localLog("Removing single shot scan");
- removeScanRequest((ClientInfo) msg.obj, msg.arg2);
- break;
case WifiScanner.CMD_SET_HOTLIST:
setHotlist(ci, msg.arg2, (WifiScanner.HotlistSettings) msg.obj);
replySucceeded(msg);
@@ -533,7 +891,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case CMD_SCAN_FAILED:
// TODO handle this gracefully (currently no implementations are know to
// report this)
- Log.e(TAG, "WifiScanner background scan gave CMD_SCAN_TERMINATED");
+ Log.e(TAG, "WifiScanner background scan gave CMD_SCAN_FAILED");
break;
case CMD_PNO_NETWORK_FOUND: {
ScanResult[] results = (ScanResult[]) msg.obj;
@@ -572,8 +930,14 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private class ClientInfo {
private final AsyncChannel mChannel;
+ /**
+ * Indicates if the client is still connected
+ * If the client is no longer connected then messages to it will be signlently dropped
+ */
+ private boolean mDisconnected = false;
private final int mUid;
private final WorkSource mWorkSource;
+
private boolean mScanWorkReported = false;
ClientInfo(int uid, AsyncChannel c) {
@@ -583,6 +947,18 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
if (DBG) localLog("New client, channel: " + c);
}
+ void sendMessage(int what, int arg1, int arg2) {
+ if (!mDisconnected) {
+ mChannel.sendMessage(what, arg1, arg2);
+ }
+ }
+
+ void sendMessage(int what, int arg1, int arg2, Object obj) {
+ if (!mDisconnected) {
+ mChannel.sendMessage(what, arg1, arg2, obj);
+ }
+ }
+
void reportBatchedScanStart() {
if (mUid == 0)
return;
@@ -610,7 +986,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
// TODO migrate batterystats to accept scan duration per hour instead of csph
int getCsph() {
int totalScanDurationPerHour = 0;
- for (ScanSettings settings : getScanSettings()) {
+ for (ScanSettings settings : getBackgroundScanSettings()) {
int scanDurationMs = mChannelHelper.estimateScanDuration(settings);
int scans_per_Hour = settings.periodInMs == 0 ? 1 : (3600 * 1000) /
settings.periodInMs;
@@ -625,7 +1001,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
reportBatchedScanStop();
mScanWorkReported = false;
}
- if (mScanSettings.isEmpty() == false) {
+ if (mBackgroundScanSettings.isEmpty()) {
reportBatchedScanStart();
mScanWorkReported = true;
}
@@ -633,14 +1009,15 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
@Override
public String toString() {
- return "ClientInfo[uid=" + mUid + ", channel=" + mChannel + "]";
+ return "ClientInfo[uid=" + mUid + "]";
}
void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder sb = new StringBuilder();
sb.append(toString());
- Iterator<Map.Entry<Integer, ScanSettings>> it = mScanSettings.entrySet().iterator();
+ Iterator<Map.Entry<Integer, ScanSettings>> it =
+ mBackgroundScanSettings.entrySet().iterator();
for (; it.hasNext(); ) {
Map.Entry<Integer, ScanSettings> entry = it.next();
sb.append("ScanId ").append(entry.getKey()).append("\n");
@@ -653,33 +1030,26 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
pw.println(sb.toString());
}
- HashMap<Integer, ScanSettings> mScanSettings = new HashMap<Integer, ScanSettings>(4);
- HashMap<Integer, Integer> mScanPeriods = new HashMap<Integer, Integer>(4);
+ private final Map<Integer, ScanSettings> mBackgroundScanSettings =
+ new HashMap<Integer, ScanSettings>(4);
+ private final SparseIntArray mBackgroundScanPeriods = new SparseIntArray(4);
- void addScanRequest(ScanSettings settings, int id) {
- mScanSettings.put(id, settings);
+ void addBackgroundScanRequest(ScanSettings settings, int id) {
+ mBackgroundScanSettings.put(id, settings);
reportScanWorkUpdate();
}
- void removeScanRequest(int id) {
- ScanSettings settings = mScanSettings.remove(id);
- if (settings != null && settings.periodInMs == 0) {
- /* this was a single shot scan */
- mChannel.sendMessage(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, id);
- }
+ void removeBackgroundScanRequest(int id) {
+ mBackgroundScanSettings.remove(id);
reportScanWorkUpdate();
}
- Iterator<Map.Entry<Integer, ScanSettings>> getScans() {
- return mScanSettings.entrySet().iterator();
- }
-
- Collection<ScanSettings> getScanSettings() {
- return mScanSettings.values();
+ Collection<ScanSettings> getBackgroundScanSettings() {
+ return mBackgroundScanSettings.values();
}
void reportScanResults(ScanData[] results) {
- Iterator<Integer> it = mScanSettings.keySet().iterator();
+ Iterator<Integer> it = mBackgroundScanSettings.keySet().iterator();
while (it.hasNext()) {
int handler = it.next();
reportScanResults(results, handler);
@@ -687,7 +1057,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
void reportScanResults(ScanData[] results, int handler) {
- ScanSettings settings = mScanSettings.get(handler);
+ ScanSettings settings = mBackgroundScanSettings.get(handler);
ScanData[] resultsToDeliver = mScheduler.filterResultsForSettings(results, settings);
@@ -696,11 +1066,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
deliverScanResults(handler, resultsToDeliver);
}
-
- if (settings.periodInMs == 0) {
- /* this is a single shot scan; stop the scan now */
- mStateMachine.sendMessage(CMD_STOP_SCAN_INTERNAL, 0, handler, this);
- }
}
void deliverScanResults(int handler, ScanData results[]) {
@@ -710,10 +1075,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
void reportFullScanResult(ScanResult result) {
- Iterator<Integer> it = mScanSettings.keySet().iterator();
+ Iterator<Integer> it = mBackgroundScanSettings.keySet().iterator();
while (it.hasNext()) {
int handler = it.next();
- ScanSettings settings = mScanSettings.get(handler);
+ ScanSettings settings = mBackgroundScanSettings.get(handler);
if (mScheduler.shouldReportFullScanResultForSettings(result, settings)) {
ScanResult newResult = new ScanResult(result);
if (result.informationElements != null) {
@@ -728,18 +1093,18 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
void reportPeriodChanged(int handler, ScanSettings settings, int newPeriodInMs) {
- Integer prevPeriodObject = mScanPeriods.get(handler);
- int prevPeriodInMs = settings.periodInMs;
- if (prevPeriodObject != null) {
- prevPeriodInMs = prevPeriodObject;
+ int prevPeriodInMs = mBackgroundScanPeriods.get(handler, 0);
+ if (prevPeriodInMs == 0) {
+ prevPeriodInMs = settings.periodInMs;
}
if (prevPeriodInMs != newPeriodInMs) {
+ mBackgroundScanPeriods.put(handler, newPeriodInMs);
mChannel.sendMessage(WifiScanner.CMD_PERIOD_CHANGED, newPeriodInMs, handler);
}
}
- private final HashMap<Integer, WifiScanner.HotlistSettings> mHotlistSettings =
+ private final Map<Integer, WifiScanner.HotlistSettings> mHotlistSettings =
new HashMap<Integer, WifiScanner.HotlistSettings>();
void addHostlistSettings(WifiScanner.HotlistSettings settings, int handler) {
@@ -841,7 +1206,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
void cleanup() {
- mScanSettings.clear();
+ mDisconnected = true;
+ mBackgroundScanSettings.clear();
updateSchedule();
mHotlistSettings.clear();
@@ -891,7 +1257,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mChannelHelper.updateChannels();
ArrayList<ScanSettings> settings = new ArrayList<>();
for (ClientInfo client : mClients.values()) {
- settings.addAll(client.getScanSettings());
+ settings.addAll(client.getBackgroundScanSettings());
}
mScheduler.updateSchedule(settings);
@@ -920,7 +1286,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
+ ChannelHelper.toString(bucket));
}
- if (mScannerImpl.startBatchedScan(schedule, mStateMachine)) {
+ if (mScannerImpl.startBatchedScan(schedule, mBackgroundScanStateMachine)) {
if (DBG) Log.d(TAG, "scan restarted with " + schedule.num_buckets
+ " bucket(s) and base period: " + schedule.base_period_ms);
return true;
@@ -957,7 +1323,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
localLog(sb.toString());
}
- boolean addScanRequest(ClientInfo ci, int handler, ScanSettings settings) {
+ boolean addBackgroundScanRequest(ClientInfo ci, int handler, ScanSettings settings) {
// sanity check the input
if (ci == null) {
Log.d(TAG, "Failing scan request ClientInfo not found " + handler);
@@ -1006,13 +1372,13 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
}
- logScanRequest("addScanRequest", ci, handler, settings);
- ci.addScanRequest(settings, handler);
+ logScanRequest("addBackgroundScanRequest", ci, handler, settings);
+ ci.addBackgroundScanRequest(settings, handler);
if (updateSchedule()) {
return true;
} else {
- ci.removeScanRequest(handler);
+ ci.removeBackgroundScanRequest(handler);
localLog("Failing scan request because failed to reset scan");
return false;
}
@@ -1042,13 +1408,14 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
boolean addScanRequestForPno(ClientInfo ci, int handler, ScanSettings settings,
PnoSettings pnoSettings) {
- if (!mScannerImpl.setPnoList(convertPnoSettingsToNative(pnoSettings), mStateMachine)) {
+ if (!mScannerImpl.setPnoList(convertPnoSettingsToNative(pnoSettings),
+ mBackgroundScanStateMachine)) {
return false;
}
if (!mScannerImpl.shouldScheduleBackgroundScanForPno()) {
return true;
}
- return addScanRequest(ci, handler, settings);
+ return addBackgroundScanRequest(ci, handler, settings);
}
void removeScanRequestForPno(ClientInfo ci, int handler, PnoSettings pnoSettings) {
@@ -1056,39 +1423,13 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
if (!mScannerImpl.shouldScheduleBackgroundScanForPno()) {
return;
}
- removeScanRequest(ci, handler);
+ removeBackgroundScanRequest(ci, handler);
}
- boolean addSingleScanRequest(ClientInfo ci, int handler, ScanSettings settings) {
- if (ci == null) {
- Log.d(TAG, "Failing single scan request ClientInfo not found " + handler);
- return false;
- }
- if (settings.reportEvents == 0) {
- settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
- }
- if (settings.periodInMs == 0) {
- settings.periodInMs = 10000; // 10s - although second scan should never happen
- }
-
- logScanRequest("addSingleScanRequest", ci, handler, settings);
- ci.addScanRequest(settings, handler);
-
- if (updateSchedule()) {
- /* reset periodInMs to 0 to indicate single shot scan */
- settings.periodInMs = 0;
- return true;
- } else {
- ci.removeScanRequest(handler);
- localLog("Failing scan request because failed to reset scan");
- return false;
- }
- }
-
- void removeScanRequest(ClientInfo ci, int handler) {
+ void removeBackgroundScanRequest(ClientInfo ci, int handler) {
if (ci != null) {
- logScanRequest("removeScanRequest", ci, handler, null);
- ci.removeScanRequest(handler);
+ logScanRequest("removeBackgroundScanRequest", ci, handler, null);
+ ci.removeBackgroundScanRequest(handler);
updateSchedule();
}
}
@@ -1144,7 +1485,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
WifiScanner.HotlistSettings settings = new WifiScanner.HotlistSettings();
settings.bssidInfos = bssidInfos;
settings.apLostThreshold = apLostThreshold;
- mScannerImpl.setHotlist(settings, mStateMachine);
+ mScannerImpl.setHotlist(settings, mBackgroundScanStateMachine);
}
}
@@ -1229,7 +1570,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private static final String ACTION_TIMEOUT =
"com.android.server.WifiScanningServiceImpl.action.TIMEOUT";
- AlarmManager mAlarmManager;
PendingIntent mTimeoutIntent;
ScanResult mCurrentBssids[];
@@ -1238,18 +1578,16 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mClients.put(null, mClientInfo);
+ // CHECKSTYLE:OFF IndentationCheck
addState(mDefaultState);
- addState(mStationaryState, mDefaultState);
- addState(mMovingState, mDefaultState);
+ addState(mStationaryState, mDefaultState);
+ addState(mMovingState, mDefaultState);
+ // CHECKSTYLE:ON IndentationCheck
setInitialState(mDefaultState);
}
public void enable() {
- if (mAlarmManager == null) {
- mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- }
-
if (mTimeoutIntent == null) {
Intent intent = new Intent(ACTION_TIMEOUT, null);
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
@@ -1640,7 +1978,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
pw.println("listeners:");
for (ClientInfo client : mClients.values()) {
- for (ScanSettings settings : client.getScanSettings()) {
+ for (ScanSettings settings : client.getBackgroundScanSettings()) {
pw.println(" " + toString(client.mUid, settings));
}
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 9519d80ca..bbca61123 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -111,6 +111,7 @@ import com.android.server.wifi.hotspot2.IconEvent;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.Utils;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
+import com.android.server.wifi.util.ScanDetailUtil;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -2072,17 +2073,52 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
}
+ // TODO this is a temporary measure to bridge between WifiScanner and WifiStateMachine until
+ // scan functionality is refactored out of WifiStateMachine.
/**
* return true iff scan request is accepted
*/
- private boolean startScanNative(Set<Integer> freqs, Set<Integer> hiddenNetworkIds) {
- if (mWifiNative.scan(freqs, hiddenNetworkIds)) {
- mIsScanOngoing = true;
- mIsFullScanOngoing = (freqs == null);
- lastScanFreqs = freqs;
- return true;
+ private boolean startScanNative(final Set<Integer> freqs, Set<Integer> hiddenNetworkIds) {
+ WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
+ if (freqs == null) {
+ settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
+ } else {
+ settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
+ int index = 0;
+ settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
+ for (Integer freq : freqs) {
+ settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
+ }
}
- return false;
+ settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
+ | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
+ if (hiddenNetworkIds != null && hiddenNetworkIds.size() > 0) {
+ int i = 0;
+ settings.hiddenNetworkIds = new int[hiddenNetworkIds.size()];
+ for (Integer netId : hiddenNetworkIds) {
+ settings.hiddenNetworkIds[i++] = netId;
+ }
+ }
+ WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
+ // ignore all events since WifiStateMachine is registered for the supplicant events
+ public void onSuccess() {
+ }
+ public void onFailure(int reason, String description) {
+ mIsScanOngoing = false;
+ mIsFullScanOngoing = false;
+ }
+ public void onResults(WifiScanner.ScanData[] results) {
+ }
+ public void onFullResult(ScanResult fullScanResult) {
+ }
+ public void onPeriodChanged(int periodInMs) {
+ }
+ };
+ mWifiScanner.startScan(settings, nativeScanListener);
+ mIsScanOngoing = true;
+ mIsFullScanOngoing = (freqs == null);
+ lastScanFreqs = freqs;
+ return true;
}
/**
@@ -4494,12 +4530,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
}
- void connectScanningService() {
- if (mWifiScanner == null) {
- mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
- }
- }
-
private void handleIPv4Success(DhcpResults dhcpResults) {
if (DBG) {
logd("handleIPv4Success <" + dhcpResults.toString() + ">");
@@ -5564,11 +5594,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
class DriverStartedState extends State {
@Override
public void enter() {
-
if (DBG) {
logd("DriverStartedState enter");
}
+ // We can't do this in the constructor because WifiStateMachine is created before the
+ // wifi scanning service is initialized
+ if (mWifiScanner == null) {
+ mWifiScanner =
+ (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
+ }
+
mWifiLogger.startLogging(DBG);
mIsRunning = true;
updateBatteryWorkSource(null);
@@ -6194,11 +6230,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
class ConnectModeState extends State {
@Override
- public void enter() {
- connectScanningService();
- }
-
- @Override
public boolean processMessage(Message message) {
WifiConfiguration config;
int netId;
diff --git a/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java b/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java
index baf317280..6d4edb40d 100644
--- a/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java
@@ -199,7 +199,6 @@ public abstract class BaseWifiScannerImplTest {
WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
- Set<Integer> expectedScan = createFreqSet(2400, 2450);
InOrder order = inOrder(eventHandler, mWifiNative);
diff --git a/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java b/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java
index 3ef073ce6..11acea80d 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java
@@ -18,13 +18,10 @@ package com.android.server.wifi;
import static com.android.server.wifi.ScanTestUtil.setupMockChannels;
-import android.os.Handler;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Before;
-import java.lang.reflect.Field;
-
/**
* Unit tests for {@link com.android.server.wifi.HalWifiScannerImpl}.
*/
@@ -38,14 +35,5 @@ public class HalWifiScannerTest extends BaseWifiScannerImplTest {
new int[]{5150, 5175},
new int[]{5600, 5650});
mScanner = new HalWifiScannerImpl(mWifiNative, mLooper.getLooper());
-
- // TODO remove this once HalWifiScannerImpl wifi monitor registration is enabled
- Field eventHandlerField = HalWifiScannerImpl.class.getDeclaredField("mEventHandler");
- eventHandlerField.setAccessible(true);
- Handler eventHandler = (Handler) eventHandlerField.get(mScanner);
- WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- WifiMonitor.SCAN_FAILED_EVENT, eventHandler);
- WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- WifiMonitor.SCAN_RESULTS_EVENT, eventHandler);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/MultiClientSchedulerTest.java b/tests/wifitests/src/com/android/server/wifi/MultiClientSchedulerTest.java
index f0e8e95b8..86db34cb6 100644
--- a/tests/wifitests/src/com/android/server/wifi/MultiClientSchedulerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/MultiClientSchedulerTest.java
@@ -16,6 +16,8 @@
package com.android.server.wifi;
+import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
+import static com.android.server.wifi.ScanTestUtil.assertNativeScanSettingsEquals;
import static com.android.server.wifi.ScanTestUtil.channelsToSpec;
import static com.android.server.wifi.ScanTestUtil.createRequest;
@@ -465,36 +467,23 @@ public class MultiClientSchedulerTest {
mScheduler.updateSchedule(requests);
WifiNative.ScanSettings schedule = mScheduler.getSchedule();
- assertEquals("base_period_ms", computeExpectedPeriod(settings.periodInMs),
- schedule.base_period_ms);
- assertBuckets(schedule, 1);
+ int expectedPeriod = computeExpectedPeriod(settings.periodInMs);
+ NativeScanSettingsBuilder expectedBuilder = new NativeScanSettingsBuilder()
+ .withBasePeriod(expectedPeriod)
+ .withMaxApPerScan(settings.numBssidsPerScan == 0
+ ? DEFAULT_MAX_AP_PER_SCAN
+ : settings.numBssidsPerScan)
+ .withMaxScansToCache(settings.maxScansToCache == 0
+ ? DEFAULT_MAX_BATCH
+ : settings.maxScansToCache);
- if (settings.numBssidsPerScan == 0) {
- assertEquals("bssids per scan", DEFAULT_MAX_AP_PER_SCAN, schedule.max_ap_per_scan);
- } else {
- assertEquals("bssids per scan", settings.numBssidsPerScan, schedule.max_ap_per_scan);
- }
- if (settings.maxScansToCache == 0) {
- assertEquals("scans to cache", DEFAULT_MAX_BATCH,
- schedule.report_threshold_num_scans);
- } else {
- assertEquals("scans to cache", settings.maxScansToCache,
- schedule.report_threshold_num_scans);
- }
- assertEquals("reportEvents", settings.reportEvents, schedule.buckets[0].report_events);
- assertEquals("period", computeExpectedPeriod(settings.periodInMs),
- schedule.buckets[0].period_ms);
if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
- assertEquals("band", settings.band, schedule.buckets[0].band);
- assertEquals("channels", getAllChannels(settings),
- getAllChannels(schedule.buckets[0]));
- }
- else {
- assertEquals("band", settings.band, schedule.buckets[0].band);
- assertEquals("num_channels", 0, schedule.buckets[0].num_channels);
- assertTrue("channels", schedule.buckets[0].channels == null
- || schedule.buckets[0].channels.length == 0);
+ expectedBuilder.addBucketWithChannels(expectedPeriod, settings.reportEvents,
+ settings.channels);
+ } else {
+ expectedBuilder.addBucketWithBand(expectedPeriod, settings.reportEvents, settings.band);
}
+ assertNativeScanSettingsEquals(expectedBuilder.build(), schedule);
}
private void assertBuckets(WifiNative.ScanSettings schedule, int numBuckets) {
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanResults.java b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
index f628cac93..9c452fb21 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanResults.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
@@ -26,6 +26,7 @@ import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
@@ -38,6 +39,32 @@ public class ScanResults {
private final ScanData mScanData;
private final ScanResult[] mScanResults;
+ private ScanResults(ArrayList<ScanDetail> scanDetails, ScanData scanData,
+ ScanResult[] scanResults) {
+ mScanDetails.addAll(scanDetails);
+ mScanData = scanData;
+ mScanResults = scanResults;
+ }
+
+ /**
+ * Merge the results contained in a number of ScanResults into a single ScanResults
+ */
+ public static ScanResults merge(ScanResults... others) {
+ ArrayList<ScanDetail> scanDetails = new ArrayList<>();
+ ArrayList<ScanResult> scanDataResults = new ArrayList<>();
+ ArrayList<ScanResult> rawScanResults = new ArrayList<>();
+ for (ScanResults other : others) {
+ scanDetails.addAll(other.getScanDetailArrayList());
+ scanDataResults.addAll(Arrays.asList(other.getScanData().getResults()));
+ rawScanResults.addAll(Arrays.asList(other.getRawScanResults()));
+ }
+ Collections.sort(scanDataResults, SCAN_RESULT_RSSI_COMPARATOR);
+ int id = others[0].getScanData().getId();
+ return new ScanResults(scanDetails, new ScanData(id, 0, scanDataResults
+ .toArray(new ScanResult[scanDataResults.size()])),
+ rawScanResults.toArray(new ScanResult[rawScanResults.size()]));
+ }
+
private static String generateBssid(Random r) {
return String.format("%02X:%02X:%02X:%02X:%02X:%02X",
r.nextInt(256), r.nextInt(256), r.nextInt(256),
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
index de46dff42..34793cd8f 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
@@ -171,6 +171,42 @@ public class ScanTestUtil {
}
}
+ /**
+ * Compute the expected native scan settings that are expected for the given
+ * WifiScanner.ScanSettings.
+ */
+ public static WifiNative.ScanSettings computeSingleScanNativeSettings(
+ WifiScanner.ScanSettings requestSettings) {
+ int reportEvents = requestSettings.reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ NativeScanSettingsBuilder builder = new NativeScanSettingsBuilder()
+ .withBasePeriod(0)
+ .withMaxApPerScan(0)
+ .withMaxPercentToCache(0)
+ .withMaxScansToCache(0);
+ if (requestSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
+ builder.addBucketWithChannels(0, reportEvents, requestSettings.channels);
+ } else {
+ builder.addBucketWithBand(0, reportEvents, requestSettings.band);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Compute the expected native scan settings that are expected for the given channels.
+ */
+ public static WifiNative.ScanSettings createSingleScanNativeSettingsForChannels(
+ int reportEvents, WifiScanner.ChannelSpec... channels) {
+ int actualReportEvents = reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ return new NativeScanSettingsBuilder()
+ .withBasePeriod(0)
+ .withMaxApPerScan(0)
+ .withMaxPercentToCache(0)
+ .withMaxScansToCache(0)
+ .addBucketWithChannels(0, actualReportEvents, channels)
+ .build();
+ }
+
public static Set<Integer> createFreqSet(int... elements) {
Set<Integer> set = new HashSet<>();
for (int e : elements) {
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java
index 72e9da5ec..f3adb119e 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java
@@ -31,14 +31,12 @@ import static org.mockito.Mockito.when;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
-import android.os.Handler;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -53,15 +51,6 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
public void setup() throws Exception {
mScanner = new SupplicantWifiScannerImpl(mContext, mWifiNative,
mLooper.getLooper());
-
- // TODO remove this once SupplicantWifiScannerImpl wifi monitor registration is enabled
- Field eventHandlerField = SupplicantWifiScannerImpl.class.getDeclaredField("mEventHandler");
- eventHandlerField.setAccessible(true);
- Handler eventHandler = (Handler) eventHandlerField.get(mScanner);
- WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- WifiMonitor.SCAN_FAILED_EVENT, eventHandler);
- WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
- WifiMonitor.SCAN_RESULTS_EVENT, eventHandler);
}
@Test
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
index 853c895bd..3d4055a52 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
@@ -16,13 +16,19 @@
package com.android.server.wifi;
+import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
import static com.android.server.wifi.ScanTestUtil.assertNativeScanSettingsEquals;
import static com.android.server.wifi.ScanTestUtil.assertScanDatasEquals;
+import static com.android.server.wifi.ScanTestUtil.channelsToSpec;
+import static com.android.server.wifi.ScanTestUtil.computeSingleScanNativeSettings;
import static com.android.server.wifi.ScanTestUtil.createRequest;
+import static com.android.server.wifi.ScanTestUtil.createSingleScanNativeSettingsForChannels;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -54,6 +60,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.matchers.CapturingMatcher;
/**
* Unit tests for {@link com.android.server.wifi.WifiScanningServiceImpl}.
@@ -63,6 +70,7 @@ public class WifiScanningServiceTest {
public static final String TAG = "WifiScanningServiceTest";
@Mock Context mContext;
+ MockAlarmManager mAlarmManager;
@Mock WifiScannerImpl mWifiScannerImpl;
@Mock WifiScannerImpl.WifiScannerImplFactory mWifiScannerImplFactory;
@Mock IBatteryStats mBatteryStats;
@@ -73,6 +81,10 @@ public class WifiScanningServiceTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mAlarmManager = new MockAlarmManager();
+ when(mContext.getSystemService(Context.ALARM_SERVICE))
+ .thenReturn(mAlarmManager.getAlarmManager());
+
ChannelHelper channelHelper = new PresetKnownBandsChannelHelper(
new int[]{2400, 2450},
new int[]{5150, 5175},
@@ -117,9 +129,22 @@ public class WifiScanningServiceTest {
return messageCaptor.getValue();
}
+ private Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler,
+ final int what) {
+ CapturingMatcher<Message> messageMatcher = new CapturingMatcher<Message>() {
+ public boolean matches(Object argument) {
+ Message message = (Message) argument;
+ return message.what == what;
+ }
+ };
+ order.verify(handler).handleMessage(argThat(messageMatcher));
+ return messageMatcher.getLastValue();
+ }
+
private void verifyScanResultsRecieved(InOrder order, Handler handler, int listenerId,
WifiScanner.ScanData... expected) {
- Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler);
+ Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler,
+ WifiScanner.CMD_SCAN_RESULT);
assertScanResultsMessage(listenerId, expected, scanResultMessage);
}
@@ -131,12 +156,29 @@ public class WifiScanningServiceTest {
((WifiScanner.ParcelableScanData) scanResultMessage.obj).getResults());
}
+ private void verifySingleScanCompletedRecieved(InOrder order, Handler handler, int listenerId) {
+ Message completedMessage = verifyHandleMessageAndGetMessage(order, handler,
+ WifiScanner.CMD_SINGLE_SCAN_COMPLETED);
+ assertSingleScanCompletedMessage(listenerId, completedMessage);
+ }
+
+ private void assertSingleScanCompletedMessage(int listenerId, Message completedMessage) {
+ assertEquals("what", WifiScanner.CMD_SINGLE_SCAN_COMPLETED, completedMessage.what);
+ assertEquals("listenerId", listenerId, completedMessage.arg2);
+ }
+
private void sendBackgroundScanRequest(BidirectionalAsyncChannel controlChannel,
int scanRequestId, WifiScanner.ScanSettings settings) {
controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_BACKGROUND_SCAN, 0,
scanRequestId, settings));
}
+ private void sendSingleScanRequest(BidirectionalAsyncChannel controlChannel,
+ int scanRequestId, WifiScanner.ScanSettings settings) {
+ controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_SINGLE_SCAN, 0,
+ scanRequestId, settings));
+ }
+
private void verifySuccessfulResponse(InOrder order, Handler handler, int arg2) {
Message response = verifyHandleMessageAndGetMessage(order, handler);
assertSuccessfulResponse(arg2, response);
@@ -174,6 +216,18 @@ public class WifiScanningServiceTest {
}
}
+ private WifiNative.ScanEventHandler verifyStartSingleScan(InOrder order,
+ WifiNative.ScanSettings expected) {
+ ArgumentCaptor<WifiNative.ScanSettings> scanSettingsCaptor =
+ ArgumentCaptor.forClass(WifiNative.ScanSettings.class);
+ ArgumentCaptor<WifiNative.ScanEventHandler> scanEventHandlerCaptor =
+ ArgumentCaptor.forClass(WifiNative.ScanEventHandler.class);
+ order.verify(mWifiScannerImpl).startSingleScan(scanSettingsCaptor.capture(),
+ scanEventHandlerCaptor.capture());
+ assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue());
+ return scanEventHandlerCaptor.getValue();
+ }
+
private void verifyStartBackgroundScan(InOrder order, WifiNative.ScanSettings expected) {
ArgumentCaptor<WifiNative.ScanSettings> scanSettingsCaptor =
ArgumentCaptor.forClass(WifiNative.ScanSettings.class);
@@ -182,6 +236,7 @@ public class WifiScanningServiceTest {
assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue());
}
+ private static final int MAX_AP_PER_SCAN = 16;
private void startServiceAndLoadDriver() {
mWifiScanningServiceImpl.startService();
when(mWifiScannerImpl.getScanCapabilities(any(WifiNative.ScanCapabilities.class)))
@@ -189,7 +244,7 @@ public class WifiScanningServiceTest {
public boolean answer(WifiNative.ScanCapabilities capabilities) {
capabilities.max_scan_cache_size = Integer.MAX_VALUE;
capabilities.max_scan_buckets = 8;
- capabilities.max_ap_cache_per_scan = 16;
+ capabilities.max_ap_cache_per_scan = MAX_AP_PER_SCAN;
capabilities.max_rssi_sample_size = 8;
capabilities.max_scan_reporting_threshold = 10;
capabilities.max_hotlist_bssids = 0;
@@ -209,7 +264,7 @@ public class WifiScanningServiceTest {
@Test
public void construct() throws Exception {
- verifyNoMoreInteractions(mContext, mWifiScannerImpl, mWifiScannerImpl,
+ verifyNoMoreInteractions(mWifiScannerImpl, mWifiScannerImpl,
mWifiScannerImplFactory, mBatteryStats);
}
@@ -253,4 +308,403 @@ public class WifiScanningServiceTest {
verifyFailedResponse(order, handler, 0, WifiScanner.REASON_INVALID_REQUEST,
"Invalid request");
}
+
+ private void doSuccessfulSingleScan(WifiScanner.ScanSettings requestSettings,
+ WifiNative.ScanSettings nativeSettings, ScanResults results) {
+ int requestId = 12;
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results.getScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId);
+ verifyNoMoreInteractions(handler);
+ }
+
+ /**
+ * Do a single scan for a band and verify that it is successful.
+ */
+ @Test
+ public void sendSingleScanBandRequest() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
+ ScanResults.create(0, 2400, 5150, 5175));
+ }
+
+ /**
+ * Do a single scan for a list of channels and verify that it is successful.
+ */
+ @Test
+ public void sendSingleScanChannelsRequest() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
+ ScanResults.create(0, 2400, 5150, 5175));
+ }
+
+ /**
+ * Do a single scan, which the hardware fails to start, and verify that a failure response is
+ * delivered.
+ */
+ @Test
+ public void sendSingleScanRequestWhichFailsToStart() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 33;
+
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // scan fails
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(false);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings);
+
+ mLooper.dispatchAll();
+ // Scan is successfully queue, but then fails to execute
+ ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+ order.verify(handler, times(2)).handleMessage(messageCaptor.capture());
+ assertSuccessfulResponse(requestId, messageCaptor.getAllValues().get(0));
+ assertFailedResponse(requestId, WifiScanner.REASON_UNSPECIFIED,
+ "Failed to start single scan", messageCaptor.getAllValues().get(1));
+ }
+
+ /**
+ * Do a single scan, which successfully starts, but fails partway through and verify that a
+ * failure response is delivered.
+ */
+ @Test
+ public void sendSingleScanRequestWhichFailsAfterStart() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 33;
+
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // successful start
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings);
+
+ // Scan is successfully queue
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler =
+ verifyStartSingleScan(order, computeSingleScanNativeSettings(requestSettings));
+ verifySuccessfulResponse(order, handler, requestId);
+
+ // but then fails to execute
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
+ mLooper.dispatchAll();
+ verifyFailedResponse(order, handler, requestId,
+ WifiScanner.REASON_UNSPECIFIED, "Scan failed");
+ }
+
+ // TODO Add more single scan tests
+ // * disable wifi while scanning
+ // * disable wifi while scanning with pending scan
+
+ /**
+ * Send a single scan request and then a second one after the first completes.
+ */
+ @Test
+ public void sendSingleScanRequestAfterPreviousCompletes() {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ ScanResults results1 = ScanResults.create(0, 2400);
+
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ ScanResults results2 = ScanResults.create(0, 2450);
+
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(order,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(order, handler, requestId1);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results1.getScanData());
+ eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId1, results1.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId1);
+
+ // Run scan 2
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(order,
+ computeSingleScanNativeSettings(requestSettings2));
+ verifySuccessfulResponse(order, handler, requestId2);
+
+ // dispatch scan 2 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results2.getScanData());
+ eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId2, results2.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId2);
+ }
+
+ /**
+ * Send a single scan request and then a second one before the first completes.
+ * Verify that both are scheduled and succeed.
+ */
+ @Test
+ public void sendSingleScanRequestWhilePreviousScanRunning() {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ ScanResults results1 = ScanResults.create(0, 2400);
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ ScanResults results2 = ScanResults.create(0, 2450);
+
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder handlerOrder = inOrder(handler);
+ InOrder nativeOrder = inOrder(mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(handlerOrder, handler, requestId1);
+
+ // Queue scan 2 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId2);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results1.getScanData());
+ eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
+ verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
+
+ // now that the first scan completed we expect the second one to start
+ WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings2));
+
+ // dispatch scan 2 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results2.getScanData());
+ eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(handlerOrder, handler, requestId2, results2.getScanData());
+ verifySingleScanCompletedRecieved(handlerOrder, handler, requestId2);
+ }
+
+
+
+ /**
+ * Send a single scan request and then two more before the first completes.
+ * Verify that the first completes and the second two are merged.
+ */
+ @Test
+ public void sendMultipleSingleScanRequestWhilePreviousScanRunning() {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ ScanResults results1 = ScanResults.create(0, 2400);
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
+
+ WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5150), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId3 = 15;
+ ScanResults results3 = ScanResults.create(0, 5150, 5150, 5150, 5150);
+
+ WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels(
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channelsToSpec(2450, 5175, 5150));
+ ScanResults results2and3 = ScanResults.merge(results2, results3);
+
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder handlerOrder = inOrder(handler);
+ InOrder nativeOrder = inOrder(mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(handlerOrder, handler, requestId1);
+
+ // Queue scan 2 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId2);
+
+ // Queue scan 3 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId3, requestSettings3);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId3);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results1.getScanData());
+ eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
+ verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
+
+ // now that the first scan completed we expect the second and third ones to start
+ WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder,
+ nativeSettings2and3);
+
+ // dispatch scan 2 and 3 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results2and3.getScanData());
+ eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+
+ // unfortunatally the order that these events are dispatched is dependant on the order which
+ // they are iterated through internally
+ ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+ handlerOrder.verify(handler, times(4)).handleMessage(messageCaptor.capture());
+ int firstListenerId = messageCaptor.getAllValues().get(0).arg2;
+ assertTrue(firstListenerId + " was neither " + requestId2 + " nor " + requestId3,
+ firstListenerId == requestId2 || firstListenerId == requestId3);
+ if (firstListenerId == requestId2) {
+ assertScanResultsMessage(requestId2,
+ new WifiScanner.ScanData[] {results2.getScanData()},
+ messageCaptor.getAllValues().get(0));
+ assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(1));
+ assertScanResultsMessage(requestId3,
+ new WifiScanner.ScanData[] {results3.getScanData()},
+ messageCaptor.getAllValues().get(2));
+ assertSingleScanCompletedMessage(requestId3, messageCaptor.getAllValues().get(3));
+ } else {
+ assertScanResultsMessage(requestId3,
+ new WifiScanner.ScanData[] {results3.getScanData()},
+ messageCaptor.getAllValues().get(0));
+ assertSingleScanCompletedMessage(requestId3, messageCaptor.getAllValues().get(1));
+ assertScanResultsMessage(requestId2,
+ new WifiScanner.ScanData[] {results2.getScanData()},
+ messageCaptor.getAllValues().get(2));
+ assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(3));
+ }
+ }
+
+ private void doSuccessfulBackgroundScan(WifiScanner.ScanSettings requestSettings,
+ WifiNative.ScanSettings nativeSettings) {
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ sendBackgroundScanRequest(controlChannel, 12, requestSettings);
+ mLooper.dispatchAll();
+ verifyStartBackgroundScan(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, 12);
+ verifyNoMoreInteractions(handler);
+ }
+
+ /**
+ * Do a background scan for a band and verify that it is successful.
+ */
+ @Test
+ public void sendBackgroundScanBandRequest() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 20000,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder()
+ .withBasePeriod(20000)
+ .withMaxApPerScan(MAX_AP_PER_SCAN)
+ .withMaxScansToCache(WifiScanningScheduler.DEFAULT_MAX_SCANS_TO_BATCH)
+ .addBucketWithBand(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
+ WifiScanner.WIFI_BAND_BOTH)
+ .build();
+ doSuccessfulBackgroundScan(requestSettings, nativeSettings);
+ }
+
+ /**
+ * Do a background scan for a list of channels and verify that it is successful.
+ */
+ @Test
+ public void sendBackgroundScanChannelsRequest() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(5150), 20000,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder()
+ .withBasePeriod(20000)
+ .withMaxApPerScan(MAX_AP_PER_SCAN)
+ .withMaxScansToCache(WifiScanningScheduler.DEFAULT_MAX_SCANS_TO_BATCH)
+ .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5150)
+ .build();
+ doSuccessfulBackgroundScan(requestSettings, nativeSettings);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index f868c522b..2663b0c8e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -45,6 +45,7 @@ import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
import android.net.wifi.p2p.IWifiP2pManager;
import android.os.BatteryStats;
@@ -81,6 +82,7 @@ import com.android.server.wifi.p2p.WifiP2pServiceImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -92,8 +94,10 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Unit tests for {@link com.android.server.wifi.WifiStateMachine}.
@@ -234,6 +238,8 @@ public class WifiStateMachineTest {
when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(
mock(ConnectivityManager.class));
+ when(context.getSystemService(Context.WIFI_SCANNING_SERVICE)).thenReturn(mWifiScanner);
+
return context;
}
@@ -281,7 +287,7 @@ public class WifiStateMachineTest {
ScanDetail detail = new ScanDetail(nd, sWifiSsid, sBSSID, "", rssi, sFreq,
Long.MAX_VALUE, /* needed so that scan results aren't rejected because
there older than scan start */
- null, null);
+ ie, new ArrayList<String>());
return detail;
}
@@ -312,6 +318,7 @@ public class WifiStateMachineTest {
WifiConfigManager mWifiConfigManager;
@Mock WifiNative mWifiNative;
+ @Mock WifiScanner mWifiScanner;
@Mock SupplicantStateTracker mSupplicantStateTracker;
@Mock WifiMetrics mWifiMetrics;
@Mock UserManager mUserManager;
@@ -743,6 +750,36 @@ public class WifiStateMachineTest {
forgetNetworkAndVerifyFailure();
}
+ private void verifyScan(int band, int reportEvents, Set<Integer> configuredNetworkIds) {
+ ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor =
+ ArgumentCaptor.forClass(WifiScanner.ScanSettings.class);
+ ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor =
+ ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
+ verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture());
+ WifiScanner.ScanSettings actualSettings = scanSettingsCaptor.getValue();
+ assertEquals("band", band, actualSettings.band);
+ assertEquals("reportEvents", reportEvents, actualSettings.reportEvents);
+
+ if (configuredNetworkIds == null) {
+ configuredNetworkIds = new HashSet<>();
+ }
+ Set<Integer> actualConfiguredNetworkIds = new HashSet<>();
+ if (actualSettings.hiddenNetworkIds != null) {
+ for (int i = 0; i < actualSettings.hiddenNetworkIds.length; ++i) {
+ actualConfiguredNetworkIds.add(actualSettings.hiddenNetworkIds[i]);
+ }
+ }
+ assertEquals("configured networks", configuredNetworkIds, actualConfiguredNetworkIds);
+
+ when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
+ mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
+
+ mLooper.dispatchAll();
+
+ List<ScanResult> reportedResults = mWsm.syncGetScanResultsList();
+ assertEquals(8, reportedResults.size());
+ }
+
@Test
public void scan() throws Exception {
addNetworkAndVerifySuccess();
@@ -751,14 +788,9 @@ public class WifiStateMachineTest {
mWsm.startScan(-1, 0, null, null);
mLooper.dispatchAll();
- verify(mWifiNative).scan(null, mWifiConfigManager.getHiddenConfiguredNetworkIds());
-
- when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
- mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
- mLooper.dispatchAll();
-
- List<ScanResult> results = mWsm.syncGetScanResultsList();
- assertEquals(8, results.size());
+ verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
+ | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT, null);
}
@Test
@@ -769,14 +801,10 @@ public class WifiStateMachineTest {
mWsm.startScan(-1, 0, null, null);
mLooper.dispatchAll();
- verify(mWifiNative).scan(null, mWifiConfigManager.getHiddenConfiguredNetworkIds());
-
- when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
- mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
- mLooper.dispatchAll();
-
- List<ScanResult> results = mWsm.syncGetScanResultsList();
- assertEquals(8, results.size());
+ verifyScan(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
+ | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
+ mWifiConfigManager.getHiddenConfiguredNetworkIds());
}
@Test