Fail safely on invalid ScanResults when creating NetworkKey

Added tests for NetworkKey#createFromScanResult

Bug: 34671341
Test: runtest --path
frameworks/base/core/tests/coretests/src/android/net/NetworkKeyTest.java
runtest --path
frameworks/base/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java

Change-Id: Ideac1615917649cd3934421228a82aeed37e7ad1
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index e5f0bf0..31a74dc 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.Objects;
 
@@ -41,6 +42,8 @@
 // etc.) so that clients can pull out these details depending on the type of network.
 public class NetworkKey implements Parcelable {
 
+    private static final String TAG = "NetworkKey";
+
     /** A wifi network, for which {@link #wifiKey} will be populated. */
     public static final int TYPE_WIFI = 1;
 
@@ -59,13 +62,28 @@
     /**
      * Constructs a new NetworkKey for the given wifi {@link ScanResult}.
      *
-     * @throws IllegalArgumentException if the given ScanResult is malformed
+     * @return  A new {@link NetworkKey} instance or <code>null</code> if the given
+     *          {@link ScanResult} instance is malformed.
      * @hide
      */
-    public static NetworkKey createFromScanResult(ScanResult result) {
-        return new NetworkKey(
-                new WifiKey(
-                        '"' + result.wifiSsid.toString() + '"', result.BSSID));
+    @Nullable
+    public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
+        if (result != null && result.wifiSsid != null) {
+            final String ssid = result.wifiSsid.toString();
+            final String bssid = result.BSSID;
+            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
+                    && !TextUtils.isEmpty(bssid)) {
+                WifiKey wifiKey;
+                try {
+                    wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Unable to create WifiKey.", e);
+                    return null;
+                }
+                return new NetworkKey(wifiKey);
+            }
+        }
+        return null;
     }
 
     /**
@@ -83,7 +101,14 @@
             final String bssid = wifiInfo.getBSSID();
             if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
                     && !TextUtils.isEmpty(bssid)) {
-                return new NetworkKey(new WifiKey(ssid, bssid));
+                WifiKey wifiKey;
+                try {
+                    wifiKey = new WifiKey(ssid, bssid);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Unable to create WifiKey.", e);
+                    return null;
+                }
+                return new NetworkKey(wifiKey);
             }
         }
         return null;
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index 1afe9da..fff23a0 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -4,6 +4,7 @@
 import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.when;
 
+import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiSsid;
 import android.support.test.runner.AndroidJUnit4;
@@ -17,7 +18,9 @@
 @RunWith(AndroidJUnit4.class)
 public class NetworkKeyTest {
     private static final String VALID_SSID = "\"ssid1\"";
+    private static final String VALID_UNQUOTED_SSID = "ssid1";
     private static final String VALID_BSSID = "00:00:00:00:00:00";
+    private static final String INVALID_BSSID = "invalid_bssid";
     @Mock private WifiInfo mWifiInfo;
 
     @Before
@@ -64,6 +67,13 @@
     }
 
     @Test
+    public void createFromWifi_invalidBssid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
+        when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID);
+        assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
+    }
+
+    @Test
     public void createFromWifi_validWifiInfo() throws Exception {
         when(mWifiInfo.getSSID()).thenReturn(VALID_SSID);
         when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
@@ -72,4 +82,72 @@
         final NetworkKey actual = NetworkKey.createFromWifiInfo(mWifiInfo);
         assertEquals(expected, actual);
     }
+
+    @Test
+    public void createFromScanResult_nullInput() {
+        assertNull(NetworkKey.createFromScanResult(null));
+    }
+
+    @Test
+    public void createFromScanResult_nullWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.BSSID = VALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_emptyWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded("");
+        scanResult.BSSID = VALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_noneWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(WifiSsid.NONE);
+        scanResult.BSSID = VALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_nullBssid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_emptyBssid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.BSSID = "";
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_invalidBssid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.BSSID = INVALID_BSSID;
+
+        assertNull(NetworkKey.createFromScanResult(scanResult));
+    }
+
+    @Test
+    public void createFromScanResult_validWifiSsid() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.BSSID = VALID_BSSID;
+
+        NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID));
+        NetworkKey actual = NetworkKey.createFromScanResult(scanResult);
+        assertEquals(expected, actual);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 0ec16ae2..9ac4d2d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -510,7 +510,7 @@
                 }
 
                 NetworkKey key = NetworkKey.createFromScanResult(result);
-                if (!mRequestedScores.contains(key)) {
+                if (key != null && !mRequestedScores.contains(key)) {
                     scoresToRequest.add(key);
                 }
 
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 3e89852..b33538cb 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -603,7 +603,10 @@
             mScanResultKeys = new ArraySet<>(size);
             for (int i = 0; i < size; i++) {
                 ScanResult scanResult = scanResults.get(i);
-                mScanResultKeys.add(NetworkKey.createFromScanResult(scanResult));
+                NetworkKey key = NetworkKey.createFromScanResult(scanResult);
+                if (key != null) {
+                    mScanResultKeys.add(key);
+                }
             }
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 3a88e9c..c0b79be 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -117,6 +117,7 @@
     private static final String SSID = "ssid";
     private static final String SSID_2 = "ssid_2";
     private static final String SSID_3 = "ssid_3";
+    private static final String INVALID_BSSID = "invalid_bssid";
     private static final ComponentName RECOMMENDATION_SERVICE_COMP =
             new ComponentName("newPackageName", "newScoringServiceClass");
     private static final ScoredNetwork SCORED_NETWORK =
@@ -778,6 +779,54 @@
     }
 
     @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_nullSsid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn(null);
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_noneSsid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_emptySsid() throws Exception {
+        when(mWifiInfo.getSSID()).thenReturn("");
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
+    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_invalidBssid() throws Exception {
+        when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID);
+        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
+                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
     public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception {
         NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
                 new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
@@ -813,6 +862,24 @@
     }
 
     @Test
+    public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception {
+        List<ScanResult> invalidScanResults = Lists.newArrayList(
+                new ScanResult(),
+                createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid),
+                createScanResult(WifiSsid.NONE, SCORED_NETWORK.networkKey.wifiKey.bssid),
+                createScanResult(SSID, null),
+                createScanResult(SSID, INVALID_BSSID)
+        );
+        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
+                new NetworkScoreService.ScanResultsScoreCacheFilter(() -> invalidScanResults);
+
+        List<ScoredNetwork> actualList =
+                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
+
+        assertTrue(actualList.isEmpty());
+    }
+
+    @Test
     public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception {
         NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
                 new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults);