summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Wills <mwills@google.com>2015-11-03 17:16:09 -0800
committerMitchell Wills <mwills@google.com>2016-01-29 09:53:34 -0800
commit772124d1f1ddb2b9537de5efc748943808dafe80 (patch)
tree1355a426c9910d9de1958d3dd3eaa14d564aaee3
parent8541f6411048c5c6281699153b8c7c73e1f30c4c (diff)
Refactor WifiScanner support for oneshot scans
Seperate oneshot scans so they are no longer implemented using background scans and make WifiStateMachine use WifiScanner for single scans. This changes requires a few parts: 1. Implement single scan logic in WifiScanningServiceImpl for merging and executing scan requests using the single scan native interface. 2. Writing tests for the new code in 1 3. Make supplicant start scans by using WifiScanner and when it recieves callbacks dispatch scan complete/failure messages. 4. Enable HalWifiScannerImpl and SupplicantWifiScannerImpl to listen to supplicant scan events now that WifiStateMachine does not. Bug: 26525037 Change-Id: Iddd6d64b35fed129048e1fd5c79acb6982bfc418
-rw-r--r--service/java/com/android/server/wifi/HalWifiScannerImpl.java32
-rw-r--r--service/java/com/android/server/wifi/ScanDetailUtil.java41
-rw-r--r--service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java39
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java35
-rw-r--r--service/java/com/android/server/wifi/WifiScanningScheduler.java16
-rw-r--r--service/java/com/android/server/wifi/WifiScanningServiceImpl.java513
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java99
-rw-r--r--tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java17
-rw-r--r--tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java12
-rw-r--r--tests/wifitests/src/com/android/server/wifi/MultiClientSchedulerTest.java51
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanResults.java30
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java75
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java41
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java507
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java43
15 files changed, 1224 insertions, 327 deletions
diff --git a/service/java/com/android/server/wifi/HalWifiScannerImpl.java b/service/java/com/android/server/wifi/HalWifiScannerImpl.java
index fc5d18f4a..dc6fc1b61 100644
--- a/service/java/com/android/server/wifi/HalWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/HalWifiScannerImpl.java
@@ -50,14 +50,10 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
mWifiNative = wifiNative;
mEventHandler = new Handler(looper, this);
- // 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
@@ -66,7 +62,9 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
case WifiMonitor.SCAN_FAILED_EVENT:
Log.w(TAG, "Single scan failed");
if (mSingleScanEventHandler != null) {
- // TODO indicate failure to caller
+ if (mSingleScanEventHandler != null) {
+ mSingleScanEventHandler.onScanStatus(WifiNative.WIFI_SCAN_DISABLED);
+ }
mSingleScanEventHandler = null;
}
break;
@@ -116,9 +114,17 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
}
mSingleScanEventHandler = eventHandler;
- if (!mWifiNative.scan(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, freqs)) {
- mSingleScanEventHandler = null;
- // TODO call on failure callback in handler
+ if (!mWifiNative.scan(freqs)) {
+ Log.e(TAG, "Failed to start scan, freqs=" + freqs);
+ // indicate scan failure async
+ mEventHandler.post(new Runnable() {
+ public void run() {
+ if (mSingleScanEventHandler != null) {
+ mSingleScanEventHandler.onScanStatus(WifiNative.WIFI_SCAN_DISABLED);
+ }
+ mSingleScanEventHandler = null;
+ }
+ });
}
return true;
}
@@ -148,7 +154,7 @@ public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callb
Arrays.sort(results, SCAN_RESULT_SORT_COMPARATOR);
mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, results);
if (mSingleScanEventHandler != null) {
- mSingleScanEventHandler.onScanResultsAvailable();
+ mSingleScanEventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
mSingleScanEventHandler = null;
}
}
diff --git a/service/java/com/android/server/wifi/ScanDetailUtil.java b/service/java/com/android/server/wifi/ScanDetailUtil.java
new file mode 100644
index 000000000..07eaafbb6
--- /dev/null
+++ b/service/java/com/android/server/wifi/ScanDetailUtil.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.net.wifi.ScanResult;
+
+import com.android.server.wifi.hotspot2.NetworkDetail;
+
+/**
+ * Utility for converting a ScanResult to a ScanDetail.
+ * Only fields that are suppported in ScanResult are copied.
+ */
+public class ScanDetailUtil {
+ private ScanDetailUtil() { /* not constructable */ }
+
+ public static ScanDetail toScanDetail(ScanResult scanResult) {
+ NetworkDetail networkDetail = new NetworkDetail(scanResult.BSSID,
+ scanResult.informationElements, scanResult.anqpLines, scanResult.frequency);
+ ScanDetail scanDetail = new ScanDetail(networkDetail, scanResult.wifiSsid,
+ scanResult.BSSID, scanResult.capabilities, scanResult.level, scanResult.frequency,
+ scanResult.timestamp);
+ scanDetail.getScanResult().informationElements = scanResult.informationElements;
+ scanDetail.getScanResult().anqpLines = scanResult.anqpLines;
+ return scanDetail;
+ }
+
+}
diff --git a/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java b/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java
index 78e213797..8c8b3f27d 100644
--- a/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/SupplicantWifiScannerImpl.java
@@ -95,14 +95,10 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mEventHandler = new Handler(looper, this);
- // 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
@@ -115,6 +111,7 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
capabilities.max_hotlist_bssids = 0;
capabilities.max_significant_wifi_change_aps = 0;
// TODO reenable once scan results handlers are enabled again
+ // NOTE: this only disables background scan requests
return false;
}
@@ -255,7 +252,8 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
}
Set<Integer> freqs = new HashSet<>();
- LastScanSettings newScanSettings = new LastScanSettings(SystemClock.elapsedRealtime());
+ final LastScanSettings newScanSettings =
+ new LastScanSettings(SystemClock.elapsedRealtime());
// Update scan settings if there is a pending scan
if (!mBackgroundScanPaused) {
@@ -358,8 +356,7 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
}
if (freqs.size() > 0) {
- boolean success = mWifiNative.scan(
- WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, freqs);
+ boolean success = mWifiNative.scan(freqs);
if (success) {
// TODO handle scan timeout
Log.d(TAG, "Starting wifi scan for " + freqs.size() + " freqs"
@@ -367,8 +364,18 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
+ ", single=" + newScanSettings.singleScanActive);
mLastScanSettings = newScanSettings;
} else {
- Log.w(TAG, "Failed starting wifi scan for " + freqs.size() + " freqs");
- // TODO indicate failure for single and background scans
+ Log.e(TAG, "Failed to start scan, freqs=" + freqs);
+ // indicate scan failure async
+ mEventHandler.post(new Runnable() {
+ public void run() {
+ newScanSettings.singleScanActive = false;
+ if (newScanSettings.singleScanEventHandler != null) {
+ newScanSettings.singleScanEventHandler
+ .onScanStatus(WifiNative.WIFI_SCAN_DISABLED);
+ }
+ }
+ });
+ // TODO if scans fail enough background scans should be failed as well
}
}
}
@@ -457,7 +464,8 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
/ 100)
|| mBackgroundScanBuffer.size()
>= mLastScanSettings.reportNumScansThreshold))) {
- mBackgroundScanEventHandler.onScanStatus();
+ mBackgroundScanEventHandler
+ .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
}
}
@@ -484,7 +492,8 @@ public class SupplicantWifiScannerImpl extends WifiScannerImpl implements Handle
Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
- mLastScanSettings.singleScanEventHandler.onScanResultsAvailable();
+ mLastScanSettings.singleScanEventHandler
+ .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
}
mLastScanSettings = null;
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 8166328dc..0560345f6 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -324,12 +324,9 @@ public class WifiNative {
}
- public static final int SCAN_WITHOUT_CONNECTION_SETUP = 1;
- public static final int SCAN_WITH_CONNECTION_SETUP = 2;
-
- public boolean scan(int type, Set<Integer> freqs) {
+ public boolean scan(Set<Integer> freqs) {
if(freqs == null) {
- return scan(type, (String)null);
+ return scan((String) null);
}
else if (freqs.size() != 0) {
StringBuilder freqList = new StringBuilder();
@@ -340,22 +337,18 @@ public class WifiNative {
freqList.append(freq.toString());
first = false;
}
- return scan(type, freqList.toString());
+ return scan(freqList.toString());
}
else {
return false;
}
}
- private boolean scan(int type, String freqList) {
- if (type == SCAN_WITHOUT_CONNECTION_SETUP) {
- if (freqList == null) return doBooleanCommand("SCAN TYPE=ONLY");
- else return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList);
- } else if (type == SCAN_WITH_CONNECTION_SETUP) {
- if (freqList == null) return doBooleanCommand("SCAN");
- else return doBooleanCommand("SCAN freq=" + freqList);
+ private boolean scan(String freqList) {
+ if (freqList == null) {
+ return doBooleanCommand("SCAN TYPE=ONLY"); // Scan all channels
} else {
- throw new IllegalArgumentException("Invalid scan type");
+ return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList);
}
}
@@ -677,6 +670,7 @@ public class WifiNative {
ScanDetail scan = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
level, freq, tsf);
scan.getScanResult().informationElements = infoElements;
+ scan.getScanResult().anqpLines = anqpLines;
results.add(scan);
} catch (IllegalArgumentException iae) {
Log.d(TAG, "Failed to parse information elements: " + iae);
@@ -1731,18 +1725,17 @@ public class WifiNative {
}
public static interface ScanEventHandler {
- void onScanResultsAvailable();
void onFullScanResult(ScanResult fullScanResult);
- void onScanStatus();
+ void onScanStatus(int event);
void onScanPaused(WifiScanner.ScanData[] data);
void onScanRestarted();
}
/* scan status, keep these values in sync with gscan.h */
- private static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
- private static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
- private static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
- private static final int WIFI_SCAN_DISABLED = 3;
+ public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
+ public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
+ public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
+ public static final int WIFI_SCAN_DISABLED = 3;
// Callback from native
private static void onScanStatus(int id, int event) {
@@ -1751,7 +1744,7 @@ public class WifiNative {
|| event == WIFI_SCAN_THRESHOLD_PERCENT) {
if (handler != null) {
// TODO pass event back to framework
- handler.onScanStatus();
+ handler.onScanStatus(event);
}
}
else if (event == WIFI_SCAN_DISABLED) {
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 777b3f9b6..3d61c1a63 100644
--- a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
@@ -43,6 +43,8 @@ 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;
@@ -190,13 +192,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:
+ mStateMachine.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;
}
}
}
@@ -213,7 +217,7 @@ 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_DISABLED = BASE + 10;
private final Context mContext;
private final Looper mLooper;
@@ -224,6 +228,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private WifiNative.ScanSettings mPreviousSchedule;
private WifiScanningStateMachine mStateMachine;
+ private WifiSingleScanStateMachine mSingleScanStateMachine;
private ClientHandler mClientHandler;
private final IBatteryStats mBatteryStats;
@@ -243,6 +248,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mClientHandler = new ClientHandler(mLooper);
mStateMachine = new WifiScanningStateMachine(mLooper);
mWifiChangeStateMachine = new WifiChangeStateMachine(mLooper);
+ mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
mContext.registerReceiver(
new BroadcastReceiver() {
@@ -253,16 +259,342 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
if (DBG) localLog("SCAN_AVAILABLE : " + state);
if (state == WifiManager.WIFI_STATE_ENABLED) {
mStateMachine.sendMessage(CMD_DRIVER_LOADED);
+ mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
mStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
+ mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
}
}
}, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));
mStateMachine.start();
mWifiChangeStateMachine.start();
+ mSingleScanStateMachine.start();
+ }
+
+ /**
+ * 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 ClientHandlerMap(int initialSize) {
+ super(initialSize);
+ }
+
+ 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 NotScanningState.
+ */
+ class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler {
+ private final DefaultState mDefaultState = new DefaultState();
+ private final DriverStartedState mDriverStartedState = new DriverStartedState();
+ private final NotScanningState mNotScanningState = new NotScanningState();
+ private final ScanningState mScanningState = new ScanningState();
+
+ private ClientHandlerMap<ScanSettings> mActiveScans = new ClientHandlerMap<>(4);
+ private ClientHandlerMap<ScanSettings> mPendingScans = new ClientHandlerMap<>(4);
+
+ public WifiSingleScanStateMachine(Looper looper) {
+ super("WifiSingleScanStateMachine", looper);
+
+ setLogRecSize(128);
+ setLogOnlyTransitions(false);
+
+ // CHECKSTYLE:OFF IndentationCheck
+ addState(mDefaultState);
+ addState(mDriverStartedState, mDefaultState);
+ addState(mNotScanningState, 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_DISABLED:
+ sendMessage(CMD_SCAN_DISABLED);
+ 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(mNotScanningState);
+ 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 NotScanningState
+ * to hold common functionality and handle cleaning up scans when the driver is shut down.
+ */
+ class DriverStartedState extends State {
+ @Override
+ public void exit() {
+ sendOpFailedToAll(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ mPendingScans.clear();
+ }
+
+ @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
+ 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 NotScanningState extends State {
+ @Override
+ public void enter() {
+ tryToStartNewScan();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ return NOT_HANDLED;
+ }
+ }
+
+ class ScanningState extends State {
+ @Override
+ public void exit() {
+ // if any scans are still active (never got results available then indicate failure
+ sendOpFailedToAll(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ mActiveScans.clear();
+ }
+
+ // TODO correctly handle battery blaming
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_SCAN_RESULTS_AVAILABLE:
+ reportScanResults(mScannerImpl.getLatestSingleScanResults());
+ mActiveScans.clear();
+ transitionTo(mNotScanningState);
+ return HANDLED;
+ case CMD_FULL_SCAN_RESULTS:
+ reportFullScanResult((ScanResult) msg.obj);
+ return HANDLED;
+ case CMD_SCAN_DISABLED:
+ sendOpFailedToAll(mActiveScans, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ mActiveScans.clear();
+ transitionTo(mNotScanningState);
+ 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;
+ }
+ ChannelSpec[] channels = WifiChannelHelper.getChannelsForScanSettings(settings);
+ if (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() {
+ // TODO move merging logic to a scheduler
+ int reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
+ ArrayList<Integer> allChannels = new ArrayList<>();
+ for (ScanSettings settings : mPendingScans.values()) {
+ ChannelSpec[] channels = WifiChannelHelper.getChannelsForScanSettings(settings);
+ for (int i = 0; i < channels.length; ++i) {
+ allChannels.add(channels[i].frequency);
+ }
+ if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
+ reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
+ }
+ }
+ if (allChannels.size() > 0) {
+ WifiNative.ScanSettings settings = new WifiNative.ScanSettings();
+ settings.num_buckets = 1;
+ WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
+ bucketSettings.bucket = 0;
+ bucketSettings.period_ms = 0;
+ bucketSettings.report_events = reportEvents;
+ bucketSettings.num_channels = allChannels.size();
+ bucketSettings.channels = new WifiNative.ChannelSettings[allChannels.size()];
+ for (int i = 0; i < bucketSettings.channels.length; ++i) {
+ bucketSettings.channels[i] = new WifiNative.ChannelSettings();
+ bucketSettings.channels[i].frequency = allChannels.get(i);
+ }
+ 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
+ sendOpFailedToAll(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
+ "Failed to start single scan");
+ mPendingScans.clear();
+ }
+ } else {
+ // notify and cancel failed scans
+ sendOpFailedToAll(mPendingScans, WifiScanner.REASON_INVALID_REQUEST,
+ "No channels specified");
+ mPendingScans.clear();
+ }
+ }
+
+ void sendOpFailedToAll(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));
+ }
+ }
+
+ // TODO fix shouldReport checks
+ // currently these checks work becuase 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);
+ }
+ }
+ }
+
+
class WifiScanningStateMachine extends StateMachine implements WifiNative.ScanEventHandler,
WifiNative.HotlistEventHandler, WifiNative.SignificantWifiChangeEventHandler {
@@ -276,23 +608,31 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
setLogRecSize(512);
setLogOnlyTransitions(false);
+ // CHECKSTYLE:OFF IndentationCheck
addState(mDefaultState);
addState(mStartedState, mDefaultState);
addState(mPausedState, mDefaultState);
+ // CHECKSTYLE:ON IndentationCheck
setInitialState(mDefaultState);
}
@Override
- public void onScanResultsAvailable() {
- if (DBG) localLog("onScanResultAvailable event received");
- sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
- }
-
- @Override
- public void onScanStatus() {
- if (DBG) localLog("onScanStatus event received");
- sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
+ 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_DISABLED:
+ sendMessage(CMD_SCAN_DISABLED);
+ break;
+ default:
+ Log.e(TAG, "Unknown scan status event: " + event);
+ break;
+ }
}
@Override
@@ -340,6 +680,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);
}
@@ -408,33 +751,19 @@ 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_GET_SCAN_RESULTS:
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);
@@ -491,6 +820,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
reportScanResults((ScanData[]) msg.obj);
transitionTo(mPausedState);
break;
+ case CMD_SCAN_DISABLED:
+ // TODO handle this gracefully (currently no implementations are know to
+ // report this)
+ break;
default:
return NOT_HANDLED;
}
@@ -523,8 +856,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) {
@@ -534,6 +873,12 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
if (DBG) localLog("New client, channel: " + c);
}
+ void sendMessage(int what, int arg1, int arg2, Object obj) {
+ if (!mDisconnected) {
+ mChannel.sendMessage(what, arg1, arg2, obj);
+ }
+ }
+
void reportBatchedScanStart() {
if (mUid == 0)
return;
@@ -560,7 +905,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
int getCsph() {
int csph = 0;
- for (ScanSettings settings : getScanSettings()) {
+ for (ScanSettings settings : getBackgroundScanSettings()) {
int num_channels = WifiChannelHelper.getChannelsForScanSettings(settings).length;
int scans_per_Hour = settings.periodInMs == 0 ? 1 : (3600 * 1000) /
settings.periodInMs;
@@ -575,7 +920,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
reportBatchedScanStop();
mScanWorkReported = false;
}
- if (mScanSettings.isEmpty() == false) {
+ if (mBackgroundScanSettings.isEmpty()) {
reportBatchedScanStart();
mScanWorkReported = true;
}
@@ -583,14 +928,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");
@@ -603,33 +949,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);
@@ -637,7 +976,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);
@@ -646,11 +985,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[]) {
@@ -660,10 +994,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) {
@@ -678,18 +1012,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) {
@@ -780,7 +1114,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
void cleanup() {
- mScanSettings.clear();
+ mDisconnected = true;
+ mBackgroundScanSettings.clear();
updateSchedule();
mHotlistSettings.clear();
@@ -829,7 +1164,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private boolean updateSchedule() {
ArrayList<ScanSettings> settings = new ArrayList<>();
for (ClientInfo client : mClients.values()) {
- settings.addAll(client.getScanSettings());
+ settings.addAll(client.getBackgroundScanSettings());
}
mScheduler.updateSchedule(settings);
@@ -897,7 +1232,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);
@@ -941,48 +1276,22 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
}
- logScanRequest("addScanRequest", ci, handler, settings);
- ci.addScanRequest(settings, handler);
-
- if (updateSchedule()) {
- return true;
- } else {
- ci.removeScanRequest(handler);
- localLog("Failing scan request because failed to reset scan");
- return false;
- }
- }
-
- 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);
+ logScanRequest("addBackgroundScanRequest", ci, handler, settings);
+ ci.addBackgroundScanRequest(settings, handler);
if (updateSchedule()) {
- /* reset periodInMs to 0 to indicate single shot scan */
- settings.periodInMs = 0;
return true;
} else {
- ci.removeScanRequest(handler);
+ ci.removeBackgroundScanRequest(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();
}
}
@@ -1125,9 +1434,11 @@ 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);
}
@@ -1531,7 +1842,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 ec4d815d6..1a4c2ece0 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -1400,8 +1400,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.RX_HS20_ANQP_ICON_EVENT,
getHandler());
- mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SCAN_FAILED_EVENT, getHandler());
- mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SCAN_RESULTS_EVENT, getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SSID_REENABLED, getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SSID_TEMP_DISABLED, getHandler());
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_CONNECTION_EVENT, getHandler());
@@ -1997,7 +1995,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
}
- private void handleScanRequest(int type, Message message) {
+ private void handleScanRequest(Message message) {
ScanSettings settings = null;
WorkSource workSource = null;
@@ -2018,7 +2016,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
// call wifi native to start the scan
- if (startScanNative(type, freqs)) {
+ if (startScanNative(freqs)) {
// only count battery consumption if scan request is accepted
noteScanStart(message.arg1, workSource);
// a full scan covers everything, clearing scan request buffer
@@ -2069,17 +2067,57 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
+ // TODO this is a temporary measure to bridge between WifiScanner and WifiStateMachine until
+ // scan functionality is refactored out of WifiStateMachine.
+ private WifiScanner.ScanListener mLastNativeScanListener = null;
+ private volatile ArrayList<ScanDetail> mLastNativeScanResults = new ArrayList<ScanDetail>();
/**
* return true iff scan request is accepted
*/
- private boolean startScanNative(int type, Set<Integer> freqs) {
- if (mWifiNative.scan(type, freqs)) {
- mIsScanOngoing = true;
- mIsFullScanOngoing = (freqs == null);
- lastScanFreqs = freqs;
- return true;
+ private boolean startScanNative(Set<Integer> freqs) {
+ if (mLastNativeScanListener != null) {
+ mWifiScanner.stopScan(mLastNativeScanListener);
+ mLastNativeScanListener = null;
+ }
+ 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;
+ mLastNativeScanListener = new WifiScanner.ScanListener() {
+ private final ArrayList<ScanDetail> mNewScanResults = new ArrayList<>();
+
+ public void onSuccess() {
+ // the scan started successfully, but has not completed yet
+ }
+ public void onFailure(int reason, String description) {
+ Log.e(TAG, "Scan failed: reason=" + reason + ", " + description);
+ sendMessage(WifiMonitor.SCAN_FAILED_EVENT);
+ }
+ public void onResults(WifiScanner.ScanData[] results) {
+ mLastNativeScanResults = mNewScanResults;
+ sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
+ }
+ public void onFullResult(ScanResult fullScanResult) {
+ mNewScanResults.add(ScanDetailUtil.toScanDetail(fullScanResult));
+ }
+ public void onPeriodChanged(int periodInMs) {
+ // does not occur for single scan
+ }
+ };
+ mWifiScanner.startScan(settings, mLastNativeScanListener);
+ mIsScanOngoing = true;
+ mIsFullScanOngoing = (freqs == null);
+ lastScanFreqs = freqs;
+ return true;
}
/**
@@ -3943,7 +3981,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
mNumScanResultsKnown = 0;
mNumScanResultsReturned = 0;
- ArrayList<ScanDetail> scanResults = mWifiNative.getScanResults();
+ ArrayList<ScanDetail> scanResults = mLastNativeScanResults;
if (scanResults.isEmpty()) {
mScanResults = new ArrayList<>();
@@ -5013,13 +5051,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
mDhcpActive = false;
}
- void connectScanningService() {
-
- if (mWifiScanner == null) {
- mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE);
- }
- }
-
private void handleIPv4Success(DhcpResults dhcpResults, int reason) {
if (PDBG) {
@@ -6155,11 +6186,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
class DriverStartedState extends State {
@Override
public void enter() {
-
if (PDBG) {
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(mVerboseLoggingLevel > 0);
mIsRunning = true;
updateBatteryWorkSource(null);
@@ -6252,7 +6289,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
switch(message.what) {
case CMD_START_SCAN:
- handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
+ handleScanRequest(message);
break;
case CMD_SET_FREQUENCY_BAND:
int band = message.arg1;
@@ -6265,7 +6302,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
// Flush old data - like scan results
mWifiNative.bssFlush();
// Fetch the latest scan results when frequency band is set
-// startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);
+ // startScanNative(null);
if (PDBG) logd("done set frequency band " + band);
@@ -6541,7 +6578,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
// Handle scan. All the connection related commands are
// handled only in ConnectModeState
case CMD_START_SCAN:
- handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
+ handleScanRequest(message);
break;
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
SupplicantState state = handleSupplicantStateChange(message);
@@ -7039,11 +7076,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
class ConnectModeState extends State {
@Override
- public void enter() {
- connectScanningService();
- }
-
- @Override
public boolean processMessage(Message message) {
WifiConfiguration config;
int netId;
@@ -8089,8 +8121,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
logd("starting scan for " + config.configKey() + " with " + freqs);
//}
// Call wifi native to start the scan
- if (startScanNative(
- WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, freqs)) {
+ if (startScanNative(freqs)) {
// Only count battery consumption if scan request is accepted
noteScanStart(SCAN_ALARM_SOURCE, null);
messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
@@ -8383,8 +8414,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
+ fullBandConnectedTimeIntervalMilli);
}
}
- handleScanRequest(
- WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
+ handleScanRequest(message);
} else {
if (!startScanForConfiguration(
currentConfiguration, restrictChannelList)) {
@@ -8405,8 +8435,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
+ fullBandConnectedTimeIntervalMilli);
}
}
- handleScanRequest(
- WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
+ handleScanRequest(message);
}
}
@@ -9357,7 +9386,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
/* Disable background scan temporarily during a regular scan */
enableBackgroundScan(false);
- handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message);
+ handleScanRequest(message);
ret = HANDLED;
} else {
diff --git a/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java b/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java
index 0ff439152..9a21843f4 100644
--- a/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/BaseWifiScannerImplTest.java
@@ -25,7 +25,6 @@ import static com.android.server.wifi.ScanTestUtil.setupMockChannels;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
@@ -140,7 +139,7 @@ public abstract class BaseWifiScannerImplTest {
WifiNative.ScanEventHandler eventHandler2 = mock(WifiNative.ScanEventHandler.class);
// scan start succeeds
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
assertTrue(mScanner.startSingleScan(settings, eventHandler));
assertFalse("second scan while first scan running should fail immediately",
@@ -164,12 +163,13 @@ public abstract class BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// scan fails
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(false);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(false);
// start scan
assertTrue(mScanner.startSingleScan(settings, eventHandler));
- // TODO expect failure callback once implemented
+ mLooper.dispatchAll();
+ order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_DISABLED);
verifyNoMoreInteractions(eventHandler);
}
@@ -213,7 +213,7 @@ public abstract class BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// scans succeed
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// start first scan
assertTrue(mScanner.startSingleScan(settings, eventHandler));
@@ -257,7 +257,7 @@ public abstract class BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// scan succeeds
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// start scan
assertTrue(mScanner.startSingleScan(settings, eventHandler));
@@ -270,8 +270,7 @@ public abstract class BaseWifiScannerImplTest {
protected void expectSuccessfulSingleScan(InOrder order,
WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScan,
ScanResults results, boolean expectFullResults) {
- order.verify(mWifiNative).scan(eq(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP),
- eq(expectedScan));
+ order.verify(mWifiNative).scan(eq(expectedScan));
when(mWifiNative.getScanResults()).thenReturn(results.getScanDetailArrayList());
@@ -286,7 +285,7 @@ public abstract class BaseWifiScannerImplTest {
}
}
- order.verify(eventHandler).onScanResultsAvailable();
+ order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
assertScanDataEquals(results.getScanData(), mScanner.getLatestSingleScanResults());
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java b/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java
index 162fc2c0c..d253ff723 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalWifiScannerTest.java
@@ -16,13 +16,10 @@
package com.android.server.wifi;
-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}.
*/
@@ -32,14 +29,5 @@ public class HalWifiScannerTest extends BaseWifiScannerImplTest {
@Before
public void setUp() throws Exception {
mScanner = new HalWifiScannerImpl(WifiNative.getWlanNativeInterface(), 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 97da4a473..94ce31d38 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;
import static com.android.server.wifi.ScanTestUtil.getAllChannels;
@@ -44,7 +46,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Set;
/**
* Unit tests for {@link com.android.server.wifi.MultiClientScheduler}.
@@ -459,43 +460,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);
- Set<Integer> expectedChannels = new HashSet<>();
- for (ChannelSpec channel : getAllChannels(settings)) {
- expectedChannels.add(channel.frequency);
- }
- Set<Integer> actualChannels = new HashSet<>();
- for (ChannelSpec channel : getAllChannels(schedule.buckets[0])) {
- actualChannels.add(channel.frequency);
- }
- assertEquals("channels", expectedChannels, actualChannels);
- }
- 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,
+ getAllChannels(settings));
+ } 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 d418451fc..b6007b26c 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanResults.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
@@ -28,7 +28,9 @@ 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;
/**
@@ -39,6 +41,29 @@ 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;
+ }
+
+ 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),
@@ -102,11 +127,14 @@ public class ScanResults {
int rssi = r.nextInt(40) - 99; // -99 to -60
ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1];
ie[0] = generateSsidIe(ssid);
- NetworkDetail nd = new NetworkDetail(bssid, ie, new ArrayList<String>(), freq);
+ List<String> anqpLines = new ArrayList<>();
+ NetworkDetail nd = new NetworkDetail(bssid, ie, anqpLines, freq);
ScanDetail detail = new ScanDetail(nd, WifiSsid.createFromAsciiEncoded(ssid),
bssid, "", rssi, freq,
Long.MAX_VALUE); /* needed so that scan results aren't rejected because
there older than scan start */
+ detail.getScanResult().informationElements = ie;
+ detail.getScanResult().anqpLines = anqpLines;
results[i] = detail;
}
return results;
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
index 3b06c0386..cc583e420 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
@@ -18,6 +18,7 @@ package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.net.wifi.ScanResult;
@@ -27,8 +28,6 @@ import android.net.wifi.WifiScanner.ScanData;
import android.net.wifi.WifiScanner.ScanSettings;
import android.net.wifi.WifiSsid;
-import com.android.server.wifi.WifiNative.BucketSettings;
-
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
@@ -115,6 +114,10 @@ public class ScanTestUtil {
mSettings.report_threshold_num_scans = maxScans;
return this;
}
+ public NativeScanSettingsBuilder withMaxPercentToCache(int percent) {
+ mSettings.report_threshold_percent = percent;
+ return this;
+ }
public NativeScanSettingsBuilder addBucketWithBand(
int period, int reportEvents, int band) {
@@ -128,6 +131,11 @@ public class ScanTestUtil {
public NativeScanSettingsBuilder addBucketWithChannels(
int period, int reportEvents, int... channels) {
+ return addBucketWithChannels(period, reportEvents, channelsToSpec(channels));
+ }
+
+ public NativeScanSettingsBuilder addBucketWithChannels(
+ int period, int reportEvents, ChannelSpec... channels) {
WifiNative.BucketSettings bucket = new WifiNative.BucketSettings();
bucket.bucket = mSettings.num_buckets;
bucket.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
@@ -135,7 +143,7 @@ public class ScanTestUtil {
bucket.channels = new WifiNative.ChannelSettings[channels.length];
for (int i = 0; i < channels.length; ++i) {
bucket.channels[i] = new WifiNative.ChannelSettings();
- bucket.channels[i].frequency = channels[i];
+ bucket.channels[i].frequency = channels[i].frequency;
}
bucket.period_ms = period;
bucket.report_events = reportEvents;
@@ -154,6 +162,26 @@ public class ScanTestUtil {
}
}
+ public static WifiNative.ScanSettings computeSingleScanNativeSettings(
+ WifiScanner.ScanSettings requestSettings) {
+ return createSingleScanNativeSettings(requestSettings.reportEvents,
+ getAllChannels(requestSettings));
+ }
+
+ public static WifiNative.ScanSettings createSingleScanNativeSettings(
+ int reportEvents, ChannelSpec... channels) {
+ // TODO requests using bands should be scheduled using the band, but are currently
+ // converted to channels before scheduling. This should probably change
+ return new NativeScanSettingsBuilder()
+ .withBasePeriod(0)
+ .withMaxApPerScan(0)
+ .withMaxPercentToCache(0)
+ .withMaxScansToCache(0)
+ .addBucketWithChannels(0,
+ reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channels)
+ .build();
+ }
+
public static Set<Integer> createFreqSet(int... elements) {
Set<Integer> set = new HashSet<>();
for (int e : elements) {
@@ -237,7 +265,46 @@ public class ScanTestUtil {
return channelSpecs;
}
- public static ChannelSpec[] getAllChannels(BucketSettings bucket) {
+ public static void assertNativeScanSettingsEquals(WifiNative.ScanSettings expected,
+ WifiNative.ScanSettings actual) {
+ assertEquals("bssids per scan", expected.max_ap_per_scan, actual.max_ap_per_scan);
+ assertEquals("scans to cache", expected.report_threshold_num_scans,
+ actual.report_threshold_num_scans);
+ assertEquals("percent to cache", expected.report_threshold_percent,
+ actual.report_threshold_percent);
+ assertEquals("base period", expected.base_period_ms, actual.base_period_ms);
+
+ assertEquals("number of buckets", expected.num_buckets, actual.num_buckets);
+ assertNotNull("buckets was null", actual.buckets);
+ for (int i = 0; i < expected.buckets.length; ++i) {
+ assertNotNull("buckets[" + i + "] was null", actual.buckets[i]);
+ assertEquals("buckets[" + i + "].period",
+ expected.buckets[i].period_ms, actual.buckets[i].period_ms);
+ assertEquals("buckets[" + i + "].reportEvents",
+ expected.buckets[i].report_events, actual.buckets[i].report_events);
+
+ assertEquals("buckets[" + i + "].band",
+ expected.buckets[i].band, actual.buckets[i].band);
+ if (expected.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
+ Set<Integer> expectedChannels = new HashSet<>();
+ for (ChannelSpec channel : getAllChannels(expected.buckets[i])) {
+ expectedChannels.add(channel.frequency);
+ }
+ Set<Integer> actualChannels = new HashSet<>();
+ for (ChannelSpec channel : getAllChannels(actual.buckets[i])) {
+ actualChannels.add(channel.frequency);
+ }
+ assertEquals("channels", expectedChannels, actualChannels);
+ } else {
+ assertEquals("buckets[" + i + "].num_channels", 0, actual.buckets[i].num_channels);
+ assertTrue("buckets[" + i + "].channels",
+ actual.buckets[i].channels == null
+ || actual.buckets[i].channels.length == 0);
+ }
+ }
+ }
+
+ public static ChannelSpec[] getAllChannels(WifiNative.BucketSettings bucket) {
if (bucket.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
ChannelSpec[] channels = new ChannelSpec[bucket.num_channels];
for (int i = 0; i < bucket.num_channels; i++) {
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java
index b08e52dc8..94b9dc330 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantWifiScannerTest.java
@@ -22,7 +22,6 @@ import static com.android.server.wifi.ScanTestUtil.createFreqSet;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
@@ -32,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.Set;
@@ -53,15 +50,6 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
public void setup() throws Exception {
mScanner = new SupplicantWifiScannerImpl(mContext, WifiNative.getWlanNativeInterface(),
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
@@ -332,7 +320,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// All scans fail
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(false);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(false);
// Start scan
mScanner.startBatchedScan(settings, eventHandler);
@@ -367,7 +355,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// All scan starts succeed
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// Start scan
mScanner.startBatchedScan(settings, eventHandler);
@@ -412,7 +400,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// All scan starts succeed
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// Start scan
mScanner.startBatchedScan(settings, eventHandler);
@@ -467,7 +455,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// All scan starts succeed
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// Start scan
mScanner.startBatchedScan(settings, eventHandler);
@@ -477,8 +465,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
// alarm for next period
assertEquals(1, mAlarmManager.getPendingCount());
- order.verify(mWifiNative).scan(eq(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP),
- eq(expectedPeriods[0].getScanFreqs()));
+ order.verify(mWifiNative).scan(eq(expectedPeriods[0].getScanFreqs()));
mScanner.pauseBatchedScan();
@@ -544,7 +531,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// All scan starts succeed
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// Start scan
mScanner.startBatchedScan(settings, eventHandler);
@@ -583,7 +570,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
InOrder order = inOrder(eventHandler, mWifiNative);
// All scans succeed
- when(mWifiNative.scan(anyInt(), any(Set.class))).thenReturn(true);
+ when(mWifiNative.scan(any(Set.class))).thenReturn(true);
// Start scan
mScanner.startBatchedScan(settings, eventHandler);
@@ -643,7 +630,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
ArrayList<ScanDetail> nativeResults, WifiScanner.ScanData[] expectedScanResults,
ScanResult[] fullResults, int periodId) {
// Verify scan started
- order.verify(mWifiNative).scan(eq(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP), eq(scanFreqs));
+ order.verify(mWifiNative).scan(eq(scanFreqs));
// Setup scan results
when(mWifiNative.getScanResults()).thenReturn(nativeResults);
@@ -660,7 +647,7 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
if (expectedScanResults != null) {
// Verify scan results delivered
- order.verify(eventHandler).onScanStatus();
+ order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
assertScanDatasEquals("period[" + periodId + "].", expectedScanResults,
mScanner.getLatestBatchedScanResults(true));
}
@@ -669,22 +656,26 @@ public class SupplicantWifiScannerTest extends BaseWifiScannerImplTest {
private void expectFailedScanStart(InOrder order, WifiNative.ScanEventHandler eventHandler,
Set<Integer> scanFreqs) {
// Verify scan started
- order.verify(mWifiNative).scan(eq(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP), eq(scanFreqs));
+ order.verify(mWifiNative).scan(eq(scanFreqs));
+
+ // TODO verify failure event
}
private void expectFailedEventScan(InOrder order, WifiNative.ScanEventHandler eventHandler,
Set<Integer> scanFreqs) {
// Verify scan started
- order.verify(mWifiNative).scan(eq(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP), eq(scanFreqs));
+ order.verify(mWifiNative).scan(eq(scanFreqs));
// Notify scan has failed
mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_FAILED_EVENT);
assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
+
+ // TODO verify failure event
}
private void dispatchOnlyAlarm() {
assertEquals("dispatch only one alarm", 1, mAlarmManager.dispatchAll());
- assertEquals("dispatch only one message", 1, mLooper.dispatchAll());
+ mLooper.dispatchAll();
}
private static class ScanPeriod {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
index 4093936b6..42d89525a 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
@@ -16,12 +16,21 @@
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.createSingleScanNativeSettings;
import static com.android.server.wifi.ScanTestUtil.installWlanWifiNative;
import static com.android.server.wifi.ScanTestUtil.setupMockChannels;
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.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.validateMockitoUsage;
@@ -48,6 +57,7 @@ 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;
@@ -89,13 +99,16 @@ public class WifiScanningServiceTest {
}
- ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
+ /**
+ * Internal BroadcastReceiver that WifiScanningServiceImpl uses to listen for broadcasts
+ * this is initialized by calling startServiceAndLoadDriver
+ */
+ BroadcastReceiver mBroadcastReceiver;
private void sendWifiScanAvailable(int scanAvailable) {
Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, scanAvailable);
- mBroadcastReceiverCaptor.getValue().onReceive(mContext, intent);
+ mBroadcastReceiver.onReceive(mContext, intent);
}
private WifiScanner.ScanSettings generateValidScanSettings() {
@@ -112,45 +125,96 @@ public class WifiScanningServiceTest {
return controlChannel;
}
- private Message sendRequest(BidirectionalAsyncChannel controlChannel, Handler handler,
- Message msg) {
- controlChannel.sendMessage(msg);
- mLooper.dispatchAll();
+ private Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler) {
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
- verify(handler).handleMessage(messageCaptor.capture());
+ order.verify(handler).handleMessage(messageCaptor.capture());
return messageCaptor.getValue();
}
- private void sendAndAssertSuccessfulyBackgroundScan(BidirectionalAsyncChannel controlChannel,
- Handler handler, int scanRequestId, WifiScanner.ScanSettings settings) {
- Message response = sendRequest(controlChannel, handler,
- Message.obtain(null, WifiScanner.CMD_START_BACKGROUND_SCAN, 0, scanRequestId,
- settings));
- assertEquals("response.what", WifiScanner.CMD_OP_SUCCEEDED, response.what);
- assertEquals("response.arg2", scanRequestId, response.arg2);
- assertEquals("response.obj", null, response.obj);
+ private void verifyScanResultsRecieved(InOrder order, Handler handler, int listenerId,
+ WifiScanner.ScanData... expected) {
+ Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler);
+ assertScanResultsMessage(listenerId, expected, scanResultMessage);
+ }
+
+ private void assertScanResultsMessage(int listenerId, WifiScanner.ScanData[] expected,
+ Message scanResultMessage) {
+ assertEquals("what", WifiScanner.CMD_SCAN_RESULT, scanResultMessage.what);
+ assertEquals("listenerId", listenerId, scanResultMessage.arg2);
+ assertScanDatasEquals(expected,
+ ((WifiScanner.ParcelableScanData) scanResultMessage.obj).getResults());
+ }
+
+ 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);
+ }
+
+ private void assertSuccessfulResponse(int arg2, Message response) {
+ if (response.what == WifiScanner.CMD_OP_FAILED) {
+ WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj;
+ fail("response indicates failure, reason=" + result.reason
+ + ", description=" + result.description);
+ } else {
+ assertEquals("response.what", WifiScanner.CMD_OP_SUCCEEDED, response.what);
+ assertEquals("response.arg2", arg2, response.arg2);
+ }
}
- private void sendAndAssertFailedBackgroundScan(BidirectionalAsyncChannel controlChannel,
- Handler handler, int scanRequestId, WifiScanner.ScanSettings settings,
+ private void verifyFailedResponse(InOrder order, Handler handler, int arg2,
int expectedErrorReason, String expectedErrorDescription) {
- Message response = sendRequest(controlChannel, handler,
- Message.obtain(null, WifiScanner.CMD_START_BACKGROUND_SCAN, 0, scanRequestId,
- settings));
- assertFailedResponse(scanRequestId, expectedErrorReason, expectedErrorDescription,
- response);
+ Message response = verifyHandleMessageAndGetMessage(order, handler);
+ assertFailedResponse(arg2, expectedErrorReason, expectedErrorDescription, response);
}
private void assertFailedResponse(int arg2, int expectedErrorReason,
String expectedErrorDescription, Message response) {
- assertEquals("response.what", WifiScanner.CMD_OP_FAILED, response.what);
- assertEquals("response.arg2", arg2, response.arg2);
- assertEquals("response.obj.reason",
- expectedErrorReason, ((WifiScanner.OperationResult) response.obj).reason);
- assertEquals("response.obj.description",
- expectedErrorDescription, ((WifiScanner.OperationResult) response.obj).description);
+ if (response.what == WifiScanner.CMD_OP_SUCCEEDED) {
+ fail("response indicates success");
+ } else {
+ assertEquals("response.what", WifiScanner.CMD_OP_FAILED, response.what);
+ assertEquals("response.arg2", arg2, response.arg2);
+ WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj;
+ assertEquals("response.obj.reason",
+ expectedErrorReason, result.reason);
+ assertEquals("response.obj.description",
+ expectedErrorDescription, result.description);
+ }
}
+ 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);
+ order.verify(mWifiScannerImpl).startBatchedScan(scanSettingsCaptor.capture(),
+ any(WifiNative.ScanEventHandler.class));
+ 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)))
@@ -158,7 +222,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;
@@ -166,8 +230,12 @@ public class WifiScanningServiceTest {
return true;
}
});
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
verify(mContext)
- .registerReceiver(mBroadcastReceiverCaptor.capture(), any(IntentFilter.class));
+ .registerReceiver(broadcastReceiverCaptor.capture(), any(IntentFilter.class));
+ mBroadcastReceiver = broadcastReceiverCaptor.getValue();
+
sendWifiScanAvailable(WifiManager.WIFI_STATE_ENABLED);
mLooper.dispatchAll();
}
@@ -185,8 +253,10 @@ public class WifiScanningServiceTest {
Handler handler = mock(Handler.class);
BidirectionalAsyncChannel controlChannel = connectChannel(handler);
- sendAndAssertFailedBackgroundScan(controlChannel, handler, 122, generateValidScanSettings(),
- WifiScanner.REASON_UNSPECIFIED, "not available");
+ InOrder order = inOrder(handler);
+ sendBackgroundScanRequest(controlChannel, 122, generateValidScanSettings());
+ mLooper.dispatchAll();
+ verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available");
}
@Test
@@ -196,10 +266,12 @@ public class WifiScanningServiceTest {
Handler handler = mock(Handler.class);
BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler);
when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
any(WifiNative.ScanEventHandler.class))).thenReturn(true);
- sendAndAssertSuccessfulyBackgroundScan(controlChannel, handler, 192,
- generateValidScanSettings());
+ sendBackgroundScanRequest(controlChannel, 192, generateValidScanSettings());
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, 192);
}
@Test
@@ -208,9 +280,368 @@ public class WifiScanningServiceTest {
Handler handler = mock(Handler.class);
BidirectionalAsyncChannel controlChannel = connectChannel(handler);
- Message response = sendRequest(controlChannel, handler,
- Message.obtain(null, Protocol.BASE_WIFI_MANAGER));
- assertFailedResponse(0, WifiScanner.REASON_INVALID_REQUEST, "Invalid request", response);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+ controlChannel.sendMessage(Message.obtain(null, Protocol.BASE_WIFI_MANAGER));
+ mLooper.dispatchAll();
+ 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, 12, results.getScanData());
+ verifyNoMoreInteractions(handler);
+ }
+
+ @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));
+ }
+
+ @Test
+ public void sendSingleScanChannelsRequest() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
+ ScanResults.create(0, 2400, 2400, 2400));
}
+ @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));
+ }
+
+ @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_DISABLED);
+ mLooper.dispatchAll();
+ verifyFailedResponse(order, handler, requestId,
+ WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted");
+ }
+
+ // TODO Add more single scan tests
+ // * disable wifi while scanning
+ // * disable wifi while scanning with pending scan
+
+ @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());
+
+ // 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());
+ }
+
+ @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());
+
+ // 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());
+ }
+
+
+
+ @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 = createSingleScanNativeSettings(
+ 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());
+
+ // 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(2)).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));
+ assertScanResultsMessage(requestId3,
+ new WifiScanner.ScanData[] {results3.getScanData()},
+ messageCaptor.getAllValues().get(1));
+ } else {
+ assertScanResultsMessage(requestId3,
+ new WifiScanner.ScanData[] {results3.getScanData()},
+ messageCaptor.getAllValues().get(0));
+ assertScanResultsMessage(requestId2,
+ new WifiScanner.ScanData[] {results2.getScanData()},
+ messageCaptor.getAllValues().get(1));
+ }
+ }
+
+ 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);
+ }
+
+ @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);
+ }
+
+ @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 c092f0d79..096a7397e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -41,6 +41,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;
@@ -73,6 +74,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.Mockito;
import org.mockito.MockitoAnnotations;
@@ -83,6 +85,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -192,6 +195,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;
}
@@ -256,16 +261,20 @@ 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 */);
+ detail.getScanResult().informationElements = ie;
+ detail.getScanResult().anqpLines = new ArrayList<String>();
return detail;
}
- private ArrayList<ScanDetail> getMockScanResults() {
+ private ScanResult[] getMockScanResults() {
ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825);
- ArrayList<ScanDetail> list = sr.getScanDetailArrayList();
+ // copy generated results and add space on the end for one more
+ ScanResult[] results = Arrays.copyOf(sr.getScanData().getResults(),
+ sr.getScanData().getResults().length + 1);
int rssi = -65;
- list.add(getGoogleGuestScanDetail(rssi));
- return list;
+ results[results.length - 1] = getGoogleGuestScanDetail(rssi).getScanResult();
+ return results;
}
static final String sSSID = "\"GoogleGuest\"";
@@ -283,6 +292,7 @@ public class WifiStateMachineTest {
MockWifiMonitor mWifiMonitor;
@Mock WifiNative mWifiNative;
+ @Mock WifiScanner mWifiScanner;
@Mock SupplicantStateTracker mSupplicantStateTracker;
@Mock WifiMetrics mWifiMetrics;
@@ -510,14 +520,27 @@ public class WifiStateMachineTest {
mWsm.startScan(-1, 0, null, null);
wait(200);
- verify(mWifiNative).scan(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null);
-
- when(mWifiNative.getScanResults()).thenReturn(getMockScanResults());
- mWsm.sendMessage(WifiMonitor.SCAN_RESULTS_EVENT);
+ 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());
+ assertEquals("band", WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
+ scanSettingsCaptor.getValue().band);
+ assertEquals("reportEvents", WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
+ | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
+ scanSettingsCaptor.getValue().reportEvents);
+
+ ScanResult[] results = getMockScanResults();
+ for (ScanResult result : results) {
+ scanListenerCaptor.getValue().onFullResult(result);
+ }
+ scanListenerCaptor.getValue().onResults(
+ new WifiScanner.ScanData[] {new WifiScanner.ScanData(0, 0, results)});
wait(200);
- List<ScanResult> results = mWsm.syncGetScanResultsList();
- assertEquals(8, results.size());
+ List<ScanResult> reportedResults = mWsm.syncGetScanResultsList();
+ assertEquals(8, reportedResults.size());
}
@Test