summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2016-03-28 17:51:57 -0700
committerRoshan Pius <rpius@google.com>2016-03-30 17:00:21 -0700
commitc343aec32e1d3fe320eb97c527b0bcfb2d334e45 (patch)
tree6cb94c5c0fb8b46493e98d435a0492103ef9819f
parenta91494208927643d011b4fa62db2064d9e8228c1 (diff)
WifiScanningServiceImpl: Create PNO state machine
Adding a PNO state machine to fetch full scan results for all types of PNO when reporting events back to the client. BUG: 27886011 TEST: Compiles & unit-test passes TEST: Made changes in WifiConnectivityManager to use the scan results to auto-connect. Change-Id: I18879cb1bf82226e329c6076e8443e0986ddbe27
-rw-r--r--service/java/com/android/server/wifi/WifiScanningServiceImpl.java655
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanResults.java25
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java66
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java298
4 files changed, 849 insertions, 195 deletions
diff --git a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
index 7619b7024..9320f4101 100644
--- a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java
@@ -198,12 +198,14 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
switch (msg.what) {
case WifiScanner.CMD_START_BACKGROUND_SCAN:
case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
- case WifiScanner.CMD_START_PNO_SCAN:
- case WifiScanner.CMD_STOP_PNO_SCAN:
case WifiScanner.CMD_SET_HOTLIST:
case WifiScanner.CMD_RESET_HOTLIST:
mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
break;
+ case WifiScanner.CMD_START_PNO_SCAN:
+ case WifiScanner.CMD_STOP_PNO_SCAN:
+ mPnoScanStateMachine.sendMessage(Message.obtain(msg));
+ break;
case WifiScanner.CMD_START_SINGLE_SCAN:
case WifiScanner.CMD_STOP_SINGLE_SCAN:
mSingleScanStateMachine.sendMessage(Message.obtain(msg));
@@ -248,6 +250,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private WifiBackgroundScanStateMachine mBackgroundScanStateMachine;
private WifiSingleScanStateMachine mSingleScanStateMachine;
private WifiChangeStateMachine mWifiChangeStateMachine;
+ private WifiPnoScanStateMachine mPnoScanStateMachine;
private ClientHandler mClientHandler;
private final IBatteryStats mBatteryStats;
private final AlarmManager mAlarmManager;
@@ -271,6 +274,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper);
mWifiChangeStateMachine = new WifiChangeStateMachine(mLooper);
mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
+ mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper);
mContext.registerReceiver(
new BroadcastReceiver() {
@@ -282,9 +286,11 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
if (state == WifiManager.WIFI_STATE_ENABLED) {
mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
+ mPnoScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
+ mPnoScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
}
}
}, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));
@@ -292,6 +298,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mBackgroundScanStateMachine.start();
mWifiChangeStateMachine.start();
mSingleScanStateMachine.start();
+ mPnoScanStateMachine.start();
}
/**
@@ -687,8 +694,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
class WifiBackgroundScanStateMachine extends StateMachine
- implements WifiNative.ScanEventHandler, WifiNative.HotlistEventHandler,
- WifiNative.PnoEventHandler {
+ implements WifiNative.ScanEventHandler, WifiNative.HotlistEventHandler {
private final DefaultState mDefaultState = new DefaultState();
private final StartedState mStartedState = new StartedState();
@@ -710,8 +716,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
return settings;
}
};
- private final ClientHandlerMap<PnoSettings> mActivePnoScans =
- new ClientHandlerMap<>();
private final ClientHandlerMap<WifiScanner.HotlistSettings> mActiveHotlistSettings =
new ClientHandlerMap<>();
@@ -796,23 +800,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
sendMessage(CMD_HOTLIST_AP_LOST, 0, 0, results);
}
- @Override
- public void onPnoNetworkFound(ScanResult[] results) {
- if (DBG) localLog("onWifiPnoNetworkFound event received");
- sendMessage(CMD_PNO_NETWORK_FOUND, 0, 0, results);
- }
-
- @Override
- public void onPnoScanFailed() {
- if (DBG) localLog("onWifiPnoScanFailed event received");
- sendMessage(CMD_PNO_SCAN_FAILED, 0, 0, null);
- }
-
class DefaultState extends State {
@Override
public void enter() {
if (DBG) localLog("DefaultState");
- mActivePnoScans.clear();
mActiveBackgroundScans.clear();
mActiveHotlistSettings.clear();
}
@@ -851,8 +842,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
break;
case WifiScanner.CMD_START_BACKGROUND_SCAN:
case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
- case WifiScanner.CMD_START_PNO_SCAN:
- case WifiScanner.CMD_STOP_PNO_SCAN:
case WifiScanner.CMD_START_SINGLE_SCAN:
case WifiScanner.CMD_STOP_SINGLE_SCAN:
case WifiScanner.CMD_SET_HOTLIST:
@@ -886,8 +875,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
@Override
public void exit() {
- sendPnoScanFailedToAllAndClear(
- WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted");
sendBackgroundScanFailedToAllAndClear(
WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted");
sendHotlistFailedToAllAndClear(
@@ -921,23 +908,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
removeBackgroundScanRequest(ci, msg.arg2);
break;
- case WifiScanner.CMD_START_PNO_SCAN: {
- mWifiMetrics.incrementBackgroundScanCount();
- Bundle pnoParams = (Bundle) msg.obj;
- PnoSettings pnoSettings =
- pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY);
- ScanSettings scanSettings =
- pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY);
- if (addScanRequestForPno(ci, msg.arg2, scanSettings, pnoSettings)) {
- replySucceeded(msg);
- } else {
- replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
- }
- break;
- }
- case WifiScanner.CMD_STOP_PNO_SCAN:
- removeScanRequestForPno(ci, msg.arg2);
- break;
case WifiScanner.CMD_GET_SCAN_RESULTS:
reportScanResults(mScannerImpl.getLatestBatchedScanResults(true));
replySucceeded(msg);
@@ -970,14 +940,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
sendBackgroundScanFailedToAllAndClear(
WifiScanner.REASON_UNSPECIFIED, "Background Scan failed");
break;
- case CMD_PNO_NETWORK_FOUND:
- ScanResult[] results = (ScanResult[]) msg.obj;
- reportPnoNetworkFound(results);
- break;
- case CMD_PNO_SCAN_FAILED:
- sendPnoScanFailedToAllAndClear(
- WifiScanner.REASON_UNSPECIFIED, "Pno Scan start failed");
- break;
default:
return NOT_HANDLED;
}
@@ -1169,17 +1131,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
ScanData[] resultsToDeliver =
mScheduler.filterResultsForSettings(results, settings);
if (resultsToDeliver != null) {
- // If this background scan was started for PNO scan, the last scan data should
- // be reported as a PNO network found event.
- if (settings.isPnoScan) {
- ScanData lastScanData = resultsToDeliver[resultsToDeliver.length - 1];
- reportPnoNetworkFound(lastScanData.getResults());
- } else {
- logCallback("backgroundScanResults", ci, handler);
- WifiScanner.ParcelableScanData parcelableScanData =
- new WifiScanner.ParcelableScanData(resultsToDeliver);
- ci.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData);
- }
+ logCallback("backgroundScanResults", ci, handler);
+ WifiScanner.ParcelableScanData parcelableScanData =
+ new WifiScanner.ParcelableScanData(resultsToDeliver);
+ ci.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData);
}
}
}
@@ -1194,108 +1149,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mActiveBackgroundScans.clear();
}
- private WifiNative.PnoSettings convertPnoSettingsToNative(PnoSettings pnoSettings) {
- WifiNative.PnoSettings nativePnoSetting = new WifiNative.PnoSettings();
- nativePnoSetting.min5GHzRssi = pnoSettings.min5GHzRssi;
- nativePnoSetting.min24GHzRssi = pnoSettings.min24GHzRssi;
- nativePnoSetting.initialScoreMax = pnoSettings.initialScoreMax;
- nativePnoSetting.currentConnectionBonus = pnoSettings.currentConnectionBonus;
- nativePnoSetting.sameNetworkBonus = pnoSettings.sameNetworkBonus;
- nativePnoSetting.secureBonus = pnoSettings.secureBonus;
- nativePnoSetting.band5GHzBonus = pnoSettings.band5GHzBonus;
- nativePnoSetting.isConnected = pnoSettings.isConnected;
- nativePnoSetting.networkList =
- new WifiNative.PnoNetwork[pnoSettings.networkList.length];
- for (int i = 0; i < pnoSettings.networkList.length; i++) {
- nativePnoSetting.networkList[i] = new WifiNative.PnoNetwork();
- nativePnoSetting.networkList[i].ssid = pnoSettings.networkList[i].ssid;
- nativePnoSetting.networkList[i].networkId = pnoSettings.networkList[i].networkId;
- nativePnoSetting.networkList[i].priority = pnoSettings.networkList[i].priority;
- nativePnoSetting.networkList[i].flags = pnoSettings.networkList[i].flags;
- nativePnoSetting.networkList[i].auth_bit_field =
- pnoSettings.networkList[i].authBitField;
- }
- return nativePnoSetting;
- }
-
- private boolean addScanRequestForPno(ClientInfo ci, int handler, ScanSettings scanSettings,
- PnoSettings pnoSettings) {
- if (ci == null) {
- Log.d(TAG, "Failing scan request ClientInfo not found " + handler);
- return false;
- }
-
- boolean shouldScheduleBackgroundScan;
- if (mScannerImpl.isHwPnoSupported(pnoSettings.isConnected)) {
- WifiNative.PnoSettings nativePnoSettings = convertPnoSettingsToNative(pnoSettings);
- if (!mScannerImpl.setHwPnoList(nativePnoSettings, mBackgroundScanStateMachine)) {
- return false;
- }
- // HW PNO is supported, check if we need a background scan running for this.
- shouldScheduleBackgroundScan = mScannerImpl.shouldScheduleBackgroundScanForHwPno();
-
- } else {
- // HW PNO is not supported, we need to revert to normal background scans and
- // report events after each scan.
- scanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
- shouldScheduleBackgroundScan = true;
- }
- // We need to schedule a background scan either because HW PNO requires background
- // scan or if there is no HW PNO scan support.
- if (shouldScheduleBackgroundScan) {
- if (!addBackgroundScanRequest(ci, handler, scanSettings, null)) {
- loge("Background scan request for PNO failed.");
- return false;
- }
- }
-
- logScanRequest("addPnoScanRequest", ci, handler, scanSettings, pnoSettings);
- mActivePnoScans.put(ci, handler, pnoSettings);
- return true;
- }
-
- private void removeScanRequestForPno(ClientInfo ci, int handler) {
- if (ci != null) {
- PnoSettings pnoSettings = mActivePnoScans.remove(ci, handler);
- logScanRequest("removePnoScanRequest", ci, handler, null, pnoSettings);
-
- boolean wasBackgroundScanScheduled;
- if (mScannerImpl.isHwPnoSupported(pnoSettings.isConnected)) {
- mScannerImpl.resetHwPnoList();
- wasBackgroundScanScheduled =
- mScannerImpl.shouldScheduleBackgroundScanForHwPno();
- } else {
- wasBackgroundScanScheduled = true;
- }
- if (wasBackgroundScanScheduled) {
- removeBackgroundScanRequest(ci, handler);
- }
- }
- }
-
- private void reportPnoNetworkFound(ScanResult[] results) {
- WifiScanner.ParcelableScanResults parcelableScanResults =
- new WifiScanner.ParcelableScanResults(results);
- for (Map.Entry<Pair<ClientInfo, Integer>, PnoSettings> entry
- : mActivePnoScans.entrySet()) {
- ClientInfo ci = entry.getKey().first;
- int handler = entry.getKey().second;
- logCallback("pnoNetworkFound", ci, handler);
- ci.reportEvent(
- WifiScanner.CMD_PNO_NETWORK_FOUND, 0, handler, parcelableScanResults);
- }
- }
-
- private void sendPnoScanFailedToAllAndClear(int reason, String description) {
- for (Pair<ClientInfo, Integer> key : mActivePnoScans.keySet()) {
- ClientInfo ci = key.first;
- int handler = key.second;
- ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler,
- new WifiScanner.OperationResult(reason, description));
- }
- mActivePnoScans.clear();
- }
-
private void addHotlist(ClientInfo ci, int handler, WifiScanner.HotlistSettings settings) {
mActiveHotlistSettings.put(ci, handler, settings);
resetHotlist();
@@ -1384,6 +1237,463 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
}
+ /**
+ * PNO scan state machine has 5 states:
+ * -Default State
+ * -Started State
+ * -Hw Pno Scan state
+ * -Single Scan state
+ * -Sw Pno Scan state
+ *
+ * These are the main state transitions:
+ * 1. Start at |Default State|
+ * 2. Move to |Started State| when we get the |WIFI_SCAN_AVAILABLE| broadcast from WifiManager.
+ * 3. When a new PNO scan request comes in:
+ * a.1. Switch to |Hw Pno Scan state| when the device supports HW PNO
+ * (This could either be HAL based ePNO or supplicant based PNO).
+ * a.2. In |Hw Pno Scan state| when PNO scan results are received, check if the result
+ * contains IE (information elements). If yes, send the results to the client, else
+ * switch to |Single Scan state| and send the result to the client when the scan result
+ * is obtained.
+ * b.1. Switch to |Sw Pno Scan state| when the device does not supports HW PNO
+ * (This is for older devices which do not support HW PNO and for connected PNO on
+ * devices which support supplicant based PNO)
+ * b.2. In |Sw Pno Scan state| send the result to the client when the background scan result
+ * is obtained
+ *
+ * Note: PNO scans only work for a single client today. We don't have support in HW to support
+ * multiple requests at the same time, so will need non-trivial changes to support (if at all
+ * possible) in WifiScanningService.
+ */
+ class WifiPnoScanStateMachine extends StateMachine implements WifiNative.PnoEventHandler {
+
+ private final DefaultState mDefaultState = new DefaultState();
+ private final StartedState mStartedState = new StartedState();
+ private final HwPnoScanState mHwPnoScanState = new HwPnoScanState();
+ private final SwPnoScanState mSwPnoScanState = new SwPnoScanState();
+ private final SingleScanState mSingleScanState = new SingleScanState();
+ private InternalClientInfo mInternalClientInfo;
+
+ private final ClientHandlerMap<Pair<PnoSettings, ScanSettings>> mActivePnoScans =
+ new ClientHandlerMap<>();
+
+ WifiPnoScanStateMachine(Looper looper) {
+ super(TAG, looper);
+
+ setLogRecSize(512);
+ setLogOnlyTransitions(false);
+
+ // CHECKSTYLE:OFF IndentationCheck
+ addState(mDefaultState);
+ addState(mStartedState, mDefaultState);
+ addState(mHwPnoScanState, mStartedState);
+ addState(mSingleScanState, mHwPnoScanState);
+ addState(mSwPnoScanState, mStartedState);
+ // CHECKSTYLE:ON IndentationCheck
+
+ setInitialState(mDefaultState);
+ }
+
+ public void removePnoSettings(ClientInfo ci) {
+ mActivePnoScans.removeAll(ci);
+ removeInternalClientOnEmpty();
+ transitionTo(mStartedState);
+ }
+
+ @Override
+ public void onPnoNetworkFound(ScanResult[] results) {
+ if (DBG) localLog("onWifiPnoNetworkFound event received");
+ sendMessage(CMD_PNO_NETWORK_FOUND, 0, 0, results);
+ }
+
+ @Override
+ public void onPnoScanFailed() {
+ if (DBG) localLog("onWifiPnoScanFailed event received");
+ sendMessage(CMD_PNO_SCAN_FAILED, 0, 0, null);
+ }
+
+ class DefaultState extends State {
+ @Override
+ public void enter() {
+ if (DBG) localLog("DefaultState");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_DRIVER_LOADED:
+ transitionTo(mStartedState);
+ break;
+ case CMD_DRIVER_UNLOADED:
+ transitionTo(mDefaultState);
+ break;
+ case WifiScanner.CMD_START_PNO_SCAN:
+ case WifiScanner.CMD_STOP_PNO_SCAN:
+ replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available");
+ break;
+ case CMD_PNO_NETWORK_FOUND:
+ case CMD_PNO_SCAN_FAILED:
+ case WifiScanner.CMD_SCAN_RESULT:
+ case WifiScanner.CMD_OP_FAILED:
+ loge("Unexpected message " + msg.what);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class StartedState extends State {
+ @Override
+ public void enter() {
+ if (DBG) localLog("StartedState");
+ }
+
+ @Override
+ public void exit() {
+ sendPnoScanFailedToAllAndClear(
+ WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ ClientInfo ci = mClients.get(msg.replyTo);
+ switch (msg.what) {
+ case WifiScanner.CMD_START_PNO_SCAN:
+ Bundle pnoParams = (Bundle) msg.obj;
+ PnoSettings pnoSettings =
+ pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY);
+ // This message is handled after the transition to SwPnoScan/HwPnoScan state
+ deferMessage(msg);
+ if (mScannerImpl.isHwPnoSupported(pnoSettings.isConnected)) {
+ transitionTo(mHwPnoScanState);
+ } else {
+ transitionTo(mSwPnoScanState);
+ }
+ break;
+ case WifiScanner.CMD_STOP_PNO_SCAN:
+ replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "no scan running");
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class HwPnoScanState extends State {
+ @Override
+ public void enter() {
+ if (DBG) localLog("HwPnoScanState");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ ClientInfo ci = mClients.get(msg.replyTo);
+ switch (msg.what) {
+ case WifiScanner.CMD_START_PNO_SCAN:
+ Bundle pnoParams = (Bundle) msg.obj;
+ PnoSettings pnoSettings =
+ pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY);
+ ScanSettings scanSettings =
+ pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY);
+ if (addHwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) {
+ replySucceeded(msg);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ transitionTo(mStartedState);
+ }
+ break;
+ case WifiScanner.CMD_STOP_PNO_SCAN:
+ removeHwPnoScanRequest(ci, msg.arg2);
+ transitionTo(mStartedState);
+ break;
+ case CMD_PNO_NETWORK_FOUND:
+ ScanResult[] scanResults = ((ScanResult[]) msg.obj);
+ if (isSingleScanNeeded(scanResults)) {
+ addSingleScanRequest(getScanSettings());
+ transitionTo(mSingleScanState);
+ } else {
+ reportPnoNetworkFound((ScanResult[]) msg.obj);
+ }
+ break;
+ case CMD_PNO_SCAN_FAILED:
+ sendPnoScanFailedToAllAndClear(
+ WifiScanner.REASON_UNSPECIFIED, "pno scan failed");
+ transitionTo(mStartedState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class SingleScanState extends State {
+ @Override
+ public void enter() {
+ if (DBG) localLog("SingleScanState");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ ClientInfo ci = mClients.get(msg.replyTo);
+ switch (msg.what) {
+ case WifiScanner.CMD_SCAN_RESULT:
+ WifiScanner.ParcelableScanData parcelableScanData =
+ (WifiScanner.ParcelableScanData) msg.obj;
+ ScanData[] scanDatas = parcelableScanData.getResults();
+ ScanData lastScanData = scanDatas[scanDatas.length - 1];
+ reportPnoNetworkFound(lastScanData.getResults());
+ transitionTo(mHwPnoScanState);
+ break;
+ case WifiScanner.CMD_OP_FAILED:
+ sendPnoScanFailedToAllAndClear(
+ WifiScanner.REASON_UNSPECIFIED, "single scan failed");
+ transitionTo(mStartedState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class SwPnoScanState extends State {
+ private final ArrayList<ScanResult> mSwPnoFullScanResults = new ArrayList<>();
+
+ @Override
+ public void enter() {
+ if (DBG) localLog("SwPnoScanState");
+ mSwPnoFullScanResults.clear();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ ClientInfo ci = mClients.get(msg.replyTo);
+ switch (msg.what) {
+ case WifiScanner.CMD_START_PNO_SCAN:
+ Bundle pnoParams = (Bundle) msg.obj;
+ PnoSettings pnoSettings =
+ pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY);
+ ScanSettings scanSettings =
+ pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY);
+ if (addSwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) {
+ replySucceeded(msg);
+ } else {
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ transitionTo(mStartedState);
+ }
+ break;
+ case WifiScanner.CMD_STOP_PNO_SCAN:
+ removeSwPnoScanRequest(ci, msg.arg2);
+ transitionTo(mStartedState);
+ break;
+ case WifiScanner.CMD_FULL_SCAN_RESULT:
+ // Aggregate full scan results until we get the |CMD_SCAN_RESULT| message
+ mSwPnoFullScanResults.add((ScanResult) msg.obj);
+ break;
+ case WifiScanner.CMD_SCAN_RESULT:
+ ScanResult[] scanResults = mSwPnoFullScanResults.toArray(
+ new ScanResult[mSwPnoFullScanResults.size()]);
+ reportPnoNetworkFound(scanResults);
+ mSwPnoFullScanResults.clear();
+ break;
+ case WifiScanner.CMD_OP_FAILED:
+ sendPnoScanFailedToAllAndClear(
+ WifiScanner.REASON_UNSPECIFIED, "background scan failed");
+ transitionTo(mStartedState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ private WifiNative.PnoSettings convertPnoSettingsToNative(PnoSettings pnoSettings) {
+ WifiNative.PnoSettings nativePnoSetting = new WifiNative.PnoSettings();
+ nativePnoSetting.min5GHzRssi = pnoSettings.min5GHzRssi;
+ nativePnoSetting.min24GHzRssi = pnoSettings.min24GHzRssi;
+ nativePnoSetting.initialScoreMax = pnoSettings.initialScoreMax;
+ nativePnoSetting.currentConnectionBonus = pnoSettings.currentConnectionBonus;
+ nativePnoSetting.sameNetworkBonus = pnoSettings.sameNetworkBonus;
+ nativePnoSetting.secureBonus = pnoSettings.secureBonus;
+ nativePnoSetting.band5GHzBonus = pnoSettings.band5GHzBonus;
+ nativePnoSetting.isConnected = pnoSettings.isConnected;
+ nativePnoSetting.networkList =
+ new WifiNative.PnoNetwork[pnoSettings.networkList.length];
+ for (int i = 0; i < pnoSettings.networkList.length; i++) {
+ nativePnoSetting.networkList[i] = new WifiNative.PnoNetwork();
+ nativePnoSetting.networkList[i].ssid = pnoSettings.networkList[i].ssid;
+ nativePnoSetting.networkList[i].networkId = pnoSettings.networkList[i].networkId;
+ nativePnoSetting.networkList[i].priority = pnoSettings.networkList[i].priority;
+ nativePnoSetting.networkList[i].flags = pnoSettings.networkList[i].flags;
+ nativePnoSetting.networkList[i].auth_bit_field =
+ pnoSettings.networkList[i].authBitField;
+ }
+ return nativePnoSetting;
+ }
+
+ // Retrieve the active PNO settings.
+ private PnoSettings getPnoSettings() {
+ return mActivePnoScans.entrySet().iterator().next().getValue().first;
+ }
+
+ // Retrieve the active scan settings.
+ private ScanSettings getScanSettings() {
+ return mActivePnoScans.entrySet().iterator().next().getValue().second;
+ }
+
+ private void removeInternalClientOnEmpty() {
+ if (mActivePnoScans.isEmpty()) {
+ if (mInternalClientInfo != null) {
+ mInternalClientInfo.cleanup();
+ mInternalClientInfo = null;
+ } else {
+ loge("No Internal client for PNO");
+ }
+ }
+ }
+
+ private void addInternalClient(ClientInfo ci) {
+ if (mInternalClientInfo == null) {
+ mInternalClientInfo =
+ new InternalClientInfo(ci.getUid(), new Messenger(this.getHandler()));
+ mInternalClientInfo.register();
+ } else {
+ loge("Internal client for PNO already exists");
+ }
+ }
+
+ private void addPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings,
+ PnoSettings pnoSettings) {
+ mActivePnoScans.put(ci, handler, Pair.create(pnoSettings, scanSettings));
+ addInternalClient(ci);
+ }
+
+ private Pair<PnoSettings, ScanSettings> removePnoScanRequest(ClientInfo ci, int handler) {
+ Pair<PnoSettings, ScanSettings> settings = mActivePnoScans.remove(ci, handler);
+ removeInternalClientOnEmpty();
+ return settings;
+ }
+
+ private boolean addHwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings,
+ PnoSettings pnoSettings) {
+ if (ci == null) {
+ Log.d(TAG, "Failing scan request ClientInfo not found " + handler);
+ return false;
+ }
+ if (!mActivePnoScans.isEmpty()) {
+ loge("Failing scan request because there is already an active scan");
+ return false;
+ }
+ WifiNative.PnoSettings nativePnoSettings = convertPnoSettingsToNative(pnoSettings);
+ if (!mScannerImpl.setHwPnoList(nativePnoSettings, mPnoScanStateMachine)) {
+ return false;
+ }
+ logScanRequest("addHwPnoScanRequest", ci, handler, scanSettings, pnoSettings);
+ addPnoScanRequest(ci, handler, scanSettings, pnoSettings);
+ // HW PNO is supported, check if we need a background scan running for this.
+ if (mScannerImpl.shouldScheduleBackgroundScanForHwPno()) {
+ addBackgroundScanRequest(scanSettings);
+ }
+ return true;
+ }
+
+ private void removeHwPnoScanRequest(ClientInfo ci, int handler) {
+ if (ci != null) {
+ mScannerImpl.resetHwPnoList();
+ Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler);
+ logScanRequest(
+ "removeHwPnoScanRequest", ci, handler, settings.second, settings.first);
+ }
+ }
+
+ private boolean addSwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings,
+ PnoSettings pnoSettings) {
+ if (ci == null) {
+ Log.d(TAG, "Failing scan request ClientInfo not found " + handler);
+ return false;
+ }
+ if (!mActivePnoScans.isEmpty()) {
+ loge("Failing scan request because there is already an active scan");
+ return false;
+ }
+ logScanRequest("addSwPnoScanRequest", ci, handler, scanSettings, pnoSettings);
+ addPnoScanRequest(ci, handler, scanSettings, pnoSettings);
+ // HW PNO is not supported, we need to revert to normal background scans and
+ // report events after each scan and we need full scan results to get the IE information
+ scanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
+ | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
+ addBackgroundScanRequest(scanSettings);
+ return true;
+ }
+
+ private void removeSwPnoScanRequest(ClientInfo ci, int handler) {
+ if (ci != null) {
+ Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler);
+ logScanRequest(
+ "removeSwPnoScanRequest", ci, handler, settings.second, settings.first);
+ }
+ }
+
+ private void reportPnoNetworkFound(ScanResult[] results) {
+ WifiScanner.ParcelableScanResults parcelableScanResults =
+ new WifiScanner.ParcelableScanResults(results);
+ for (Map.Entry<Pair<ClientInfo, Integer>, Pair<PnoSettings, ScanSettings>> entry
+ : mActivePnoScans.entrySet()) {
+ ClientInfo ci = entry.getKey().first;
+ int handler = entry.getKey().second;
+ logCallback("pnoNetworkFound", ci, handler);
+ ci.reportEvent(
+ WifiScanner.CMD_PNO_NETWORK_FOUND, 0, handler, parcelableScanResults);
+ }
+ }
+
+ private void sendPnoScanFailedToAllAndClear(int reason, String description) {
+ for (Pair<ClientInfo, Integer> key : mActivePnoScans.keySet()) {
+ ClientInfo ci = key.first;
+ int handler = key.second;
+ ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler,
+ new WifiScanner.OperationResult(reason, description));
+ }
+ mActivePnoScans.clear();
+ removeInternalClientOnEmpty();
+ }
+
+ private void addBackgroundScanRequest(ScanSettings settings) {
+ if (DBG) localLog("Starting background scan");
+ if (mInternalClientInfo != null) {
+ mInternalClientInfo.sendScanRequestToClientHandler(
+ WifiScanner.CMD_START_BACKGROUND_SCAN, settings);
+ }
+ }
+
+ private void addSingleScanRequest(ScanSettings settings) {
+ if (DBG) localLog("Starting single scan");
+ if (mInternalClientInfo != null) {
+ mInternalClientInfo.sendScanRequestToClientHandler(
+ WifiScanner.CMD_START_SINGLE_SCAN, settings);
+ }
+ }
+
+ /**
+ * Checks if IE are present in scan data, if no single scan is needed to report event to
+ * client
+ */
+ private boolean isSingleScanNeeded(ScanResult[] scanResults) {
+ for (ScanResult scanResult : scanResults) {
+ if (scanResult.informationElements != null
+ && scanResult.informationElements.length > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
private abstract class ClientInfo {
private final int mUid;
private final WorkSource mWorkSource;
@@ -1482,25 +1792,6 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
public String toString() {
return "ClientInfo[uid=" + mUid + "]";
}
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- StringBuilder sb = new StringBuilder();
- sb.append(toString());
-
- Map<Integer, ScanSettings> settingsMap =
- mBackgroundScanStateMachine.getBackgroundScanSettingsHandlerMap(this);
- Iterator<Map.Entry<Integer, ScanSettings>> it = settingsMap.entrySet().iterator();
- for (; it.hasNext(); ) {
- Map.Entry<Integer, ScanSettings> entry = it.next();
- sb.append("ScanId ").append(entry.getKey()).append("\n");
-
- ScanSettings scanSettings = entry.getValue();
- describeTo(sb, scanSettings);
- sb.append("\n");
- }
-
- pw.println(sb.toString());
- }
}
/**
@@ -1534,6 +1825,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
// only for external client because this will otherwise cause an infinite recursion
// when the internal client in WifiChangeStateMachine is cleaned up.
mWifiChangeStateMachine.removeWifiChangeHandler(this);
+ mPnoScanStateMachine.removePnoSettings(this);
super.cleanup();
}
}
@@ -1582,6 +1874,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
msg.obj = bundle;
}
msg.replyTo = mMessenger;
+ msg.sendingUid = getUid();
mClientHandler.sendMessage(msg);
}
@@ -2108,6 +2401,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
+ ChannelHelper.toString(bucket));
}
}
+ pw.println("PNO scan state machine transitions:");
+ mPnoScanStateMachine.dump(fd, pw, args);
}
void logScanRequest(String request, ClientInfo ci, int id, ScanSettings settings,
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanResults.java b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
index 9c452fb21..bc76d0f90 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanResults.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
@@ -95,7 +95,7 @@ public class ScanResults {
* to the returned scan details. Duplicates can be specified to create multiple
* ScanDetails with the same frequency.
*/
- private static ScanDetail[] generateNativeResults(int seed, int... freqs) {
+ private static ScanDetail[] generateNativeResults(boolean needIE, int seed, int... freqs) {
ScanDetail[] results = new ScanDetail[freqs.length];
// Seed the results based on the provided seed as well as the test method name
// This provides more varied scan results between individual tests that are very similar.
@@ -105,8 +105,13 @@ public class ScanResults {
String ssid = new BigInteger(128, r).toString(36);
String bssid = generateBssid(r);
int rssi = r.nextInt(40) - 99; // -99 to -60
- ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1];
- ie[0] = generateSsidIe(ssid);
+ ScanResult.InformationElement[] ie;
+ if (needIE) {
+ ie = new ScanResult.InformationElement[1];
+ ie[0] = generateSsidIe(ssid);
+ } else {
+ ie = new ScanResult.InformationElement[0];
+ }
List<String> anqpLines = new ArrayList<>();
NetworkDetail nd = new NetworkDetail(bssid, ie, anqpLines, freq);
ScanDetail detail = new ScanDetail(nd, WifiSsid.createFromAsciiEncoded(ssid),
@@ -120,6 +125,13 @@ public class ScanResults {
}
/**
+ * Create scan results with no IE information.
+ */
+ private static ScanDetail[] generateNativeResults(int seed, int... freqs) {
+ return generateNativeResults(true, seed, freqs);
+ }
+
+ /**
* Create a ScanResults with randomly generated results seeded by the id.
* @see #generateNativeResults for more details on how results are generated
*/
@@ -128,6 +140,13 @@ public class ScanResults {
}
/**
+ * Create a ScanResults with no IE information.
+ */
+ public static ScanResults createWithNoIE(int id, int... freqs) {
+ return new ScanResults(id, -1, generateNativeResults(false, id, freqs));
+ }
+
+ /**
* Create a ScanResults with the given ScanDetails
*/
public static ScanResults create(int id, ScanDetail... nativeResults) {
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
index c63588a06..9b27c48f7 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanTestUtil.java
@@ -240,16 +240,14 @@ public class ScanTestUtil {
return createScanDatas(freqs, new int[freqs.length] /* defaults all 0 */);
}
- private static void assertScanDataEquals(String prefix, ScanData expected, ScanData actual) {
- assertNotNull(prefix + "expected ScanData was null", expected);
- assertNotNull(prefix + "actual ScanData was null", actual);
- assertEquals(prefix + "id", expected.getId(), actual.getId());
- assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags());
- assertEquals(prefix + "results.length",
- expected.getResults().length, actual.getResults().length);
- for (int j = 0; j < expected.getResults().length; ++j) {
- ScanResult expectedResult = expected.getResults()[j];
- ScanResult actualResult = actual.getResults()[j];
+ private static void assertScanResultsEquals(String prefix, ScanResult[] expected,
+ ScanResult[] actual) {
+ assertNotNull(prefix + "expected ScanResults was null", expected);
+ assertNotNull(prefix + "actual ScanResults was null", actual);
+ assertEquals(prefix + "results.length", expected.length, actual.length);
+ for (int j = 0; j < expected.length; ++j) {
+ ScanResult expectedResult = expected[j];
+ ScanResult actualResult = actual[j];
assertEquals(prefix + "results[" + j + "].SSID",
expectedResult.SSID, actualResult.SSID);
assertEquals(prefix + "results[" + j + "].wifiSsid",
@@ -269,6 +267,21 @@ public class ScanTestUtil {
}
}
+ /**
+ * Asserts if the provided scan result arrays are the same.
+ */
+ public static void assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual) {
+ assertScanResultsEquals("", expected, actual);
+ }
+
+ private static void assertScanDataEquals(String prefix, ScanData expected, ScanData actual) {
+ assertNotNull(prefix + "expected ScanData was null", expected);
+ assertNotNull(prefix + "actual ScanData was null", actual);
+ assertEquals(prefix + "id", expected.getId(), actual.getId());
+ assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags());
+ assertScanResultsEquals(prefix, expected.getResults(), actual.getResults());
+ }
+
public static void assertScanDataEquals(ScanData expected, ScanData actual) {
assertScanDataEquals("", expected, actual);
}
@@ -338,6 +351,39 @@ public class ScanTestUtil {
}
/**
+ * Asserts if the provided pno settings are the same.
+ */
+ public static void assertNativePnoSettingsEquals(WifiNative.PnoSettings expected,
+ WifiNative.PnoSettings actual) {
+ assertNotNull("expected was null", expected);
+ assertNotNull("actaul was null", actual);
+ assertEquals("min5GHzRssi", expected.min5GHzRssi, actual.min5GHzRssi);
+ assertEquals("min24GHzRssi", expected.min24GHzRssi, actual.min24GHzRssi);
+ assertEquals("initialScoreMax", expected.initialScoreMax, actual.initialScoreMax);
+ assertEquals("currentConnectionBonus", expected.currentConnectionBonus,
+ actual.currentConnectionBonus);
+ assertEquals("sameNetworkBonus", expected.sameNetworkBonus, actual.sameNetworkBonus);
+ assertEquals("secureBonus", expected.secureBonus, actual.secureBonus);
+ assertEquals("band5GHzBonus", expected.band5GHzBonus, actual.band5GHzBonus);
+ assertEquals("isConnected", expected.isConnected, actual.isConnected);
+ assertNotNull("expected networkList was null", expected.networkList);
+ assertNotNull("actual networkList was null", actual.networkList);
+ assertEquals("networkList.length", expected.networkList.length, actual.networkList.length);
+ for (int i = 0; i < expected.networkList.length; i++) {
+ assertEquals("networkList[" + i + "].ssid",
+ expected.networkList[i].ssid, actual.networkList[i].ssid);
+ assertEquals("networkList[" + i + "].networkId",
+ expected.networkList[i].networkId, actual.networkList[i].networkId);
+ assertEquals("networkList[" + i + "].priority",
+ expected.networkList[i].priority, actual.networkList[i].priority);
+ assertEquals("networkList[" + i + "].flags",
+ expected.networkList[i].flags, actual.networkList[i].flags);
+ assertEquals("networkList[" + i + "].auth_bit_field",
+ expected.networkList[i].auth_bit_field, actual.networkList[i].auth_bit_field);
+ }
+ }
+
+ /**
* Convert a list of channel frequencies to an array of equivalent WifiNative.ChannelSettings
*/
public static WifiNative.ChannelSettings[] channelsToNativeSettings(int... channels) {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
index 27c17b0c0..f0b2f60b9 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiScanningServiceTest.java
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.*;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
import android.os.Bundle;
@@ -32,6 +33,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.WorkSource;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.Protocol;
@@ -49,6 +51,10 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.internal.matchers.CapturingMatcher;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
/**
* Unit tests for {@link com.android.server.wifi.WifiScanningServiceImpl}.
*/
@@ -226,12 +232,16 @@ public class WifiScanningServiceTest {
return scanEventHandlerCaptor.getValue();
}
- private void verifyStartBackgroundScan(InOrder order, WifiNative.ScanSettings expected) {
+ private WifiNative.ScanEventHandler verifyStartBackgroundScan(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).startBatchedScan(scanSettingsCaptor.capture(),
- any(WifiNative.ScanEventHandler.class));
+ scanEventHandlerCaptor.capture());
assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue());
+ return scanEventHandlerCaptor.getValue();
}
private static final int MAX_AP_PER_SCAN = 16;
@@ -714,4 +724,288 @@ public class WifiScanningServiceTest {
.build();
doSuccessfulBackgroundScan(requestSettings, nativeSettings);
}
+
+ private Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> createScanSettingsForHwPno()
+ throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(
+ channelsToSpec(0, 2400, 5150, 5175), 20000, 0, 20,
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder()
+ .withBasePeriod(20000)
+ .withMaxApPerScan(MAX_AP_PER_SCAN)
+ .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH)
+ .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
+ 0, 2400, 5150, 5175)
+ .build();
+ return Pair.create(requestSettings, nativeSettings);
+ }
+
+ private Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> createScanSettingsForSwPno()
+ throws Exception {
+ Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> settingsPair =
+ createScanSettingsForHwPno();
+
+ WifiScanner.ScanSettings requestSettings = settingsPair.first;
+ WifiNative.ScanSettings nativeSettings = settingsPair.second;
+ // reportEvents field is overridden for SW PNO
+ for (int i = 0; i < nativeSettings.buckets.length; i++) {
+ nativeSettings.buckets[i].report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
+ | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
+ }
+ return Pair.create(requestSettings, nativeSettings);
+ }
+
+ private Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> createPnoSettings(
+ ScanResults results)
+ throws Exception {
+ WifiScanner.PnoSettings requestPnoSettings = new WifiScanner.PnoSettings();
+ requestPnoSettings.networkList =
+ new WifiScanner.PnoSettings.PnoNetwork[results.getRawScanResults().length];
+ int i = 0;
+ for (ScanResult scanResult : results.getRawScanResults()) {
+ requestPnoSettings.networkList[i++] =
+ new WifiScanner.PnoSettings.PnoNetwork(scanResult.SSID);
+ }
+
+ WifiNative.PnoSettings nativePnoSettings = new WifiNative.PnoSettings();
+ nativePnoSettings.min5GHzRssi = requestPnoSettings.min5GHzRssi;
+ nativePnoSettings.min24GHzRssi = requestPnoSettings.min24GHzRssi;
+ nativePnoSettings.initialScoreMax = requestPnoSettings.initialScoreMax;
+ nativePnoSettings.currentConnectionBonus = requestPnoSettings.currentConnectionBonus;
+ nativePnoSettings.sameNetworkBonus = requestPnoSettings.sameNetworkBonus;
+ nativePnoSettings.secureBonus = requestPnoSettings.secureBonus;
+ nativePnoSettings.band5GHzBonus = requestPnoSettings.band5GHzBonus;
+ nativePnoSettings.isConnected = requestPnoSettings.isConnected;
+ nativePnoSettings.networkList =
+ new WifiNative.PnoNetwork[requestPnoSettings.networkList.length];
+ for (i = 0; i < requestPnoSettings.networkList.length; i++) {
+ nativePnoSettings.networkList[i] = new WifiNative.PnoNetwork();
+ nativePnoSettings.networkList[i].ssid = requestPnoSettings.networkList[i].ssid;
+ nativePnoSettings.networkList[i].networkId =
+ requestPnoSettings.networkList[i].networkId;
+ nativePnoSettings.networkList[i].priority = requestPnoSettings.networkList[i].priority;
+ nativePnoSettings.networkList[i].flags = requestPnoSettings.networkList[i].flags;
+ nativePnoSettings.networkList[i].auth_bit_field =
+ requestPnoSettings.networkList[i].authBitField;
+ }
+ return Pair.create(requestPnoSettings, nativePnoSettings);
+ }
+
+ private ScanResults createScanResultsForPno() {
+ return ScanResults.create(0, 2400, 5150, 5175);
+ }
+
+ private ScanResults createScanResultsForPnoWithNoIE() {
+ return ScanResults.createWithNoIE(0, 2400, 5150, 5175);
+ }
+
+ private WifiNative.PnoEventHandler verifyHwPno(InOrder order,
+ WifiNative.PnoSettings expected) {
+ ArgumentCaptor<WifiNative.PnoSettings> pnoSettingsCaptor =
+ ArgumentCaptor.forClass(WifiNative.PnoSettings.class);
+ ArgumentCaptor<WifiNative.PnoEventHandler> pnoEventHandlerCaptor =
+ ArgumentCaptor.forClass(WifiNative.PnoEventHandler.class);
+ order.verify(mWifiScannerImpl).setHwPnoList(pnoSettingsCaptor.capture(),
+ pnoEventHandlerCaptor.capture());
+ assertNativePnoSettingsEquals(expected, pnoSettingsCaptor.getValue());
+ return pnoEventHandlerCaptor.getValue();
+ }
+
+ private void sendPnoScanRequest(BidirectionalAsyncChannel controlChannel,
+ int scanRequestId, WifiScanner.ScanSettings scanSettings,
+ WifiScanner.PnoSettings pnoSettings) {
+ Bundle pnoParams = new Bundle();
+ scanSettings.isPnoScan = true;
+ pnoParams.putParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
+ pnoParams.putParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
+ controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_PNO_SCAN, 0,
+ scanRequestId, pnoParams));
+ }
+
+ private void assertPnoNetworkFoundMessage(int listenerId, ScanResult[] expected,
+ Message networkFoundMessage) {
+ assertEquals("what", WifiScanner.CMD_PNO_NETWORK_FOUND, networkFoundMessage.what);
+ assertEquals("listenerId", listenerId, networkFoundMessage.arg2);
+ ScanTestUtil.assertScanResultsEquals(expected,
+ ((WifiScanner.ParcelableScanResults) networkFoundMessage.obj).getResults());
+ }
+
+ private void verifyPnoNetworkFoundRecieved(InOrder order, Handler handler, int listenerId,
+ ScanResult[] expected) {
+ Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler,
+ WifiScanner.CMD_PNO_NETWORK_FOUND);
+ assertPnoNetworkFoundMessage(listenerId, expected, scanResultMessage);
+ }
+
+ private void expectSuccessfulBackgroundScan(InOrder order,
+ WifiNative.ScanSettings nativeSettings, ScanResults results) {
+ when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartBackgroundScan(order, nativeSettings);
+ WifiScanner.ScanData[] scanDatas = new WifiScanner.ScanData[1];
+ scanDatas[0] = results.getScanData();
+ for (ScanResult fullScanResult : results.getRawScanResults()) {
+ eventHandler.onFullScanResult(fullScanResult, 0);
+ }
+ when(mWifiScannerImpl.getLatestBatchedScanResults(anyBoolean())).thenReturn(scanDatas);
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+ mLooper.dispatchAll();
+ }
+
+ private void expectHwPnoScanWithNoBackgroundScan(InOrder order, Handler handler, int requestId,
+ WifiNative.PnoSettings nativeSettings, ScanResults results) {
+ when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(true);
+ when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(false);
+
+ when(mWifiScannerImpl.setHwPnoList(any(WifiNative.PnoSettings.class),
+ any(WifiNative.PnoEventHandler.class))).thenReturn(true);
+ mLooper.dispatchAll();
+ WifiNative.PnoEventHandler eventHandler = verifyHwPno(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+ eventHandler.onPnoNetworkFound(results.getRawScanResults());
+ mLooper.dispatchAll();
+ }
+
+ private void expectHwPnoScanWithBackgroundScan(InOrder order, Handler handler, int requestId,
+ WifiNative.ScanSettings nativeScanSettings,
+ WifiNative.PnoSettings nativePnoSettings, ScanResults results) {
+ when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(true);
+ when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(true);
+
+ when(mWifiScannerImpl.setHwPnoList(any(WifiNative.PnoSettings.class),
+ any(WifiNative.PnoEventHandler.class))).thenReturn(true);
+ when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+ mLooper.dispatchAll();
+ WifiNative.PnoEventHandler eventHandler = verifyHwPno(order, nativePnoSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+ verifyStartBackgroundScan(order, nativeScanSettings);
+ eventHandler.onPnoNetworkFound(results.getRawScanResults());
+ mLooper.dispatchAll();
+ }
+
+ private void expectHwPnoScanWithBackgroundScanWithNoIE(InOrder order, Handler handler,
+ int requestId, WifiNative.ScanSettings nativeBackgroundScanSettings,
+ WifiNative.ScanSettings nativeSingleScanSettings,
+ WifiNative.PnoSettings nativePnoSettings, ScanResults results) {
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ expectHwPnoScanWithBackgroundScan(order, handler, requestId, nativeBackgroundScanSettings,
+ nativePnoSettings, results);
+ WifiNative.ScanEventHandler eventHandler =
+ verifyStartSingleScan(order, nativeSingleScanSettings);
+ when(mWifiScannerImpl.getLatestSingleScanResults()).thenReturn(results.getScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+ mLooper.dispatchAll();
+ }
+ private void expectSwPnoScan(InOrder order, WifiNative.ScanSettings nativeScanSettings,
+ ScanResults results) {
+ when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(false);
+ when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(true);
+
+ expectSuccessfulBackgroundScan(order, nativeScanSettings, results);
+ }
+
+ /**
+ * Tests Supplicant PNO scan when the PNO scan results contain IE info. This ensures that the
+ * PNO scan results are plumbed back to the client as a PNO network found event.
+ */
+ @Test
+ public void testSuccessfulHwPnoScanWithNoBackgroundScan() throws Exception {
+ startServiceAndLoadDriver();
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+ int requestId = 12;
+
+ ScanResults scanResults = createScanResultsForPno();
+ Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
+ createScanSettingsForHwPno();
+ Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
+ createPnoSettings(scanResults);
+
+ sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
+ expectHwPnoScanWithNoBackgroundScan(order, handler, requestId, pnoSettings.second,
+ scanResults);
+ verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
+ }
+
+ /**
+ * Tests Hal ePNO scan when the PNO scan results contain IE info. This ensures that the
+ * PNO scan results are plumbed back to the client as a PNO network found event.
+ */
+ @Test
+ public void testSuccessfulHwPnoScanWithBackgroundScan() throws Exception {
+ startServiceAndLoadDriver();
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+ int requestId = 12;
+
+ ScanResults scanResults = createScanResultsForPno();
+ Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
+ createScanSettingsForHwPno();
+ Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
+ createPnoSettings(scanResults);
+
+ sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
+ expectHwPnoScanWithBackgroundScan(order, handler, requestId, scanSettings.second,
+ pnoSettings.second, scanResults);
+ verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
+ }
+
+ /**
+ * Tests Hal ePNO scan when the PNO scan results don't contain IE info. This ensures that the
+ * single scan results are plumbed back to the client as a PNO network found event.
+ */
+ @Test
+ public void testSuccessfulHwPnoScanWithBackgroundScanWithNoIE() throws Exception {
+ startServiceAndLoadDriver();
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+ int requestId = 12;
+
+ ScanResults scanResults = createScanResultsForPnoWithNoIE();
+ Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
+ createScanSettingsForHwPno();
+ Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
+ createPnoSettings(scanResults);
+
+ sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
+ expectHwPnoScanWithBackgroundScanWithNoIE(order, handler, requestId, scanSettings.second,
+ computeSingleScanNativeSettings(scanSettings.first), pnoSettings.second,
+ scanResults);
+
+ ArrayList<ScanResult> sortScanList =
+ new ArrayList<ScanResult>(Arrays.asList(scanResults.getRawScanResults()));
+ Collections.sort(sortScanList, WifiScannerImpl.SCAN_RESULT_SORT_COMPARATOR);
+ verifyPnoNetworkFoundRecieved(order, handler, requestId,
+ sortScanList.toArray(new ScanResult[sortScanList.size()]));
+ }
+
+ /**
+ * Tests SW PNO scan. This ensures that the background scan results are plumbed back to the
+ * client as a PNO network found event.
+ */
+ @Test
+ public void testSuccessfulSwPnoScan() throws Exception {
+ startServiceAndLoadDriver();
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+ int requestId = 12;
+
+ ScanResults scanResults = createScanResultsForPno();
+ Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
+ createScanSettingsForSwPno();
+ Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
+ createPnoSettings(scanResults);
+
+ sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
+ expectSwPnoScan(order, scanSettings.second, scanResults);
+ verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
+ }
}