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