WifiNetworkSuggestionStoreData: New Module to persist suggestion
The new module serializes/deserializes network suggestions from store
files.
Bug: 115504887
Test: ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh
Change-Id: I5655f56bf592a326d91e6c5e69add437e5467e52
diff --git a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java
new file mode 100644
index 0000000..76f8910
--- /dev/null
+++ b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiNetworkSuggestion;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.XmlUtils;
+import com.android.server.wifi.util.XmlUtil;
+import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * This class performs serialization and parsing of XML data block that contain the list of WiFi
+ * network suggestions.
+ */
+public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData {
+ private static final String TAG = "NetworkSuggestionStoreData";
+
+ private static final String XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_MAP =
+ "NetworkSuggestionMap";
+ private static final String XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP =
+ "NetworkSuggestionPerApp";
+ private static final String XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION = "NetworkSuggestion";
+ private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration";
+ private static final String XML_TAG_IS_APP_INTERACTION_REQUIRED = "IsAppInteractionRequired";
+ private static final String XML_TAG_IS_USER_INTERACTION_REQUIRED = "IsUserInteractionRequired";
+ private static final String XML_TAG_SUGGESTOR_UID = "SuggestorUid";
+ private static final String XML_TAG_SUGGESTOR_PACKAGE_NAME = "SuggestorPackageName";
+
+ /**
+ * Interface define the data source for the network suggestions store data.
+ */
+ public interface DataSource {
+ /**
+ * Retrieve the network suggestion list from the data source.
+ *
+ * @return Map of package name to set of {@link WifiNetworkSuggestion}
+ */
+ Map<String, Set<WifiNetworkSuggestion>> getNetworkSuggestions();
+
+ /**
+ * Set the network suggestions list in the data source.
+ *
+ * @param networkSuggestions Map of package name to set of {@link WifiNetworkSuggestion}
+ */
+ void setNetworkSuggestions(Map<String, Set<WifiNetworkSuggestion>> networkSuggestions);
+
+ /**
+ * Clear internal data structure in preparation for user switch or initial store read.
+ */
+ void reset();
+
+ /**
+ * Indicates whether there is new data to serialize.
+ */
+ boolean hasNewDataToSerialize();
+ }
+
+ private final DataSource mDataSource;
+
+ public NetworkSuggestionStoreData(DataSource dataSource) {
+ mDataSource = dataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out)
+ throws XmlPullParserException, IOException {
+ serializeNetworkSuggestionsMap(out, mDataSource.getNetworkSuggestions());
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth)
+ throws XmlPullParserException, IOException {
+ // Ignore empty reads.
+ if (in == null) {
+ return;
+ }
+ mDataSource.setNetworkSuggestions(parseNetworkSuggestionsMap(in, outerTagDepth));
+ }
+
+ @Override
+ public void resetData() {
+ mDataSource.reset();
+ }
+
+ @Override
+ public boolean hasNewDataToSerialize() {
+ return mDataSource.hasNewDataToSerialize();
+ }
+
+ @Override
+ public String getName() {
+ return XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_MAP;
+ }
+
+ @Override
+ public @WifiConfigStore.StoreFileId int getStoreFileId() {
+ return WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS;
+ }
+
+ /**
+ * Serialize the map of package name to network suggestions to an output stream in XML format.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void serializeNetworkSuggestionsMap(
+ XmlSerializer out, Map<String, Set<WifiNetworkSuggestion>> networkSuggestionsMap)
+ throws XmlPullParserException, IOException {
+ if (networkSuggestionsMap == null) {
+ return;
+ }
+ for (Entry<String, Set<WifiNetworkSuggestion>> entry : networkSuggestionsMap.entrySet()) {
+ String packageName = entry.getKey();
+ Set<WifiNetworkSuggestion> networkSuggestions = entry.getValue();
+
+ XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP);
+ XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_PACKAGE_NAME, packageName);
+ serializeNetworkSuggestions(out, networkSuggestions);
+ XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP);
+ }
+ }
+
+ /**
+ * Serialize the set of network suggestions to an output stream in XML format.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void serializeNetworkSuggestions(
+ XmlSerializer out, Set<WifiNetworkSuggestion> networkSuggestions)
+ throws XmlPullParserException, IOException {
+ for (WifiNetworkSuggestion networkSuggestion : networkSuggestions) {
+ serializeNetworkSuggestion(out, networkSuggestion);
+ }
+ }
+
+ /**
+ * Serialize a {@link WifiNetworkSuggestion} to an output stream in XML format.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void serializeNetworkSuggestion(XmlSerializer out, WifiNetworkSuggestion suggestion)
+ throws XmlPullParserException, IOException {
+ XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION);
+
+ // Serialize WifiConfiguration.
+ XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
+ WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, suggestion.wifiConfiguration);
+ XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
+
+ // Serialize other fields
+ XmlUtil.writeNextValue(out, XML_TAG_IS_APP_INTERACTION_REQUIRED,
+ suggestion.isAppInteractionRequired);
+ XmlUtil.writeNextValue(out, XML_TAG_IS_USER_INTERACTION_REQUIRED,
+ suggestion.isUserInteractionRequired);
+ XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_UID, suggestion.suggestorUid);
+
+ XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION);
+ }
+
+ /**
+ * Parse a map of package name to network suggestions from an input stream in XML format.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private Map<String, Set<WifiNetworkSuggestion>> parseNetworkSuggestionsMap(
+ XmlPullParser in, int outerTagDepth)
+ throws XmlPullParserException, IOException {
+ Map<String, Set<WifiNetworkSuggestion>> networkSuggestionsMap = new HashMap<>();
+ while (XmlUtil.gotoNextSectionWithNameOrEnd(
+ in, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP, outerTagDepth)) {
+ // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are
+ // fatal and should abort the entire loading process.
+ try {
+ String packageName =
+ (String) XmlUtil.readNextValueWithName(in, XML_TAG_SUGGESTOR_PACKAGE_NAME);
+ Set<WifiNetworkSuggestion> networkSuggestions =
+ parseNetworkSuggestions(in, outerTagDepth + 1);
+ networkSuggestionsMap.put(packageName, networkSuggestions);
+ } catch (RuntimeException e) {
+ // Failed to parse this network, skip it.
+ Log.e(TAG, "Failed to parse network suggestion. Skipping...", e);
+ }
+ }
+ return networkSuggestionsMap;
+ }
+
+ /**
+ * Parse a set of network suggestions from an input stream in XML format.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private Set<WifiNetworkSuggestion> parseNetworkSuggestions(XmlPullParser in, int outerTagDepth)
+ throws XmlPullParserException, IOException {
+ Set<WifiNetworkSuggestion> networkSuggestions = new HashSet<>();
+ while (XmlUtil.gotoNextSectionWithNameOrEnd(
+ in, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION, outerTagDepth)) {
+ // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are
+ // fatal and should abort the entire loading process.
+ try {
+ WifiNetworkSuggestion networkSuggestion =
+ parseNetworkSuggestion(in, outerTagDepth + 1);
+ networkSuggestions.add(networkSuggestion);
+ } catch (RuntimeException e) {
+ // Failed to parse this network, skip it.
+ Log.e(TAG, "Failed to parse network suggestion. Skipping...", e);
+ }
+ }
+ return networkSuggestions;
+ }
+
+ /**
+ * Parse a {@link WifiNetworkSuggestion} from an input stream in XML format.
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private WifiNetworkSuggestion parseNetworkSuggestion(XmlPullParser in, int outerTagDepth)
+ throws XmlPullParserException, IOException {
+ WifiConfiguration wifiConfiguration = null;
+ boolean isAppInteractionRequired = false;
+ boolean isUserInteractionRequired = false;
+ int suggestorUid = Process.INVALID_UID;
+
+ // Loop through and parse out all the elements from the stream within this section.
+ while (XmlUtils.nextElementWithin(in, outerTagDepth)) {
+ if (in.getAttributeValue(null, "name") != null) {
+ // Value elements.
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ switch (valueName[0]) {
+ case XML_TAG_IS_APP_INTERACTION_REQUIRED:
+ isAppInteractionRequired = (boolean) value;
+ break;
+ case XML_TAG_IS_USER_INTERACTION_REQUIRED:
+ isUserInteractionRequired = (boolean) value;
+ break;
+ case XML_TAG_SUGGESTOR_UID:
+ suggestorUid = (int) value;
+ break;
+ default:
+ throw new XmlPullParserException(
+ "Unknown value name found: " + valueName[0]);
+ }
+ } else {
+ if (!TextUtils.equals(in.getName(), XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION)) {
+ throw new XmlPullParserException("Unexpected section under configuration: "
+ + in.getName());
+ }
+ Pair<String, WifiConfiguration> parsedConfigWithConfigKey =
+ WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
+ wifiConfiguration = parsedConfigWithConfigKey.second;
+ }
+ }
+ if (wifiConfiguration == null) {
+ throw new XmlPullParserException("XML parsing of wifi configuration failed");
+ }
+ if (suggestorUid == -1) {
+ throw new XmlPullParserException("XML parsing of suggestor uid failed");
+ }
+ return new WifiNetworkSuggestion(wifiConfiguration, isAppInteractionRequired,
+ isUserInteractionRequired, suggestorUid);
+ }
+}
+
diff --git a/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java b/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java
new file mode 100644
index 0000000..12776b2
--- /dev/null
+++ b/service/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.net.wifi.WifiNetworkSuggestion;
+import android.support.test.filters.SmallTest;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.NetworkSuggestionStoreData}.
+ */
+@SmallTest
+public class NetworkSuggestionStoreDataTest {
+ private static final int TEST_UID_1 = 14556;
+ private static final int TEST_UID_2 = 14536;
+ private static final String TEST_PACKAGE_NAME_1 = "com.android.test.1";
+ private static final String TEST_PACKAGE_NAME_2 = "com.android.test.2";
+ private static final String TEST_CORRUPT_DATA_INVALID_SSID =
+ "<NetworkSuggestionPerApp>\n"
+ + "<string name=\"SuggestorPackageName\">com.android.test.1</string>\n"
+ + "<NetworkSuggestion>\n"
+ + "<WifiConfiguration>\n"
+ + "<string name=\"ConfigKey\">"WifiConfigurationTestUtilSSID7"NONE</string>\n"
+ + "<blah blah=\"SSID\">"WifiConfigurationTestUtilSSID7"</blah>\n"
+ + "<null name=\"BSSID\" />\n"
+ + "<null name=\"PreSharedKey\" />\n"
+ + "<null name=\"WEPKeys\" />\n"
+ + "<int name=\"WEPTxKeyIndex\" value=\"0\" />\n"
+ + "<boolean name=\"HiddenSSID\" value=\"false\" />\n"
+ + "<boolean name=\"RequirePMF\" value=\"false\" />\n"
+ + "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">01</byte-array>\n"
+ + "<byte-array name=\"AllowedProtocols\" num=\"0\"></byte-array>\n"
+ + "<byte-array name=\"AllowedAuthAlgos\" num=\"0\"></byte-array>\n"
+ + "<byte-array name=\"AllowedGroupCiphers\" num=\"0\"></byte-array>\n"
+ + "<byte-array name=\"AllowedPairwiseCiphers\" num=\"0\"></byte-array>\n"
+ + "<byte-array name=\"AllowedGroupMgmtCiphers\" num=\"0\"></byte-array>\n"
+ + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n"
+ + "<boolean name=\"Shared\" value=\"true\" />\n"
+ + "<int name=\"Status\" value=\"2\" />\n"
+ + "<null name=\"FQDN\" />\n"
+ + "<null name=\"ProviderFriendlyName\" />\n"
+ + "<null name=\"LinkedNetworksList\" />\n"
+ + "<null name=\"DefaultGwMacAddress\" />\n"
+ + "<boolean name=\"ValidatedInternetAccess\" value=\"false\" />\n"
+ + "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n"
+ + "<int name=\"UserApproved\" value=\"0\" />\n"
+ + "<boolean name=\"MeteredHint\" value=\"false\" />\n"
+ + "<int name=\"MeteredOverride\" value=\"0\" />\n"
+ + "<boolean name=\"UseExternalScores\" value=\"false\" />\n"
+ + "<int name=\"NumAssociation\" value=\"0\" />\n"
+ + "<int name=\"CreatorUid\" value=\"5\" />\n"
+ + "<null name=\"CreatorName\" />\n"
+ + "<null name=\"CreationTime\" />\n"
+ + "<int name=\"LastUpdateUid\" value=\"-1\" />\n"
+ + "<null name=\"LastUpdateName\" />\n"
+ + "<int name=\"LastConnectUid\" value=\"0\" />\n"
+ + "<boolean name=\"IsLegacyPasspointConfig\" value=\"false\" />\n"
+ + "<long-array name=\"RoamingConsortiumOIs\" num=\"0\" />\n"
+ + "<string name=\"RandomizedMacAddress\">02:00:00:00:00:00</string>\n"
+ + "</WifiConfiguration>\n"
+ + "<boolean name=\"IsAppInteractionRequired\" value=\"false\" />\n"
+ + "<boolean name=\"IsUserInteractionRequired\" value=\"false\" />\n"
+ + "<int name=\"SuggestorUid\" value=\"14556\" />\n"
+ + "</NetworkSuggestion>\n"
+ + "</NetworkSuggestionPerApp>";
+
+ private @Mock NetworkSuggestionStoreData.DataSource mDataSource;
+ private NetworkSuggestionStoreData mNetworkSuggestionStoreData;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mNetworkSuggestionStoreData = new NetworkSuggestionStoreData(mDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ */
+ private byte[] serializeData() throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mNetworkSuggestionStoreData.serializeData(out);
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ */
+ private void deserializeData(byte[] data) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mNetworkSuggestionStoreData.deserializeData(in, in.getDepth());
+ }
+
+ /**
+ * Verify store file Id.
+ */
+ @Test
+ public void verifyStoreFileId() throws Exception {
+ assertEquals(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS,
+ mNetworkSuggestionStoreData.getStoreFileId());
+ }
+
+ /**
+ * Serialize/Deserialize a single network suggestion from a single app.
+ */
+ @Test
+ public void serializeDeserializeSingleNetworkSuggestionFromSingleApp() throws Exception {
+ WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), false, false, TEST_UID_1);
+ Map<String, Set<WifiNetworkSuggestion>> networkSuggestionsMap = new HashMap<>();
+ Set<WifiNetworkSuggestion> networkSuggestionsSet = new HashSet<WifiNetworkSuggestion>() {{
+ add(networkSuggestion);
+ }};
+ networkSuggestionsMap.put(TEST_PACKAGE_NAME_1, networkSuggestionsSet);
+
+ assertSerializeDeserialize(networkSuggestionsMap);
+ }
+
+ /**
+ * Serialize/Deserialize a single network suggestion from multiple apps.
+ */
+ @Test
+ public void serializeDeserializeSingleNetworkSuggestionFromMultipleApps() throws Exception {
+ WifiNetworkSuggestion networkSuggestion1 = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), false, false, TEST_UID_1);
+ Set<WifiNetworkSuggestion> networkSuggestionsSet1 = new HashSet<WifiNetworkSuggestion>() {{
+ add(networkSuggestion1);
+ }};
+ WifiNetworkSuggestion networkSuggestion2 = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_2);
+ Set<WifiNetworkSuggestion> networkSuggestionsSet2 = new HashSet<WifiNetworkSuggestion>() {{
+ add(networkSuggestion2);
+ }};
+ Map<String, Set<WifiNetworkSuggestion>> networkSuggestionsMap = new HashMap<>();
+ networkSuggestionsMap.put(TEST_PACKAGE_NAME_1, networkSuggestionsSet1);
+ networkSuggestionsMap.put(TEST_PACKAGE_NAME_2, networkSuggestionsSet2);
+
+ assertSerializeDeserialize(networkSuggestionsMap);
+ }
+
+ /**
+ * Serialize/Deserialize multiple network suggestion from multiple apps.
+ */
+ @Test
+ public void serializeDeserializeMultipleNetworkSuggestionFromMultipleApps() throws Exception {
+ WifiNetworkSuggestion networkSuggestion1 = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), false, true, TEST_UID_1);
+ WifiNetworkSuggestion networkSuggestion2 = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_1);
+ Set<WifiNetworkSuggestion> networkSuggestionsSet1 = new HashSet<WifiNetworkSuggestion>() {{
+ add(networkSuggestion1);
+ add(networkSuggestion2);
+ }};
+ WifiNetworkSuggestion networkSuggestion3 = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), true, false, TEST_UID_2);
+ WifiNetworkSuggestion networkSuggestion4 = new WifiNetworkSuggestion(
+ WifiConfigurationTestUtil.createOpenNetwork(), false, true, TEST_UID_2);
+ Set<WifiNetworkSuggestion> networkSuggestionsSet2 = new HashSet<WifiNetworkSuggestion>() {{
+ add(networkSuggestion3);
+ add(networkSuggestion4);
+ }};
+ Map<String, Set<WifiNetworkSuggestion>> networkSuggestionsMap = new HashMap<>();
+ networkSuggestionsMap.put(TEST_PACKAGE_NAME_1, networkSuggestionsSet1);
+ networkSuggestionsMap.put(TEST_PACKAGE_NAME_2, networkSuggestionsSet2);
+
+ assertSerializeDeserialize(networkSuggestionsMap);
+ }
+
+ /**
+ * Deserialize corrupt data and ensure that we gracefully handle any errors in the data.
+ * graceful == throw XmlPullParserException (which is handled in
+ * {@link WifiConfigManager#loadFromStore()}).
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void deserializeCorruptData() throws Exception {
+ deserializeData(TEST_CORRUPT_DATA_INVALID_SSID.getBytes());
+ }
+
+ private void assertSerializeDeserialize(
+ Map<String, Set<WifiNetworkSuggestion>> networkSuggestionsMap) throws Exception {
+ // Setup the data to serialize.
+ when(mDataSource.getNetworkSuggestions()).thenReturn(networkSuggestionsMap);
+
+ // Serialize/deserialize data.
+ deserializeData(serializeData());
+
+ // Verify the deserialized data.
+ ArgumentCaptor<HashMap> deserializedNetworkSuggestionsMap =
+ ArgumentCaptor.forClass(HashMap.class);
+ verify(mDataSource).setNetworkSuggestions(deserializedNetworkSuggestionsMap.capture());
+ assertEquals(networkSuggestionsMap, deserializedNetworkSuggestionsMap.getValue());
+ }
+}