diff options
author | Roshan Pius <rpius@google.com> | 2016-03-28 17:51:57 -0700 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2016-03-30 17:00:21 -0700 |
commit | c343aec32e1d3fe320eb97c527b0bcfb2d334e45 (patch) | |
tree | 6cb94c5c0fb8b46493e98d435a0492103ef9819f | |
parent | a91494208927643d011b4fa62db2064d9e8228c1 (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
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()); + } } |