diff options
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( |