summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/WifiBackupRestore.java331
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java26
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java36
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java214
4 files changed, 590 insertions, 17 deletions
diff --git a/service/java/com/android/server/wifi/WifiBackupRestore.java b/service/java/com/android/server/wifi/WifiBackupRestore.java
index 012d95470..a3bde7b37 100644
--- a/service/java/com/android/server/wifi/WifiBackupRestore.java
+++ b/service/java/com/android/server/wifi/WifiBackupRestore.java
@@ -23,18 +23,24 @@ import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiEnterpriseConfig;
import android.util.Log;
+import android.util.SparseArray;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
+import com.android.server.net.IpConfigStore;
import com.android.server.wifi.util.XmlUtil;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
@@ -42,7 +48,9 @@ import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.BitSet;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import static android.net.IpConfiguration.IpAssignment;
import static android.net.IpConfiguration.ProxySettings;
@@ -423,8 +431,8 @@ public class WifiBackupRestore {
// configKey stored in the XML data.
String configKeyCalculated = configuration.configKey();
if (!configKeyInData.equals(configKeyCalculated)) {
- Log.e(TAG, "Configuration key does not match. InData: " + configKeyInData
- + "Calculated: " + configKeyCalculated);
+ Log.e(TAG, "Configuration key does not match. Retrieved: " + configKeyInData
+ + ", Calculated: " + configKeyCalculated);
return null;
}
// Now retrieve any IP configuration info if present.
@@ -566,4 +574,323 @@ public class WifiBackupRestore {
}
Log.d(TAG, logString + ": " + xmlString);
}
+
+ /**
+ * Restore state from the older supplicant back up data.
+ * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
+ *
+ * @param supplicantData Raw byte stream of wpa_supplicant.conf
+ * @param ipConfigData Raw byte stream of ipconfig.txt
+ * @return list of networks retrieved from the backed up data.
+ */
+ public List<WifiConfiguration> retrieveConfigurationsFromSupplicantBackupData(
+ byte[] supplicantData, byte[] ipConfigData) {
+ if (supplicantData == null || ipConfigData == null
+ || supplicantData.length == 0 || ipConfigData.length == 0) {
+ Log.e(TAG, "Invalid supplicant backup data received");
+ return null;
+ }
+
+ SupplicantBackupMigration.SupplicantNetworks supplicantNetworks =
+ new SupplicantBackupMigration.SupplicantNetworks();
+ // Incorporate the networks present in the backup data.
+ char[] restoredAsBytes = new char[supplicantData.length];
+ for (int i = 0; i < supplicantData.length; i++) {
+ restoredAsBytes[i] = (char) supplicantData[i];
+ }
+
+ BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
+ supplicantNetworks.readNetworksFromStream(in);
+ if (mVerboseLoggingEnabled) {
+ Log.d(TAG, "Final network list from old backup:");
+ supplicantNetworks.dump();
+ }
+
+ // Retrieve corresponding WifiConfiguration objects.
+ List<WifiConfiguration> configurations = supplicantNetworks.retrieveWifiConfigurations();
+
+ // Now retrieve all the IpConfiguration objects and set in the corresponding
+ // WifiConfiguration objects.
+ SparseArray<IpConfiguration> networks =
+ IpConfigStore.readIpAndProxyConfigurations(new ByteArrayInputStream(ipConfigData));
+ if (networks != null) {
+ for (int i = 0; i < networks.size(); i++) {
+ int id = networks.keyAt(i);
+ for (WifiConfiguration configuration : configurations) {
+ // This is a dangerous lookup, but that's how it is currently written.
+ if (configuration.configKey().hashCode() == id) {
+ configuration.setIpConfiguration(networks.valueAt(i));
+ }
+ }
+ }
+ } else {
+ Log.e(TAG, "Invalid Ip config data");
+ }
+ return configurations;
+ }
+
+ /**
+ * These sub classes contain the logic to parse older backups and restore wifi state from it.
+ * Most of the code here has been migrated over from BackupSettingsAgent.
+ * This is kind of ugly text parsing, but it is needed to support the migration of this data.
+ */
+ public static class SupplicantBackupMigration {
+ /**
+ * List of keys to look out for in wpa_supplicant.conf parsing.
+ * These key values are declared in different parts of the wifi codebase today.
+ */
+ @VisibleForTesting
+ public static final String SUPPLICANT_KEY_SSID = WifiConfiguration.ssidVarName;
+ public static final String SUPPLICANT_KEY_KEY_MGMT = WifiConfiguration.KeyMgmt.varName;
+ public static final String SUPPLICANT_KEY_CLIENT_CERT = WifiEnterpriseConfig.CLIENT_CERT_KEY;
+ public static final String SUPPLICANT_KEY_CA_CERT = WifiEnterpriseConfig.CA_CERT_KEY;
+ public static final String SUPPLICANT_KEY_CA_PATH = WifiEnterpriseConfig.CA_PATH_KEY;
+ public static final String SUPPLICANT_KEY_EAP = WifiEnterpriseConfig.EAP_KEY;
+ public static final String SUPPLICANT_KEY_PSK = WifiConfiguration.pskVarName;
+ public static final String SUPPLICANT_KEY_WEP_KEY0 = WifiConfiguration.wepKeyVarNames[0];
+ public static final String SUPPLICANT_KEY_WEP_KEY1 = WifiConfiguration.wepKeyVarNames[1];
+ public static final String SUPPLICANT_KEY_WEP_KEY2 = WifiConfiguration.wepKeyVarNames[2];
+ public static final String SUPPLICANT_KEY_WEP_KEY3 = WifiConfiguration.wepKeyVarNames[3];
+ public static final String SUPPLICANT_KEY_WEP_KEY_IDX = WifiConfiguration.wepTxKeyIdxVarName;
+ public static final String SUPPLICANT_KEY_ID_STR = WifiConfigStore.ID_STRING_VAR_NAME;
+
+ /**
+ * Class for capturing a network definition from the wifi supplicant config file.
+ */
+ static class SupplicantNetwork {
+ final ArrayList<String> rawLines = new ArrayList<String>();
+ String ssid;
+ String key_mgmt;
+ String psk;
+ String[] wepKeys = new String[4];
+ String wepTxKeyIdx;
+ String id_str;
+ boolean certUsed = false;
+ boolean isEap = false;
+
+ /**
+ * Read lines from wpa_supplicant.conf stream for this network.
+ */
+ public static SupplicantNetwork readNetworkFromStream(BufferedReader in) {
+ final SupplicantNetwork n = new SupplicantNetwork();
+ String line;
+ try {
+ while (in.ready()) {
+ line = in.readLine();
+ if (line == null || line.startsWith("}")) {
+ break;
+ }
+ n.parseLine(line);
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ return n;
+ }
+
+ /**
+ * Parse a line from wpa_supplicant.conf stream for this network.
+ */
+ void parseLine(String line) {
+ // Can't rely on particular whitespace patterns so strip leading/trailing.
+ line = line.trim();
+ if (line.isEmpty()) return; // only whitespace; drop the line.
+ rawLines.add(line);
+
+ // Now parse the network block within wpa_supplicant.conf and store the important
+ // lines for procesing later.
+ if (line.startsWith(SUPPLICANT_KEY_SSID)) {
+ ssid = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_KEY_MGMT)) {
+ key_mgmt = line;
+ if (line.contains("EAP")) {
+ isEap = true;
+ }
+ } else if (line.startsWith(SUPPLICANT_KEY_CLIENT_CERT)) {
+ certUsed = true;
+ } else if (line.startsWith(SUPPLICANT_KEY_CA_CERT)) {
+ certUsed = true;
+ } else if (line.startsWith(SUPPLICANT_KEY_CA_PATH)) {
+ certUsed = true;
+ } else if (line.startsWith(SUPPLICANT_KEY_EAP)) {
+ isEap = true;
+ } else if (line.startsWith(SUPPLICANT_KEY_PSK)) {
+ psk = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_WEP_KEY0)) {
+ wepKeys[0] = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_WEP_KEY1)) {
+ wepKeys[1] = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_WEP_KEY2)) {
+ wepKeys[2] = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_WEP_KEY3)) {
+ wepKeys[3] = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_WEP_KEY_IDX)) {
+ wepTxKeyIdx = line;
+ } else if (line.startsWith(SUPPLICANT_KEY_ID_STR)) {
+ id_str = line;
+ }
+ }
+
+ /**
+ * Raw dump of wpa_supplicant.conf lines.
+ */
+ public void dump() {
+ Log.v(TAG, "network={");
+ for (String line : rawLines) {
+ Log.v(TAG, " " + line);
+ }
+ Log.v(TAG, "}");
+ }
+
+ /**
+ * Create WifiConfiguration object from the parsed data for this network.
+ */
+ public WifiConfiguration createWifiConfiguration() {
+ if (ssid == null) {
+ // No SSID => malformed network definition
+ return null;
+ }
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = ssid.substring(ssid.indexOf('=') + 1);
+
+ if (key_mgmt == null) {
+ // no key_mgmt specified; this is defined as equivalent to "WPA-PSK WPA-EAP"
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ } else {
+ // Need to parse the key_mgmt line
+ final String bareKeyMgmt = key_mgmt.substring(key_mgmt.indexOf('=') + 1);
+ String[] typeStrings = bareKeyMgmt.split("\\s+");
+
+ // Parse out all the key management regimes permitted for this network.
+ // The literal strings here are the standard values permitted in
+ // wpa_supplicant.conf.
+ for (int i = 0; i < typeStrings.length; i++) {
+ final String ktype = typeStrings[i];
+ if (ktype.equals("NONE")) {
+ configuration.allowedKeyManagement.set(
+ WifiConfiguration.KeyMgmt.NONE);
+ } else if (ktype.equals("WPA-PSK")) {
+ configuration.allowedKeyManagement.set(
+ WifiConfiguration.KeyMgmt.WPA_PSK);
+ } else if (ktype.equals("WPA-EAP")) {
+ configuration.allowedKeyManagement.set(
+ WifiConfiguration.KeyMgmt.WPA_EAP);
+ } else if (ktype.equals("IEEE8021X")) {
+ configuration.allowedKeyManagement.set(
+ WifiConfiguration.KeyMgmt.IEEE8021X);
+ }
+ }
+ }
+ if (psk != null) {
+ configuration.preSharedKey = psk.substring(psk.indexOf('=') + 1);
+ }
+ if (wepKeys[0] != null) {
+ configuration.wepKeys[0] = wepKeys[0].substring(wepKeys[0].indexOf('=') + 1);
+ }
+ if (wepKeys[1] != null) {
+ configuration.wepKeys[1] = wepKeys[1].substring(wepKeys[1].indexOf('=') + 1);
+ }
+ if (wepKeys[2] != null) {
+ configuration.wepKeys[2] = wepKeys[2].substring(wepKeys[2].indexOf('=') + 1);
+ }
+ if (wepKeys[3] != null) {
+ configuration.wepKeys[3] = wepKeys[3].substring(wepKeys[3].indexOf('=') + 1);
+ }
+ if (wepTxKeyIdx != null) {
+ configuration.wepTxKeyIndex =
+ Integer.valueOf(wepTxKeyIdx.substring(wepTxKeyIdx.indexOf('=') + 1));
+ }
+ if (id_str != null) {
+ String id_string = id_str.substring(id_str.indexOf('=') + 1);
+ Map<String, String> extras = WifiNative.parseNetworkExtra(id_string);
+ configuration.creatorUid =
+ Integer.valueOf(extras.get(WifiConfigStore.ID_STRING_KEY_CREATOR_UID));
+ String configKey = extras.get(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY);
+ if (!configKey.equals(configuration.configKey())) {
+ Log.e(TAG, "Configuration key does not match. Retrieved: " + configKey
+ + ", Calculated: " + configuration.configKey());
+ return null;
+ }
+ }
+ return configuration;
+ }
+ }
+
+ /**
+ * Ingest multiple wifi config fragments from wpa_supplicant.conf, looking for network={}
+ * blocks and eliminating duplicates
+ */
+ static class SupplicantNetworks {
+ // One for fast lookup, one for maintaining ordering
+ final HashSet<SupplicantNetwork> mKnownNetworks = new HashSet<>();
+ final ArrayList<SupplicantNetwork> mNetworks = new ArrayList<>(8);
+
+ /**
+ * Parse the wpa_supplicant.conf file stream and add networks.
+ */
+ public void readNetworksFromStream(BufferedReader in) {
+ try {
+ String line;
+ while (in.ready()) {
+ line = in.readLine();
+ if (line != null) {
+ // Parse out 'network=' decls so we can ignore duplicates
+ if (line.startsWith("network")) {
+ SupplicantNetwork net = SupplicantNetwork.readNetworkFromStream(in);
+ // Don't propagate EAP network definitions
+ if (net.isEap) {
+ Log.v(TAG, "Skipping EAP network " + net.ssid + " / "
+ + net.key_mgmt);
+ continue;
+ }
+ Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
+ mKnownNetworks.add(net);
+ mNetworks.add(net);
+ }
+ }
+ }
+ } catch (IOException e) {
+ // whatever happened, we're done now
+ }
+ }
+
+ /**
+ * Retrieve a list of WifiConfiguration objects parsed from wpa_supplicant.conf
+ *
+ * @return
+ */
+ public List<WifiConfiguration> retrieveWifiConfigurations() {
+ ArrayList<WifiConfiguration> wifiConfigurations = new ArrayList<>();
+ for (SupplicantNetwork net : mNetworks) {
+ if (net.certUsed) {
+ // Networks that use certificates for authentication can't be restored
+ // because the certificates they need don't get restored (because they
+ // are stored in keystore, and can't be restored)
+ continue;
+ }
+
+ if (net.isEap) {
+ // Similarly, omit EAP network definitions to avoid propagating
+ // controlled enterprise network definitions.
+ continue;
+ }
+ WifiConfiguration wifiConfiguration = net.createWifiConfiguration();
+ if (wifiConfiguration != null) {
+ wifiConfigurations.add(wifiConfiguration);
+ }
+ }
+ return wifiConfigurations;
+ }
+
+ /**
+ * Raw dump of wpa_supplicant.conf lines.
+ */
+ public void dump() {
+ for (SupplicantNetwork net : mNetworks) {
+ net.dump();
+ }
+ }
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 9828e6610..68397b774 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -45,6 +45,7 @@ import android.util.LocalLog;
import android.util.Log;
import com.android.internal.annotations.Immutable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.server.connectivity.KeepalivePacketData;
import com.android.server.wifi.hotspot2.NetworkDetail;
@@ -389,17 +390,26 @@ public class WifiNative {
}
public boolean setNetworkExtra(int netId, String name, Map<String, String> values) {
+ String encoded = createNetworkExtra(values);
+ if (encoded == null) {
+ return false;
+ }
+ return setNetworkVariable(netId, name, "\"" + encoded + "\"");
+ }
+
+ @VisibleForTesting
+ public static String createNetworkExtra(Map<String, String> values) {
final String encoded;
try {
encoded = URLEncoder.encode(new JSONObject(values).toString(), "UTF-8");
} catch (NullPointerException e) {
Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
- return false;
+ return null;
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
- return false;
+ return null;
}
- return setNetworkVariable(netId, name, "\"" + encoded + "\"");
+ return encoded;
}
public boolean setNetworkVariable(int netId, String name, String value) {
@@ -413,12 +423,16 @@ public class WifiNative {
}
public Map<String, String> getNetworkExtra(int netId, String name) {
- final String wrapped = getNetworkVariable(netId, name);
- if (wrapped == null || !wrapped.startsWith("\"") || !wrapped.endsWith("\"")) {
+ final String extraString = getNetworkVariable(netId, name);
+ return parseNetworkExtra(extraString);
+ }
+
+ public static Map<String, String> parseNetworkExtra(String extraSting) {
+ if (extraSting == null || !extraSting.startsWith("\"") || !extraSting.endsWith("\"")) {
return null;
}
try {
- final String encoded = wrapped.substring(1, wrapped.length() - 1);
+ final String encoded = extraSting.substring(1, extraSting.length() - 1);
// This method reads a JSON dictionary that was written by setNetworkExtra(). However,
// on devices that upgraded from Marshmallow, it may encounter a legacy value instead -
// an FQDN stored as a plain string. If such a value is encountered, the JSONObject
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 3f8c26985..34c7438f9 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -1974,6 +1974,7 @@ public class WifiServiceImpl extends IWifiManager.Stub {
/**
* Restore state from the backed up data.
+ *
* @param data Raw byte stream of the backed up data.
*/
@Override
@@ -2002,4 +2003,39 @@ public class WifiServiceImpl extends IWifiManager.Stub {
mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
}
}
+
+ /**
+ * Restore state from the older supplicant back up data.
+ * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
+ *
+ * @param supplicantData Raw byte stream of wpa_supplicant.conf
+ * @param ipConfigData Raw byte stream of ipconfig.txt
+ * @hide
+ */
+ public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
+ enforceChangePermission();
+ if (mWifiStateMachineChannel == null) {
+ Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
+ return;
+ }
+
+ Slog.d(TAG, "Restore supplicant backup data");
+ List<WifiConfiguration> wifiConfigurations =
+ mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
+ supplicantData, ipConfigData);
+ if (wifiConfigurations == null) {
+ Slog.e(TAG, "Backup data parse failed");
+ return;
+ }
+
+ for (WifiConfiguration configuration : wifiConfigurations) {
+ int networkId =
+ mWifiStateMachine.syncAddOrUpdateNetwork(
+ mWifiStateMachineChannel, configuration);
+ if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
+ Slog.e(TAG, "Restore network failed: " + configuration.configKey());
+ }
+ mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java
index 6dc5bc10d..5d3741176 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java
@@ -28,11 +28,19 @@ import android.net.wifi.WifiConfiguration;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import com.android.server.net.IpConfigStore;
+
import org.junit.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Random;
/**
@@ -55,7 +63,7 @@ public class WifiBackupRestoreTest {
private static final int TEST_STATIC_IP_LINK_PREFIX_LENGTH = 8;
private static final String TEST_STATIC_IP_GATEWAY_ADDRESS = "192.168.48.1";
private static final String[] TEST_STATIC_IP_DNS_SERVER_ADDRESSES =
- new String[] { "192.168.48.1", "192.168.48.10" };
+ new String[]{"192.168.48.1", "192.168.48.10"};
private static final String TEST_STATIC_PROXY_HOST = "192.168.48.1";
private static final int TEST_STATIC_PROXY_PORT = 8000;
private static final String TEST_STATIC_PROXY_EXCLUSION_LIST = "";
@@ -258,6 +266,101 @@ public class WifiBackupRestoreTest {
}
/**
+ * Verify that a single open network configuration is serialized & deserialized correctly from
+ * old backups.
+ */
+ @Test
+ public void testSingleOpenNetworkSupplicantBackupRestore() {
+ List<WifiConfiguration> configurations = new ArrayList<>();
+ configurations.add(createOpenNetwork(0));
+
+ byte[] supplicantData = createWpaSupplicantConfBackupData(configurations);
+ byte[] ipConfigData = createIpConfBackupData(configurations);
+ List<WifiConfiguration> retrievedConfigurations =
+ mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
+ supplicantData, ipConfigData);
+ assertConfigurationsEqual(configurations, retrievedConfigurations);
+ }
+
+ /**
+ * Verify that a single PSK network configuration is serialized & deserialized correctly from
+ * old backups.
+ */
+ @Test
+ public void testSinglePskNetworkSupplicantBackupRestore() {
+ List<WifiConfiguration> configurations = new ArrayList<>();
+ configurations.add(createPskNetwork(0));
+
+ byte[] supplicantData = createWpaSupplicantConfBackupData(configurations);
+ byte[] ipConfigData = createIpConfBackupData(configurations);
+ List<WifiConfiguration> retrievedConfigurations =
+ mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
+ supplicantData, ipConfigData);
+ assertConfigurationsEqual(configurations, retrievedConfigurations);
+ }
+
+ /**
+ * Verify that a single WEP network configuration is serialized & deserialized correctly from
+ * old backups.
+ */
+ @Test
+ public void testSingleWepNetworkSupplicantBackupRestore() {
+ List<WifiConfiguration> configurations = new ArrayList<>();
+ configurations.add(createWepNetwork(0));
+
+ byte[] supplicantData = createWpaSupplicantConfBackupData(configurations);
+ byte[] ipConfigData = createIpConfBackupData(configurations);
+ List<WifiConfiguration> retrievedConfigurations =
+ mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
+ supplicantData, ipConfigData);
+ assertConfigurationsEqual(configurations, retrievedConfigurations);
+ }
+
+ /**
+ * Verify that a single enterprise network configuration is not serialized from old backups.
+ */
+ @Test
+ public void testSingleEnterpriseNetworkNotSupplicantBackupRestore() {
+ List<WifiConfiguration> configurations = new ArrayList<>();
+ configurations.add(createEapNetwork(0));
+
+ byte[] supplicantData = createWpaSupplicantConfBackupData(configurations);
+ byte[] ipConfigData = createIpConfBackupData(configurations);
+ List<WifiConfiguration> retrievedConfigurations =
+ mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
+ supplicantData, ipConfigData);
+ assertTrue(retrievedConfigurations.isEmpty());
+ }
+
+ /**
+ * Verify that multiple networks with different credential types and IpConfiguration types are
+ * serialized and deserialized correctly from old backups
+ */
+ @Test
+ public void testMultipleNetworksWithDifferentIpConfigurationsAllSupplicantBackupRestore() {
+ List<WifiConfiguration> configurations = new ArrayList<>();
+
+ WifiConfiguration wepNetwork = createWepNetwork(0);
+ wepNetwork.setIpConfiguration(createDHCPIpConfigurationWithPacProxy());
+ configurations.add(wepNetwork);
+
+ WifiConfiguration pskNetwork = createPskNetwork(1);
+ pskNetwork.setIpConfiguration(createStaticIpConfigurationWithPacProxy());
+ configurations.add(pskNetwork);
+
+ WifiConfiguration openNetwork = createOpenNetwork(2);
+ openNetwork.setIpConfiguration(createStaticIpConfigurationWithStaticProxy());
+ configurations.add(openNetwork);
+
+ byte[] supplicantData = createWpaSupplicantConfBackupData(configurations);
+ byte[] ipConfigData = createIpConfBackupData(configurations);
+ List<WifiConfiguration> retrievedConfigurations =
+ mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
+ supplicantData, ipConfigData);
+ assertConfigurationsEqual(configurations, retrievedConfigurations);
+ }
+
+ /**
* Verify that any corrupted data provided by Backup/Restore is ignored correctly.
*/
@Test
@@ -272,27 +375,27 @@ public class WifiBackupRestoreTest {
}
private WifiConfiguration createOpenNetwork(int id) {
- String ssid = TEST_SSID + id;
+ String ssid = "\"" + TEST_SSID + id + "\"";
return WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid,
- false, false, null, null,
+ true, true, null, null,
WifiConfigurationTestUtil.SECURITY_NONE);
}
private WifiConfiguration createPskNetwork(int id) {
- String ssid = TEST_SSID + id;
+ String ssid = "\"" + TEST_SSID + id + "\"";
WifiConfiguration configuration =
WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid,
- false, false, null, null,
+ true, true, null, null,
WifiConfigurationTestUtil.SECURITY_PSK);
configuration.preSharedKey = TEST_PSK;
return configuration;
}
private WifiConfiguration createWepNetwork(int id) {
- String ssid = TEST_SSID + id;
+ String ssid = "\"" + TEST_SSID + id + "\"";
WifiConfiguration configuration =
WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid,
- false, false, null, null,
+ true, true, null, null,
WifiConfigurationTestUtil.SECURITY_WEP);
configuration.wepKeys = TEST_WEP_KEYS;
configuration.wepTxKeyIndex = TEST_WEP_TX_KEY_INDEX;
@@ -300,10 +403,10 @@ public class WifiBackupRestoreTest {
}
private WifiConfiguration createEapNetwork(int id) {
- String ssid = TEST_SSID + id;
+ String ssid = "\"" + TEST_SSID + id + "\"";
WifiConfiguration configuration =
WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid,
- false, false, TEST_FQDN, TEST_PROVIDER_FRIENDLY_NAME,
+ true, true, TEST_FQDN, TEST_PROVIDER_FRIENDLY_NAME,
WifiConfigurationTestUtil.SECURITY_EAP);
return configuration;
}
@@ -365,6 +468,99 @@ public class WifiBackupRestoreTest {
}
/**
+ * Helper method to write a list of networks in wpa_supplicant.conf format to the output stream.
+ */
+ private byte[] createWpaSupplicantConfBackupData(List<WifiConfiguration> configurations) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ OutputStreamWriter out = new OutputStreamWriter(bos);
+ try {
+ for (WifiConfiguration configuration : configurations) {
+ writeConfigurationToWpaSupplicantConf(out, configuration);
+ }
+ out.flush();
+ return bos.toByteArray();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Helper method to write a network in wpa_supplicant.conf format to the output stream.
+ * This was created using a sample wpa_supplicant.conf file. Using the raw key strings here
+ * (instead of consts in WifiBackupRestore).
+ */
+ private void writeConfigurationToWpaSupplicantConf(
+ OutputStreamWriter out, WifiConfiguration configuration)
+ throws IOException {
+ out.write("network={\n");
+ out.write(" " + "ssid=" + configuration.SSID + "\n");
+ String allowedKeyManagement = "";
+ if (configuration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
+ allowedKeyManagement += "NONE";
+ }
+ if (configuration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
+ allowedKeyManagement += "WPA-PSK ";
+ }
+ if (configuration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
+ allowedKeyManagement += "WPA-EAP ";
+ }
+ if (configuration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) {
+ allowedKeyManagement += "IEEE8021X ";
+ }
+ out.write(" " + "key_mgmt=" + allowedKeyManagement + "\n");
+ if (configuration.preSharedKey != null) {
+ out.write(" " + "psk=" + configuration.preSharedKey + "\n");
+ }
+ if (configuration.wepKeys[0] != null) {
+ out.write(" " + "wep_key0=" + configuration.wepKeys[0] + "\n");
+ }
+ if (configuration.wepKeys[1] != null) {
+ out.write(" " + "wep_key1=" + configuration.wepKeys[1] + "\n");
+ }
+ if (configuration.wepKeys[2] != null) {
+ out.write(" " + "wep_key2=" + configuration.wepKeys[2] + "\n");
+ }
+ if (configuration.wepKeys[3] != null) {
+ out.write(" " + "wep_key3=" + configuration.wepKeys[3] + "\n");
+ }
+ if (configuration.wepKeys[0] != null || configuration.wepKeys[1] != null
+ || configuration.wepKeys[2] != null || configuration.wepKeys[3] != null) {
+ out.write(" " + "wep_tx_keyidx=" + configuration.wepTxKeyIndex + "\n");
+ }
+ Map<String, String> extras = new HashMap<>();
+ extras.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, configuration.configKey());
+ extras.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
+ Integer.toString(configuration.creatorUid));
+ String idString = WifiNative.createNetworkExtra(extras);
+ if (idString != null) {
+ idString = "\"" + idString + "\"";
+ out.write(" " + "id_str=" + idString + "\n");
+ }
+ out.write("}\n");
+ out.write("\n");
+ }
+
+ /**
+ * Helper method to write a list of networks in ipconfig.txt format to the output stream.
+ */
+ private byte[] createIpConfBackupData(List<WifiConfiguration> configurations) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(bos);
+ try {
+ // write version first.
+ out.writeInt(2);
+ for (WifiConfiguration configuration : configurations) {
+ IpConfigStore.writeConfig(out, configuration.configKey().hashCode(),
+ configuration.getIpConfiguration());
+ }
+ out.flush();
+ return bos.toByteArray();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
* Asserts that the 2 lists of configurations are equal
*/
private void assertConfigurationsEqual(