summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2017-02-24 09:15:47 -0800
committerRoshan Pius <rpius@google.com>2017-02-28 05:38:48 -0800
commitd4c5eca00c9cae55561210479ed61a977923e0da (patch)
tree2e11b9746bc9f3a213e1a5535c3af2aa85c18487
parentbdfeb91af1b24703aabb72f1f33ed533e93880a9 (diff)
[WifiVendorHal] Bgscan callback handling
To preserve current API surface exposed by WifiNative to Wifiscanner, cache the scan results received and simulate the necessary scan events to WifiScanner. We can cleanup this along with scanner later. Also, fixed a couple of other nits. Bug: 34899890 Test: Unit tests Change-Id: I9b6ce2e5e7d72be0b058de6c335bd80829f2cc78
-rw-r--r--service/java/com/android/server/wifi/WifiVendorHal.java114
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java193
2 files changed, 297 insertions, 10 deletions
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index 6a869b17e..02846aa80 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -37,6 +37,7 @@ import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
import android.hardware.wifi.V1_0.StaRoamingConfig;
import android.hardware.wifi.V1_0.StaRoamingState;
import android.hardware.wifi.V1_0.StaScanData;
+import android.hardware.wifi.V1_0.StaScanDataFlagMask;
import android.hardware.wifi.V1_0.StaScanResult;
import android.hardware.wifi.V1_0.WifiBand;
import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
@@ -48,6 +49,7 @@ import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
+import android.hardware.wifi.V1_0.WifiInformationElement;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
import android.net.apf.ApfCapabilities;
@@ -58,6 +60,7 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiLinkLayerStats;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
+import android.net.wifi.WifiSsid;
import android.net.wifi.WifiWakeReasonAndCounts;
import android.os.HandlerThread;
import android.os.RemoteException;
@@ -301,6 +304,7 @@ public class WifiVendorHal {
public StaBackgroundScanParameters param;
public WifiNative.ScanEventHandler eventHandler = null;
public boolean paused = false;
+ public WifiScanner.ScanData[] latestScanResults = null;
CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) {
cmdId = id;
@@ -309,8 +313,10 @@ public class WifiVendorHal {
param.maxApPerScan = settings.max_ap_per_scan;
param.reportThresholdPercent = settings.report_threshold_percent;
param.reportThresholdNumScans = settings.report_threshold_num_scans;
- for (WifiNative.BucketSettings bs : settings.buckets) {
- param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs));
+ if (settings.buckets != null) {
+ for (WifiNative.BucketSettings bs : settings.buckets) {
+ param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs));
+ }
}
}
}
@@ -498,6 +504,20 @@ public class WifiVendorHal {
}
/**
+ * Gets the latest scan results received from the HIDL interface callback.
+ * TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor
+ * WifiScanner to use the scan results from the callback.
+ */
+ public WifiScanner.ScanData[] getScanResults() {
+ kilroy();
+ synchronized (sLock) {
+ if (mIWifiStaIface == null) return null;
+ if (mScan == null) return null;
+ return mScan.latestScanResults;
+ }
+ }
+
+ /**
* Get the link layer statistics
*
* Note - we always enable link layer stats on a STA interface.
@@ -1365,10 +1385,7 @@ public class WifiVendorHal {
int cmdId = 0; //TODO(b/34901818) We only aspire to support one program at a time
if (filter == null) return false;
// Copy the program before taking the lock.
- ArrayList<Byte> program = new ArrayList<>(filter.length);
- for (byte b : filter) {
- program.add(b);
- }
+ ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter);
synchronized (sLock) {
try {
if (mIWifiStaIface == null) return false;
@@ -2223,6 +2240,69 @@ public class WifiVendorHal {
Log.e(TAG, "th " + cur.getId() + " line " + s.getLineNumber() + " " + name);
}
+ // This creates a blob of IE elements from the array received.
+ // TODO: This ugly conversion can be removed if we put IE elements in ScanResult.
+ private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) {
+ if (ies == null || ies.isEmpty()) return new byte[0];
+ ArrayList<Byte> ieBlob = new ArrayList<>();
+ for (WifiInformationElement ie : ies) {
+ ieBlob.add(ie.id);
+ ieBlob.addAll(ie.data);
+ }
+ return NativeUtil.byteArrayFromArrayList(ieBlob);
+ }
+
+ // This is only filling up the fields of Scan Result used by Gscan clients.
+ private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) {
+ if (scanResult == null) return null;
+ ScanResult frameworkScanResult = new ScanResult();
+ frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid);
+ frameworkScanResult.wifiSsid =
+ WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid));
+ frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid);
+ frameworkScanResult.level = scanResult.rssi;
+ frameworkScanResult.frequency = scanResult.frequency;
+ frameworkScanResult.timestamp = scanResult.timeStampInUs;
+ frameworkScanResult.bytes = hidlIeArrayToFrameworkIeBlob(scanResult.informationElements);
+ return frameworkScanResult;
+ }
+
+ private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) {
+ if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0];
+ ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()];
+ int i = 0;
+ for (StaScanResult scanResult : scanResults) {
+ frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult);
+ }
+ return frameworkScanResults;
+ }
+
+ /**
+ * This just returns whether the scan was interrupted or not.
+ */
+ private static int hidlToFrameworkScanDataFlags(int flag) {
+ if (flag == StaScanDataFlagMask.INTERRUPTED) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ private static WifiScanner.ScanData[] hidlToFrameworkScanDatas(
+ int cmdId, ArrayList<StaScanData> scanDatas) {
+ if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0];
+ WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()];
+ int i = 0;
+ for (StaScanData scanData : scanDatas) {
+ int flags = hidlToFrameworkScanDataFlags(scanData.flags);
+ ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results);
+ frameworkScanDatas[i++] =
+ new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned, false,
+ frameworkScanResults);
+ }
+ return frameworkScanDatas;
+ }
+
/**
* Callback for events on the STA interface.
*/
@@ -2231,18 +2311,38 @@ public class WifiVendorHal {
public void onBackgroundScanFailure(int cmdId) {
kilroy();
Log.d(TAG, "onBackgroundScanFailure " + cmdId);
+ synchronized (sLock) {
+ if (mScan != null && cmdId == mScan.cmdId) {
+ mScan.eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
+ }
+ }
}
@Override
- public void onBackgroundFullScanResult(int cmdId, StaScanResult result) {
+ public void onBackgroundFullScanResult(
+ int cmdId, StaScanResult result) {
kilroy();
Log.d(TAG, "onBackgroundFullScanResult " + cmdId);
+ synchronized (sLock) {
+ if (mScan != null && cmdId == mScan.cmdId) {
+ mScan.eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), 0);
+ }
+ }
}
@Override
public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
kilroy();
Log.d(TAG, "onBackgroundScanResults " + cmdId);
+ // WifiScanner currently uses the results callback to fetch the scan results.
+ // So, simulate that by sending out the notification and then caching the results
+ // locally. This will then be returned to WifiScanner via getScanResults.
+ synchronized (sLock) {
+ if (mScan != null && cmdId == mScan.cmdId) {
+ mScan.eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+ mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
+ }
+ }
}
@Override
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index 9de08cf91..cbd3510d7 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
@@ -28,6 +28,10 @@ import android.hardware.wifi.V1_0.RttCapabilities;
import android.hardware.wifi.V1_0.RttConfig;
import android.hardware.wifi.V1_0.StaApfPacketFilterCapabilities;
import android.hardware.wifi.V1_0.StaBackgroundScanCapabilities;
+import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
+import android.hardware.wifi.V1_0.StaScanData;
+import android.hardware.wifi.V1_0.StaScanDataFlagMask;
+import android.hardware.wifi.V1_0.StaScanResult;
import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
@@ -37,15 +41,20 @@ import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
+import android.hardware.wifi.V1_0.WifiInformationElement;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
import android.net.apf.ApfCapabilities;
import android.net.wifi.RttManager;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
+import android.net.wifi.WifiSsid;
import android.net.wifi.WifiWakeReasonAndCounts;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.Pair;
import com.android.server.connectivity.KeepalivePacketData;
import com.android.server.wifi.util.NativeUtil;
@@ -63,6 +72,7 @@ import org.mockito.stubbing.Answer;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Random;
/**
@@ -88,6 +98,7 @@ public class WifiVendorHalTest {
@Mock
private IWifiRttController mIWifiRttController;
private IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
+ private IWifiChipEventCallback mIWifiChipEventCallback;
/**
* Identity function to supply a type to its argument, which is a lambda
@@ -145,16 +156,25 @@ public class WifiVendorHalTest {
mIWifiStaIfaceEventCallback = (IWifiStaIfaceEventCallback) args[0];
return (mWifiStatusSuccess);
}));
+ mIWifiChipEventCallback = null;
+ when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class)))
+ .thenAnswer(answerWifiStatus((invocation) -> {
+ Object[] args = invocation.getArguments();
+ mIWifiChipEventCallback = (IWifiChipEventCallback) args[0];
+ return (mWifiStatusSuccess);
+ }));
+
// Create the vendor HAL object under test.
mWifiVendorHal = new WifiVendorHal(mHalDeviceManager, mWifiStateMachineHandlerThread);
// Initialize the vendor HAL to capture the registered callback.
mWifiVendorHal.initialize();
- ArgumentCaptor<WifiVendorHal.HalDeviceManagerStatusListener> callbackCaptor =
+ ArgumentCaptor<WifiVendorHal.HalDeviceManagerStatusListener> hdmCallbackCaptor =
ArgumentCaptor.forClass(WifiVendorHal.HalDeviceManagerStatusListener.class);
verify(mHalDeviceManager).registerStatusListener(
- callbackCaptor.capture(), any(Looper.class));
- mHalDeviceManagerStatusCallbacks = callbackCaptor.getValue();
+ hdmCallbackCaptor.capture(), any(Looper.class));
+ mHalDeviceManagerStatusCallbacks = hdmCallbackCaptor.getValue();
+
}
/**
@@ -1324,4 +1344,171 @@ public class WifiVendorHalTest {
assertTrue(mWifiVendorHal.startVendorHalAp());
assertArrayEquals(sample, mWifiVendorHal.getDriverStateDump());
}
+
+ /**
+ * Test that background scan failure is handled correctly.
+ */
+ @Test
+ public void testBgScanFailureCallback() throws Exception {
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertNotNull(mIWifiStaIfaceEventCallback);
+
+ WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
+ startBgScan(eventHandler);
+
+ mIWifiStaIfaceEventCallback.onBackgroundScanFailure(mWifiVendorHal.mScan.cmdId);
+ verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
+ }
+
+ /**
+ * Test that background scan failure is handled correctly.
+ */
+ @Test
+ public void testBgScanFailureCallbackWithInvalidCmdId() throws Exception {
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertNotNull(mIWifiStaIfaceEventCallback);
+
+ WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
+ startBgScan(eventHandler);
+
+ mIWifiStaIfaceEventCallback.onBackgroundScanFailure(mWifiVendorHal.mScan.cmdId + 1);
+ verify(eventHandler, never()).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
+ }
+
+ /**
+ * Test that background scan full results are handled correctly.
+ */
+ @Test
+ public void testBgScanFullScanResults() throws Exception {
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertNotNull(mIWifiStaIfaceEventCallback);
+
+ WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
+ startBgScan(eventHandler);
+
+ Pair<StaScanResult, ScanResult> result = createHidlAndFrameworkBgScanResult();
+ mIWifiStaIfaceEventCallback.onBackgroundFullScanResult(
+ mWifiVendorHal.mScan.cmdId, result.first);
+
+ ArgumentCaptor<ScanResult> scanResultCaptor = ArgumentCaptor.forClass(ScanResult.class);
+ verify(eventHandler).onFullScanResult(scanResultCaptor.capture(), eq(0));
+
+ assertScanResultEqual(result.second, scanResultCaptor.getValue());
+ }
+
+ /**
+ * Test that background scan results are handled correctly.
+ */
+ @Test
+ public void testBgScanScanResults() throws Exception {
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ assertNotNull(mIWifiStaIfaceEventCallback);
+
+ WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
+ startBgScan(eventHandler);
+
+ Pair<ArrayList<StaScanData>, ArrayList<WifiScanner.ScanData>> data =
+ createHidlAndFrameworkBgScanDatas();
+ mIWifiStaIfaceEventCallback.onBackgroundScanResults(
+ mWifiVendorHal.mScan.cmdId, data.first);
+
+ verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
+ assertScanDatasEqual(
+ data.second, Arrays.asList(mWifiVendorHal.mScan.latestScanResults));
+ }
+
+ private void startBgScan(WifiNative.ScanEventHandler eventHandler) throws Exception {
+ when(mIWifiStaIface.startBackgroundScan(
+ anyInt(), any(StaBackgroundScanParameters.class))).thenReturn(mWifiStatusSuccess);
+ assertTrue(mWifiVendorHal.startScan(new WifiNative.ScanSettings(), eventHandler));
+ }
+
+ // Create a pair of HIDL scan result and its corresponding framework scan result for
+ // comparison.
+ private Pair<StaScanResult, ScanResult> createHidlAndFrameworkBgScanResult() {
+ StaScanResult staScanResult = new StaScanResult();
+ Random random = new Random();
+ byte[] ssid = new byte[8];
+ random.nextBytes(ssid);
+ staScanResult.ssid.addAll(NativeUtil.byteArrayToArrayList(ssid));
+ random.nextBytes(staScanResult.bssid);
+ staScanResult.frequency = 2432;
+ staScanResult.rssi = -45;
+ staScanResult.timeStampInUs = 5;
+ WifiInformationElement ie1 = new WifiInformationElement();
+ byte[] ie1_data = new byte[56];
+ random.nextBytes(ie1_data);
+ ie1.id = 1;
+ ie1.data.addAll(NativeUtil.byteArrayToArrayList(ie1_data));
+ staScanResult.informationElements.add(ie1);
+
+ // Now create the corresponding Scan result structure.
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = NativeUtil.encodeSsid(staScanResult.ssid);
+ scanResult.BSSID = NativeUtil.macAddressFromByteArray(staScanResult.bssid);
+ scanResult.wifiSsid = WifiSsid.createFromByteArray(ssid);
+ scanResult.frequency = staScanResult.frequency;
+ scanResult.level = staScanResult.rssi;
+ scanResult.timestamp = staScanResult.timeStampInUs;
+ scanResult.bytes = new byte[57];
+ scanResult.bytes[0] = ie1.id;
+ System.arraycopy(ie1_data, 0, scanResult.bytes, 1, ie1_data.length);
+
+ return Pair.create(staScanResult, scanResult);
+ }
+
+ // Create a pair of HIDL scan datas and its corresponding framework scan datas for
+ // comparison.
+ private Pair<ArrayList<StaScanData>, ArrayList<WifiScanner.ScanData>>
+ createHidlAndFrameworkBgScanDatas() {
+ ArrayList<StaScanData> staScanDatas = new ArrayList<>();
+ StaScanData staScanData = new StaScanData();
+
+ Pair<StaScanResult, ScanResult> result = createHidlAndFrameworkBgScanResult();
+ staScanData.results.add(result.first);
+ staScanData.bucketsScanned = 5;
+ staScanData.flags = StaScanDataFlagMask.INTERRUPTED;
+ staScanDatas.add(staScanData);
+
+ ArrayList<WifiScanner.ScanData> scanDatas = new ArrayList<>();
+ ScanResult[] scanResults = new ScanResult[1];
+ scanResults[0] = result.second;
+ WifiScanner.ScanData scanData =
+ new WifiScanner.ScanData(mWifiVendorHal.mScan.cmdId, 1,
+ staScanData.bucketsScanned, false, scanResults);
+ scanDatas.add(scanData);
+ return Pair.create(staScanDatas, scanDatas);
+ }
+
+ private void assertScanResultEqual(ScanResult expected, ScanResult actual) {
+ assertEquals(expected.SSID, actual.SSID);
+ assertEquals(expected.wifiSsid.getHexString(), actual.wifiSsid.getHexString());
+ assertEquals(expected.BSSID, actual.BSSID);
+ assertEquals(expected.frequency, actual.frequency);
+ assertEquals(expected.level, actual.level);
+ assertEquals(expected.timestamp, actual.timestamp);
+ assertArrayEquals(expected.bytes, actual.bytes);
+ }
+
+ private void assertScanResultsEqual(ScanResult[] expected, ScanResult[] actual) {
+ assertEquals(expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertScanResultEqual(expected[i], actual[i]);
+ }
+ }
+
+ private void assertScanDataEqual(WifiScanner.ScanData expected, WifiScanner.ScanData actual) {
+ assertEquals(expected.getId(), actual.getId());
+ assertEquals(expected.getFlags(), actual.getFlags());
+ assertEquals(expected.getBucketsScanned(), actual.getBucketsScanned());
+ assertScanResultsEqual(expected.getResults(), actual.getResults());
+ }
+
+ private void assertScanDatasEqual(
+ List<WifiScanner.ScanData> expected, List<WifiScanner.ScanData> actual) {
+ assertEquals(expected.size(), actual.size());
+ for (int i = 0; i < expected.size(); i++) {
+ assertScanDataEqual(expected.get(i), actual.get(i));
+ }
+ }
}