diff options
5 files changed, 920 insertions, 410 deletions
diff --git a/service/java/com/android/server/wifi/WifiBackupRestore.java b/service/java/com/android/server/wifi/WifiBackupRestore.java index c37a70c8d..5de29a2c2 100644 --- a/service/java/com/android/server/wifi/WifiBackupRestore.java +++ b/service/java/com/android/server/wifi/WifiBackupRestore.java @@ -17,21 +17,17 @@ package com.android.server.wifi; import android.net.IpConfiguration; -import android.net.LinkAddress; -import android.net.NetworkUtils; -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 com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil; +import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -45,17 +41,11 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; -import java.net.Inet4Address; -import java.net.InetAddress; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.BitSet; import java.util.List; import java.util.Map; -import static android.net.IpConfiguration.IpAssignment; -import static android.net.IpConfiguration.ProxySettings; - /** * Class used to backup/restore data using the SettingsBackupAgent. * There are 2 symmetric API's exposed here: @@ -79,41 +69,20 @@ public class WifiBackupRestore { private static final int INITIAL_BACKUP_DATA_VERSION = 1; /** - * List of XML tags in the backed up data + * List of XML section header tags in the backed up data */ private static final String XML_TAG_DOCUMENT_HEADER = "WifiBackupData"; private static final String XML_TAG_VERSION = "Version"; - private static final String XML_TAG_SECTION_HEADER_CONFIGURATION_LIST = "ConfigurationList"; - private static final String XML_TAG_SECTION_HEADER_CONFIGURATION = "Configuration"; - private static final String XML_TAG_CONFIGURATION_SSID = "SSID"; - private static final String XML_TAG_CONFIGURATION_BSSID = "BSSID"; - private static final String XML_TAG_CONFIGURATION_CONFIG_KEY = "ConfigKey"; - private static final String XML_TAG_CONFIGURATION_PRE_SHARED_KEY = "PreSharedKey"; - private static final String XML_TAG_CONFIGURATION_WEP_KEYS = "WEPKeys"; - private static final String XML_TAG_CONFIGURATION_WEP_TX_KEY_INDEX = "WEPTxKeyIndex"; - private static final String XML_TAG_CONFIGURATION_HIDDEN_SSID = "HiddenSSID"; - private static final String XML_TAG_CONFIGURATION_ALLOWED_KEY_MGMT = "AllowedKeyMgmt"; - private static final String XML_TAG_CONFIGURATION_ALLOWED_PROTOCOLS = "AllowedProtocols"; - private static final String XML_TAG_CONFIGURATION_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos"; - private static final String XML_TAG_CONFIGURATION_SHARED = "Shared"; - private static final String XML_TAG_CONFIGURATION_CREATOR_UID = "CreatorUid"; + private static final String XML_TAG_SECTION_HEADER_NETWORK_LIST = "NetworkList"; + private static final String XML_TAG_SECTION_HEADER_NETWORK = "Network"; + private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration"; private static final String XML_TAG_SECTION_HEADER_IP_CONFIGURATION = "IpConfiguration"; - private static final String XML_TAG_IP_CONFIGURATION_IP_ASSIGNMENT = "IpAssignment"; - private static final String XML_TAG_IP_CONFIGURATION_LINK_ADDRESS = "LinkAddress"; - private static final String XML_TAG_IP_CONFIGURATION_LINK_PREFIX_LENGTH = "LinkPrefixLength"; - private static final String XML_TAG_IP_CONFIGURATION_GATEWAY_ADDRESS = "GatewayAddress"; - private static final String XML_TAG_IP_CONFIGURATION_DNS_SERVER_ADDRESSES = "DNSServers"; - private static final String XML_TAG_IP_CONFIGURATION_PROXY_SETTINGS = "ProxySettings"; - private static final String XML_TAG_IP_CONFIGURATION_PROXY_HOST = "ProxyHost"; - private static final String XML_TAG_IP_CONFIGURATION_PROXY_PORT = "ProxyPort"; - private static final String XML_TAG_IP_CONFIGURATION_PROXY_PAC_FILE = "ProxyPac"; - private static final String XML_TAG_IP_CONFIGURATION_PROXY_EXCLUSION_LIST = "ProxyExclusionList"; /** * Regex to mask out passwords in backup data dump. */ private static final String PASSWORD_MASK_SEARCH_PATTERN = - "(<.*" + XML_TAG_CONFIGURATION_PRE_SHARED_KEY + ".*>)(.*)(<.*>)"; + "(<.*" + WifiConfigurationXmlUtil.XML_TAG_PRE_SHARED_KEY + ".*>)(.*)(<.*>)"; private static final String PASSWORD_MASK_REPLACE_PATTERN = "$1*$3"; /** @@ -152,7 +121,7 @@ public class WifiBackupRestore { XmlUtil.writeNextValue(out, XML_TAG_VERSION, CURRENT_BACKUP_DATA_VERSION); - writeWifiConfigurationsToXml(out, configurations); + writeNetworkConfigurationsToXml(out, configurations); XmlUtil.writeDocumentEnd(out, XML_TAG_DOCUMENT_HEADER); @@ -174,10 +143,10 @@ public class WifiBackupRestore { /** * Write the list of configurations to the XML stream. */ - private void writeWifiConfigurationsToXml( + private void writeNetworkConfigurationsToXml( XmlSerializer out, List<WifiConfiguration> configurations) throws XmlPullParserException, IOException { - XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_CONFIGURATION_LIST); + XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_LIST); for (WifiConfiguration configuration : configurations) { // We don't want to backup/restore enterprise/passpoint configurations. if (configuration.isEnterprise() || configuration.isPasspoint()) { @@ -185,151 +154,31 @@ public class WifiBackupRestore { continue; } // Write this configuration data now. - XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_CONFIGURATION); - writeWifiConfigurationToXml(out, configuration); - XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_CONFIGURATION); - } - XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_CONFIGURATION_LIST); - } - - /** - * Write WepKeys to the XML stream. - * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements - * are null. XmlUtils serialization doesn't handle this array of nulls well . - * So, write null if the keys are not initialized. - */ - private void writeWepKeysToXml(XmlSerializer out, String[] wepKeys) - throws XmlPullParserException, IOException { - if (wepKeys[0] != null) { - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_WEP_KEYS, wepKeys); - } else { - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_WEP_KEYS, null); + XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK); + writeNetworkConfigurationToXml(out, configuration); + XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK); } + XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_LIST); } /** * Write the configuration data elements from the provided Configuration to the XML stream. * Uses XmlUtils to write the values of each element. */ - private void writeWifiConfigurationToXml(XmlSerializer out, WifiConfiguration configuration) + private void writeNetworkConfigurationToXml(XmlSerializer out, WifiConfiguration configuration) throws XmlPullParserException, IOException { - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_CONFIG_KEY, configuration.configKey()); - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_SSID, configuration.SSID); - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_BSSID, configuration.BSSID); - XmlUtil.writeNextValue( - out, XML_TAG_CONFIGURATION_PRE_SHARED_KEY, configuration.preSharedKey); - writeWepKeysToXml(out, configuration.wepKeys); - XmlUtil.writeNextValue( - out, XML_TAG_CONFIGURATION_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex); - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_HIDDEN_SSID, configuration.hiddenSSID); - XmlUtil.writeNextValue( - out, XML_TAG_CONFIGURATION_ALLOWED_KEY_MGMT, - configuration.allowedKeyManagement.toByteArray()); - XmlUtil.writeNextValue( - out, XML_TAG_CONFIGURATION_ALLOWED_PROTOCOLS, - configuration.allowedProtocols.toByteArray()); - XmlUtil.writeNextValue( - out, XML_TAG_CONFIGURATION_ALLOWED_AUTH_ALGOS, - configuration.allowedAuthAlgorithms.toByteArray()); - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_SHARED, configuration.shared); - XmlUtil.writeNextValue(out, XML_TAG_CONFIGURATION_CREATOR_UID, configuration.creatorUid); - + XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); + WifiConfigurationXmlUtil.writeWifiConfigurationToXmlForBackup(out, configuration); + XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); if (configuration.getIpConfiguration() != null) { XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION); - writeIpConfigurationToXml(out, configuration.getIpConfiguration()); + IpConfigurationXmlUtil.writeIpConfigurationToXml( + out, configuration.getIpConfiguration()); XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION); } } /** - * Write the static IP configuration data elements to XML stream - */ - private void writeStaticIpConfigurationToXml(XmlSerializer out, - StaticIpConfiguration staticIpConfiguration) - throws XmlPullParserException, IOException { - if (staticIpConfiguration.ipAddress != null) { - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_LINK_ADDRESS, - staticIpConfiguration.ipAddress.getAddress().getHostAddress()); - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_LINK_PREFIX_LENGTH, - staticIpConfiguration.ipAddress.getPrefixLength()); - } else { - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_LINK_ADDRESS, null); - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_LINK_PREFIX_LENGTH, null); - } - if (staticIpConfiguration.gateway != null) { - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_GATEWAY_ADDRESS, - staticIpConfiguration.gateway.getHostAddress()); - } else { - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_GATEWAY_ADDRESS, null); - - } - if (staticIpConfiguration.dnsServers != null) { - // Create a string array of DNS server addresses - String[] dnsServers = new String[staticIpConfiguration.dnsServers.size()]; - int dnsServerIdx = 0; - for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { - dnsServers[dnsServerIdx++] = inetAddr.getHostAddress(); - } - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_DNS_SERVER_ADDRESSES, dnsServers); - } else { - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_DNS_SERVER_ADDRESSES, null); - } - } - - /** - * Write the IP configuration data elements from the provided Configuration to the XML stream. - * Uses XmlUtils to write the values of each element. - */ - private void writeIpConfigurationToXml(XmlSerializer out, IpConfiguration ipConfiguration) - throws XmlPullParserException, IOException { - - // Write IP assignment settings - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_IP_ASSIGNMENT, - ipConfiguration.ipAssignment.toString()); - switch (ipConfiguration.ipAssignment) { - case STATIC: - writeStaticIpConfigurationToXml(out, ipConfiguration.getStaticIpConfiguration()); - break; - default: - break; - } - - // Write proxy settings - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_PROXY_SETTINGS, - ipConfiguration.proxySettings.toString()); - switch (ipConfiguration.proxySettings) { - case STATIC: - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_PROXY_HOST, - ipConfiguration.httpProxy.getHost()); - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_PROXY_PORT, - ipConfiguration.httpProxy.getPort()); - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_PROXY_EXCLUSION_LIST, - ipConfiguration.httpProxy.getExclusionListAsString()); - break; - case PAC: - XmlUtil.writeNextValue( - out, XML_TAG_IP_CONFIGURATION_PROXY_PAC_FILE, - ipConfiguration.httpProxy.getPacFileUrl().toString()); - break; - default: - break; - } - } - - /** * Parse out the configurations from the back up data. * * @param data raw byte stream representing the XML data. @@ -354,13 +203,13 @@ public class WifiBackupRestore { XmlUtil.gotoDocumentStart(in, XML_TAG_DOCUMENT_HEADER); int rootTagDepth = in.getDepth(); - int version = (int) XmlUtil.readNextValue(in, XML_TAG_VERSION); + int version = (int) XmlUtil.readNextValueWithName(in, XML_TAG_VERSION); if (version < INITIAL_BACKUP_DATA_VERSION || version > CURRENT_BACKUP_DATA_VERSION) { Log.e(TAG, "Invalid version of data: " + version); return null; } - return parseWifiConfigurationsFromXml(in, rootTagDepth, version); + return parseNetworkConfigurationsFromXml(in, rootTagDepth, version); } catch (XmlPullParserException e) { Log.e(TAG, "Error parsing the backup data: " + e); } catch (IOException e) { @@ -377,23 +226,22 @@ public class WifiBackupRestore { * @param dataVersion version number parsed from incoming data. * @return List<WifiConfiguration> object if parsing is successful, null otherwise. */ - private List<WifiConfiguration> parseWifiConfigurationsFromXml( + private List<WifiConfiguration> parseNetworkConfigurationsFromXml( XmlPullParser in, int outerTagDepth, int dataVersion) throws XmlPullParserException, IOException { // Find the configuration list section. if (!XmlUtil.gotoNextSection( - in, XML_TAG_SECTION_HEADER_CONFIGURATION_LIST, outerTagDepth)) { - Log.e(TAG, "Error parsing the backup data. Did not find configuration list"); + in, XML_TAG_SECTION_HEADER_NETWORK_LIST, outerTagDepth)) { + Log.e(TAG, "Error parsing the backup data. Did not find network list"); // Malformed XML input, bail out. return null; } // Find all the configurations within the configuration list section. - int confListTagDepth = outerTagDepth + 1; + int networkListTagDepth = outerTagDepth + 1; List<WifiConfiguration> configurations = new ArrayList<>(); - while (XmlUtil.gotoNextSection( - in, XML_TAG_SECTION_HEADER_CONFIGURATION, confListTagDepth)) { + while (XmlUtil.gotoNextSection(in, XML_TAG_SECTION_HEADER_NETWORK, networkListTagDepth)) { WifiConfiguration configuration = - parseWifiConfigurationFromXml(in, dataVersion, confListTagDepth); + parseNetworkConfigurationFromXml(in, dataVersion, networkListTagDepth); if (configuration != null) { Log.v(TAG, "Parsed Configuration: " + configuration.configKey()); configurations.add(configuration); @@ -403,21 +251,6 @@ public class WifiBackupRestore { } /** - * Parse WepKeys from the XML stream. - * Populate wepKeys array only if they were present in the backup data. - */ - private void parseWepKeysFromXml(XmlPullParser in, String[] wepKeys) - throws XmlPullParserException, IOException { - String[] wepKeysInData = - (String[]) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_WEP_KEYS); - if (wepKeysInData != null) { - for (int i = 0; i < wepKeys.length; i++) { - wepKeys[i] = wepKeysInData[i]; - } - } - } - - /** * Parses the configuration data elements from the provided XML stream to a Configuration. * * @param in XmlPullParser instance pointing to the XML stream. @@ -425,53 +258,29 @@ public class WifiBackupRestore { * @param dataVersion version number parsed from incoming data. * @return WifiConfiguration object if parsing is successful, null otherwise. */ - private WifiConfiguration parseWifiConfigurationFromXml(XmlPullParser in, int dataVersion, + private WifiConfiguration parseNetworkConfigurationFromXml(XmlPullParser in, int dataVersion, int outerTagDepth) throws XmlPullParserException, IOException { - // Any version migration needs to be handled here in future. if (dataVersion == INITIAL_BACKUP_DATA_VERSION) { - WifiConfiguration configuration = new WifiConfiguration(); - String configKeyInData = - (String) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_CONFIG_KEY); - configuration.SSID = - (String) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_SSID); - configuration.BSSID = - (String) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_BSSID); - configuration.preSharedKey = - (String) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_PRE_SHARED_KEY); - parseWepKeysFromXml(in, configuration.wepKeys); - configuration.wepTxKeyIndex = - (int) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_WEP_TX_KEY_INDEX); - configuration.hiddenSSID = - (boolean) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_HIDDEN_SSID); - byte[] allowedKeyMgmt = - (byte[]) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_ALLOWED_KEY_MGMT); - configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); - byte[] allowedProtocols = - (byte[]) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_ALLOWED_PROTOCOLS); - configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); - byte[] allowedAuthAlgorithms = - (byte[]) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_ALLOWED_AUTH_ALGOS); - configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms); - configuration.shared = - (boolean) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_SHARED); - configuration.creatorUid = - (int) XmlUtil.readNextValue(in, XML_TAG_CONFIGURATION_CREATOR_UID); - - // We should not have all the data to calculate the configKey. Compare it against the - // configKey stored in the XML data. - String configKeyCalculated = configuration.configKey(); - if (!configKeyInData.equals(configKeyCalculated)) { - Log.e(TAG, "Configuration key does not match. Retrieved: " + configKeyInData - + ", Calculated: " + configKeyCalculated); - return null; + WifiConfiguration configuration = null; + int networkTagDepth = outerTagDepth + 1; + // Retrieve WifiConfiguration object first. + if (XmlUtil.gotoNextSection( + in, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION, networkTagDepth)) { + int configTagDepth = networkTagDepth + 1; + configuration = + WifiConfigurationXmlUtil.parseWifiConfigurationFromXml(in, configTagDepth); + if (configuration == null) { + return null; + } } // Now retrieve any IP configuration info if present. - int confTagDepth = outerTagDepth + 1; if (XmlUtil.gotoNextSection( - in, XML_TAG_SECTION_HEADER_IP_CONFIGURATION, confTagDepth)) { - IpConfiguration ipConfiguration = parseIpConfigurationFromXml(in, dataVersion); + in, XML_TAG_SECTION_HEADER_IP_CONFIGURATION, networkTagDepth)) { + int configTagDepth = networkTagDepth + 1; + IpConfiguration ipConfiguration = + IpConfigurationXmlUtil.parseIpConfigurationFromXml(in, configTagDepth); configuration.setIpConfiguration(ipConfiguration); } return configuration; @@ -480,120 +289,6 @@ public class WifiBackupRestore { } /** - * Parse out the static IP configuration from the XML stream. - */ - private StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in) - throws XmlPullParserException, IOException { - - StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); - String linkAddressString = - (String) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_LINK_ADDRESS); - Integer linkPrefixLength = - (Integer) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_LINK_PREFIX_LENGTH); - if (linkAddressString != null && linkPrefixLength != null) { - LinkAddress linkAddress = new LinkAddress( - NetworkUtils.numericToInetAddress(linkAddressString), - linkPrefixLength); - if (linkAddress.getAddress() instanceof Inet4Address) { - staticIpConfiguration.ipAddress = linkAddress; - } else { - Log.w(TAG, "Non-IPv4 address: " + linkAddress); - } - } - String gatewayAddressString = - (String) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_GATEWAY_ADDRESS); - if (gatewayAddressString != null) { - LinkAddress dest = null; - InetAddress gateway = - NetworkUtils.numericToInetAddress(gatewayAddressString); - RouteInfo route = new RouteInfo(dest, gateway); - if (route.isIPv4Default()) { - staticIpConfiguration.gateway = gateway; - } else { - Log.w(TAG, "Non-IPv4 default route: " + route); - } - } - String[] dnsServerAddressesString = - (String[]) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_DNS_SERVER_ADDRESSES); - if (dnsServerAddressesString != null) { - for (String dnsServerAddressString : dnsServerAddressesString) { - InetAddress dnsServerAddress = - NetworkUtils.numericToInetAddress(dnsServerAddressString); - staticIpConfiguration.dnsServers.add(dnsServerAddress); - } - } - return staticIpConfiguration; - } - - /** - * Parses the IP configuration data elements from the provided XML stream to a IpConfiguration. - * - * @param in XmlPullParser instance pointing to the XML stream. - * @param dataVersion version number parsed from incoming data. - * @return IpConfiguration object if parsing is successful, null otherwise. - */ - private IpConfiguration parseIpConfigurationFromXml(XmlPullParser in, int dataVersion) - throws XmlPullParserException, IOException { - - // Any version migration needs to be handled here in future. - if (dataVersion == INITIAL_BACKUP_DATA_VERSION) { - IpConfiguration ipConfiguration = new IpConfiguration(); - - // Parse out the IP assignment info first. - String ipAssignmentString = - (String) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_IP_ASSIGNMENT); - IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString); - ipConfiguration.setIpAssignment(ipAssignment); - switch (ipAssignment) { - case STATIC: - StaticIpConfiguration staticIpConfiguration = - parseStaticIpConfigurationFromXml(in); - ipConfiguration.setStaticIpConfiguration(staticIpConfiguration); - break; - case DHCP: - case UNASSIGNED: - break; - default: - Log.wtf(TAG, "Unknown ip assignment type: " + ipAssignment); - return null; - } - - // Parse out the proxy settings next. - String proxySettingsString = - (String) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_PROXY_SETTINGS); - ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString); - ipConfiguration.setProxySettings(proxySettings); - switch (proxySettings) { - case STATIC: - String proxyHost = - (String) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_PROXY_HOST); - int proxyPort = - (int) XmlUtil.readNextValue(in, XML_TAG_IP_CONFIGURATION_PROXY_PORT); - String proxyExclusionList = - (String) XmlUtil.readNextValue(in, - XML_TAG_IP_CONFIGURATION_PROXY_EXCLUSION_LIST); - ipConfiguration.setHttpProxy( - new ProxyInfo(proxyHost, proxyPort, proxyExclusionList)); - break; - case PAC: - String proxyPacFile = - (String) XmlUtil.readNextValue(in, - XML_TAG_IP_CONFIGURATION_PROXY_PAC_FILE); - ipConfiguration.setHttpProxy(new ProxyInfo(proxyPacFile)); - break; - case NONE: - case UNASSIGNED: - break; - default: - Log.wtf(TAG, "Unknown proxy settings type: " + proxySettings); - return null; - } - return ipConfiguration; - } - return null; - } - - /** * Create log dump of the backup data in XML format with the preShared * key masked. */ @@ -711,7 +406,6 @@ public class WifiBackupRestore { * 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_HIDDEN = WifiConfiguration.hiddenSSIDVarName; public static final String SUPPLICANT_KEY_KEY_MGMT = WifiConfiguration.KeyMgmt.varName; @@ -735,6 +429,22 @@ public class WifiBackupRestore { private static final String PASSWORD_MASK_REPLACE_PATTERN = "$1*"; /** + * Create log dump of the backup data in wpa_supplicant.conf format with the preShared + * key masked. + */ + public static String createLogFromBackupData(byte[] data) { + String supplicantConfString; + try { + supplicantConfString = new String(data, StandardCharsets.UTF_8.name()); + supplicantConfString = supplicantConfString.replaceAll( + PASSWORD_MASK_SEARCH_PATTERN, PASSWORD_MASK_REPLACE_PATTERN); + } catch (UnsupportedEncodingException e) { + return ""; + } + return supplicantConfString; + } + + /** * Class for capturing a network definition from the wifi supplicant config file. */ static class SupplicantNetwork { @@ -944,21 +654,5 @@ public class WifiBackupRestore { return wifiConfigurations; } } - - /** - * Create log dump of the backup data in wpa_supplicant.conf format with the preShared - * key masked. - */ - public static String createLogFromBackupData(byte[] data) { - String supplicantConfString; - try { - supplicantConfString = new String(data, StandardCharsets.UTF_8.name()); - supplicantConfString = supplicantConfString.replaceAll( - PASSWORD_MASK_SEARCH_PATTERN, PASSWORD_MASK_REPLACE_PATTERN); - } catch (UnsupportedEncodingException e) { - return ""; - } - return supplicantConfString; - } } } diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java index 9073959e7..214450c6e 100644 --- a/service/java/com/android/server/wifi/util/XmlUtil.java +++ b/service/java/com/android/server/wifi/util/XmlUtil.java @@ -16,6 +16,17 @@ package com.android.server.wifi.util; +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.NetworkUtils; +import android.net.ProxyInfo; +import android.net.RouteInfo; +import android.net.StaticIpConfiguration; +import android.net.wifi.WifiConfiguration; +import android.util.Log; + import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; @@ -23,11 +34,13 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.BitSet; /** * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core. * The utility provides methods to write/parse section headers and write/parse values. - * * This utility is designed for formatting the XML into the following format: * <Document Header> * <Section 1 Header> @@ -46,11 +59,29 @@ public class XmlUtil { private static final String TAG = "WifiXmlUtil"; /** - * Move the XML stream to the start of the next tag or the end of document. + * Ensure that the XML stream is at a start tag or the end of document. + * + * @throws {XmlPullParserException}, if parsing errors occur. */ - private static void gotoNextElement(XmlPullParser in) + private static void gotoStartTag(XmlPullParser in) throws XmlPullParserException, IOException { - XmlUtils.nextElement(in); + int type = in.getEventType(); + while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { + type = in.next(); + } + } + + /** + * Ensure that the XML stream is at an end tag or the end of document. + * + * @throws {XmlPullParserException}, if parsing errors occur. + */ + private static void gotoEndTag(XmlPullParser in) + throws XmlPullParserException, IOException { + int type = in.getEventType(); + while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) { + type = in.next(); + } } /** @@ -58,6 +89,7 @@ public class XmlUtil { * * @param in XmlPullParser instance pointing to the XML stream. * @param headerName expected name for the start tag. + * @throws {XmlPullParserException}, if parsing errors occur. */ public static void gotoDocumentStart(XmlPullParser in, String headerName) throws XmlPullParserException, IOException { @@ -65,13 +97,14 @@ public class XmlUtil { } /** - * Move the XML stream to the next section header. The provided outerdepth is used to find - * sub sections within the provided depth. + * Move the XML stream to the next section header. The provided outerDepth is used to find + * sub sections within that depth. * * @param in XmlPullParser instance pointing to the XML stream. * @param headerName expected name for the start tag. * @param outerDepth Find section within this depth. * @return {@code true} if a start tag with the provided name is found, {@code false} otherwise + * @throws {XmlPullParserException}, if parsing errors occur. */ public static boolean gotoNextSection(XmlPullParser in, String headerName, int outerDepth) throws XmlPullParserException, IOException { @@ -84,8 +117,49 @@ public class XmlUtil { } /** + * Checks if the stream is at the end of a section of values. This moves the stream to next tag + * and checks if it finds an end tag at the specified depth. + * + * @param in XmlPullParser instance pointing to the XML stream. + * @param sectionDepth depth of the start tag of this section. Used to match the end tag. + * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise + * @throws {XmlPullParserException}, if parsing errors occur. + */ + public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth) + throws XmlPullParserException, IOException { + if (in.nextTag() == XmlPullParser.END_TAG && in.getDepth() == sectionDepth) { + return true; + } else { + return false; + } + } + + /** + * Read the current value in the XML stream using core XmlUtils and stores the retrieved + * value name in the string provided. This method reads the value contained in current start + * tag. + * Note: Because there could be genuine null values being read from the XML, this method raises + * an exception to indicate errors. + * + * @param in XmlPullParser instance pointing to the XML stream. + * @param valueName An array of one string, used to return the name attribute + * of the value's tag. + * @return value retrieved from the XML stream. + * @throws {XmlPullParserException}, if parsing errors occur. + */ + public static Object readCurrentValue(XmlPullParser in, String[] valueName) + throws XmlPullParserException, IOException { + Object value = XmlUtils.readValueXml(in, valueName); + // XmlUtils.readValue does not always move the stream to the end of the tag. So, move + // it to the end tag before returning from here. + gotoEndTag(in); + return value; + } + + /** * Read the next value in the XML stream using core XmlUtils and ensure that it matches the - * provided name. + * provided name. This method moves the stream to the next start tag and reads the value + * contained in it. * Note: Because there could be genuine null values being read from the XML, this method raises * an exception to indicate errors. * @@ -94,23 +168,16 @@ public class XmlUtil { * @throws {XmlPullParserException}, if the value read does not match |expectedName|, * or if parsing errors occur. */ - public static Object readNextValue(XmlPullParser in, String expectedName) + public static Object readNextValueWithName(XmlPullParser in, String expectedName) throws XmlPullParserException, IOException { - String[] names = new String[1]; - names[0] = new String(); - gotoNextElement(in); - Object value = XmlUtils.readValueXml(in, names); - if (names[0].equals(expectedName)) { - // XmlUtils.readValue does not always move the stream to the end of the tag. So, move - // it to the end before returning from here. - while (in.getEventType() != XmlPullParser.END_DOCUMENT - && in.getEventType() != XmlPullParser.END_TAG) { - in.next(); - } + String[] valueName = new String[1]; + XmlUtils.nextElement(in); + Object value = readCurrentValue(in, valueName); + if (valueName[0].equals(expectedName)) { return value; } throw new XmlPullParserException( - "Value not found. Expected: " + expectedName + ", but got: " + names[0]); + "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]); } /** @@ -120,7 +187,7 @@ public class XmlUtil { * @param headerName name for the start tag. */ public static void writeDocumentStart(XmlSerializer out, String headerName) - throws XmlPullParserException, IOException { + throws IOException { out.startDocument(null, true); out.startTag(null, headerName); } @@ -132,7 +199,7 @@ public class XmlUtil { * @param headerName name for the end tag. */ public static void writeDocumentEnd(XmlSerializer out, String headerName) - throws XmlPullParserException, IOException { + throws IOException { out.endTag(null, headerName); out.endDocument(); } @@ -144,7 +211,7 @@ public class XmlUtil { * @param headerName name for the start tag. */ public static void writeNextSectionStart(XmlSerializer out, String headerName) - throws XmlPullParserException, IOException { + throws IOException { out.startTag(null, headerName); } @@ -155,7 +222,7 @@ public class XmlUtil { * @param headerName name for the end tag. */ public static void writeNextSectionEnd(XmlSerializer out, String headerName) - throws XmlPullParserException, IOException { + throws IOException { out.endTag(null, headerName); } @@ -170,5 +237,412 @@ public class XmlUtil { throws XmlPullParserException, IOException { XmlUtils.writeValueXml(value, name, out); } + + /** + * Utility class to serialize and deseriaize WifConfiguration object to XML & vice versa. + * This is used by both #com.android.server.wifi.WifiConfigStore & + * #com.android.server.wifi.WifiBackupRestore modules. + * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store. + * There is only 1 version of |parseXmlToConfiguration| for both backup & config store. + * The parse method is written so that any element added/deleted in future revisions can + * be easily handled. + */ + public static class WifiConfigurationXmlUtil { + /** + * List of XML tags corresponding to WifiConfiguration object elements. + */ + public static final String XML_TAG_SSID = "SSID"; + public static final String XML_TAG_BSSID = "BSSID"; + public static final String XML_TAG_CONFIG_KEY = "ConfigKey"; + public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey"; + public static final String XML_TAG_WEP_KEYS = "WEPKeys"; + public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex"; + public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID"; + public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt"; + public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols"; + public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos"; + public static final String XML_TAG_SHARED = "Shared"; + public static final String XML_TAG_CREATOR_UID = "CreatorUid"; + + /** + * Write WepKeys to the XML stream. + * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements + * are null. XmlUtils serialization doesn't handle this array of nulls well . + * So, write null if the keys are not initialized. + */ + private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys) + throws XmlPullParserException, IOException { + if (wepKeys[0] != null) { + XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeys); + } else { + XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null); + } + } + + /** + * Write the Configuration data elements that are common for backup & config store to the + * XML stream. + * + * @param out XmlSerializer instance pointing to the XML stream. + * @param configuration WifiConfiguration object to be serialized. + */ + public static void writeCommonWifiConfigurationElementsToXml(XmlSerializer out, + WifiConfiguration configuration) + throws XmlPullParserException, IOException { + XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.configKey()); + XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID); + XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID); + XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, configuration.preSharedKey); + writeWepKeysToXml(out, configuration.wepKeys); + XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex); + XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID); + XmlUtil.writeNextValue( + out, XML_TAG_ALLOWED_KEY_MGMT, + configuration.allowedKeyManagement.toByteArray()); + XmlUtil.writeNextValue( + out, XML_TAG_ALLOWED_PROTOCOLS, + configuration.allowedProtocols.toByteArray()); + XmlUtil.writeNextValue( + out, XML_TAG_ALLOWED_AUTH_ALGOS, + configuration.allowedAuthAlgorithms.toByteArray()); + XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared); + XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid); + } + + /** + * Write the Configuration data elements for backup from the provided Configuration to the + * XML stream. + * Note: This is a subset of the elements serialized for config store. + * + * @param out XmlSerializer instance pointing to the XML stream. + * @param configuration WifiConfiguration object to be serialized. + */ + public static void writeWifiConfigurationToXmlForBackup(XmlSerializer out, + WifiConfiguration configuration) + throws XmlPullParserException, IOException { + writeCommonWifiConfigurationElementsToXml(out, configuration); + } + + /** + * Write the Configuration data elements for config store from the provided Configuration + * to the XML stream. + */ + public static void writeWifiConfigurationToXmlForConfigStore(XmlSerializer out, + WifiConfiguration configuration) + throws XmlPullParserException, IOException { + writeCommonWifiConfigurationElementsToXml(out, configuration); + // TODO: Will need to add more elements which needs to be persisted. + } + + /** + * Populate wepKeys array only if they were non-null in the backup data. + */ + private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys) + throws XmlPullParserException, IOException { + String[] wepKeysInData = (String[]) value; + if (wepKeysInData != null) { + for (int i = 0; i < wepKeys.length; i++) { + wepKeys[i] = wepKeysInData[i]; + } + } + } + + /** + * Parses the configuration data elements from the provided XML stream to a Configuration. + * Note: This is used for parsing both backup data and config store data. Looping through + * the tags make it easy to add or remove elements in the future versions if needed. + * + * @param in XmlPullParser instance pointing to the XML stream. + * @param outerTagDepth depth of the outer tag in the XML document. + * @return WifiConfiguration object if parsing is successful, null otherwise. + */ + public static WifiConfiguration parseWifiConfigurationFromXml(XmlPullParser in, + int outerTagDepth) + throws XmlPullParserException, IOException { + WifiConfiguration configuration = new WifiConfiguration(); + String configKeyInData = null; + + // Loop through and parse out all the elements from the stream within this section. + while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { + String[] valueName = new String[1]; + Object value = XmlUtil.readCurrentValue(in, valueName); + if (valueName[0] == null) { + Log.e(TAG, "Missing value name"); + return null; + } + switch (valueName[0]) { + case XML_TAG_CONFIG_KEY: + configKeyInData = (String) value; + break; + case XML_TAG_SSID: + configuration.SSID = (String) value; + break; + case XML_TAG_BSSID: + configuration.BSSID = (String) value; + break; + case XML_TAG_PRE_SHARED_KEY: + configuration.preSharedKey = (String) value; + break; + case XML_TAG_WEP_KEYS: + populateWepKeysFromXmlValue(value, configuration.wepKeys); + break; + case XML_TAG_WEP_TX_KEY_INDEX: + configuration.wepTxKeyIndex = (int) value; + break; + case XML_TAG_HIDDEN_SSID: + configuration.hiddenSSID = (boolean) value; + break; + case XML_TAG_ALLOWED_KEY_MGMT: + byte[] allowedKeyMgmt = (byte[]) value; + configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); + break; + case XML_TAG_ALLOWED_PROTOCOLS: + byte[] allowedProtocols = (byte[]) value; + configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); + break; + case XML_TAG_ALLOWED_AUTH_ALGOS: + byte[] allowedAuthAlgorithms = (byte[]) value; + configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms); + break; + case XML_TAG_SHARED: + configuration.shared = (boolean) value; + break; + case XML_TAG_CREATOR_UID: + configuration.creatorUid = (int) value; + break; + default: + Log.e(TAG, "Unknown value name found: " + valueName[0]); + return null; + } + } + // We should now have all the data to calculate the configKey. Compare it against the + // configKey stored in the XML data. + String configKeyCalculated = configuration.configKey(); + if (configKeyInData == null || !configKeyInData.equals(configKeyCalculated)) { + Log.e(TAG, "Configuration key does not match. Retrieved: " + configKeyInData + + ", Calculated: " + configKeyCalculated); + return null; + } + return configuration; + } + } + + /** + * Utility class to serialize and deseriaize IpConfiguration object to XML & vice versa. + * This is used by both #com.android.server.wifi.WifiConfigStore & + * #com.android.server.wifi.WifiBackupRestore modules. + */ + public static class IpConfigurationXmlUtil { + + /** + * List of XML tags corresponding to IpConfiguration object elements. + */ + public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment"; + public static final String XML_TAG_LINK_ADDRESS = "LinkAddress"; + public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength"; + public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress"; + public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers"; + public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings"; + public static final String XML_TAG_PROXY_HOST = "ProxyHost"; + public static final String XML_TAG_PROXY_PORT = "ProxyPort"; + public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac"; + public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList"; + + /** + * Write the static IP configuration data elements to XML stream. + */ + private static void writeStaticIpConfigurationToXml(XmlSerializer out, + StaticIpConfiguration staticIpConfiguration) + throws XmlPullParserException, IOException { + if (staticIpConfiguration.ipAddress != null) { + XmlUtil.writeNextValue( + out, XML_TAG_LINK_ADDRESS, + staticIpConfiguration.ipAddress.getAddress().getHostAddress()); + XmlUtil.writeNextValue( + out, XML_TAG_LINK_PREFIX_LENGTH, + staticIpConfiguration.ipAddress.getPrefixLength()); + } else { + XmlUtil.writeNextValue( + out, XML_TAG_LINK_ADDRESS, null); + XmlUtil.writeNextValue( + out, XML_TAG_LINK_PREFIX_LENGTH, null); + } + if (staticIpConfiguration.gateway != null) { + XmlUtil.writeNextValue( + out, XML_TAG_GATEWAY_ADDRESS, + staticIpConfiguration.gateway.getHostAddress()); + } else { + XmlUtil.writeNextValue( + out, XML_TAG_GATEWAY_ADDRESS, null); + + } + if (staticIpConfiguration.dnsServers != null) { + // Create a string array of DNS server addresses + String[] dnsServers = new String[staticIpConfiguration.dnsServers.size()]; + int dnsServerIdx = 0; + for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { + dnsServers[dnsServerIdx++] = inetAddr.getHostAddress(); + } + XmlUtil.writeNextValue( + out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers); + } else { + XmlUtil.writeNextValue( + out, XML_TAG_DNS_SERVER_ADDRESSES, null); + } + } + + /** + * Write the IP configuration data elements from the provided Configuration to the XML + * stream. + */ + public static void writeIpConfigurationToXml(XmlSerializer out, + IpConfiguration ipConfiguration) + throws XmlPullParserException, IOException { + // Write IP assignment settings + XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT, + ipConfiguration.ipAssignment.toString()); + switch (ipConfiguration.ipAssignment) { + case STATIC: + writeStaticIpConfigurationToXml( + out, ipConfiguration.getStaticIpConfiguration()); + break; + default: + break; + } + + // Write proxy settings + XmlUtil.writeNextValue( + out, XML_TAG_PROXY_SETTINGS, + ipConfiguration.proxySettings.toString()); + switch (ipConfiguration.proxySettings) { + case STATIC: + XmlUtil.writeNextValue( + out, XML_TAG_PROXY_HOST, + ipConfiguration.httpProxy.getHost()); + XmlUtil.writeNextValue( + out, XML_TAG_PROXY_PORT, + ipConfiguration.httpProxy.getPort()); + XmlUtil.writeNextValue( + out, XML_TAG_PROXY_EXCLUSION_LIST, + ipConfiguration.httpProxy.getExclusionListAsString()); + break; + case PAC: + XmlUtil.writeNextValue( + out, XML_TAG_PROXY_PAC_FILE, + ipConfiguration.httpProxy.getPacFileUrl().toString()); + break; + default: + break; + } + } + + /** + * Parse out the static IP configuration from the XML stream. + */ + private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in) + throws XmlPullParserException, IOException { + StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + + String linkAddressString = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS); + Integer linkPrefixLength = + (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH); + if (linkAddressString != null && linkPrefixLength != null) { + LinkAddress linkAddress = new LinkAddress( + NetworkUtils.numericToInetAddress(linkAddressString), + linkPrefixLength); + if (linkAddress.getAddress() instanceof Inet4Address) { + staticIpConfiguration.ipAddress = linkAddress; + } else { + Log.w(TAG, "Non-IPv4 address: " + linkAddress); + } + } + String gatewayAddressString = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS); + if (gatewayAddressString != null) { + LinkAddress dest = null; + InetAddress gateway = + NetworkUtils.numericToInetAddress(gatewayAddressString); + RouteInfo route = new RouteInfo(dest, gateway); + if (route.isIPv4Default()) { + staticIpConfiguration.gateway = gateway; + } else { + Log.w(TAG, "Non-IPv4 default route: " + route); + } + } + String[] dnsServerAddressesString = + (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES); + if (dnsServerAddressesString != null) { + for (String dnsServerAddressString : dnsServerAddressesString) { + InetAddress dnsServerAddress = + NetworkUtils.numericToInetAddress(dnsServerAddressString); + staticIpConfiguration.dnsServers.add(dnsServerAddress); + } + } + return staticIpConfiguration; + } + + /** + * Parses the IP configuration data elements from the provided XML stream to a + * IpConfiguration. + * + * @param in XmlPullParser instance pointing to the XML stream. + * @param outerTagDepth depth of the outer tag in the XML document. + * @return IpConfiguration object if parsing is successful, null otherwise. + */ + public static IpConfiguration parseIpConfigurationFromXml(XmlPullParser in, + int outerTagDepth) + throws XmlPullParserException, IOException { + IpConfiguration ipConfiguration = new IpConfiguration(); + + // Parse out the IP assignment info first. + String ipAssignmentString = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT); + IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString); + ipConfiguration.setIpAssignment(ipAssignment); + switch (ipAssignment) { + case STATIC: + ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in)); + break; + case DHCP: + case UNASSIGNED: + break; + default: + Log.wtf(TAG, "Unknown ip assignment type: " + ipAssignment); + return null; + } + + // Parse out the proxy settings next. + String proxySettingsString = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS); + ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString); + ipConfiguration.setProxySettings(proxySettings); + switch (proxySettings) { + case STATIC: + String proxyHost = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST); + int proxyPort = + (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT); + String proxyExclusionList = + (String) XmlUtil.readNextValueWithName( + in, XML_TAG_PROXY_EXCLUSION_LIST); + ipConfiguration.setHttpProxy( + new ProxyInfo(proxyHost, proxyPort, proxyExclusionList)); + break; + case PAC: + String proxyPacFile = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE); + ipConfiguration.setHttpProxy(new ProxyInfo(proxyPacFile)); + break; + case NONE: + case UNASSIGNED: + break; + default: + Log.wtf(TAG, "Unknown proxy settings type: " + proxySettings); + return null; + } + return ipConfiguration; + } + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java index 518d1cb7b..58de72158 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiBackupRestoreTest.java @@ -687,30 +687,12 @@ public class WifiBackupRestoreTest { for (WifiConfiguration actualConfiguration : actual) { String actualConfigKey = actualConfiguration.configKey(); if (actualConfigKey.equals(expectedConfigKey)) { - assertConfigurationEqual(expectedConfiguration, actualConfiguration); + WifiConfigurationTestUtil.assertConfigurationEqual( + expectedConfiguration, actualConfiguration); didCompare = true; } } assertTrue(didCompare); } } - - /** - * Asserts that the 2 WifiConfigurations are equal - */ - private void assertConfigurationEqual( - WifiConfiguration expected, WifiConfiguration actual) { - assertEquals(expected.SSID, actual.SSID); - assertEquals(expected.BSSID, actual.BSSID); - assertEquals(expected.preSharedKey, actual.preSharedKey); - assertEquals(expected.wepKeys, actual.wepKeys); - assertEquals(expected.wepTxKeyIndex, actual.wepTxKeyIndex); - assertEquals(expected.hiddenSSID, actual.hiddenSSID); - assertEquals(expected.allowedKeyManagement, actual.allowedKeyManagement); - assertEquals(expected.allowedProtocols, actual.allowedProtocols); - assertEquals(expected.allowedAuthAlgorithms, actual.allowedAuthAlgorithms); - assertEquals(expected.shared, actual.shared); - assertEquals(expected.creatorUid, actual.creatorUid); - assertEquals(expected.getIpConfiguration(), actual.getIpConfiguration()); - } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java index 7117c2a61..85fe81b58 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java @@ -19,6 +19,8 @@ package com.android.server.wifi; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; +import static org.junit.Assert.*; + /** * Helper for creating and populating WifiConfigurations in unit tests. */ @@ -92,4 +94,23 @@ public class WifiConfigurationTestUtil { } return config; } + + /** + * Asserts that the 2 WifiConfigurations are equal + */ + public static void assertConfigurationEqual( + WifiConfiguration expected, WifiConfiguration actual) { + assertEquals(expected.SSID, actual.SSID); + assertEquals(expected.BSSID, actual.BSSID); + assertEquals(expected.preSharedKey, actual.preSharedKey); + assertEquals(expected.wepKeys, actual.wepKeys); + assertEquals(expected.wepTxKeyIndex, actual.wepTxKeyIndex); + assertEquals(expected.hiddenSSID, actual.hiddenSSID); + assertEquals(expected.allowedKeyManagement, actual.allowedKeyManagement); + assertEquals(expected.allowedProtocols, actual.allowedProtocols); + assertEquals(expected.allowedAuthAlgorithms, actual.allowedAuthAlgorithms); + assertEquals(expected.shared, actual.shared); + assertEquals(expected.creatorUid, actual.creatorUid); + assertEquals(expected.getIpConfiguration(), actual.getIpConfiguration()); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java new file mode 100644 index 000000000..fd07ab2c1 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2016 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.util; + +import android.net.IpConfiguration; +import android.net.LinkAddress; +import android.net.NetworkUtils; +import android.net.ProxyInfo; +import android.net.StaticIpConfiguration; +import android.net.wifi.WifiConfiguration; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Xml; + +import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.WifiConfigurationTestUtil; +import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil; +import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; + +import org.junit.Test; +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.io.IOException; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; + +/** + * Unit tests for {@link com.android.server.wifi.util.XmlUtil}. + */ +@SmallTest +public class XmlUtilTest { + + private static final int TEST_NETWORK_ID = -1; + private static final int TEST_UID = 1; + private static final String TEST_SSID = "\"XmlUtilSSID\""; + private static final String TEST_PSK = "XmlUtilPsk"; + private static final String[] TEST_WEP_KEYS = + {"XmlUtilWep1", "XmlUtilWep2", "XmlUtilWep3", "XmlUtilWep3"}; + private static final int TEST_WEP_TX_KEY_INDEX = 1; + private static final String TEST_STATIC_IP_LINK_ADDRESS = "192.168.48.2"; + 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"}; + 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 = ""; + private static final String TEST_PAC_PROXY_LOCATION = "http://"; + private final String mXmlDocHeader = "XmlUtilTest"; + + /** + * Verify that a open WifiConfiguration is serialized & deserialized correctly. + */ + @Test + public void testOpenWifiConfigurationSerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeWifiConfiguration(createOpenNetwork()); + } + + /** + * Verify that a open hidden WifiConfiguration is serialized & deserialized correctly. + */ + @Test + public void testOpenHiddenWifiConfigurationSerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeWifiConfiguration(createOpenHiddenNetwork()); + } + + /** + * Verify that a psk WifiConfiguration is serialized & deserialized correctly. + */ + @Test + public void testPskWifiConfigurationSerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeWifiConfiguration(createPskNetwork()); + } + + /** + * Verify that a psk hidden WifiConfiguration is serialized & deserialized correctly. + */ + @Test + public void testPskHiddenWifiConfigurationSerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeWifiConfiguration(createPskHiddenNetwork()); + } + + /** + * Verify that a psk hidden WifiConfiguration is serialized & deserialized correctly. + */ + @Test + public void testWepWifiConfigurationSerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeWifiConfiguration(createWepNetwork()); + } + + /** + * Verify that a static IpConfiguration with PAC proxy is serialized & deserialized correctly. + */ + @Test + public void testStaticIpConfigurationWithPacProxySerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeIpConfiguration(createStaticIpConfigurationWithPacProxy()); + } + + /** + * Verify that a static IpConfiguration with static proxy is serialized & deserialized correctly. + */ + @Test + public void testStaticIpConfigurationWithStaticProxySerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeIpConfiguration(createStaticIpConfigurationWithStaticProxy()); + } + + /** + * Verify that a partial static IpConfiguration with PAC proxy is serialized & deserialized + * correctly. + */ + @Test + public void testPartialStaticIpConfigurationWithPacProxySerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeIpConfiguration(createPartialStaticIpConfigurationWithPacProxy()); + } + + /** + * Verify that a DHCP IpConfiguration with PAC proxy is serialized & deserialized + * correctly. + */ + @Test + public void testDHCPIpConfigurationWithPacProxySerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeIpConfiguration(createDHCPIpConfigurationWithPacProxy()); + } + + /** + * Verify that a DHCP IpConfiguration with Static proxy is serialized & deserialized + * correctly. + */ + @Test + public void testDHCPIpConfigurationWithStaticProxySerializeDeserialize() + throws IOException, XmlPullParserException { + serializeDeserializeIpConfiguration(createDHCPIpConfigurationWithStaticProxy()); + } + + private WifiConfiguration createOpenNetwork() { + return WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, TEST_SSID, + true, true, null, null, + WifiConfigurationTestUtil.SECURITY_NONE); + } + + private WifiConfiguration createOpenHiddenNetwork() { + WifiConfiguration configuration = createOpenNetwork(); + configuration.hiddenSSID = true; + return configuration; + } + + private WifiConfiguration createPskNetwork() { + WifiConfiguration configuration = + WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, TEST_SSID, + true, true, null, null, + WifiConfigurationTestUtil.SECURITY_PSK); + configuration.preSharedKey = TEST_PSK; + return configuration; + } + + private WifiConfiguration createPskHiddenNetwork() { + WifiConfiguration configuration = createPskNetwork(); + configuration.hiddenSSID = true; + return configuration; + } + + private WifiConfiguration createWepNetwork() { + WifiConfiguration configuration = + WifiConfigurationTestUtil.generateWifiConfig(TEST_NETWORK_ID, TEST_UID, TEST_SSID, + true, true, null, null, + WifiConfigurationTestUtil.SECURITY_WEP); + configuration.wepKeys = TEST_WEP_KEYS; + configuration.wepTxKeyIndex = TEST_WEP_TX_KEY_INDEX; + return configuration; + } + + private StaticIpConfiguration createStaticIpConfiguration() { + StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + LinkAddress linkAddress = + new LinkAddress(NetworkUtils.numericToInetAddress(TEST_STATIC_IP_LINK_ADDRESS), + TEST_STATIC_IP_LINK_PREFIX_LENGTH); + staticIpConfiguration.ipAddress = linkAddress; + InetAddress gatewayAddress = + NetworkUtils.numericToInetAddress(TEST_STATIC_IP_GATEWAY_ADDRESS); + staticIpConfiguration.gateway = gatewayAddress; + for (String dnsServerAddress : TEST_STATIC_IP_DNS_SERVER_ADDRESSES) { + staticIpConfiguration.dnsServers.add( + NetworkUtils.numericToInetAddress(dnsServerAddress)); + } + return staticIpConfiguration; + } + + private StaticIpConfiguration createPartialStaticIpConfiguration() { + StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + LinkAddress linkAddress = + new LinkAddress(NetworkUtils.numericToInetAddress(TEST_STATIC_IP_LINK_ADDRESS), + TEST_STATIC_IP_LINK_PREFIX_LENGTH); + staticIpConfiguration.ipAddress = linkAddress; + // Only set the link address, don't set the gateway/dns servers. + return staticIpConfiguration; + } + + private IpConfiguration createStaticIpConfigurationWithPacProxy() { + StaticIpConfiguration staticIpConfiguration = createStaticIpConfiguration(); + ProxyInfo proxyInfo = new ProxyInfo(TEST_PAC_PROXY_LOCATION); + return new IpConfiguration(IpConfiguration.IpAssignment.STATIC, + IpConfiguration.ProxySettings.PAC, staticIpConfiguration, proxyInfo); + } + + private IpConfiguration createStaticIpConfigurationWithStaticProxy() { + StaticIpConfiguration staticIpConfiguration = createStaticIpConfiguration(); + ProxyInfo proxyInfo = + new ProxyInfo(TEST_STATIC_PROXY_HOST, + TEST_STATIC_PROXY_PORT, + TEST_STATIC_PROXY_EXCLUSION_LIST); + return new IpConfiguration(IpConfiguration.IpAssignment.STATIC, + IpConfiguration.ProxySettings.STATIC, staticIpConfiguration, proxyInfo); + } + + private IpConfiguration createPartialStaticIpConfigurationWithPacProxy() { + StaticIpConfiguration staticIpConfiguration = createPartialStaticIpConfiguration(); + ProxyInfo proxyInfo = new ProxyInfo(TEST_PAC_PROXY_LOCATION); + return new IpConfiguration(IpConfiguration.IpAssignment.STATIC, + IpConfiguration.ProxySettings.PAC, staticIpConfiguration, proxyInfo); + } + + private IpConfiguration createDHCPIpConfigurationWithPacProxy() { + ProxyInfo proxyInfo = new ProxyInfo(TEST_PAC_PROXY_LOCATION); + return new IpConfiguration(IpConfiguration.IpAssignment.DHCP, + IpConfiguration.ProxySettings.PAC, null, proxyInfo); + } + + private IpConfiguration createDHCPIpConfigurationWithStaticProxy() { + ProxyInfo proxyInfo = + new ProxyInfo(TEST_STATIC_PROXY_HOST, + TEST_STATIC_PROXY_PORT, + TEST_STATIC_PROXY_EXCLUSION_LIST); + return new IpConfiguration(IpConfiguration.IpAssignment.DHCP, + IpConfiguration.ProxySettings.STATIC, null, proxyInfo); + } + + private byte[] serializeWifiConfigurationForBackup(WifiConfiguration configuration) + throws IOException, XmlPullParserException { + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, mXmlDocHeader); + WifiConfigurationXmlUtil.writeWifiConfigurationToXmlForBackup(out, configuration); + XmlUtil.writeDocumentEnd(out, mXmlDocHeader); + return outputStream.toByteArray(); + } + + private byte[] serializeWifiConfigurationForConfigStore( + WifiConfiguration configuration) + throws IOException, XmlPullParserException { + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, mXmlDocHeader); + WifiConfigurationXmlUtil.writeWifiConfigurationToXmlForConfigStore(out, configuration); + XmlUtil.writeDocumentEnd(out, mXmlDocHeader); + return outputStream.toByteArray(); + } + + private WifiConfiguration deserializeWifiConfiguration(byte[] data) + throws IOException, XmlPullParserException { + // Deserialize the configuration object. + final XmlPullParser in = Xml.newPullParser(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(data); + in.setInput(inputStream, StandardCharsets.UTF_8.name()); + XmlUtil.gotoDocumentStart(in, mXmlDocHeader); + return WifiConfigurationXmlUtil.parseWifiConfigurationFromXml(in, in.getDepth()); + } + + /** + * This helper method tests both the serialization for backup/restore and config store. + */ + private void serializeDeserializeWifiConfiguration(WifiConfiguration configuration) + throws IOException, XmlPullParserException { + WifiConfiguration retrievedConfiguration; + // Test serialization/deserialization for backup first. + retrievedConfiguration = + deserializeWifiConfiguration( + serializeWifiConfigurationForBackup(configuration)); + WifiConfigurationTestUtil.assertConfigurationEqual(configuration, retrievedConfiguration); + + // Test serialization/deserialization for config store. + retrievedConfiguration = + deserializeWifiConfiguration( + serializeWifiConfigurationForConfigStore(configuration)); + WifiConfigurationTestUtil.assertConfigurationEqual(configuration, retrievedConfiguration); + } + + private void serializeDeserializeIpConfiguration(IpConfiguration configuration) + throws IOException, XmlPullParserException { + String docHeader = "XmlUtilTest"; + + // Serialize the configuration object. + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + XmlUtil.writeDocumentStart(out, docHeader); + IpConfigurationXmlUtil.writeIpConfigurationToXml(out, configuration); + XmlUtil.writeDocumentEnd(out, docHeader); + + // Deserialize the configuration object. + final XmlPullParser in = Xml.newPullParser(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); + in.setInput(inputStream, StandardCharsets.UTF_8.name()); + XmlUtil.gotoDocumentStart(in, docHeader); + IpConfiguration retrievedConfiguration = + IpConfigurationXmlUtil.parseIpConfigurationFromXml(in, in.getDepth()); + assertEquals(configuration, retrievedConfiguration); + } +} |