XmlUtil.java revision 642b0bb43ed856bac0503d3169d67026de2c1b02
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi.util; 18 19import android.net.IpConfiguration; 20import android.net.IpConfiguration.IpAssignment; 21import android.net.IpConfiguration.ProxySettings; 22import android.net.LinkAddress; 23import android.net.NetworkUtils; 24import android.net.ProxyInfo; 25import android.net.RouteInfo; 26import android.net.StaticIpConfiguration; 27import android.net.wifi.WifiConfiguration; 28import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; 29import android.net.wifi.WifiEnterpriseConfig; 30import android.util.Log; 31import android.util.Pair; 32 33import com.android.internal.util.XmlUtils; 34 35import org.xmlpull.v1.XmlPullParser; 36import org.xmlpull.v1.XmlPullParserException; 37import org.xmlpull.v1.XmlSerializer; 38 39import java.io.IOException; 40import java.net.Inet4Address; 41import java.net.InetAddress; 42import java.util.BitSet; 43import java.util.HashMap; 44 45/** 46 * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core. 47 * The utility provides methods to write/parse section headers and write/parse values. 48 * This utility is designed for formatting the XML into the following format: 49 * <Document Header> 50 * <Section 1 Header> 51 * <Value 1> 52 * <Value 2> 53 * ... 54 * <Sub Section 1 Header> 55 * <Value 1> 56 * <Value 2> 57 * ... 58 * </Sub Section 1 Header> 59 * </Section 1 Header> 60 * </Document Header> 61 */ 62public class XmlUtil { 63 private static final String TAG = "WifiXmlUtil"; 64 65 /** 66 * Ensure that the XML stream is at a start tag or the end of document. 67 * 68 * @throws XmlPullParserException if parsing errors occur. 69 */ 70 private static void gotoStartTag(XmlPullParser in) 71 throws XmlPullParserException, IOException { 72 int type = in.getEventType(); 73 while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { 74 type = in.next(); 75 } 76 } 77 78 /** 79 * Ensure that the XML stream is at an end tag or the end of document. 80 * 81 * @throws XmlPullParserException if parsing errors occur. 82 */ 83 private static void gotoEndTag(XmlPullParser in) 84 throws XmlPullParserException, IOException { 85 int type = in.getEventType(); 86 while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) { 87 type = in.next(); 88 } 89 } 90 91 /** 92 * Start processing the XML stream at the document header. 93 * 94 * @param in XmlPullParser instance pointing to the XML stream. 95 * @param headerName expected name for the start tag. 96 * @throws XmlPullParserException if parsing errors occur. 97 */ 98 public static void gotoDocumentStart(XmlPullParser in, String headerName) 99 throws XmlPullParserException, IOException { 100 XmlUtils.beginDocument(in, headerName); 101 } 102 103 /** 104 * Move the XML stream to the next section header or indicate if there are no more sections. 105 * The provided outerDepth is used to find sub sections within that depth. 106 * 107 * Use this to move across sections if the ordering of sections are variable. The returned name 108 * can be used to decide what section is next. 109 * 110 * @param in XmlPullParser instance pointing to the XML stream. 111 * @param headerName An array of one string, used to return the name of the next section. 112 * @param outerDepth Find section within this depth. 113 * @return {@code true} if a next section is found, {@code false} if there are no more sections. 114 * @throws XmlPullParserException if parsing errors occur. 115 */ 116 public static boolean gotoNextSectionOrEnd( 117 XmlPullParser in, String[] headerName, int outerDepth) 118 throws XmlPullParserException, IOException { 119 if (XmlUtils.nextElementWithin(in, outerDepth)) { 120 headerName[0] = in.getName(); 121 return true; 122 } 123 return false; 124 } 125 126 /** 127 * Move the XML stream to the next section header or indicate if there are no more sections. 128 * If a section, exists ensure that the name matches the provided name. 129 * The provided outerDepth is used to find sub sections within that depth. 130 * 131 * Use this to move across repeated sections until the end. 132 * 133 * @param in XmlPullParser instance pointing to the XML stream. 134 * @param expectedName expected name for the section header. 135 * @param outerDepth Find section within this depth. 136 * @return {@code true} if a next section is found, {@code false} if there are no more sections. 137 * @throws XmlPullParserException if the section header name does not match |expectedName|, 138 * or if parsing errors occur. 139 */ 140 public static boolean gotoNextSectionWithNameOrEnd( 141 XmlPullParser in, String expectedName, int outerDepth) 142 throws XmlPullParserException, IOException { 143 String[] headerName = new String[1]; 144 if (gotoNextSectionOrEnd(in, headerName, outerDepth)) { 145 if (headerName[0].equals(expectedName)) { 146 return true; 147 } 148 throw new XmlPullParserException( 149 "Next section name does not match expected name: " + expectedName); 150 } 151 return false; 152 } 153 154 /** 155 * Move the XML stream to the next section header and ensure that the name matches the provided 156 * name. 157 * The provided outerDepth is used to find sub sections within that depth. 158 * 159 * Use this to move across sections if the ordering of sections are fixed. 160 * 161 * @param in XmlPullParser instance pointing to the XML stream. 162 * @param expectedName expected name for the section header. 163 * @param outerDepth Find section within this depth. 164 * @throws XmlPullParserException if the section header name does not match |expectedName|, 165 * there are no more sections or if parsing errors occur. 166 */ 167 public static void gotoNextSectionWithName( 168 XmlPullParser in, String expectedName, int outerDepth) 169 throws XmlPullParserException, IOException { 170 if (!gotoNextSectionWithNameOrEnd(in, expectedName, outerDepth)) { 171 throw new XmlPullParserException("Section not found. Expected: " + expectedName); 172 } 173 } 174 175 /** 176 * Checks if the stream is at the end of a section of values. This moves the stream to next tag 177 * and checks if it finds an end tag at the specified depth. 178 * 179 * @param in XmlPullParser instance pointing to the XML stream. 180 * @param sectionDepth depth of the start tag of this section. Used to match the end tag. 181 * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise 182 * @throws XmlPullParserException if parsing errors occur. 183 */ 184 public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth) 185 throws XmlPullParserException, IOException { 186 return !XmlUtils.nextElementWithin(in, sectionDepth); 187 } 188 189 /** 190 * Read the current value in the XML stream using core XmlUtils and stores the retrieved 191 * value name in the string provided. This method reads the value contained in current start 192 * tag. 193 * Note: Because there could be genuine null values being read from the XML, this method raises 194 * an exception to indicate errors. 195 * 196 * @param in XmlPullParser instance pointing to the XML stream. 197 * @param valueName An array of one string, used to return the name attribute 198 * of the value's tag. 199 * @return value retrieved from the XML stream. 200 * @throws XmlPullParserException if parsing errors occur. 201 */ 202 public static Object readCurrentValue(XmlPullParser in, String[] valueName) 203 throws XmlPullParserException, IOException { 204 Object value = XmlUtils.readValueXml(in, valueName); 205 // XmlUtils.readValue does not always move the stream to the end of the tag. So, move 206 // it to the end tag before returning from here. 207 gotoEndTag(in); 208 return value; 209 } 210 211 /** 212 * Read the next value in the XML stream using core XmlUtils and ensure that it matches the 213 * provided name. This method moves the stream to the next start tag and reads the value 214 * contained in it. 215 * Note: Because there could be genuine null values being read from the XML, this method raises 216 * an exception to indicate errors. 217 * 218 * @param in XmlPullParser instance pointing to the XML stream. 219 * @return value retrieved from the XML stream. 220 * @throws XmlPullParserException if the value read does not match |expectedName|, 221 * or if parsing errors occur. 222 */ 223 public static Object readNextValueWithName(XmlPullParser in, String expectedName) 224 throws XmlPullParserException, IOException { 225 String[] valueName = new String[1]; 226 XmlUtils.nextElement(in); 227 Object value = readCurrentValue(in, valueName); 228 if (valueName[0].equals(expectedName)) { 229 return value; 230 } 231 throw new XmlPullParserException( 232 "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]); 233 } 234 235 /** 236 * Write the XML document start with the provided document header name. 237 * 238 * @param out XmlSerializer instance pointing to the XML stream. 239 * @param headerName name for the start tag. 240 */ 241 public static void writeDocumentStart(XmlSerializer out, String headerName) 242 throws IOException { 243 out.startDocument(null, true); 244 out.startTag(null, headerName); 245 } 246 247 /** 248 * Write the XML document end with the provided document header name. 249 * 250 * @param out XmlSerializer instance pointing to the XML stream. 251 * @param headerName name for the end tag. 252 */ 253 public static void writeDocumentEnd(XmlSerializer out, String headerName) 254 throws IOException { 255 out.endTag(null, headerName); 256 out.endDocument(); 257 } 258 259 /** 260 * Write a section start header tag with the provided section name. 261 * 262 * @param out XmlSerializer instance pointing to the XML stream. 263 * @param headerName name for the start tag. 264 */ 265 public static void writeNextSectionStart(XmlSerializer out, String headerName) 266 throws IOException { 267 out.startTag(null, headerName); 268 } 269 270 /** 271 * Write a section end header tag with the provided section name. 272 * 273 * @param out XmlSerializer instance pointing to the XML stream. 274 * @param headerName name for the end tag. 275 */ 276 public static void writeNextSectionEnd(XmlSerializer out, String headerName) 277 throws IOException { 278 out.endTag(null, headerName); 279 } 280 281 /** 282 * Write the value with the provided name in the XML stream using core XmlUtils. 283 * 284 * @param out XmlSerializer instance pointing to the XML stream. 285 * @param name name of the value. 286 * @param value value to be written. 287 */ 288 public static void writeNextValue(XmlSerializer out, String name, Object value) 289 throws XmlPullParserException, IOException { 290 XmlUtils.writeValueXml(value, name, out); 291 } 292 293 /** 294 * Utility class to serialize and deseriaize {@link WifiConfiguration} object to XML & 295 * vice versa. 296 * This is used by both {@link com.android.server.wifi.WifiConfigStore} & 297 * {@link com.android.server.wifi.WifiBackupRestore} modules. 298 * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store. 299 * There is only 1 version of |parseXmlToConfiguration| for both backup & config store. 300 * The parse method is written so that any element added/deleted in future revisions can 301 * be easily handled. 302 */ 303 public static class WifiConfigurationXmlUtil { 304 /** 305 * List of XML tags corresponding to WifiConfiguration object elements. 306 */ 307 public static final String XML_TAG_SSID = "SSID"; 308 public static final String XML_TAG_BSSID = "BSSID"; 309 public static final String XML_TAG_CONFIG_KEY = "ConfigKey"; 310 public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey"; 311 public static final String XML_TAG_WEP_KEYS = "WEPKeys"; 312 public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex"; 313 public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID"; 314 public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt"; 315 public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols"; 316 public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos"; 317 public static final String XML_TAG_SHARED = "Shared"; 318 public static final String XML_TAG_FQDN = "FQDN"; 319 public static final String XML_TAG_PROVIDER_FRIENDLY_NAME = "ProviderFriendlyName"; 320 public static final String XML_TAG_LINKED_NETWORKS_LIST = "LinkedNetworksList"; 321 public static final String XML_TAG_DEFAULT_GW_MAC_ADDRESS = "DefaultGwMacAddress"; 322 public static final String XML_TAG_VALIDATED_INTERNET_ACCESS = "ValidatedInternetAccess"; 323 public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected"; 324 public static final String XML_TAG_USER_APPROVED = "UserApproved"; 325 public static final String XML_TAG_METERED_HINT = "MeteredHint"; 326 public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores"; 327 public static final String XML_TAG_NUM_ASSOCIATION = "NumAssociation"; 328 public static final String XML_TAG_CREATOR_UID = "CreatorUid"; 329 public static final String XML_TAG_CREATOR_NAME = "CreatorName"; 330 public static final String XML_TAG_CREATION_TIME = "CreationTime"; 331 public static final String XML_TAG_LAST_UPDATE_UID = "LastUpdateUid"; 332 public static final String XML_TAG_LAST_UPDATE_NAME = "LastUpdateName"; 333 public static final String XML_TAG_LAST_CONNECT_UID = "LastConnectUid"; 334 335 /** 336 * Write WepKeys to the XML stream. 337 * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements 338 * are set to null. User may chose to set any one of the key elements in WifiConfiguration. 339 * XmlUtils serialization doesn't handle this array of nulls well . 340 * So, write empty strings if some of the keys are not initialized and null if all of 341 * the elements are empty. 342 */ 343 private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys) 344 throws XmlPullParserException, IOException { 345 String[] wepKeysToWrite = new String[wepKeys.length]; 346 boolean hasWepKey = false; 347 for (int i = 0; i < wepKeys.length; i++) { 348 if (wepKeys[i] == null) { 349 wepKeysToWrite[i] = new String(); 350 } else { 351 wepKeysToWrite[i] = wepKeys[i]; 352 hasWepKey = true; 353 } 354 } 355 if (hasWepKey) { 356 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite); 357 } else { 358 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null); 359 } 360 } 361 362 /** 363 * Write the Configuration data elements that are common for backup & config store to the 364 * XML stream. 365 * 366 * @param out XmlSerializer instance pointing to the XML stream. 367 * @param configuration WifiConfiguration object to be serialized. 368 */ 369 public static void writeCommonElementsToXml( 370 XmlSerializer out, WifiConfiguration configuration) 371 throws XmlPullParserException, IOException { 372 XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.configKey()); 373 XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID); 374 XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID); 375 XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, configuration.preSharedKey); 376 writeWepKeysToXml(out, configuration.wepKeys); 377 XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex); 378 XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID); 379 XmlUtil.writeNextValue( 380 out, XML_TAG_ALLOWED_KEY_MGMT, 381 configuration.allowedKeyManagement.toByteArray()); 382 XmlUtil.writeNextValue( 383 out, XML_TAG_ALLOWED_PROTOCOLS, 384 configuration.allowedProtocols.toByteArray()); 385 XmlUtil.writeNextValue( 386 out, XML_TAG_ALLOWED_AUTH_ALGOS, 387 configuration.allowedAuthAlgorithms.toByteArray()); 388 XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared); 389 } 390 391 /** 392 * Write the Configuration data elements for backup from the provided Configuration to the 393 * XML stream. 394 * Note: This is a subset of the elements serialized for config store. 395 * 396 * @param out XmlSerializer instance pointing to the XML stream. 397 * @param configuration WifiConfiguration object to be serialized. 398 */ 399 public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration) 400 throws XmlPullParserException, IOException { 401 writeCommonElementsToXml(out, configuration); 402 } 403 404 /** 405 * Write the Configuration data elements for config store from the provided Configuration 406 * to the XML stream. 407 * 408 * @param out XmlSerializer instance pointing to the XML stream. 409 * @param configuration WifiConfiguration object to be serialized. 410 */ 411 public static void writeToXmlForConfigStore( 412 XmlSerializer out, WifiConfiguration configuration) 413 throws XmlPullParserException, IOException { 414 writeCommonElementsToXml(out, configuration); 415 XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN); 416 XmlUtil.writeNextValue( 417 out, XML_TAG_PROVIDER_FRIENDLY_NAME, configuration.providerFriendlyName); 418 XmlUtil.writeNextValue( 419 out, XML_TAG_LINKED_NETWORKS_LIST, configuration.linkedConfigurations); 420 XmlUtil.writeNextValue( 421 out, XML_TAG_DEFAULT_GW_MAC_ADDRESS, configuration.defaultGwMacAddress); 422 XmlUtil.writeNextValue( 423 out, XML_TAG_VALIDATED_INTERNET_ACCESS, configuration.validatedInternetAccess); 424 XmlUtil.writeNextValue( 425 out, XML_TAG_NO_INTERNET_ACCESS_EXPECTED, 426 configuration.noInternetAccessExpected); 427 XmlUtil.writeNextValue(out, XML_TAG_USER_APPROVED, configuration.userApproved); 428 XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint); 429 XmlUtil.writeNextValue( 430 out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores); 431 XmlUtil.writeNextValue(out, XML_TAG_NUM_ASSOCIATION, configuration.numAssociation); 432 XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid); 433 XmlUtil.writeNextValue(out, XML_TAG_CREATOR_NAME, configuration.creatorName); 434 XmlUtil.writeNextValue(out, XML_TAG_CREATION_TIME, configuration.creationTime); 435 XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_UID, configuration.lastUpdateUid); 436 XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_NAME, configuration.lastUpdateName); 437 XmlUtil.writeNextValue(out, XML_TAG_LAST_CONNECT_UID, configuration.lastConnectUid); 438 } 439 440 /** 441 * Populate wepKeys array elements only if they were non-empty in the backup data. 442 * 443 * @throws XmlPullParserException if parsing errors occur. 444 */ 445 private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys) 446 throws XmlPullParserException, IOException { 447 String[] wepKeysInData = (String[]) value; 448 if (wepKeysInData == null) { 449 return; 450 } 451 if (wepKeysInData.length != wepKeys.length) { 452 throw new XmlPullParserException( 453 "Invalid Wep Keys length: " + wepKeysInData.length); 454 } 455 for (int i = 0; i < wepKeys.length; i++) { 456 if (wepKeysInData[i].isEmpty()) { 457 wepKeys[i] = null; 458 } else { 459 wepKeys[i] = wepKeysInData[i]; 460 } 461 } 462 } 463 464 /** 465 * Parses the configuration data elements from the provided XML stream to a 466 * WifiConfiguration object. 467 * Note: This is used for parsing both backup data and config store data. Looping through 468 * the tags make it easy to add or remove elements in the future versions if needed. 469 * 470 * @param in XmlPullParser instance pointing to the XML stream. 471 * @param outerTagDepth depth of the outer tag in the XML document. 472 * @return Pair<Config key, WifiConfiguration object> if parsing is successful, 473 * null otherwise. 474 */ 475 public static Pair<String, WifiConfiguration> parseFromXml( 476 XmlPullParser in, int outerTagDepth) 477 throws XmlPullParserException, IOException { 478 WifiConfiguration configuration = new WifiConfiguration(); 479 String configKeyInData = null; 480 481 // Loop through and parse out all the elements from the stream within this section. 482 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 483 String[] valueName = new String[1]; 484 Object value = XmlUtil.readCurrentValue(in, valueName); 485 if (valueName[0] == null) { 486 throw new XmlPullParserException("Missing value name"); 487 } 488 switch (valueName[0]) { 489 case XML_TAG_CONFIG_KEY: 490 configKeyInData = (String) value; 491 break; 492 case XML_TAG_SSID: 493 configuration.SSID = (String) value; 494 break; 495 case XML_TAG_BSSID: 496 configuration.BSSID = (String) value; 497 break; 498 case XML_TAG_PRE_SHARED_KEY: 499 configuration.preSharedKey = (String) value; 500 break; 501 case XML_TAG_WEP_KEYS: 502 populateWepKeysFromXmlValue(value, configuration.wepKeys); 503 break; 504 case XML_TAG_WEP_TX_KEY_INDEX: 505 configuration.wepTxKeyIndex = (int) value; 506 break; 507 case XML_TAG_HIDDEN_SSID: 508 configuration.hiddenSSID = (boolean) value; 509 break; 510 case XML_TAG_ALLOWED_KEY_MGMT: 511 byte[] allowedKeyMgmt = (byte[]) value; 512 configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); 513 break; 514 case XML_TAG_ALLOWED_PROTOCOLS: 515 byte[] allowedProtocols = (byte[]) value; 516 configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); 517 break; 518 case XML_TAG_ALLOWED_AUTH_ALGOS: 519 byte[] allowedAuthAlgorithms = (byte[]) value; 520 configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms); 521 break; 522 case XML_TAG_SHARED: 523 configuration.shared = (boolean) value; 524 break; 525 case XML_TAG_FQDN: 526 configuration.FQDN = (String) value; 527 break; 528 case XML_TAG_PROVIDER_FRIENDLY_NAME: 529 configuration.providerFriendlyName = (String) value; 530 break; 531 case XML_TAG_LINKED_NETWORKS_LIST: 532 configuration.linkedConfigurations = (HashMap<String, Integer>) value; 533 break; 534 case XML_TAG_DEFAULT_GW_MAC_ADDRESS: 535 configuration.defaultGwMacAddress = (String) value; 536 break; 537 case XML_TAG_VALIDATED_INTERNET_ACCESS: 538 configuration.validatedInternetAccess = (boolean) value; 539 break; 540 case XML_TAG_NO_INTERNET_ACCESS_EXPECTED: 541 configuration.noInternetAccessExpected = (boolean) value; 542 break; 543 case XML_TAG_USER_APPROVED: 544 configuration.userApproved = (int) value; 545 break; 546 case XML_TAG_METERED_HINT: 547 configuration.meteredHint = (boolean) value; 548 break; 549 case XML_TAG_USE_EXTERNAL_SCORES: 550 configuration.useExternalScores = (boolean) value; 551 break; 552 case XML_TAG_NUM_ASSOCIATION: 553 configuration.numAssociation = (int) value; 554 break; 555 case XML_TAG_CREATOR_UID: 556 configuration.creatorUid = (int) value; 557 break; 558 case XML_TAG_CREATOR_NAME: 559 configuration.creatorName = (String) value; 560 break; 561 case XML_TAG_CREATION_TIME: 562 configuration.creationTime = (String) value; 563 break; 564 case XML_TAG_LAST_UPDATE_UID: 565 configuration.lastUpdateUid = (int) value; 566 break; 567 case XML_TAG_LAST_UPDATE_NAME: 568 configuration.lastUpdateName = (String) value; 569 break; 570 case XML_TAG_LAST_CONNECT_UID: 571 configuration.lastConnectUid = (int) value; 572 break; 573 default: 574 throw new XmlPullParserException( 575 "Unknown value name found: " + valueName[0]); 576 } 577 } 578 return Pair.create(configKeyInData, configuration); 579 } 580 } 581 582 /** 583 * Utility class to serialize and deseriaize {@link IpConfiguration} object to XML & vice versa. 584 * This is used by both {@link com.android.server.wifi.WifiConfigStore} & 585 * {@link com.android.server.wifi.WifiBackupRestore} modules. 586 */ 587 public static class IpConfigurationXmlUtil { 588 589 /** 590 * List of XML tags corresponding to IpConfiguration object elements. 591 */ 592 public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment"; 593 public static final String XML_TAG_LINK_ADDRESS = "LinkAddress"; 594 public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength"; 595 public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress"; 596 public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers"; 597 public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings"; 598 public static final String XML_TAG_PROXY_HOST = "ProxyHost"; 599 public static final String XML_TAG_PROXY_PORT = "ProxyPort"; 600 public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac"; 601 public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList"; 602 603 /** 604 * Write the static IP configuration data elements to XML stream. 605 */ 606 private static void writeStaticIpConfigurationToXml( 607 XmlSerializer out, StaticIpConfiguration staticIpConfiguration) 608 throws XmlPullParserException, IOException { 609 if (staticIpConfiguration.ipAddress != null) { 610 XmlUtil.writeNextValue( 611 out, XML_TAG_LINK_ADDRESS, 612 staticIpConfiguration.ipAddress.getAddress().getHostAddress()); 613 XmlUtil.writeNextValue( 614 out, XML_TAG_LINK_PREFIX_LENGTH, 615 staticIpConfiguration.ipAddress.getPrefixLength()); 616 } else { 617 XmlUtil.writeNextValue( 618 out, XML_TAG_LINK_ADDRESS, null); 619 XmlUtil.writeNextValue( 620 out, XML_TAG_LINK_PREFIX_LENGTH, null); 621 } 622 if (staticIpConfiguration.gateway != null) { 623 XmlUtil.writeNextValue( 624 out, XML_TAG_GATEWAY_ADDRESS, 625 staticIpConfiguration.gateway.getHostAddress()); 626 } else { 627 XmlUtil.writeNextValue( 628 out, XML_TAG_GATEWAY_ADDRESS, null); 629 630 } 631 if (staticIpConfiguration.dnsServers != null) { 632 // Create a string array of DNS server addresses 633 String[] dnsServers = new String[staticIpConfiguration.dnsServers.size()]; 634 int dnsServerIdx = 0; 635 for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { 636 dnsServers[dnsServerIdx++] = inetAddr.getHostAddress(); 637 } 638 XmlUtil.writeNextValue( 639 out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers); 640 } else { 641 XmlUtil.writeNextValue( 642 out, XML_TAG_DNS_SERVER_ADDRESSES, null); 643 } 644 } 645 646 /** 647 * Write the IP configuration data elements from the provided Configuration to the XML 648 * stream. 649 * 650 * @param out XmlSerializer instance pointing to the XML stream. 651 * @param ipConfiguration IpConfiguration object to be serialized. 652 */ 653 public static void writeToXml(XmlSerializer out, IpConfiguration ipConfiguration) 654 throws XmlPullParserException, IOException { 655 // Write IP assignment settings 656 XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT, 657 ipConfiguration.ipAssignment.toString()); 658 switch (ipConfiguration.ipAssignment) { 659 case STATIC: 660 writeStaticIpConfigurationToXml( 661 out, ipConfiguration.getStaticIpConfiguration()); 662 break; 663 default: 664 break; 665 } 666 667 // Write proxy settings 668 XmlUtil.writeNextValue( 669 out, XML_TAG_PROXY_SETTINGS, 670 ipConfiguration.proxySettings.toString()); 671 switch (ipConfiguration.proxySettings) { 672 case STATIC: 673 XmlUtil.writeNextValue( 674 out, XML_TAG_PROXY_HOST, 675 ipConfiguration.httpProxy.getHost()); 676 XmlUtil.writeNextValue( 677 out, XML_TAG_PROXY_PORT, 678 ipConfiguration.httpProxy.getPort()); 679 XmlUtil.writeNextValue( 680 out, XML_TAG_PROXY_EXCLUSION_LIST, 681 ipConfiguration.httpProxy.getExclusionListAsString()); 682 break; 683 case PAC: 684 XmlUtil.writeNextValue( 685 out, XML_TAG_PROXY_PAC_FILE, 686 ipConfiguration.httpProxy.getPacFileUrl().toString()); 687 break; 688 default: 689 break; 690 } 691 } 692 693 /** 694 * Parse out the static IP configuration from the XML stream. 695 */ 696 private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in) 697 throws XmlPullParserException, IOException { 698 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); 699 700 String linkAddressString = 701 (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS); 702 Integer linkPrefixLength = 703 (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH); 704 if (linkAddressString != null && linkPrefixLength != null) { 705 LinkAddress linkAddress = new LinkAddress( 706 NetworkUtils.numericToInetAddress(linkAddressString), 707 linkPrefixLength); 708 if (linkAddress.getAddress() instanceof Inet4Address) { 709 staticIpConfiguration.ipAddress = linkAddress; 710 } else { 711 Log.w(TAG, "Non-IPv4 address: " + linkAddress); 712 } 713 } 714 String gatewayAddressString = 715 (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS); 716 if (gatewayAddressString != null) { 717 LinkAddress dest = null; 718 InetAddress gateway = 719 NetworkUtils.numericToInetAddress(gatewayAddressString); 720 RouteInfo route = new RouteInfo(dest, gateway); 721 if (route.isIPv4Default()) { 722 staticIpConfiguration.gateway = gateway; 723 } else { 724 Log.w(TAG, "Non-IPv4 default route: " + route); 725 } 726 } 727 String[] dnsServerAddressesString = 728 (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES); 729 if (dnsServerAddressesString != null) { 730 for (String dnsServerAddressString : dnsServerAddressesString) { 731 InetAddress dnsServerAddress = 732 NetworkUtils.numericToInetAddress(dnsServerAddressString); 733 staticIpConfiguration.dnsServers.add(dnsServerAddress); 734 } 735 } 736 return staticIpConfiguration; 737 } 738 739 /** 740 * Parses the IP configuration data elements from the provided XML stream to an 741 * IpConfiguration object. 742 * 743 * @param in XmlPullParser instance pointing to the XML stream. 744 * @param outerTagDepth depth of the outer tag in the XML document. 745 * @return IpConfiguration object if parsing is successful, null otherwise. 746 */ 747 public static IpConfiguration parseFromXml(XmlPullParser in, int outerTagDepth) 748 throws XmlPullParserException, IOException { 749 IpConfiguration ipConfiguration = new IpConfiguration(); 750 751 // Parse out the IP assignment info first. 752 String ipAssignmentString = 753 (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT); 754 IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString); 755 ipConfiguration.setIpAssignment(ipAssignment); 756 switch (ipAssignment) { 757 case STATIC: 758 ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in)); 759 break; 760 case DHCP: 761 case UNASSIGNED: 762 break; 763 default: 764 throw new XmlPullParserException("Unknown ip assignment type: " + ipAssignment); 765 } 766 767 // Parse out the proxy settings next. 768 String proxySettingsString = 769 (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS); 770 ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString); 771 ipConfiguration.setProxySettings(proxySettings); 772 switch (proxySettings) { 773 case STATIC: 774 String proxyHost = 775 (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST); 776 int proxyPort = 777 (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT); 778 String proxyExclusionList = 779 (String) XmlUtil.readNextValueWithName( 780 in, XML_TAG_PROXY_EXCLUSION_LIST); 781 ipConfiguration.setHttpProxy( 782 new ProxyInfo(proxyHost, proxyPort, proxyExclusionList)); 783 break; 784 case PAC: 785 String proxyPacFile = 786 (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE); 787 ipConfiguration.setHttpProxy(new ProxyInfo(proxyPacFile)); 788 break; 789 case NONE: 790 case UNASSIGNED: 791 break; 792 default: 793 throw new XmlPullParserException( 794 "Unknown proxy settings type: " + proxySettings); 795 } 796 return ipConfiguration; 797 } 798 } 799 800 /** 801 * Utility class to serialize and deseriaize {@link NetworkSelectionStatus} object to XML & 802 * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module. 803 */ 804 public static class NetworkSelectionStatusXmlUtil { 805 806 /** 807 * List of XML tags corresponding to NetworkSelectionStatus object elements. 808 */ 809 public static final String XML_TAG_SELECTION_STATUS = "SelectionStatus"; 810 public static final String XML_TAG_DISABLE_REASON = "DisableReason"; 811 public static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice"; 812 public static final String XML_TAG_CONNECT_CHOICE_TIMESTAMP = "ConnectChoiceTimeStamp"; 813 public static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected"; 814 815 /** 816 * Write the NetworkSelectionStatus data elements from the provided status to the XML 817 * stream. 818 * 819 * @param out XmlSerializer instance pointing to the XML stream. 820 * @param status NetworkSelectionStatus object to be serialized. 821 */ 822 public static void writeToXml(XmlSerializer out, NetworkSelectionStatus status) 823 throws XmlPullParserException, IOException { 824 // Don't persist blacklists across reboots. So, if the status is temporarily disabled, 825 // store the status as enabled. This will ensure that when the device reboots, it is 826 // still considered for network selection. 827 int selectionStatus = status.getNetworkSelectionStatus(); 828 if (selectionStatus == NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) { 829 selectionStatus = NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; 830 } 831 XmlUtil.writeNextValue(out, XML_TAG_SELECTION_STATUS, selectionStatus); 832 XmlUtil.writeNextValue( 833 out, XML_TAG_DISABLE_REASON, status.getNetworkSelectionDisableReason()); 834 XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, status.getConnectChoice()); 835 XmlUtil.writeNextValue( 836 out, XML_TAG_CONNECT_CHOICE_TIMESTAMP, status.getConnectChoiceTimestamp()); 837 XmlUtil.writeNextValue(out, XML_TAG_HAS_EVER_CONNECTED, status.getHasEverConnected()); 838 } 839 840 /** 841 * Parses the NetworkSelectionStatus data elements from the provided XML stream to a 842 * NetworkSelectionStatus object. 843 * 844 * @param in XmlPullParser instance pointing to the XML stream. 845 * @param outerTagDepth depth of the outer tag in the XML document. 846 * @return NetworkSelectionStatus object if parsing is successful, null otherwise. 847 */ 848 public static NetworkSelectionStatus parseFromXml(XmlPullParser in, int outerTagDepth) 849 throws XmlPullParserException, IOException { 850 NetworkSelectionStatus status = new NetworkSelectionStatus(); 851 852 // Loop through and parse out all the elements from the stream within this section. 853 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 854 String[] valueName = new String[1]; 855 Object value = XmlUtil.readCurrentValue(in, valueName); 856 if (valueName[0] == null) { 857 throw new XmlPullParserException("Missing value name"); 858 } 859 switch (valueName[0]) { 860 case XML_TAG_SELECTION_STATUS: 861 status.setNetworkSelectionStatus((int) value); 862 break; 863 case XML_TAG_DISABLE_REASON: 864 status.setNetworkSelectionDisableReason((int) value); 865 break; 866 case XML_TAG_CONNECT_CHOICE: 867 status.setConnectChoice((String) value); 868 break; 869 case XML_TAG_CONNECT_CHOICE_TIMESTAMP: 870 status.setConnectChoiceTimestamp((long) value); 871 break; 872 case XML_TAG_HAS_EVER_CONNECTED: 873 status.setHasEverConnected((boolean) value); 874 break; 875 default: 876 throw new XmlPullParserException( 877 "Unknown value name found: " + valueName[0]); 878 } 879 } 880 return status; 881 } 882 } 883 884 /** 885 * Utility class to serialize and deseriaize {@link WifiEnterpriseConfig} object to XML & 886 * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module. 887 */ 888 public static class WifiEnterpriseConfigXmlUtil { 889 890 /** 891 * List of XML tags corresponding to WifiEnterpriseConfig object elements. 892 */ 893 public static final String XML_TAG_IDENTITY = "Identity"; 894 public static final String XML_TAG_ANON_IDENTITY = "AnonIdentity"; 895 public static final String XML_TAG_PASSWORD = "Password"; 896 public static final String XML_TAG_CLIENT_CERT = "ClientCert"; 897 public static final String XML_TAG_CA_CERT = "CaCert"; 898 public static final String XML_TAG_SUBJECT_MATCH = "SubjectMatch"; 899 public static final String XML_TAG_ENGINE = "Engine"; 900 public static final String XML_TAG_ENGINE_ID = "EngineId"; 901 public static final String XML_TAG_PRIVATE_KEY_ID = "PrivateKeyId"; 902 public static final String XML_TAG_ALT_SUBJECT_MATCH = "AltSubjectMatch"; 903 public static final String XML_TAG_DOM_SUFFIX_MATCH = "DomSuffixMatch"; 904 public static final String XML_TAG_CA_PATH = "CaPath"; 905 public static final String XML_TAG_EAP_METHOD = "EapMethod"; 906 public static final String XML_TAG_PHASE2_METHOD = "Phase2Method"; 907 908 /** 909 * Write the WifiEnterpriseConfig data elements from the provided config to the XML 910 * stream. 911 * 912 * @param out XmlSerializer instance pointing to the XML stream. 913 * @param enterpriseConfig WifiEnterpriseConfig object to be serialized. 914 */ 915 public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig) 916 throws XmlPullParserException, IOException { 917 XmlUtil.writeNextValue(out, XML_TAG_IDENTITY, 918 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY, "")); 919 XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY, 920 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY, "")); 921 XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, 922 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY, "")); 923 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT, 924 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY, "")); 925 XmlUtil.writeNextValue(out, XML_TAG_CA_CERT, 926 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, "")); 927 XmlUtil.writeNextValue(out, XML_TAG_SUBJECT_MATCH, 928 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY, "")); 929 XmlUtil.writeNextValue(out, XML_TAG_ENGINE, 930 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, "")); 931 XmlUtil.writeNextValue(out, XML_TAG_ENGINE_ID, 932 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, "")); 933 XmlUtil.writeNextValue(out, XML_TAG_PRIVATE_KEY_ID, 934 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, "")); 935 XmlUtil.writeNextValue(out, XML_TAG_ALT_SUBJECT_MATCH, 936 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, "")); 937 XmlUtil.writeNextValue(out, XML_TAG_DOM_SUFFIX_MATCH, 938 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, "")); 939 XmlUtil.writeNextValue(out, XML_TAG_CA_PATH, 940 enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_PATH_KEY, "")); 941 XmlUtil.writeNextValue(out, XML_TAG_EAP_METHOD, enterpriseConfig.getEapMethod()); 942 XmlUtil.writeNextValue(out, XML_TAG_PHASE2_METHOD, enterpriseConfig.getPhase2Method()); 943 } 944 945 /** 946 * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object. 947 * 948 * @param in XmlPullParser instance pointing to the XML stream. 949 * @param outerTagDepth depth of the outer tag in the XML document. 950 * @return WifiEnterpriseConfig object if parsing is successful, null otherwise. 951 */ 952 public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth) 953 throws XmlPullParserException, IOException { 954 WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); 955 956 // Loop through and parse out all the elements from the stream within this section. 957 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 958 String[] valueName = new String[1]; 959 Object value = XmlUtil.readCurrentValue(in, valueName); 960 if (valueName[0] == null) { 961 throw new XmlPullParserException("Missing value name"); 962 } 963 switch (valueName[0]) { 964 case XML_TAG_IDENTITY: 965 enterpriseConfig.setFieldValue( 966 WifiEnterpriseConfig.IDENTITY_KEY, (String) value); 967 break; 968 case XML_TAG_ANON_IDENTITY: 969 enterpriseConfig.setFieldValue( 970 WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value); 971 break; 972 case XML_TAG_PASSWORD: 973 enterpriseConfig.setFieldValue( 974 WifiEnterpriseConfig.PASSWORD_KEY, (String) value); 975 break; 976 case XML_TAG_CLIENT_CERT: 977 enterpriseConfig.setFieldValue( 978 WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value); 979 break; 980 case XML_TAG_CA_CERT: 981 enterpriseConfig.setFieldValue( 982 WifiEnterpriseConfig.CA_CERT_KEY, (String) value); 983 break; 984 case XML_TAG_SUBJECT_MATCH: 985 enterpriseConfig.setFieldValue( 986 WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value); 987 break; 988 case XML_TAG_ENGINE: 989 enterpriseConfig.setFieldValue( 990 WifiEnterpriseConfig.ENGINE_KEY, (String) value); 991 break; 992 case XML_TAG_ENGINE_ID: 993 enterpriseConfig.setFieldValue( 994 WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value); 995 break; 996 case XML_TAG_PRIVATE_KEY_ID: 997 enterpriseConfig.setFieldValue( 998 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value); 999 break; 1000 case XML_TAG_ALT_SUBJECT_MATCH: 1001 enterpriseConfig.setFieldValue( 1002 WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value); 1003 break; 1004 case XML_TAG_DOM_SUFFIX_MATCH: 1005 enterpriseConfig.setFieldValue( 1006 WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value); 1007 break; 1008 case XML_TAG_CA_PATH: 1009 enterpriseConfig.setFieldValue( 1010 WifiEnterpriseConfig.CA_PATH_KEY, (String) value); 1011 break; 1012 case XML_TAG_EAP_METHOD: 1013 enterpriseConfig.setEapMethod((int) value); 1014 break; 1015 case XML_TAG_PHASE2_METHOD: 1016 enterpriseConfig.setPhase2Method((int) value); 1017 break; 1018 default: 1019 throw new XmlPullParserException( 1020 "Unknown value name found: " + valueName[0]); 1021 } 1022 } 1023 return enterpriseConfig; 1024 } 1025 } 1026} 1027 1028