Fix crash when scanner gets results that don't match the request

Before this, when WifiScanningService processed single scan results from
supplicant that only contained results that did not match a request the
filter code would return null indicating that the results should not be
delivered, causing a NPE later. This change updates the meaning of the
bucket index that the single scan code provides to the filtering code to
instead force it to always include scan results.

Change-Id: I65cd57b14abacec3f407991188c570601d05ac77
Fixes: 28794598
diff --git a/service/java/com/android/server/wifi/scanner/ScanScheduleUtil.java b/service/java/com/android/server/wifi/scanner/ScanScheduleUtil.java
index 01418b9..9267aa0 100644
--- a/service/java/com/android/server/wifi/scanner/ScanScheduleUtil.java
+++ b/service/java/com/android/server/wifi/scanner/ScanScheduleUtil.java
@@ -94,7 +94,8 @@
      * Check if the specified bucket was scanned. If not all information is available then this
      * method will return true.
      *
-     * @param scheduledBucket Index of the bucket to check for, zero indexed, or -1 if unavailable
+     * @param scheduledBucket Index of the bucket to check for, zero indexed, or -1 if any scan
+     *                        should be treated as scanning this bucket.
      * @param bucketsScannedBitSet The bitset of all buckets scanned, 0 if unavailable
      */
     private static boolean isBucketMaybeScanned(int scheduledBucket, int bucketsScannedBitSet) {
@@ -109,11 +110,14 @@
      * Check if the specified bucket was scanned. If not all information is available then this
      * method will return false.
      *
-     * @param scheduledBucket Index of the bucket to check for, zero indexed, or -1 if unavailable
+     * @param scheduledBucket Index of the bucket to check for, zero indexed, or -1 if any scan
+     *                        should be treated as scanning this bucket.
      * @param bucketsScannedBitSet The bitset of all buckets scanned, 0 if unavailable
      */
     private static boolean isBucketDefinitlyScanned(int scheduledBucket, int bucketsScannedBitSet) {
-        if (bucketsScannedBitSet == 0 || scheduledBucket < 0) {
+        if (scheduledBucket < 0) {
+            return true;
+        } else if (bucketsScannedBitSet == 0) {
             return false;
         } else {
             return (bucketsScannedBitSet & (1 << scheduledBucket)) != 0;
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanResults.java b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
index bc76d0f..1609020 100644
--- a/tests/wifitests/src/com/android/server/wifi/ScanResults.java
+++ b/tests/wifitests/src/com/android/server/wifi/ScanResults.java
@@ -37,12 +37,14 @@
 public class ScanResults {
     private final ArrayList<ScanDetail> mScanDetails = new ArrayList<>();
     private final ScanData mScanData;
+    private final ScanData mRawScanData;
     private final ScanResult[] mScanResults;
 
     private ScanResults(ArrayList<ScanDetail> scanDetails, ScanData scanData,
             ScanResult[] scanResults) {
         mScanDetails.addAll(scanDetails);
         mScanData = scanData;
+        mRawScanData = scanData;
         mScanResults = scanResults;
     }
 
@@ -127,7 +129,7 @@
     /**
      * Create scan results with no IE information.
      */
-    private static ScanDetail[] generateNativeResults(int seed, int... freqs) {
+    public static ScanDetail[] generateNativeResults(int seed, int... freqs) {
         return generateNativeResults(true, seed, freqs);
     }
 
@@ -171,8 +173,9 @@
         }
         ScanResult[] sortedScanResults = Arrays.copyOf(mScanResults, mScanResults.length);
         Arrays.sort(sortedScanResults, SCAN_RESULT_RSSI_COMPARATOR);
+        mRawScanData = new ScanData(id, 0, sortedScanResults);
         if (maxResults == -1) {
-            mScanData = new ScanData(id, 0, sortedScanResults);
+            mScanData = mRawScanData;
         } else {
             ScanResult[] reducedScanResults = Arrays.copyOf(sortedScanResults,
                     Math.min(sortedScanResults.length, maxResults));
@@ -191,4 +194,8 @@
     public ScanResult[] getRawScanResults() {
         return mScanResults;
     }
+
+    public ScanData getRawScanData() {
+        return mRawScanData;
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/ScanScheduleUtilFilterTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/ScanScheduleUtilFilterTest.java
index 3117fd9..b8e20b5 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/ScanScheduleUtilFilterTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/ScanScheduleUtilFilterTest.java
@@ -71,7 +71,7 @@
         );
 
         assertFalse(ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper,
-                        createScanResult(5150), 0, settings, -1));
+                        createScanResult(5150), 0, settings, 0));
     }
 
     @Test
@@ -82,7 +82,7 @@
         );
 
         assertTrue(ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper,
-                        createScanResult(2400), 0, settings, -1));
+                        createScanResult(2400), 0, settings, 0));
     }
 
     @Test
@@ -93,7 +93,7 @@
         );
 
         assertFalse(ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper,
-                        createScanResult(5175), 0, settings, -1));
+                        createScanResult(5175), 0, settings, 0));
     }
 
     @Test
@@ -138,11 +138,23 @@
         );
 
         ScanData[] results = ScanScheduleUtil.filterResultsForSettings(mChannelHelper,
-                createScanDatas(new int[][]{ { 2450 } }), settings, -1);
+                createScanDatas(new int[][]{ { 2450 } }), settings, 0);
         assertScanDataFreqsEquals(null, results);
     }
 
     @Test
+    public void filterScanDataSingleNotMatchingWithDefinitlyScannedBucketIndex() {
+        ScanSettings settings = createRequest(
+                channelsToSpec(2400, 5150), 30000, 0, 20,
+                WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
+        );
+
+        ScanData[] results = ScanScheduleUtil.filterResultsForSettings(mChannelHelper,
+                createScanDatas(new int[][]{ { 2450 } }), settings, -1);
+        assertScanDataFreqsEquals(new int[][]{ { } }, results);
+    }
+
+    @Test
     public void filterScanDataSingleNotMatchingWithBucketDefinitlyScanned() {
         ScanSettings settings = createRequest(
                 channelsToSpec(2400, 5150), 30000, 0, 20,
@@ -162,7 +174,7 @@
         );
 
         ScanData[] results = ScanScheduleUtil.filterResultsForSettings(mChannelHelper,
-                createScanDatas(new int[][]{ { 2400 } }), settings, -1);
+                createScanDatas(new int[][]{ { 2400 } }), settings, 0);
 
         assertScanDataFreqsEquals(new int[][]{ { 2400 } }, results);
     }
@@ -188,7 +200,7 @@
         );
 
         ScanData[] results = ScanScheduleUtil.filterResultsForSettings(mChannelHelper,
-                createScanDatas(new int[][]{ { 2400, 2450, 5150, 5175 } }), settings, -1);
+                createScanDatas(new int[][]{ { 2400, 2450, 5150, 5175 } }), settings, 0);
 
         assertScanDataFreqsEquals(new int[][]{ { 2400, 5150 } }, results);
     }
@@ -201,7 +213,7 @@
         );
 
         ScanData[] results = ScanScheduleUtil.filterResultsForSettings(mChannelHelper,
-                createScanDatas(new int[][]{ { 2450 }, { 2450, 5175 } }), settings, -1);
+                createScanDatas(new int[][]{ { 2450 }, { 2450, 5175 } }), settings, 0);
         assertScanDataFreqsEquals(null, results);
     }
 
@@ -226,7 +238,7 @@
         );
 
         ScanData[] results = ScanScheduleUtil.filterResultsForSettings(mChannelHelper,
-                createScanDatas(new int[][]{ { 2400 }, {2400, 5150} }), settings, -1);
+                createScanDatas(new int[][]{ { 2400 }, {2400, 5150} }), settings, 0);
 
         assertScanDataFreqsEquals(new int[][]{ { 2400 }, {2400, 5150} }, results);
     }
@@ -256,7 +268,7 @@
                 createScanDatas(new int[][]{
                         { 2400, 2450, 5150, 5175, 2400 },
                         { 2400, 2450, 5175 },
-                        { 5175, 5175, 5150 } }), settings, -1);
+                        { 5175, 5175, 5150 } }), settings, 0);
 
         assertScanDataFreqsEquals(new int[][]{ { 2400, 5150, 2400 }, { 2400 }, { 5150 } }, results);
     }
@@ -272,7 +284,7 @@
                 createScanDatas(new int[][]{
                         { 2400, 2450, 5150, 5175, 2400 },
                         { 5175 },
-                        { 5175, 5175, 5150 } }), settings, -1);
+                        { 5175, 5175, 5150 } }), settings, 0);
 
         assertScanDataFreqsEquals(new int[][]{ { 2400, 5150, 2400 }, { 5150 } }, results);
     }
@@ -288,7 +300,7 @@
                 createScanDatas(new int[][]{
                         { 2400, 2450, 5150, 5175, 2400, 2400},
                         { 5175 },
-                        { 5175, 5175, 5150, 2400, 2400, 5150 } }), settings, -1);
+                        { 5175, 5175, 5150, 2400, 2400, 5150 } }), settings, 0);
 
         assertScanDataFreqsEquals(new int[][]{ { 2400, 5150, 2400 }, { 5150, 2400, 2400 } },
                 results);
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 1fb0f95..c0e0a10 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
@@ -374,7 +374,7 @@
         verifySuccessfulResponse(order, handler, requestId);
 
         when(mWifiScannerImpl.getLatestSingleScanResults())
-                .thenReturn(results.getScanData());
+                .thenReturn(results.getRawScanData());
         eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
 
         mLooper.dispatchAll();
@@ -383,7 +383,7 @@
         verifyNoMoreInteractions(handler);
         assertDumpContainsRequestLog("addSingleScanRequest", requestId);
         assertDumpContainsCallbackLog("singleScanResults", requestId,
-                "results=" + results.getRawScanResults().length);
+                "results=" + results.getScanData().getResults().length);
     }
 
     /**
@@ -409,6 +409,33 @@
     }
 
     /**
+     * Do a single scan with no results and verify that it is successful.
+     */
+    @Test
+    public void sendSingleScanRequestWithNoResults() throws Exception {
+        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
+                ScanResults.create(0, new int[0]));
+    }
+
+    /**
+     * Do a single scan with results that do not match the requested scan and verify that it is
+     * still successful (and returns no results).
+     */
+    @Test
+    public void sendSingleScanRequestWithBadRawResults() throws Exception {
+        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_24_GHZ, 0,
+                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+        // Create a set of scan results that has results not matching the request settings, but is
+        // limited to zero results for the expected results.
+        ScanResults results = ScanResults.createOverflowing(0, 0,
+                ScanResults.generateNativeResults(0, 5150, 5171));
+        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
+                results);
+    }
+
+    /**
      * Do a single scan, which the hardware fails to start, and verify that a failure response is
      * delivered.
      */