summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Wills <mwills@google.com>2016-06-23 11:07:28 -0700
committerMitchell Wills <mwills@google.com>2016-06-24 17:48:45 -0700
commit1ba04405f98489f0fbd66b6566c64324be11111a (patch)
tree00f5c77f4bf95a1f110c6d28a1d7fb81f8d550fc
parent55b1b58e72df2362888c7a1c60ad76a43523bfcf (diff)
Add a WifiScanner API to listen for ongoing scans
Bug: 29412469 Change-Id: I1b8c6f3524e937cbc902af0be391b5e6b23e8ee2
-rw-r--r--service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java32
-rw-r--r--tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java317
2 files changed, 339 insertions, 10 deletions
diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
index ee0a060cb..b98b4d121 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
@@ -214,6 +214,15 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
case WifiScanner.CMD_STOP_TRACKING_CHANGE:
mWifiChangeStateMachine.sendMessage(Message.obtain(msg));
break;
+ case WifiScanner.CMD_REGISTER_SCAN_LISTENER:
+ logScanRequest("registerScanListener", ci, msg.arg2, null, null, null);
+ mSingleScanListeners.addRequest(ci, msg.arg2, null, null);
+ replySucceeded(msg);
+ break;
+ case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER:
+ logScanRequest("deregisterScanListener", ci, msg.arg2, null, null, null);
+ mSingleScanListeners.removeRequest(ci, msg.arg2);
+ break;
default:
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request");
break;
@@ -242,6 +251,8 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private final WifiScannerImpl.WifiScannerImplFactory mScannerImplFactory;
private final ArrayMap<Messenger, ClientInfo> mClients;
+ private final RequestList<Void> mSingleScanListeners = new RequestList<>();
+
private ChannelHelper mChannelHelper;
private BackgroundScanScheduler mBackgroundScheduler;
private WifiNative.ScanSettings mPreviousSchedule;
@@ -795,6 +806,10 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result);
}
}
+
+ for (RequestInfo<Void> entry : mSingleScanListeners) {
+ entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result);
+ }
}
void reportScanResults(ScanData results) {
@@ -805,18 +820,26 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
mWifiMetrics.incrementEmptyScanResultCount();
}
}
+ ScanData[] allResults = new ScanData[] {results};
for (RequestInfo<ScanSettings> entry : mActiveScans) {
- ScanData[] resultsArray = new ScanData[] {results};
ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings(
- mChannelHelper, resultsArray, entry.settings, -1);
- WifiScanner.ParcelableScanData parcelableScanData =
+ mChannelHelper, allResults, entry.settings, -1);
+ WifiScanner.ParcelableScanData parcelableResultsToDeliver =
new WifiScanner.ParcelableScanData(resultsToDeliver);
logCallback("singleScanResults", entry.clientInfo, entry.handlerId,
describeForLog(resultsToDeliver));
- entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableScanData);
+ entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver);
// make sure the handler is removed
entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null);
}
+
+ WifiScanner.ParcelableScanData parcelableAllResults =
+ new WifiScanner.ParcelableScanData(allResults);
+ for (RequestInfo<Void> entry : mSingleScanListeners) {
+ logCallback("singleScanResults", entry.clientInfo, entry.handlerId,
+ describeForLog(allResults));
+ entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
+ }
}
}
@@ -1870,6 +1893,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub {
}
public void cleanup() {
+ mSingleScanListeners.removeAllForClient(this);
mSingleScanStateMachine.removeSingleScanRequests(this);
mBackgroundScanStateMachine.removeBackgroundScanSettings(this);
mBackgroundScanStateMachine.removeHotlistSettings(this);
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
index 529b42988..ceed019c3 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
@@ -200,6 +200,18 @@ public class WifiScanningServiceTest {
scanRequestId, scanParams));
}
+ private static void registerScanListener(BidirectionalAsyncChannel controlChannel,
+ int listenerRequestId) {
+ controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_REGISTER_SCAN_LISTENER, 0,
+ listenerRequestId, null));
+ }
+
+ private static void deregisterScanListener(BidirectionalAsyncChannel controlChannel,
+ int listenerRequestId) {
+ controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DEREGISTER_SCAN_LISTENER, 0,
+ listenerRequestId, null));
+ }
+
private static void verifySuccessfulResponse(InOrder order, Handler handler, int arg2) {
Message response = verifyHandleMessageAndGetMessage(order, handler);
assertSuccessfulResponse(arg2, response);
@@ -219,12 +231,14 @@ public class WifiScanningServiceTest {
/**
* If multiple results are expected for a single hardware scan then the order that they are
* dispatched is dependant on the order which they are iterated through internally. This
- * function validates that the order is either one way or the other.
+ * function validates that the order is either one way or the other. A scan listener can
+ * optionally be provided as well and will be checked after the after the single scan requests.
*/
private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler,
- int requestId1, ScanResults results1, int requestId2, ScanResults results2) {
+ int requestId1, ScanResults results1, int requestId2, ScanResults results2,
+ int listenerRequestId, ScanResults listenerResults) {
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
- handlerOrder.verify(handler, times(4))
+ handlerOrder.verify(handler, times(listenerResults == null ? 4 : 5))
.handleMessage(messageCaptor.capture());
int firstListenerId = messageCaptor.getAllValues().get(0).arg2;
assertTrue(firstListenerId + " was neither " + requestId2 + " nor " + requestId1,
@@ -238,6 +252,11 @@ public class WifiScanningServiceTest {
new WifiScanner.ScanData[] {results1.getScanData()},
messageCaptor.getAllValues().get(2));
assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(3));
+ if (listenerResults != null) {
+ assertScanResultsMessage(listenerRequestId,
+ new WifiScanner.ScanData[] {listenerResults.getScanData()},
+ messageCaptor.getAllValues().get(4));
+ }
} else {
assertScanResultsMessage(requestId1,
new WifiScanner.ScanData[] {results1.getScanData()},
@@ -247,9 +266,20 @@ public class WifiScanningServiceTest {
new WifiScanner.ScanData[] {results2.getScanData()},
messageCaptor.getAllValues().get(2));
assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(3));
+ if (listenerResults != null) {
+ assertScanResultsMessage(listenerRequestId,
+ new WifiScanner.ScanData[] {listenerResults.getScanData()},
+ messageCaptor.getAllValues().get(4));
+ }
}
}
+ private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler,
+ int requestId1, ScanResults results1, int requestId2, ScanResults results2) {
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2,
+ results2, -1, null);
+ }
+
private static void verifyFailedResponse(InOrder order, Handler handler, int arg2,
int expectedErrorReason, String expectedErrorDescription) {
Message response = verifyHandleMessageAndGetMessage(order, handler);
@@ -598,9 +628,95 @@ public class WifiScanningServiceTest {
verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource));
}
- // TODO Add more single scan tests
- // * disable wifi while scanning
- // * disable wifi while scanning with pending scan
+ /**
+ * Send a single scan request and then disable Wi-Fi before it completes
+ */
+ @Test
+ public void sendSingleScanRequestThenDisableWifi() {
+ WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 2293;
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, requestId);
+
+ // disable wifi
+ TestUtil.sendWifiScanAvailable(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+
+ // validate failed response
+ mLooper.dispatchAll();
+ verifyFailedResponse(order, handler, requestId, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted");
+ verifyNoMoreInteractions(handler);
+ }
+
+ /**
+ * Send a single scan request, schedule a second pending scan and disable Wi-Fi before the first
+ * scan completes.
+ */
+ @Test
+ public void sendSingleScanAndPendingScanAndListenerThenDisableWifi() {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 2293;
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 2294;
+
+ int listenerRequestId = 2295;
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // Request scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, requestId1);
+
+ // Request scan 2
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, requestId2);
+
+ // Setup scan listener
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, listenerRequestId);
+
+ // disable wifi
+ TestUtil.sendWifiScanAvailable(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+
+ // validate failed response
+ mLooper.dispatchAll();
+ ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+ order.verify(handler, times(2)).handleMessage(messageCaptor.capture());
+ assertFailedResponse(requestId1, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted", messageCaptor.getAllValues().get(0));
+ assertFailedResponse(requestId2, WifiScanner.REASON_UNSPECIFIED,
+ "Scan was interrupted", messageCaptor.getAllValues().get(1));
+ // No additional callbacks for scan listener
+ verifyNoMoreInteractions(handler);
+ }
/**
* Send a single scan request and then a second one after the first completes.
@@ -994,6 +1110,195 @@ public class WifiScanningServiceTest {
"results=" + results3.getRawScanResults().length);
}
+ /**
+ * Register a single scan listener and do a single scan
+ */
+ @Test
+ public void registerScanListener() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings);
+ ScanResults results = ScanResults.create(0, 2400, 5150, 5175);
+
+ int requestId = 12;
+ int listenerRequestId = 13;
+
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, listenerRequestId);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results.getRawScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId);
+ verifyScanResultsRecieved(order, handler, listenerRequestId, results.getScanData());
+ verifyNoMoreInteractions(handler);
+
+ assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
+ assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
+ "results=" + results.getScanData().getResults().length);
+ }
+
+ /**
+ * Register a single scan listener and do a single scan
+ */
+ @Test
+ public void deregisterScanListener() throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings);
+ ScanResults results = ScanResults.create(0, 2400, 5150, 5175);
+
+ int requestId = 12;
+ int listenerRequestId = 13;
+
+ startServiceAndLoadDriver();
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(order, handler, listenerRequestId);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
+ verifySuccessfulResponse(order, handler, requestId);
+
+ deregisterScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results.getRawScanData());
+ eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
+ verifySingleScanCompletedRecieved(order, handler, requestId);
+ verifyNoMoreInteractions(handler);
+
+ assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
+ assertDumpContainsRequestLog("deregisterScanListener", listenerRequestId);
+ }
+
+ /**
+ * Send a single scan request and then two more before the first completes. Neither are
+ * satisfied by the first scan. Verify that the first completes and the second two are merged.
+ */
+ @Test
+ public void scanListenerRecievesAllResults() throws RemoteException {
+ WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId1 = 12;
+ ScanResults results1 = ScanResults.create(0, 2400);
+
+ WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId2 = 13;
+ ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
+
+ WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5150), 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId3 = 15;
+ ScanResults results3 = ScanResults.create(0, 5150, 5150, 5150, 5150);
+
+ WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels(
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channelsToSpec(2450, 5175, 5150));
+ ScanResults results2and3 = ScanResults.merge(results2, results3);
+
+ int listenerRequestId = 13;
+
+
+ startServiceAndLoadDriver();
+
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder handlerOrder = inOrder(handler);
+ InOrder nativeOrder = inOrder(mWifiScannerImpl);
+
+ // Run scan 1
+ sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
+
+ mLooper.dispatchAll();
+ WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
+ computeSingleScanNativeSettings(requestSettings1));
+ verifySuccessfulResponse(handlerOrder, handler, requestId1);
+
+
+ // Queue scan 2 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId2);
+
+ // Queue scan 3 (will not run because previous is in progress)
+ sendSingleScanRequest(controlChannel, requestId3, requestSettings3, null);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, requestId3);
+
+ // Register scan listener
+ registerScanListener(controlChannel, listenerRequestId);
+ mLooper.dispatchAll();
+ verifySuccessfulResponse(handlerOrder, handler, listenerRequestId);
+
+ // dispatch scan 1 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results1.getScanData());
+ eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+ verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
+ verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
+ verifyScanResultsRecieved(handlerOrder, handler, listenerRequestId, results1.getScanData());
+
+ // now that the first scan completed we expect the second and third ones to start
+ WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder,
+ nativeSettings2and3);
+
+ // dispatch scan 2 and 3 results
+ when(mWifiScannerImpl.getLatestSingleScanResults())
+ .thenReturn(results2and3.getScanData());
+ eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+
+ mLooper.dispatchAll();
+
+ verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3,
+ results3, listenerRequestId, results2and3);
+
+ assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
+ assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
+ "results=" + results1.getRawScanResults().length);
+ assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
+ "results=" + results2and3.getRawScanResults().length);
+ }
+
+
private void doSuccessfulBackgroundScan(WifiScanner.ScanSettings requestSettings,
WifiNative.ScanSettings nativeSettings) {
startServiceAndLoadDriver();