• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server.wifi.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.compat.Compatibility;
22 import android.net.InetAddresses;
23 import android.net.IpConfiguration;
24 import android.net.IpConfiguration.IpAssignment;
25 import android.net.IpConfiguration.ProxySettings;
26 import android.net.LinkAddress;
27 import android.net.MacAddress;
28 import android.net.ProxyInfo;
29 import android.net.RouteInfo;
30 import android.net.StaticIpConfiguration;
31 import android.net.Uri;
32 import android.net.wifi.ScanResult;
33 import android.net.wifi.SecurityParams;
34 import android.net.wifi.SoftApConfiguration;
35 import android.net.wifi.WifiConfiguration;
36 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
37 import android.net.wifi.WifiEnterpriseConfig;
38 import android.net.wifi.WifiManager;
39 import android.net.wifi.WifiMigration;
40 import android.net.wifi.WifiSsid;
41 import android.os.ParcelUuid;
42 import android.text.TextUtils;
43 import android.util.Log;
44 import android.util.Pair;
45 import android.util.SparseIntArray;
46 
47 import com.android.modules.utils.build.SdkLevel;
48 
49 import org.xmlpull.v1.XmlPullParser;
50 import org.xmlpull.v1.XmlPullParserException;
51 import org.xmlpull.v1.XmlSerializer;
52 
53 import java.io.IOException;
54 import java.net.Inet4Address;
55 import java.net.InetAddress;
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.BitSet;
59 import java.util.Collections;
60 import java.util.HashMap;
61 import java.util.List;
62 import java.util.Locale;
63 
64 /**
65  * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core.
66  * The utility provides methods to write/parse section headers and write/parse values.
67  * This utility is designed for formatting the XML into the following format:
68  * <Document Header>
69  *  <Section 1 Header>
70  *   <Value 1>
71  *   <Value 2>
72  *   ...
73  *   <Sub Section 1 Header>
74  *    <Value 1>
75  *    <Value 2>
76  *    ...
77  *   </Sub Section 1 Header>
78  *  </Section 1 Header>
79  * </Document Header>
80  *
81  * Note: These utility methods are meant to be used for:
82  * 1. Backup/restore wifi network data to/from cloud.
83  * 2. Persisting wifi network data to/from disk.
84  */
85 public class XmlUtil {
86     private static final String TAG = "WifiXmlUtil";
87 
88     /**
89      * Ensure that the XML stream is at a start tag or the end of document.
90      *
91      * @throws XmlPullParserException if parsing errors occur.
92      */
gotoStartTag(XmlPullParser in)93     private static void gotoStartTag(XmlPullParser in)
94             throws XmlPullParserException, IOException {
95         int type = in.getEventType();
96         while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
97             type = in.next();
98         }
99     }
100 
101     /**
102      * Ensure that the XML stream is at an end tag or the end of document.
103      *
104      * @throws XmlPullParserException if parsing errors occur.
105      */
gotoEndTag(XmlPullParser in)106     private static void gotoEndTag(XmlPullParser in)
107             throws XmlPullParserException, IOException {
108         int type = in.getEventType();
109         while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) {
110             type = in.next();
111         }
112     }
113 
114     /**
115      * Start processing the XML stream at the document header.
116      *
117      * @param in         XmlPullParser instance pointing to the XML stream.
118      * @param headerName expected name for the start tag.
119      * @throws XmlPullParserException if parsing errors occur.
120      */
gotoDocumentStart(XmlPullParser in, String headerName)121     public static void gotoDocumentStart(XmlPullParser in, String headerName)
122             throws XmlPullParserException, IOException {
123         XmlUtilHelper.beginDocument(in, headerName);
124     }
125 
126     /**
127      * Move the XML stream to the next section header or indicate if there are no more sections.
128      * The provided outerDepth is used to find sub sections within that depth.
129      *
130      * Use this to move across sections if the ordering of sections are variable. The returned name
131      * can be used to decide what section is next.
132      *
133      * @param in         XmlPullParser instance pointing to the XML stream.
134      * @param headerName An array of one string, used to return the name of the next section.
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 parsing errors occur.
138      */
gotoNextSectionOrEnd( XmlPullParser in, String[] headerName, int outerDepth)139     public static boolean gotoNextSectionOrEnd(
140             XmlPullParser in, String[] headerName, int outerDepth)
141             throws XmlPullParserException, IOException {
142         if (XmlUtilHelper.nextElementWithin(in, outerDepth)) {
143             headerName[0] = in.getName();
144             return true;
145         }
146         return false;
147     }
148 
149     /**
150      * Move the XML stream to the next section header or indicate if there are no more sections.
151      * If a section, exists ensure that the name matches the provided name.
152      * The provided outerDepth is used to find sub sections within that depth.
153      *
154      * Use this to move across repeated sections until the end.
155      *
156      * @param in           XmlPullParser instance pointing to the XML stream.
157      * @param expectedName expected name for the section header.
158      * @param outerDepth   Find section within this depth.
159      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
160      * @throws XmlPullParserException if the section header name does not match |expectedName|,
161      *                                or if parsing errors occur.
162      */
gotoNextSectionWithNameOrEnd( XmlPullParser in, String expectedName, int outerDepth)163     public static boolean gotoNextSectionWithNameOrEnd(
164             XmlPullParser in, String expectedName, int outerDepth)
165             throws XmlPullParserException, IOException {
166         String[] headerName = new String[1];
167         if (gotoNextSectionOrEnd(in, headerName, outerDepth)) {
168             if (headerName[0].equals(expectedName)) {
169                 return true;
170             }
171             throw new XmlPullParserException(
172                     "Next section name does not match expected name: " + expectedName);
173         }
174         return false;
175     }
176 
177     /**
178      * Move the XML stream to the next section header and ensure that the name matches the provided
179      * name.
180      * The provided outerDepth is used to find sub sections within that depth.
181      *
182      * Use this to move across sections if the ordering of sections are fixed.
183      *
184      * @param in           XmlPullParser instance pointing to the XML stream.
185      * @param expectedName expected name for the section header.
186      * @param outerDepth   Find section within this depth.
187      * @throws XmlPullParserException if the section header name does not match |expectedName|,
188      *                                there are no more sections or if parsing errors occur.
189      */
gotoNextSectionWithName( XmlPullParser in, String expectedName, int outerDepth)190     public static void gotoNextSectionWithName(
191             XmlPullParser in, String expectedName, int outerDepth)
192             throws XmlPullParserException, IOException {
193         if (!gotoNextSectionWithNameOrEnd(in, expectedName, outerDepth)) {
194             throw new XmlPullParserException("Section not found. Expected: " + expectedName);
195         }
196     }
197 
198     /**
199      * Checks if the stream is at the end of a section of values. This moves the stream to next tag
200      * and checks if it finds an end tag at the specified depth.
201      *
202      * @param in           XmlPullParser instance pointing to the XML stream.
203      * @param sectionDepth depth of the start tag of this section. Used to match the end tag.
204      * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise
205      * @throws XmlPullParserException if parsing errors occur.
206      */
isNextSectionEnd(XmlPullParser in, int sectionDepth)207     public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth)
208             throws XmlPullParserException, IOException {
209         return !XmlUtilHelper.nextElementWithin(in, sectionDepth);
210     }
211 
212     /**
213      * Read the current value in the XML stream using core XmlUtils and stores the retrieved
214      * value name in the string provided. This method reads the value contained in current start
215      * tag.
216      * Note: Because there could be genuine null values being read from the XML, this method raises
217      * an exception to indicate errors.
218      *
219      * @param in        XmlPullParser instance pointing to the XML stream.
220      * @param valueName An array of one string, used to return the name attribute
221      *                  of the value's tag.
222      * @return value retrieved from the XML stream.
223      * @throws XmlPullParserException if parsing errors occur.
224      */
readCurrentValue(XmlPullParser in, String[] valueName)225     public static Object readCurrentValue(XmlPullParser in, String[] valueName)
226             throws XmlPullParserException, IOException {
227         Object value = XmlUtilHelper.readValueXml(in, valueName);
228         // XmlUtils.readValue does not always move the stream to the end of the tag. So, move
229         // it to the end tag before returning from here.
230         gotoEndTag(in);
231         return value;
232     }
233 
234     /**
235      * Read the next value in the XML stream using core XmlUtils and ensure that it matches the
236      * provided name. This method moves the stream to the next start tag and reads the value
237      * contained in it.
238      * Note: Because there could be genuine null values being read from the XML, this method raises
239      * an exception to indicate errors.
240      *
241      * @param in XmlPullParser instance pointing to the XML stream.
242      * @return value retrieved from the XML stream.
243      * @throws XmlPullParserException if the value read does not match |expectedName|,
244      *                                or if parsing errors occur.
245      */
readNextValueWithName(XmlPullParser in, String expectedName)246     public static Object readNextValueWithName(XmlPullParser in, String expectedName)
247             throws XmlPullParserException, IOException {
248         String[] valueName = new String[1];
249         XmlUtilHelper.nextElement(in);
250         Object value = readCurrentValue(in, valueName);
251         if (valueName[0].equals(expectedName)) {
252             return value;
253         }
254         throw new XmlPullParserException(
255                 "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]);
256     }
257 
258     /**
259      * Write the XML document start with the provided document header name.
260      *
261      * @param out        XmlSerializer instance pointing to the XML stream.
262      * @param headerName name for the start tag.
263      */
writeDocumentStart(XmlSerializer out, String headerName)264     public static void writeDocumentStart(XmlSerializer out, String headerName)
265             throws IOException {
266         out.startDocument(null, true);
267         out.startTag(null, headerName);
268     }
269 
270     /**
271      * Write the XML document end with the provided document header name.
272      *
273      * @param out        XmlSerializer instance pointing to the XML stream.
274      * @param headerName name for the end tag.
275      */
writeDocumentEnd(XmlSerializer out, String headerName)276     public static void writeDocumentEnd(XmlSerializer out, String headerName)
277             throws IOException {
278         out.endTag(null, headerName);
279         out.endDocument();
280     }
281 
282     /**
283      * Write a section start header tag with the provided section name.
284      *
285      * @param out        XmlSerializer instance pointing to the XML stream.
286      * @param headerName name for the start tag.
287      */
writeNextSectionStart(XmlSerializer out, String headerName)288     public static void writeNextSectionStart(XmlSerializer out, String headerName)
289             throws IOException {
290         out.startTag(null, headerName);
291     }
292 
293     /**
294      * Write a section end header tag with the provided section name.
295      *
296      * @param out        XmlSerializer instance pointing to the XML stream.
297      * @param headerName name for the end tag.
298      */
writeNextSectionEnd(XmlSerializer out, String headerName)299     public static void writeNextSectionEnd(XmlSerializer out, String headerName)
300             throws IOException {
301         out.endTag(null, headerName);
302     }
303 
304     /**
305      * Write the value with the provided name in the XML stream using core XmlUtils.
306      *
307      * @param out   XmlSerializer instance pointing to the XML stream.
308      * @param name  name of the value.
309      * @param value value to be written.
310      */
writeNextValue(XmlSerializer out, String name, Object value)311     public static void writeNextValue(XmlSerializer out, String name, Object value)
312             throws XmlPullParserException, IOException {
313         XmlUtilHelper.writeValueXml(value, name, out);
314     }
315 
316     /**
317      * Utility class to serialize and deserialize {@link WifiConfiguration} object to XML &
318      * vice versa.
319      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
320      * {@link com.android.server.wifi.WifiBackupRestore} modules.
321      * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store.
322      * There is only 1 version of |parseXmlToConfiguration| for both backup & config store.
323      * The parse method is written so that any element added/deleted in future revisions can
324      * be easily handled.
325      */
326     public static class WifiConfigurationXmlUtil {
327         /**
328          * List of XML tags corresponding to WifiConfiguration object elements.
329          */
330         public static final String XML_TAG_SSID = "SSID";
331         public static final String XML_TAG_BSSID = "BSSID";
332         public static final String XML_TAG_CONFIG_KEY = "ConfigKey";
333         public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
334         public static final String XML_TAG_WEP_KEYS = "WEPKeys";
335         public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex";
336         public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
337         public static final String XML_TAG_REQUIRE_PMF = "RequirePMF";
338         public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
339         public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols";
340         public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos";
341         public static final String XML_TAG_ALLOWED_GROUP_CIPHERS = "AllowedGroupCiphers";
342         public static final String XML_TAG_ALLOWED_PAIRWISE_CIPHERS = "AllowedPairwiseCiphers";
343         public static final String XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS = "AllowedGroupMgmtCiphers";
344         public static final String XML_TAG_ALLOWED_SUITE_B_CIPHERS = "AllowedSuiteBCiphers";
345         public static final String XML_TAG_SHARED = "Shared";
346         public static final String XML_TAG_STATUS = "Status";
347         public static final String XML_TAG_FQDN = "FQDN";
348         public static final String XML_TAG_PROVIDER_FRIENDLY_NAME = "ProviderFriendlyName";
349         public static final String XML_TAG_LINKED_NETWORKS_LIST = "LinkedNetworksList";
350         public static final String XML_TAG_DEFAULT_GW_MAC_ADDRESS = "DefaultGwMacAddress";
351         public static final String XML_TAG_VALIDATED_INTERNET_ACCESS = "ValidatedInternetAccess";
352         public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected";
353         public static final String XML_TAG_METERED_HINT = "MeteredHint";
354         public static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride";
355         public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores";
356         public static final String XML_TAG_CREATOR_UID = "CreatorUid";
357         public static final String XML_TAG_CREATOR_NAME = "CreatorName";
358         public static final String XML_TAG_LAST_UPDATE_UID = "LastUpdateUid";
359         public static final String XML_TAG_LAST_UPDATE_NAME = "LastUpdateName";
360         public static final String XML_TAG_LAST_CONNECT_UID = "LastConnectUid";
361         public static final String XML_TAG_IS_LEGACY_PASSPOINT_CONFIG = "IsLegacyPasspointConfig";
362         public static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs";
363         public static final String XML_TAG_RANDOMIZED_MAC_ADDRESS = "RandomizedMacAddress";
364         public static final String XML_TAG_MAC_RANDOMIZATION_SETTING = "MacRandomizationSetting";
365         public static final String XML_TAG_CARRIER_ID = "CarrierId";
366         public static final String XML_TAG_SUBSCRIPTION_ID = "SubscriptionId";
367         public static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled";
368         public static final String XML_TAG_DELETION_PRIORITY = "DeletionPriority";
369         public static final String XML_TAG_NUM_REBOOTS_SINCE_LAST_USE = "NumRebootsSinceLastUse";
370 
371         public static final String XML_TAG_IS_TRUSTED = "Trusted";
372         public static final String XML_TAG_IS_OEM_PAID = "OemPaid";
373         public static final String XML_TAG_IS_OEM_PRIVATE = "OemPrivate";
374         public static final String XML_TAG_IS_CARRIER_MERGED = "CarrierMerged";
375         public static final String XML_TAG_SECURITY_PARAMS_LIST = "SecurityParamsList";
376         public static final String XML_TAG_SECURITY_PARAMS = "SecurityParams";
377         public static final String XML_TAG_SECURITY_TYPE = "SecurityType";
378         public static final String XML_TAG_SAE_IS_H2E_ONLY_MODE = "SaeIsH2eOnlyMode";
379         public static final String XML_TAG_SAE_IS_PK_ONLY_MODE = "SaeIsPkOnlyMode";
380         public static final String XML_TAG_IS_ADDED_BY_AUTO_UPGRADE = "IsAddedByAutoUpgrade";
381         private static final String XML_TAG_IS_MOST_RECENTLY_CONNECTED = "IsMostRecentlyConnected";
382         private static final String XML_TAG_IS_RESTRICTED = "IsRestricted";
383         private static final String XML_TAG_SUBSCRIPTION_GROUP = "SubscriptionGroup";
384         public static final String XML_TAG_BSSID_ALLOW_LIST = "bssidAllowList";
385         private static final String XML_TAG_IS_REPEATER_ENABLED = "RepeaterEnabled";
386         public static final String XML_TAG_DPP_PRIVATE_EC_KEY = "DppPrivateEcKey";
387         public static final String XML_TAG_DPP_CONNECTOR = "DppConnector";
388         public static final String XML_TAG_DPP_CSIGN_KEY = "DppCSignKey";
389         public static final String XML_TAG_DPP_NET_ACCESS_KEY = "DppNetAccessKey";
390 
391         /**
392          * Write WepKeys to the XML stream.
393          * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements
394          * are set to null. User may chose to set any one of the key elements in WifiConfiguration.
395          * XmlUtils serialization doesn't handle this array of nulls well .
396          * So, write empty strings if some of the keys are not initialized and null if all of
397          * the elements are empty.
398          */
writeWepKeysToXml(XmlSerializer out, String[] wepKeys)399         private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys)
400                 throws XmlPullParserException, IOException {
401             String[] wepKeysToWrite = new String[wepKeys.length];
402             boolean hasWepKey = false;
403             for (int i = 0; i < wepKeys.length; i++) {
404                 if (wepKeys[i] == null) {
405                     wepKeysToWrite[i] = new String();
406                 } else {
407                     wepKeysToWrite[i] = wepKeys[i];
408                     hasWepKey = true;
409                 }
410             }
411             if (hasWepKey) {
412                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite);
413             } else {
414                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null);
415             }
416         }
417 
418         /**
419          * Write preshared key to the XML stream.
420          *
421          * If encryptionUtil is null or if encryption fails for some reason, the pre-shared
422          * key is stored in plaintext, else the encrypted psk is stored.
423          */
writePreSharedKeyToXml( XmlSerializer out, String preSharedKey, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)424         private static void writePreSharedKeyToXml(
425                 XmlSerializer out, String preSharedKey,
426                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
427                 throws XmlPullParserException, IOException {
428             EncryptedData encryptedData = null;
429             if (encryptionUtil != null) {
430                 if (preSharedKey != null) {
431                     encryptedData = encryptionUtil.encrypt(preSharedKey.getBytes());
432                     if (encryptedData == null) {
433                         // We silently fail encryption failures!
434                         Log.wtf(TAG, "Encryption of preSharedKey failed");
435                     }
436                 }
437             }
438             if (encryptedData != null) {
439                 XmlUtil.writeNextSectionStart(out, XML_TAG_PRE_SHARED_KEY);
440                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
441                 XmlUtil.writeNextSectionEnd(out, XML_TAG_PRE_SHARED_KEY);
442             } else {
443                 XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, preSharedKey);
444             }
445         }
446 
writeSecurityParamsListToXml( XmlSerializer out, WifiConfiguration configuration)447         private static void writeSecurityParamsListToXml(
448                 XmlSerializer out, WifiConfiguration configuration)
449                 throws XmlPullParserException, IOException {
450             XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS_LIST);
451             for (SecurityParams params: configuration.getSecurityParamsList()) {
452                 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS);
453                 XmlUtil.writeNextValue(
454                         out, XML_TAG_SECURITY_TYPE,
455                         params.getSecurityType());
456                 XmlUtil.writeNextValue(
457                         out, XML_TAG_SAE_IS_H2E_ONLY_MODE,
458                         params.isSaeH2eOnlyMode());
459                 XmlUtil.writeNextValue(
460                         out, XML_TAG_SAE_IS_PK_ONLY_MODE,
461                         params.isSaePkOnlyMode());
462                 XmlUtil.writeNextValue(
463                         out, XML_TAG_IS_ADDED_BY_AUTO_UPGRADE,
464                         params.isAddedByAutoUpgrade());
465                 XmlUtil.writeNextValue(
466                         out, XML_TAG_ALLOWED_SUITE_B_CIPHERS,
467                         params.getAllowedSuiteBCiphers().toByteArray());
468                 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS);
469             }
470 
471             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS_LIST);
472         }
473 
writeEncryptedBytesToXml( XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, String tag, byte[] data)474         private static void writeEncryptedBytesToXml(
475                 XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil,
476                 String tag, byte[] data)
477                 throws XmlPullParserException, IOException {
478             EncryptedData encryptedData = null;
479             if (encryptionUtil != null) {
480                 encryptedData = encryptionUtil.encrypt(data);
481                 if (encryptedData == null) {
482                     // We silently fail encryption failures!
483                     Log.wtf(TAG, "Encryption of " + tag + " failed");
484                 }
485             }
486             if (encryptedData != null) {
487                 XmlUtil.writeNextSectionStart(out, tag);
488                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
489                 XmlUtil.writeNextSectionEnd(out, tag);
490             } else {
491                 XmlUtil.writeNextValue(out, tag, data);
492             }
493         }
494 
495         /**
496          * Write dpp configuration and connection keys to the XML stream.
497          *
498          * If encryptionUtil is null or if encryption fails for some reason, the dpp
499          * keys are stored in plaintext, else the encrypted keys are stored.
500          */
writeDppConfigurationToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)501         private static void writeDppConfigurationToXml(
502                 XmlSerializer out, WifiConfiguration configuration,
503                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
504                 throws XmlPullParserException, IOException {
505             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_PRIVATE_EC_KEY,
506                     configuration.getDppPrivateEcKey());
507             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_CONNECTOR,
508                     configuration.getDppConnector());
509             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_CSIGN_KEY,
510                     configuration.getDppCSignKey());
511             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_NET_ACCESS_KEY,
512                     configuration.getDppNetAccessKey());
513         }
514 
515         /**
516          * Write the Configuration data elements that are common for backup & config store to the
517          * XML stream.
518          *
519          * @param out XmlSerializer instance pointing to the XML stream.
520          * @param configuration WifiConfiguration object to be serialized.
521          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. Backup/restore stores
522          *                       keys unencrypted.
523          */
writeCommonElementsToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)524         public static void writeCommonElementsToXml(
525                 XmlSerializer out, WifiConfiguration configuration,
526                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
527                 throws XmlPullParserException, IOException {
528             XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.getKey());
529             XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID);
530             writePreSharedKeyToXml(out, configuration.preSharedKey, encryptionUtil);
531             writeWepKeysToXml(out, configuration.wepKeys);
532             XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex);
533             XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID);
534             XmlUtil.writeNextValue(out, XML_TAG_REQUIRE_PMF, configuration.requirePmf);
535             XmlUtil.writeNextValue(
536                     out, XML_TAG_ALLOWED_KEY_MGMT,
537                     configuration.allowedKeyManagement.toByteArray());
538             XmlUtil.writeNextValue(
539                     out, XML_TAG_ALLOWED_PROTOCOLS,
540                     configuration.allowedProtocols.toByteArray());
541             XmlUtil.writeNextValue(
542                     out, XML_TAG_ALLOWED_AUTH_ALGOS,
543                     configuration.allowedAuthAlgorithms.toByteArray());
544             XmlUtil.writeNextValue(
545                     out, XML_TAG_ALLOWED_GROUP_CIPHERS,
546                     configuration.allowedGroupCiphers.toByteArray());
547             XmlUtil.writeNextValue(
548                     out, XML_TAG_ALLOWED_PAIRWISE_CIPHERS,
549                     configuration.allowedPairwiseCiphers.toByteArray());
550             XmlUtil.writeNextValue(
551                     out, XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS,
552                     configuration.allowedGroupManagementCiphers.toByteArray());
553             XmlUtil.writeNextValue(
554                     out, XML_TAG_ALLOWED_SUITE_B_CIPHERS,
555                     configuration.allowedSuiteBCiphers.toByteArray());
556             XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared);
557             XmlUtil.writeNextValue(out, XML_TAG_IS_AUTO_JOIN, configuration.allowAutojoin);
558             XmlUtil.writeNextValue(
559                     out, XML_TAG_DELETION_PRIORITY,
560                     configuration.getDeletionPriority());
561             XmlUtil.writeNextValue(
562                     out, XML_TAG_NUM_REBOOTS_SINCE_LAST_USE,
563                     configuration.numRebootsSinceLastUse);
564             XmlUtil.writeNextValue(out, XML_TAG_IS_REPEATER_ENABLED,
565                     configuration.isRepeaterEnabled());
566             writeSecurityParamsListToXml(out, configuration);
567         }
568 
569         /**
570          * Write the Configuration data elements for backup from the provided Configuration to the
571          * XML stream.
572          * Note: This is a subset of the elements serialized for config store.
573          *
574          * @param out           XmlSerializer instance pointing to the XML stream.
575          * @param configuration WifiConfiguration object to be serialized.
576          */
writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)577         public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)
578                 throws XmlPullParserException, IOException {
579             writeCommonElementsToXml(out, configuration, null);
580             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
581         }
582 
583         /**
584          * Write the Configuration data elements for config store from the provided Configuration
585          * to the XML stream.
586          *
587          * @param out XmlSerializer instance pointing to the XML stream.
588          * @param configuration WifiConfiguration object to be serialized.
589          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
590          */
writeToXmlForConfigStore( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)591         public static void writeToXmlForConfigStore(
592                 XmlSerializer out, WifiConfiguration configuration,
593                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
594                 throws XmlPullParserException, IOException {
595             writeCommonElementsToXml(out, configuration, encryptionUtil);
596             XmlUtil.writeNextValue(out, XML_TAG_IS_TRUSTED, configuration.trusted);
597             XmlUtil.writeNextValue(out, XML_TAG_IS_RESTRICTED, configuration.restricted);
598             XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PAID, configuration.oemPaid);
599             XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PRIVATE, configuration.oemPrivate);
600             XmlUtil.writeNextValue(out, XML_TAG_IS_CARRIER_MERGED,
601                     configuration.carrierMerged);
602             XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID);
603             XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status);
604             XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN);
605             XmlUtil.writeNextValue(
606                     out, XML_TAG_PROVIDER_FRIENDLY_NAME, configuration.providerFriendlyName);
607             XmlUtil.writeNextValue(
608                     out, XML_TAG_LINKED_NETWORKS_LIST, configuration.linkedConfigurations);
609             XmlUtil.writeNextValue(
610                     out, XML_TAG_DEFAULT_GW_MAC_ADDRESS, configuration.defaultGwMacAddress);
611             XmlUtil.writeNextValue(
612                     out, XML_TAG_VALIDATED_INTERNET_ACCESS, configuration.validatedInternetAccess);
613             XmlUtil.writeNextValue(
614                     out, XML_TAG_NO_INTERNET_ACCESS_EXPECTED,
615                     configuration.noInternetAccessExpected);
616             XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint);
617             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
618             XmlUtil.writeNextValue(
619                     out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores);
620             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid);
621             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_NAME, configuration.creatorName);
622             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_UID, configuration.lastUpdateUid);
623             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_NAME, configuration.lastUpdateName);
624             XmlUtil.writeNextValue(out, XML_TAG_LAST_CONNECT_UID, configuration.lastConnectUid);
625             XmlUtil.writeNextValue(
626                     out, XML_TAG_IS_LEGACY_PASSPOINT_CONFIG,
627                     configuration.isLegacyPasspointConfig);
628             XmlUtil.writeNextValue(
629                     out, XML_TAG_ROAMING_CONSORTIUM_OIS, configuration.roamingConsortiumIds);
630             XmlUtil.writeNextValue(out, XML_TAG_RANDOMIZED_MAC_ADDRESS,
631                     configuration.getRandomizedMacAddress().toString());
632             XmlUtil.writeNextValue(out, XML_TAG_MAC_RANDOMIZATION_SETTING,
633                     configuration.macRandomizationSetting);
634             XmlUtil.writeNextValue(out, XML_TAG_CARRIER_ID, configuration.carrierId);
635             XmlUtil.writeNextValue(out, XML_TAG_IS_MOST_RECENTLY_CONNECTED,
636                     configuration.isMostRecentlyConnected);
637             XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_ID, configuration.subscriptionId);
638             if (configuration.getSubscriptionGroup() != null) {
639                 XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_GROUP,
640                         configuration.getSubscriptionGroup().toString());
641             }
642             if (configuration.getBssidAllowlistInternal() != null) {
643                 XmlUtil.writeNextValue(out, XML_TAG_BSSID_ALLOW_LIST,
644                         covertMacAddressListToStringList(configuration
645                                 .getBssidAllowlistInternal()));
646             }
647             writeDppConfigurationToXml(out, configuration, encryptionUtil);
648         }
649 
covertMacAddressListToStringList(List<MacAddress> macList)650         private static List<String> covertMacAddressListToStringList(List<MacAddress> macList) {
651             List<String> bssidList = new ArrayList<>();
652             for (MacAddress address : macList) {
653                 bssidList.add(address.toString());
654             }
655             return bssidList;
656         }
657 
covertStringListToMacAddressList(List<String> stringList)658         private static List<MacAddress> covertStringListToMacAddressList(List<String> stringList) {
659             List<MacAddress> macAddressList = new ArrayList<>();
660             for (String address : stringList) {
661                 try {
662                     macAddressList.add(MacAddress.fromString(address));
663                 } catch (Exception e) {
664                     Log.e(TAG, "Invalid BSSID String: " + address);
665                 }
666             }
667             return macAddressList;
668         }
669 
670         /**
671          * Populate wepKeys array elements only if they were non-empty in the backup data.
672          *
673          * @throws XmlPullParserException if parsing errors occur.
674          */
populateWepKeysFromXmlValue(Object value, String[] wepKeys)675         private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys)
676                 throws XmlPullParserException, IOException {
677             String[] wepKeysInData = (String[]) value;
678             if (wepKeysInData == null) {
679                 return;
680             }
681             if (wepKeysInData.length != wepKeys.length) {
682                 throw new XmlPullParserException(
683                         "Invalid Wep Keys length: " + wepKeysInData.length);
684             }
685             for (int i = 0; i < wepKeys.length; i++) {
686                 if (wepKeysInData[i].isEmpty()) {
687                     wepKeys[i] = null;
688                 } else {
689                     wepKeys[i] = wepKeysInData[i];
690                 }
691             }
692         }
693 
parseSecurityParamsFromXml( XmlPullParser in, int outerTagDepth)694         private static SecurityParams parseSecurityParamsFromXml(
695                 XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException {
696             SecurityParams params = null;
697             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
698                 String[] valueName = new String[1];
699                 Object value = XmlUtil.readCurrentValue(in, valueName);
700                 String tagName = valueName[0];
701                 if (tagName == null) {
702                     throw new XmlPullParserException("Missing value name");
703                 }
704                 switch (tagName) {
705                     case WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE:
706                         params = SecurityParams.createSecurityParamsBySecurityType((int) value);
707                         break;
708                     case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_H2E_ONLY_MODE:
709                         if (null == params) {
710                             throw new XmlPullParserException("Missing security type.");
711                         }
712                         params.enableSaeH2eOnlyMode((boolean) value);
713                         break;
714                     case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_PK_ONLY_MODE:
715                         if (null == params) {
716                             throw new XmlPullParserException("Missing security type.");
717                         }
718                         params.enableSaePkOnlyMode((boolean) value);
719                         break;
720                     case WifiConfigurationXmlUtil.XML_TAG_IS_ADDED_BY_AUTO_UPGRADE:
721                         if (null == params) {
722                             throw new XmlPullParserException("Missing security type.");
723                         }
724                         params.setIsAddedByAutoUpgrade((boolean) value);
725                         break;
726                     case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_SUITE_B_CIPHERS:
727                         if (null == params) {
728                             throw new XmlPullParserException("Missing security type.");
729                         }
730                         byte[] suiteBCiphers = (byte[]) value;
731                         BitSet suiteBCiphersBitSet = BitSet.valueOf(suiteBCiphers);
732                         params.enableSuiteBCiphers(
733                                 suiteBCiphersBitSet.get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA),
734                                 suiteBCiphersBitSet.get(WifiConfiguration.SuiteBCipher.ECDHE_RSA));
735                         break;
736                 }
737             }
738             return params;
739         }
740 
readEncrytepdBytesFromXml( @ullable WifiConfigStoreEncryptionUtil encryptionUtil, XmlPullParser in, int outerTagDepth)741         private static byte[] readEncrytepdBytesFromXml(
742                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil,
743                 XmlPullParser in, int outerTagDepth)
744                 throws XmlPullParserException, IOException {
745             if (encryptionUtil == null) {
746                 throw new XmlPullParserException(
747                         "Encrypted preSharedKey section not expected");
748             }
749             EncryptedData encryptedData =
750                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
751             return encryptionUtil.decrypt(encryptedData);
752         }
753 
parseSecurityParamsListFromXml( XmlPullParser in, int outerTagDepth, WifiConfiguration configuration)754         private static void parseSecurityParamsListFromXml(
755                 XmlPullParser in, int outerTagDepth,
756                 WifiConfiguration configuration)
757                 throws XmlPullParserException, IOException {
758             List<SecurityParams> paramsList = new ArrayList<>();
759             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
760                 switch (in.getName()) {
761                     case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS:
762                         SecurityParams params = parseSecurityParamsFromXml(in, outerTagDepth + 1);
763                         if (params != null) {
764                             paramsList.add(params);
765                         }
766                         break;
767                 }
768             }
769             if (!paramsList.isEmpty()) {
770                 configuration.setSecurityParams(paramsList);
771             }
772         }
773 
774         /**
775          * Parses the configuration data elements from the provided XML stream to a
776          * WifiConfiguration object.
777          * Note: This is used for parsing both backup data and config store data. Looping through
778          * the tags make it easy to add or remove elements in the future versions if needed.
779          *
780          * @param in XmlPullParser instance pointing to the XML stream.
781          * @param outerTagDepth depth of the outer tag in the XML document.
782          * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not.
783          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
784          * @param fromSuggestion Is this WifiConfiguration created from a WifiNetworkSuggestion.
785          * @return Pair<Config key, WifiConfiguration object> if parsing is successful,
786          * null otherwise.
787          */
parseFromXml( XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)788         public static Pair<String, WifiConfiguration> parseFromXml(
789                 XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials,
790                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)
791                 throws XmlPullParserException, IOException {
792             WifiConfiguration configuration = new WifiConfiguration();
793             String configKeyInData = null;
794             boolean macRandomizationSettingExists = false;
795             byte[] dppConnector = null;
796             byte[] dppCSign = null;
797             byte[] dppNetAccessKey = null;
798 
799             // Loop through and parse out all the elements from the stream within this section.
800             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
801                 if (in.getAttributeValue(null, "name") != null) {
802                     // Value elements.
803                     String[] valueName = new String[1];
804                     Object value = XmlUtil.readCurrentValue(in, valueName);
805                     if (valueName[0] == null) {
806                         throw new XmlPullParserException("Missing value name");
807                     }
808                     switch (valueName[0]) {
809                         case XML_TAG_CONFIG_KEY:
810                             configKeyInData = (String) value;
811                             break;
812                         case XML_TAG_SSID:
813                             configuration.SSID = (String) value;
814                             break;
815                         case XML_TAG_BSSID:
816                             configuration.BSSID = (String) value;
817                             break;
818                         case XML_TAG_PRE_SHARED_KEY:
819                             configuration.preSharedKey = (String) value;
820                             break;
821                         case XML_TAG_WEP_KEYS:
822                             populateWepKeysFromXmlValue(value, configuration.wepKeys);
823                             break;
824                         case XML_TAG_WEP_TX_KEY_INDEX:
825                             configuration.wepTxKeyIndex = (int) value;
826                             break;
827                         case XML_TAG_HIDDEN_SSID:
828                             configuration.hiddenSSID = (boolean) value;
829                             break;
830                         case XML_TAG_REQUIRE_PMF:
831                             configuration.requirePmf = (boolean) value;
832                             break;
833                         case XML_TAG_ALLOWED_KEY_MGMT:
834                             byte[] allowedKeyMgmt = (byte[]) value;
835                             configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
836                             break;
837                         case XML_TAG_ALLOWED_PROTOCOLS:
838                             byte[] allowedProtocols = (byte[]) value;
839                             configuration.allowedProtocols = BitSet.valueOf(allowedProtocols);
840                             break;
841                         case XML_TAG_ALLOWED_AUTH_ALGOS:
842                             byte[] allowedAuthAlgorithms = (byte[]) value;
843                             configuration.allowedAuthAlgorithms = BitSet.valueOf(
844                                     allowedAuthAlgorithms);
845                             break;
846                         case XML_TAG_ALLOWED_GROUP_CIPHERS:
847                             byte[] allowedGroupCiphers = (byte[]) value;
848                             configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers);
849                             break;
850                         case XML_TAG_ALLOWED_PAIRWISE_CIPHERS:
851                             byte[] allowedPairwiseCiphers = (byte[]) value;
852                             configuration.allowedPairwiseCiphers =
853                                     BitSet.valueOf(allowedPairwiseCiphers);
854                             break;
855                         case XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS:
856                             byte[] allowedGroupMgmtCiphers = (byte[]) value;
857                             configuration.allowedGroupManagementCiphers =
858                                     BitSet.valueOf(allowedGroupMgmtCiphers);
859                             break;
860                         case XML_TAG_ALLOWED_SUITE_B_CIPHERS:
861                             byte[] allowedSuiteBCiphers = (byte[]) value;
862                             configuration.allowedSuiteBCiphers =
863                                     BitSet.valueOf(allowedSuiteBCiphers);
864                             break;
865                         case XML_TAG_SHARED:
866                             configuration.shared = (boolean) value;
867                             break;
868                         case XML_TAG_STATUS:
869                             int status = (int) value;
870                             // Any network which was CURRENT before reboot needs
871                             // to be restored to ENABLED.
872                             if (status == WifiConfiguration.Status.CURRENT) {
873                                 status = WifiConfiguration.Status.ENABLED;
874                             }
875                             configuration.status = status;
876                             break;
877                         case XML_TAG_FQDN:
878                             configuration.FQDN = (String) value;
879                             break;
880                         case XML_TAG_PROVIDER_FRIENDLY_NAME:
881                             configuration.providerFriendlyName = (String) value;
882                             break;
883                         case XML_TAG_LINKED_NETWORKS_LIST:
884                             configuration.linkedConfigurations = (HashMap<String, Integer>) value;
885                             break;
886                         case XML_TAG_DEFAULT_GW_MAC_ADDRESS:
887                             configuration.defaultGwMacAddress = (String) value;
888                             break;
889                         case XML_TAG_VALIDATED_INTERNET_ACCESS:
890                             configuration.validatedInternetAccess = (boolean) value;
891                             break;
892                         case XML_TAG_NO_INTERNET_ACCESS_EXPECTED:
893                             configuration.noInternetAccessExpected = (boolean) value;
894                             break;
895                         case XML_TAG_METERED_HINT:
896                             configuration.meteredHint = (boolean) value;
897                             break;
898                         case XML_TAG_METERED_OVERRIDE:
899                             configuration.meteredOverride = (int) value;
900                             break;
901                         case XML_TAG_USE_EXTERNAL_SCORES:
902                             configuration.useExternalScores = (boolean) value;
903                             break;
904                         case XML_TAG_CREATOR_UID:
905                             configuration.creatorUid = (int) value;
906                             break;
907                         case XML_TAG_CREATOR_NAME:
908                             configuration.creatorName = (String) value;
909                             break;
910                         case XML_TAG_LAST_UPDATE_UID:
911                             configuration.lastUpdateUid = (int) value;
912                             break;
913                         case XML_TAG_LAST_UPDATE_NAME:
914                             configuration.lastUpdateName = (String) value;
915                             break;
916                         case XML_TAG_LAST_CONNECT_UID:
917                             configuration.lastConnectUid = (int) value;
918                             break;
919                         case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG:
920                             configuration.isLegacyPasspointConfig = (boolean) value;
921                             break;
922                         case XML_TAG_ROAMING_CONSORTIUM_OIS:
923                             configuration.roamingConsortiumIds = (long[]) value;
924                             break;
925                         case XML_TAG_RANDOMIZED_MAC_ADDRESS:
926                             configuration.setRandomizedMacAddress(
927                                     MacAddress.fromString((String) value));
928                             break;
929                         case XML_TAG_MAC_RANDOMIZATION_SETTING:
930                             configuration.macRandomizationSetting = (int) value;
931                             macRandomizationSettingExists = true;
932                             break;
933                         case XML_TAG_CARRIER_ID:
934                             configuration.carrierId = (int) value;
935                             break;
936                         case XML_TAG_SUBSCRIPTION_ID:
937                             configuration.subscriptionId = (int) value;
938                             break;
939                         case XML_TAG_IS_AUTO_JOIN:
940                             configuration.allowAutojoin = (boolean) value;
941                             break;
942                         case XML_TAG_DELETION_PRIORITY:
943                             configuration.setDeletionPriority((int) value);
944                             break;
945                         case XML_TAG_NUM_REBOOTS_SINCE_LAST_USE:
946                             configuration.numRebootsSinceLastUse = (int) value;
947                             break;
948                         case XML_TAG_IS_TRUSTED:
949                             configuration.trusted = (boolean) value;
950                             break;
951                         case XML_TAG_IS_OEM_PAID:
952                             configuration.oemPaid = (boolean) value;
953                             break;
954                         case XML_TAG_IS_OEM_PRIVATE:
955                             configuration.oemPrivate = (boolean) value;
956                             break;
957                         case XML_TAG_IS_MOST_RECENTLY_CONNECTED:
958                             configuration.isMostRecentlyConnected = (boolean) value;
959                             break;
960                         case XML_TAG_IS_CARRIER_MERGED:
961                             configuration.carrierMerged = (boolean) value;
962                             break;
963                         case XML_TAG_IS_RESTRICTED:
964                             configuration.restricted = (boolean) value;
965                             break;
966                         case XML_TAG_SUBSCRIPTION_GROUP:
967                             configuration.setSubscriptionGroup(
968                                     ParcelUuid.fromString((String) value));
969                             break;
970                         case XML_TAG_BSSID_ALLOW_LIST:
971                             configuration.setBssidAllowlist(
972                                     covertStringListToMacAddressList((List<String>) value));
973                             break;
974                         case XML_TAG_IS_REPEATER_ENABLED:
975                             configuration.setRepeaterEnabled((boolean) value);
976                             break;
977                         case XML_TAG_DPP_PRIVATE_EC_KEY:
978                             configuration.setDppConfigurator((byte[]) value);
979                             break;
980                         case XML_TAG_DPP_CONNECTOR:
981                             dppConnector = (byte[]) value;
982                             break;
983                         case XML_TAG_DPP_CSIGN_KEY:
984                             dppCSign = (byte[]) value;
985                             break;
986                         case XML_TAG_DPP_NET_ACCESS_KEY:
987                             dppNetAccessKey = (byte[]) value;
988                             break;
989                         default:
990                             Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
991                             break;
992                     }
993                 } else {
994                     String tagName = in.getName();
995                     if (tagName == null) {
996                         throw new XmlPullParserException("Unexpected null tag found");
997                     }
998                     switch (tagName) {
999                         case XML_TAG_PRE_SHARED_KEY:
1000                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
1001                                 throw new XmlPullParserException(
1002                                         "Encrypted preSharedKey section not expected");
1003                             }
1004                             EncryptedData encryptedData =
1005                                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
1006                             byte[] preSharedKeyBytes = encryptionUtil.decrypt(encryptedData);
1007                             if (preSharedKeyBytes == null) {
1008                                 Log.wtf(TAG, "Decryption of preSharedKey failed");
1009                             } else {
1010                                 configuration.preSharedKey = new String(preSharedKeyBytes);
1011                             }
1012                             break;
1013                         case XML_TAG_SECURITY_PARAMS_LIST:
1014                             parseSecurityParamsListFromXml(in, outerTagDepth + 1, configuration);
1015                             break;
1016                         case XML_TAG_DPP_PRIVATE_EC_KEY:
1017                             configuration.setDppConfigurator(readEncrytepdBytesFromXml(
1018                                     encryptionUtil, in, outerTagDepth));
1019                             break;
1020                         case XML_TAG_DPP_CONNECTOR:
1021                             dppConnector = readEncrytepdBytesFromXml(encryptionUtil, in,
1022                                     outerTagDepth);
1023                             break;
1024                         case XML_TAG_DPP_CSIGN_KEY:
1025                             dppCSign = readEncrytepdBytesFromXml(encryptionUtil, in,
1026                                     outerTagDepth);
1027                             break;
1028                         case XML_TAG_DPP_NET_ACCESS_KEY:
1029                             dppNetAccessKey = readEncrytepdBytesFromXml(encryptionUtil, in,
1030                                     outerTagDepth);
1031                             break;
1032                         default:
1033                             Log.w(TAG, "Ignoring unknown tag found: " + tagName);
1034                             break;
1035                     }
1036                 }
1037             }
1038             if (!macRandomizationSettingExists) {
1039                 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
1040             }
1041             if (configuration.macRandomizationSetting
1042                     == WifiConfiguration.RANDOMIZATION_PERSISTENT && !fromSuggestion) {
1043                 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
1044             }
1045             configuration.convertLegacyFieldsToSecurityParamsIfNeeded();
1046             configuration.setDppConnectionKeys(dppConnector, dppCSign, dppNetAccessKey);
1047             return Pair.create(configKeyInData, configuration);
1048         }
1049     }
1050 
1051     /**
1052      * Utility class to serialize and deseriaize {@link IpConfiguration} object to XML & vice versa.
1053      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
1054      * {@link com.android.server.wifi.WifiBackupRestore} modules.
1055      */
1056     public static class IpConfigurationXmlUtil {
1057 
1058         /**
1059          * List of XML tags corresponding to IpConfiguration object elements.
1060          */
1061         public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment";
1062         public static final String XML_TAG_LINK_ADDRESS = "LinkAddress";
1063         public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength";
1064         public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress";
1065         public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers";
1066         public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings";
1067         public static final String XML_TAG_PROXY_HOST = "ProxyHost";
1068         public static final String XML_TAG_PROXY_PORT = "ProxyPort";
1069         public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac";
1070         public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList";
1071 
parseProxyExclusionListString( @ullable String exclusionListString)1072         private static List<String> parseProxyExclusionListString(
1073                 @Nullable String exclusionListString) {
1074             if (exclusionListString == null) {
1075                 return Collections.emptyList();
1076             } else {
1077                 return Arrays.asList(exclusionListString.toLowerCase(Locale.ROOT).split(","));
1078             }
1079         }
1080 
generateProxyExclusionListString(@onNull String[] exclusionList)1081         private static String generateProxyExclusionListString(@NonNull String[] exclusionList) {
1082             return TextUtils.join(",", exclusionList);
1083         }
1084 
1085         /**
1086          * Write the static IP configuration data elements to XML stream.
1087          */
writeStaticIpConfigurationToXml( XmlSerializer out, StaticIpConfiguration staticIpConfiguration)1088         private static void writeStaticIpConfigurationToXml(
1089                 XmlSerializer out, StaticIpConfiguration staticIpConfiguration)
1090                 throws XmlPullParserException, IOException {
1091             if (staticIpConfiguration.getIpAddress() != null) {
1092                 XmlUtil.writeNextValue(
1093                         out, XML_TAG_LINK_ADDRESS,
1094                         staticIpConfiguration.getIpAddress().getAddress().getHostAddress());
1095                 XmlUtil.writeNextValue(
1096                         out, XML_TAG_LINK_PREFIX_LENGTH,
1097                         staticIpConfiguration.getIpAddress().getPrefixLength());
1098             } else {
1099                 XmlUtil.writeNextValue(
1100                         out, XML_TAG_LINK_ADDRESS, null);
1101                 XmlUtil.writeNextValue(
1102                         out, XML_TAG_LINK_PREFIX_LENGTH, null);
1103             }
1104             if (staticIpConfiguration.getGateway() != null) {
1105                 XmlUtil.writeNextValue(
1106                         out, XML_TAG_GATEWAY_ADDRESS,
1107                         staticIpConfiguration.getGateway().getHostAddress());
1108             } else {
1109                 XmlUtil.writeNextValue(
1110                         out, XML_TAG_GATEWAY_ADDRESS, null);
1111 
1112             }
1113             // Create a string array of DNS server addresses
1114             String[] dnsServers = new String[staticIpConfiguration.getDnsServers().size()];
1115             int dnsServerIdx = 0;
1116             for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
1117                 dnsServers[dnsServerIdx++] = inetAddr.getHostAddress();
1118             }
1119             XmlUtil.writeNextValue(
1120                     out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers);
1121         }
1122 
1123         /**
1124          * Write the IP configuration data elements from the provided Configuration to the XML
1125          * stream.
1126          *
1127          * @param out             XmlSerializer instance pointing to the XML stream.
1128          * @param ipConfiguration IpConfiguration object to be serialized.
1129          */
writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)1130         public static void writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)
1131                 throws XmlPullParserException, IOException {
1132             // Write IP assignment settings
1133             XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT,
1134                     ipConfiguration.getIpAssignment().toString());
1135             switch (ipConfiguration.getIpAssignment()) {
1136                 case STATIC:
1137                     writeStaticIpConfigurationToXml(
1138                             out, ipConfiguration.getStaticIpConfiguration());
1139                     break;
1140                 case DHCP:
1141                 case UNASSIGNED:
1142                     break;
1143                 default:
1144                     Log.w(TAG, "Ignoring unknown ip assignment type: "
1145                             + ipConfiguration.getIpAssignment());
1146                     break;
1147             }
1148 
1149             // Write proxy settings
1150             XmlUtil.writeNextValue(
1151                     out, XML_TAG_PROXY_SETTINGS,
1152                     ipConfiguration.getProxySettings().toString());
1153             switch (ipConfiguration.getProxySettings()) {
1154                 case STATIC:
1155                     XmlUtil.writeNextValue(
1156                             out, XML_TAG_PROXY_HOST,
1157                             ipConfiguration.getHttpProxy().getHost());
1158                     XmlUtil.writeNextValue(
1159                             out, XML_TAG_PROXY_PORT,
1160                             ipConfiguration.getHttpProxy().getPort());
1161                     XmlUtil.writeNextValue(
1162                             out, XML_TAG_PROXY_EXCLUSION_LIST,
1163                             generateProxyExclusionListString(
1164                                     ipConfiguration.getHttpProxy().getExclusionList()));
1165                     break;
1166                 case PAC:
1167                     XmlUtil.writeNextValue(
1168                             out, XML_TAG_PROXY_PAC_FILE,
1169                             ipConfiguration.getHttpProxy().getPacFileUrl().toString());
1170                     break;
1171                 case NONE:
1172                 case UNASSIGNED:
1173                     break;
1174                 default:
1175                     Log.w(TAG, "Ignoring unknown proxy settings type: "
1176                             + ipConfiguration.getProxySettings());
1177                     break;
1178             }
1179         }
1180 
1181         /**
1182          * Parse out the static IP configuration from the XML stream.
1183          */
parseStaticIpConfigurationFromXml(XmlPullParser in)1184         private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in)
1185                 throws XmlPullParserException, IOException {
1186             StaticIpConfiguration.Builder builder = new StaticIpConfiguration.Builder();
1187 
1188             String linkAddressString =
1189                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS);
1190             Integer linkPrefixLength =
1191                     (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH);
1192             if (linkAddressString != null && linkPrefixLength != null) {
1193                 LinkAddress linkAddress = new LinkAddress(
1194                         InetAddresses.parseNumericAddress(linkAddressString),
1195                         linkPrefixLength);
1196                 if (linkAddress.getAddress() instanceof Inet4Address) {
1197                     builder.setIpAddress(linkAddress);
1198                 } else {
1199                     Log.w(TAG, "Non-IPv4 address: " + linkAddress);
1200                 }
1201             }
1202             String gatewayAddressString =
1203                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS);
1204             if (gatewayAddressString != null) {
1205                 InetAddress gateway =
1206                         InetAddresses.parseNumericAddress(gatewayAddressString);
1207                 RouteInfo route = new RouteInfo(null, gateway, null, RouteInfo.RTN_UNICAST);
1208                 if (route.isDefaultRoute()
1209                         && route.getDestination().getAddress() instanceof Inet4Address) {
1210                     builder.setGateway(gateway);
1211                 } else {
1212                     Log.w(TAG, "Non-IPv4 default route: " + route);
1213                 }
1214             }
1215             String[] dnsServerAddressesString =
1216                     (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES);
1217             if (dnsServerAddressesString != null) {
1218                 List<InetAddress> dnsServerAddresses = new ArrayList<>();
1219                 for (String dnsServerAddressString : dnsServerAddressesString) {
1220                     InetAddress dnsServerAddress =
1221                             InetAddresses.parseNumericAddress(dnsServerAddressString);
1222                     dnsServerAddresses.add(dnsServerAddress);
1223                 }
1224                 builder.setDnsServers(dnsServerAddresses);
1225             }
1226             return builder.build();
1227         }
1228 
1229         /**
1230          * Parses the IP configuration data elements from the provided XML stream to an
1231          * IpConfiguration object.
1232          *
1233          * @param in            XmlPullParser instance pointing to the XML stream.
1234          * @param outerTagDepth depth of the outer tag in the XML document.
1235          * @return IpConfiguration object if parsing is successful, null otherwise.
1236          */
parseFromXml(XmlPullParser in, int outerTagDepth)1237         public static IpConfiguration parseFromXml(XmlPullParser in, int outerTagDepth)
1238                 throws XmlPullParserException, IOException {
1239             IpConfiguration ipConfiguration = new IpConfiguration();
1240 
1241             // Parse out the IP assignment info first.
1242             String ipAssignmentString =
1243                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT);
1244             IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString);
1245             ipConfiguration.setIpAssignment(ipAssignment);
1246             switch (ipAssignment) {
1247                 case STATIC:
1248                     ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in));
1249                     break;
1250                 case DHCP:
1251                 case UNASSIGNED:
1252                     break;
1253                 default:
1254                     Log.w(TAG, "Ignoring unknown ip assignment type: " + ipAssignment);
1255                     break;
1256             }
1257 
1258             // Parse out the proxy settings next.
1259             String proxySettingsString =
1260                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS);
1261             ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString);
1262             ipConfiguration.setProxySettings(proxySettings);
1263             switch (proxySettings) {
1264                 case STATIC:
1265                     String proxyHost =
1266                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST);
1267                     int proxyPort =
1268                             (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT);
1269                     String proxyExclusionList =
1270                             (String) XmlUtil.readNextValueWithName(
1271                                     in, XML_TAG_PROXY_EXCLUSION_LIST);
1272                     ipConfiguration.setHttpProxy(
1273                             ProxyInfo.buildDirectProxy(
1274                                     proxyHost, proxyPort,
1275                                     parseProxyExclusionListString(proxyExclusionList)));
1276                     break;
1277                 case PAC:
1278                     String proxyPacFile =
1279                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE);
1280                     ipConfiguration.setHttpProxy(
1281                             ProxyInfo.buildPacProxy(Uri.parse(proxyPacFile)));
1282                     break;
1283                 case NONE:
1284                 case UNASSIGNED:
1285                     break;
1286                 default:
1287                     Log.w(TAG, "Ignoring unknown proxy settings type: " + proxySettings);
1288                     break;
1289             }
1290             return ipConfiguration;
1291         }
1292     }
1293 
1294     /**
1295      * Utility class to serialize and deserialize {@link NetworkSelectionStatus} object to XML &
1296      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1297      */
1298     public static class NetworkSelectionStatusXmlUtil {
1299 
1300         /**
1301          * List of XML tags corresponding to NetworkSelectionStatus object elements.
1302          */
1303         public static final String XML_TAG_SELECTION_STATUS = "SelectionStatus";
1304         public static final String XML_TAG_DISABLE_REASON = "DisableReason";
1305         public static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice";
1306         public static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected";
1307         public static final String XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED =
1308                 "CaptivePortalNeverDetected";
1309         public static final String XML_TAG_CONNECT_CHOICE_RSSI = "ConnectChoiceRssi";
1310 
1311         /**
1312          * Write the NetworkSelectionStatus data elements from the provided status to the XML
1313          * stream.
1314          *
1315          * @param out             XmlSerializer instance pointing to the XML stream.
1316          * @param selectionStatus NetworkSelectionStatus object to be serialized.
1317          */
writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)1318         public static void writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)
1319                 throws XmlPullParserException, IOException {
1320             XmlUtil.writeNextValue(
1321                     out, XML_TAG_SELECTION_STATUS, selectionStatus.getNetworkStatusString());
1322             XmlUtil.writeNextValue(
1323                     out, XML_TAG_DISABLE_REASON,
1324                     selectionStatus.getNetworkSelectionDisableReasonString());
1325             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, selectionStatus.getConnectChoice());
1326             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE_RSSI,
1327                     selectionStatus.getConnectChoiceRssi());
1328             XmlUtil.writeNextValue(
1329                     out, XML_TAG_HAS_EVER_CONNECTED, selectionStatus.hasEverConnected());
1330             XmlUtil.writeNextValue(out, XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED,
1331                     selectionStatus.hasNeverDetectedCaptivePortal());
1332         }
1333 
1334         /**
1335          * Parses the NetworkSelectionStatus data elements from the provided XML stream to a
1336          * NetworkSelectionStatus object.
1337          *
1338          * @param in            XmlPullParser instance pointing to the XML stream.
1339          * @param outerTagDepth depth of the outer tag in the XML document.
1340          * @return NetworkSelectionStatus object if parsing is successful, null otherwise.
1341          */
parseFromXml(XmlPullParser in, int outerTagDepth)1342         public static NetworkSelectionStatus parseFromXml(XmlPullParser in, int outerTagDepth)
1343                 throws XmlPullParserException, IOException {
1344             NetworkSelectionStatus selectionStatus = new NetworkSelectionStatus();
1345             String statusString = "";
1346             String disableReasonString = "";
1347             // Initialize hasNeverDetectedCaptivePortal to "false" for upgrading legacy configs
1348             // which do not have the XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED tag.
1349             selectionStatus.setHasNeverDetectedCaptivePortal(false);
1350 
1351             // Loop through and parse out all the elements from the stream within this section.
1352             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1353                 String[] valueName = new String[1];
1354                 Object value = XmlUtil.readCurrentValue(in, valueName);
1355                 if (valueName[0] == null) {
1356                     throw new XmlPullParserException("Missing value name");
1357                 }
1358                 switch (valueName[0]) {
1359                     case XML_TAG_SELECTION_STATUS:
1360                         statusString = (String) value;
1361                         break;
1362                     case XML_TAG_DISABLE_REASON:
1363                         disableReasonString = (String) value;
1364                         break;
1365                     case XML_TAG_CONNECT_CHOICE:
1366                         selectionStatus.setConnectChoice((String) value);
1367                         break;
1368                     case XML_TAG_CONNECT_CHOICE_RSSI:
1369                         selectionStatus.setConnectChoiceRssi((int) value);
1370                         break;
1371                     case XML_TAG_HAS_EVER_CONNECTED:
1372                         selectionStatus.setHasEverConnected((boolean) value);
1373                         break;
1374                     case XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED:
1375                         selectionStatus.setHasNeverDetectedCaptivePortal((boolean) value);
1376                     default:
1377                         Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1378                         break;
1379                 }
1380             }
1381             // Now figure out the network selection status codes from |selectionStatusString| &
1382             // |disableReasonString|.
1383             int status =
1384                     Arrays.asList(NetworkSelectionStatus.QUALITY_NETWORK_SELECTION_STATUS)
1385                             .indexOf(statusString);
1386             int disableReason =
1387                     NetworkSelectionStatus.getDisableReasonByString(disableReasonString);
1388 
1389             // If either of the above codes are invalid or if the network was temporarily disabled
1390             // (blacklisted), restore the status as enabled. We don't want to persist blacklists
1391             // across reboots.
1392             if (status == -1 || disableReason == -1 ||
1393                     status == NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) {
1394                 status = NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
1395                 disableReason = NetworkSelectionStatus.DISABLED_NONE;
1396             }
1397             selectionStatus.setNetworkSelectionStatus(status);
1398             selectionStatus.setNetworkSelectionDisableReason(disableReason);
1399             if (status == NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED) {
1400                 // Make the counter non-zero so that logging code works properly
1401                 selectionStatus.setDisableReasonCounter(disableReason, 1);
1402             }
1403             return selectionStatus;
1404         }
1405     }
1406 
1407     /**
1408      * Utility class to serialize and deseriaize {@link WifiEnterpriseConfig} object to XML &
1409      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1410      */
1411     public static class WifiEnterpriseConfigXmlUtil {
1412 
1413         /**
1414          * List of XML tags corresponding to WifiEnterpriseConfig object elements.
1415          */
1416         public static final String XML_TAG_IDENTITY = "Identity";
1417         public static final String XML_TAG_ANON_IDENTITY = "AnonIdentity";
1418         public static final String XML_TAG_PASSWORD = "Password";
1419         public static final String XML_TAG_CLIENT_CERT = "ClientCert";
1420         public static final String XML_TAG_CA_CERT = "CaCert";
1421         public static final String XML_TAG_SUBJECT_MATCH = "SubjectMatch";
1422         public static final String XML_TAG_ENGINE = "Engine";
1423         public static final String XML_TAG_ENGINE_ID = "EngineId";
1424         public static final String XML_TAG_PRIVATE_KEY_ID = "PrivateKeyId";
1425         public static final String XML_TAG_ALT_SUBJECT_MATCH = "AltSubjectMatch";
1426         public static final String XML_TAG_DOM_SUFFIX_MATCH = "DomSuffixMatch";
1427         public static final String XML_TAG_CA_PATH = "CaPath";
1428         public static final String XML_TAG_EAP_METHOD = "EapMethod";
1429         public static final String XML_TAG_PHASE2_METHOD = "Phase2Method";
1430         public static final String XML_TAG_PLMN = "PLMN";
1431         public static final String XML_TAG_REALM = "Realm";
1432         public static final String XML_TAG_OCSP = "Ocsp";
1433         public static final String XML_TAG_WAPI_CERT_SUITE = "WapiCertSuite";
1434         public static final String XML_TAG_APP_INSTALLED_ROOT_CA_CERT = "AppInstalledRootCaCert";
1435         public static final String XML_TAG_APP_INSTALLED_PRIVATE_KEY = "AppInstalledPrivateKey";
1436         public static final String XML_TAG_KEYCHAIN_KEY_ALIAS = "KeyChainAlias";
1437         public static final String XML_TAG_DECORATED_IDENTITY_PREFIX = "DecoratedIdentityPrefix";
1438         public static final String XML_TAG_TRUST_ON_FIRST_USE = "TrustOnFirstUse";
1439         public static final String XML_TAG_USER_APPROVE_NO_CA_CERT = "UserApproveNoCaCert";
1440 
1441         /**
1442          * Write password key to the XML stream.
1443          *
1444          * If encryptionUtil is null or if encryption fails for some reason, the password is stored
1445          * in plaintext, else the encrypted psk is stored.
1446          */
writePasswordToXml( XmlSerializer out, String password, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1447         private static void writePasswordToXml(
1448                 XmlSerializer out, String password,
1449                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1450                 throws XmlPullParserException, IOException {
1451             EncryptedData encryptedData = null;
1452             if (encryptionUtil != null) {
1453                 if (password != null) {
1454                     encryptedData = encryptionUtil.encrypt(password.getBytes());
1455                     if (encryptedData == null) {
1456                         // We silently fail encryption failures!
1457                         Log.wtf(TAG, "Encryption of password failed");
1458                     }
1459                 }
1460             }
1461             if (encryptedData != null) {
1462                 XmlUtil.writeNextSectionStart(out, XML_TAG_PASSWORD);
1463                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
1464                 XmlUtil.writeNextSectionEnd(out, XML_TAG_PASSWORD);
1465             } else {
1466                 XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, password);
1467             }
1468         }
1469 
1470         /**
1471          * Write the WifiEnterpriseConfig data elements from the provided config to the XML
1472          * stream.
1473          *
1474          * @param out XmlSerializer instance pointing to the XML stream.
1475          * @param enterpriseConfig WifiEnterpriseConfig object to be serialized.
1476          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
1477          */
writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1478         public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig,
1479                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1480                 throws XmlPullParserException, IOException {
1481             XmlUtil.writeNextValue(out, XML_TAG_IDENTITY,
1482                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY));
1483             XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY,
1484                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY));
1485             writePasswordToXml(
1486                     out, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY),
1487                     encryptionUtil);
1488             XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT,
1489                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY));
1490             XmlUtil.writeNextValue(out, XML_TAG_CA_CERT,
1491                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY));
1492             XmlUtil.writeNextValue(out, XML_TAG_SUBJECT_MATCH,
1493                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY));
1494             XmlUtil.writeNextValue(out, XML_TAG_ENGINE,
1495                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY));
1496             XmlUtil.writeNextValue(out, XML_TAG_ENGINE_ID,
1497                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY));
1498             XmlUtil.writeNextValue(out, XML_TAG_PRIVATE_KEY_ID,
1499                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY));
1500             XmlUtil.writeNextValue(out, XML_TAG_ALT_SUBJECT_MATCH,
1501                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY));
1502             XmlUtil.writeNextValue(out, XML_TAG_DOM_SUFFIX_MATCH,
1503                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY));
1504             XmlUtil.writeNextValue(out, XML_TAG_CA_PATH,
1505                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_PATH_KEY));
1506             XmlUtil.writeNextValue(out, XML_TAG_EAP_METHOD, enterpriseConfig.getEapMethod());
1507             XmlUtil.writeNextValue(out, XML_TAG_PHASE2_METHOD, enterpriseConfig.getPhase2Method());
1508             XmlUtil.writeNextValue(out, XML_TAG_PLMN, enterpriseConfig.getPlmn());
1509             XmlUtil.writeNextValue(out, XML_TAG_REALM, enterpriseConfig.getRealm());
1510             XmlUtil.writeNextValue(out, XML_TAG_OCSP, enterpriseConfig.getOcsp());
1511             XmlUtil.writeNextValue(out,
1512                     XML_TAG_WAPI_CERT_SUITE, enterpriseConfig.getWapiCertSuite());
1513             XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_ROOT_CA_CERT,
1514                     enterpriseConfig.isAppInstalledCaCert());
1515             XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_PRIVATE_KEY,
1516                     enterpriseConfig.isAppInstalledDeviceKeyAndCert());
1517             XmlUtil.writeNextValue(out, XML_TAG_KEYCHAIN_KEY_ALIAS,
1518                     enterpriseConfig.getClientKeyPairAliasInternal());
1519             if (SdkLevel.isAtLeastS()) {
1520                 XmlUtil.writeNextValue(out, XML_TAG_DECORATED_IDENTITY_PREFIX,
1521                         enterpriseConfig.getDecoratedIdentityPrefix());
1522             }
1523             XmlUtil.writeNextValue(out, XML_TAG_TRUST_ON_FIRST_USE,
1524                     enterpriseConfig.isTrustOnFirstUseEnabled());
1525             XmlUtil.writeNextValue(out, XML_TAG_USER_APPROVE_NO_CA_CERT,
1526                     enterpriseConfig.isUserApproveNoCaCert());
1527         }
1528 
1529         /**
1530          * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object.
1531          *
1532          * @param in XmlPullParser instance pointing to the XML stream.
1533          * @param outerTagDepth depth of the outer tag in the XML document.
1534          * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not.
1535          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
1536          * @return WifiEnterpriseConfig object if parsing is successful, null otherwise.
1537          */
parseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1538         public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth,
1539                 boolean shouldExpectEncryptedCredentials,
1540                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1541                 throws XmlPullParserException, IOException {
1542             WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
1543 
1544             // Loop through and parse out all the elements from the stream within this section.
1545             while (XmlUtilHelper.nextElementWithin(in, outerTagDepth)) {
1546                 if (in.getAttributeValue(null, "name") != null) {
1547                     // Value elements.
1548                     String[] valueName = new String[1];
1549                     Object value = XmlUtil.readCurrentValue(in, valueName);
1550                     if (valueName[0] == null) {
1551                         throw new XmlPullParserException("Missing value name");
1552                     }
1553                     switch (valueName[0]) {
1554                         case XML_TAG_IDENTITY:
1555                             enterpriseConfig.setFieldValue(
1556                                     WifiEnterpriseConfig.IDENTITY_KEY, (String) value);
1557                             break;
1558                         case XML_TAG_ANON_IDENTITY:
1559                             enterpriseConfig.setFieldValue(
1560                                     WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value);
1561                             break;
1562                         case XML_TAG_PASSWORD:
1563                             enterpriseConfig.setFieldValue(
1564                                     WifiEnterpriseConfig.PASSWORD_KEY, (String) value);
1565                             if (shouldExpectEncryptedCredentials
1566                                     && !TextUtils.isEmpty(enterpriseConfig.getFieldValue(
1567                                     WifiEnterpriseConfig.PASSWORD_KEY))) {
1568                                 // Indicates that encryption of password failed when it was last
1569                                 // written.
1570                                 Log.e(TAG, "password value not expected");
1571                             }
1572                             break;
1573                         case XML_TAG_CLIENT_CERT:
1574                             enterpriseConfig.setFieldValue(
1575                                     WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value);
1576                             break;
1577                         case XML_TAG_CA_CERT:
1578                             enterpriseConfig.setFieldValue(
1579                                     WifiEnterpriseConfig.CA_CERT_KEY, (String) value);
1580                             break;
1581                         case XML_TAG_SUBJECT_MATCH:
1582                             enterpriseConfig.setFieldValue(
1583                                     WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value);
1584                             break;
1585                         case XML_TAG_ENGINE:
1586                             enterpriseConfig.setFieldValue(
1587                                     WifiEnterpriseConfig.ENGINE_KEY, (String) value);
1588                             break;
1589                         case XML_TAG_ENGINE_ID:
1590                             enterpriseConfig.setFieldValue(
1591                                     WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value);
1592                             break;
1593                         case XML_TAG_PRIVATE_KEY_ID:
1594                             enterpriseConfig.setFieldValue(
1595                                     WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value);
1596                             break;
1597                         case XML_TAG_ALT_SUBJECT_MATCH:
1598                             enterpriseConfig.setFieldValue(
1599                                     WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value);
1600                             break;
1601                         case XML_TAG_DOM_SUFFIX_MATCH:
1602                             enterpriseConfig.setFieldValue(
1603                                     WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value);
1604                             break;
1605                         case XML_TAG_CA_PATH:
1606                             enterpriseConfig.setFieldValue(
1607                                     WifiEnterpriseConfig.CA_PATH_KEY, (String) value);
1608                             break;
1609                         case XML_TAG_OCSP:
1610                             enterpriseConfig.setOcsp((int) value);
1611                             break;
1612                         case XML_TAG_EAP_METHOD:
1613                             enterpriseConfig.setEapMethod((int) value);
1614                             break;
1615                         case XML_TAG_PHASE2_METHOD:
1616                             enterpriseConfig.setPhase2Method((int) value);
1617                             break;
1618                         case XML_TAG_PLMN:
1619                             enterpriseConfig.setPlmn((String) value);
1620                             break;
1621                         case XML_TAG_REALM:
1622                             enterpriseConfig.setRealm((String) value);
1623                             break;
1624                         case XML_TAG_WAPI_CERT_SUITE:
1625                             enterpriseConfig.setWapiCertSuite((String) value);
1626                             break;
1627                         case XML_TAG_APP_INSTALLED_ROOT_CA_CERT:
1628                             enterpriseConfig.initIsAppInstalledCaCert((boolean) value);
1629                             break;
1630                         case XML_TAG_APP_INSTALLED_PRIVATE_KEY:
1631                             enterpriseConfig.initIsAppInstalledDeviceKeyAndCert((boolean) value);
1632                             break;
1633                         case XML_TAG_KEYCHAIN_KEY_ALIAS:
1634                             if (SdkLevel.isAtLeastS()) {
1635                                 enterpriseConfig.setClientKeyPairAlias((String) value);
1636                             }
1637                             break;
1638                         case XML_TAG_DECORATED_IDENTITY_PREFIX:
1639                             if (SdkLevel.isAtLeastS()) {
1640                                 enterpriseConfig.setDecoratedIdentityPrefix((String) value);
1641                             }
1642                             break;
1643                         case XML_TAG_TRUST_ON_FIRST_USE:
1644                             enterpriseConfig.enableTrustOnFirstUse((boolean) value);
1645                             break;
1646                         case XML_TAG_USER_APPROVE_NO_CA_CERT:
1647                             enterpriseConfig.setUserApproveNoCaCert((boolean) value);
1648                             break;
1649                         default:
1650                             Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1651                             break;
1652                     }
1653                 } else {
1654                     String tagName = in.getName();
1655                     if (tagName == null) {
1656                         throw new XmlPullParserException("Unexpected null tag found");
1657                     }
1658                     switch (tagName) {
1659                         case XML_TAG_PASSWORD:
1660                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
1661                                 throw new XmlPullParserException(
1662                                         "encrypted password section not expected");
1663                             }
1664                             EncryptedData encryptedData =
1665                                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
1666                             byte[] passwordBytes = encryptionUtil.decrypt(encryptedData);
1667                             if (passwordBytes == null) {
1668                                 Log.wtf(TAG, "Decryption of password failed");
1669                             } else {
1670                                 enterpriseConfig.setFieldValue(
1671                                         WifiEnterpriseConfig.PASSWORD_KEY,
1672                                         new String(passwordBytes));
1673                             }
1674                             break;
1675                         default:
1676                             Log.w(TAG, "Ignoring unknown tag name found: " + tagName);
1677                             break;
1678                     }
1679                 }
1680             }
1681             return enterpriseConfig;
1682         }
1683     }
1684 
1685     /**
1686      * Utility class to serialize and deseriaize {@link EncryptedData} object to XML &
1687      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1688      */
1689     public static class EncryptedDataXmlUtil {
1690         /**
1691          * List of XML tags corresponding to EncryptedData object elements.
1692          */
1693         private static final String XML_TAG_ENCRYPTED_DATA = "EncryptedData";
1694         private static final String XML_TAG_IV = "IV";
1695 
1696         /**
1697          * Write the NetworkSelectionStatus data elements from the provided status to the XML
1698          * stream.
1699          *
1700          * @param out           XmlSerializer instance pointing to the XML stream.
1701          * @param encryptedData EncryptedData object to be serialized.
1702          */
writeToXml(XmlSerializer out, EncryptedData encryptedData)1703         public static void writeToXml(XmlSerializer out, EncryptedData encryptedData)
1704                 throws XmlPullParserException, IOException {
1705             XmlUtil.writeNextValue(
1706                     out, XML_TAG_ENCRYPTED_DATA, encryptedData.getEncryptedData());
1707             XmlUtil.writeNextValue(out, XML_TAG_IV, encryptedData.getIv());
1708         }
1709 
1710         /**
1711          * Parses the EncryptedData data elements from the provided XML stream to a
1712          * EncryptedData object.
1713          *
1714          * @param in            XmlPullParser instance pointing to the XML stream.
1715          * @param outerTagDepth depth of the outer tag in the XML document.
1716          * @return EncryptedData object if parsing is successful, null otherwise.
1717          */
parseFromXml(XmlPullParser in, int outerTagDepth)1718         public static EncryptedData parseFromXml(XmlPullParser in, int outerTagDepth)
1719                 throws XmlPullParserException, IOException {
1720             byte[] encryptedData = null;
1721             byte[] iv = null;
1722 
1723             // Loop through and parse out all the elements from the stream within this section.
1724             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1725                 String[] valueName = new String[1];
1726                 Object value = XmlUtil.readCurrentValue(in, valueName);
1727                 if (valueName[0] == null) {
1728                     throw new XmlPullParserException("Missing value name");
1729                 }
1730                 switch (valueName[0]) {
1731                     case XML_TAG_ENCRYPTED_DATA:
1732                         encryptedData = (byte[]) value;
1733                         break;
1734                     case XML_TAG_IV:
1735                         iv = (byte[]) value;
1736                         break;
1737                     default:
1738                         Log.e(TAG, "Unknown value name found: " + valueName[0]);
1739                         break;
1740                 }
1741             }
1742             return new EncryptedData(encryptedData, iv);
1743         }
1744     }
1745 
nextElementWithin(XmlPullParser parser, int outerDepth)1746     public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
1747             throws IOException, XmlPullParserException {
1748         return XmlUtilHelper.nextElementWithin(parser, outerDepth);
1749     }
1750 
1751     /**
1752      * Utility class to serialize and deseriaize {@link SoftApConfiguration} object to XML
1753      * & vice versa. This is used by both {@link com.android.server.wifi.SoftApStore}  modules.
1754      */
1755     public static class SoftApConfigurationXmlUtil {
1756         /**
1757          * List of XML tags corresponding to SoftApConfiguration object elements.
1758          */
1759         public static final String XML_TAG_CLIENT_MACADDRESS = "ClientMacAddress";
1760         public static final String XML_TAG_BAND_CHANNEL = "BandChannel";
1761         public static final String XML_TAG_SSID = "SSID"; // Use XML_TAG_WIFI_SSID instead
1762         public static final String XML_TAG_WIFI_SSID = "WifiSsid";
1763         public static final String XML_TAG_BSSID = "Bssid";
1764         public static final String XML_TAG_BAND = "Band";
1765         public static final String XML_TAG_CHANNEL = "Channel";
1766         public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
1767         public static final String XML_TAG_SECURITY_TYPE = "SecurityType";
1768         public static final String XML_TAG_WPA2_PASSPHRASE = "Wpa2Passphrase";
1769         public static final String XML_TAG_AP_BAND = "ApBand";
1770         public static final String XML_TAG_PASSPHRASE = "Passphrase";
1771         public static final String XML_TAG_MAX_NUMBER_OF_CLIENTS = "MaxNumberOfClients";
1772         public static final String XML_TAG_AUTO_SHUTDOWN_ENABLED = "AutoShutdownEnabled";
1773         public static final String XML_TAG_SHUTDOWN_TIMEOUT_MILLIS = "ShutdownTimeoutMillis";
1774         public static final String XML_TAG_CLIENT_CONTROL_BY_USER = "ClientControlByUser";
1775         public static final String XML_TAG_BLOCKED_CLIENT_LIST = "BlockedClientList";
1776         public static final String XML_TAG_ALLOWED_CLIENT_LIST = "AllowedClientList";
1777         public static final String XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED =
1778                 "BridgedModeOpportunisticShutdownEnabled";
1779         public static final String XML_TAG_MAC_RAMDOMIZATION_SETTING = "MacRandomizationSetting";
1780         public static final String XML_TAG_BAND_CHANNEL_MAP = "BandChannelMap";
1781         public static final String XML_TAG_80211_AX_ENABLED = "80211axEnabled";
1782         public static final String XML_TAG_80211_BE_ENABLED = "80211beEnabled";
1783         public static final String XML_TAG_USER_CONFIGURATION = "UserConfiguration";
1784         public static final String XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS =
1785                 "BridgedModeOpportunisticShutdownTimeoutMillis";
1786         public static final String XML_TAG_VENDOR_ELEMENT = "VendorElement";
1787         public static final String XML_TAG_VENDOR_ELEMENTS = "VendorElements";
1788         public static final String XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS =
1789                 "PersistentRandomizedMacAddress";
1790 
1791 
1792         /**
1793          * Parses the client list from the provided XML stream to a ArrayList object.
1794          *
1795          * @param in            XmlPullParser instance pointing to the XML stream.
1796          * @param outerTagDepth depth of the outer tag in the XML document.
1797          * @return ArrayList object if parsing is successful, null otherwise.
1798          */
parseClientListFromXml(XmlPullParser in, int outerTagDepth)1799         public static List<MacAddress> parseClientListFromXml(XmlPullParser in,
1800                 int outerTagDepth) throws XmlPullParserException, IOException,
1801                 IllegalArgumentException {
1802             List<MacAddress> clientList = new ArrayList<>();
1803             // Loop through and parse out all the elements from the stream within this section.
1804             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1805                 String[] valueName = new String[1];
1806                 Object value = XmlUtil.readCurrentValue(in, valueName);
1807                 if (valueName[0] == null) {
1808                     throw new XmlPullParserException("Missing value name");
1809                 }
1810                 switch (valueName[0]) {
1811                     case XML_TAG_CLIENT_MACADDRESS:
1812                         MacAddress client = MacAddress.fromString((String) value);
1813                         clientList.add(client);
1814                         break;
1815                     default:
1816                         Log.e(TAG, "Unknown value name found: " + valueName[0]);
1817                         break;
1818                 }
1819             }
1820             return clientList;
1821         }
1822 
1823         /**
1824          * Write the SoftApConfiguration client control list data elements
1825          * from the provided list to the XML stream.
1826          *
1827          * @param out           XmlSerializer instance pointing to the XML stream.
1828          * @param clientList Client list object to be serialized.
1829          */
writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)1830         public static void writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)
1831                 throws XmlPullParserException, IOException {
1832             for (MacAddress mac: clientList) {
1833                 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_MACADDRESS, mac.toString());
1834             }
1835         }
1836 
1837         /**
1838          * Write the SoftApConfiguration vendor elements list information elements to the XML
1839          *
1840          * @param out XmlSerializer instance pointing to the XML stream
1841          * @param elements Vendor elements list
1842          */
writeVendorElementsSetToXml( XmlSerializer out, List<ScanResult.InformationElement> elements)1843         public static void writeVendorElementsSetToXml(
1844                 XmlSerializer out, List<ScanResult.InformationElement> elements)
1845                 throws XmlPullParserException, IOException {
1846             for (ScanResult.InformationElement e : elements) {
1847                 XmlUtil.writeNextValue(out, XML_TAG_VENDOR_ELEMENT,
1848                         InformationElementUtil.toHexString(e));
1849             }
1850         }
1851 
1852         /**
1853          * Parses the vendor elements from the provided XML stream to HashSet object.
1854          *
1855          * @param in XmlPullParser instance pointing to the XML stream
1856          * @param outerTagDepth depth of the outer tag in the XML document
1857          * @return HashSet object if parsing is successful, empty set otherwise
1858          */
parseVendorElementsFromXml( XmlPullParser in, int outerTagDepth)1859         public static List<ScanResult.InformationElement> parseVendorElementsFromXml(
1860                 XmlPullParser in, int outerTagDepth)
1861                 throws XmlPullParserException, IOException, IllegalArgumentException {
1862             List<ScanResult.InformationElement> elements = new ArrayList<>();
1863             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1864                 String[] valueName = new String[1];
1865                 Object value = XmlUtil.readCurrentValue(in, valueName);
1866                 if (valueName[0] == null) {
1867                     throw new XmlPullParserException("Missing value name");
1868                 }
1869                 if (XML_TAG_VENDOR_ELEMENT.equals(valueName[0])) {
1870                     ScanResult.InformationElement[] data =
1871                             InformationElementUtil.parseInformationElements((String) value);
1872                     elements.addAll(Arrays.asList(data));
1873                 } else {
1874                     Log.e(TAG, "Unknown value name found: " + valueName[0]);
1875                 }
1876             }
1877             return elements;
1878         }
1879 
1880         /**
1881          * Parses the band and channel from the provided XML stream to a SparseIntArray object.
1882          *
1883          * @param in            XmlPullParser instance pointing to the XML stream.
1884          * @param outerTagDepth depth of the outer tag in the XML document.
1885          * @return SparseIntArray object if parsing is successful, null otherwise.
1886          */
parseChannelsFromXml(XmlPullParser in, int outerTagDepth)1887         public static SparseIntArray parseChannelsFromXml(XmlPullParser in,
1888                 int outerTagDepth) throws XmlPullParserException, IOException,
1889                 IllegalArgumentException {
1890             SparseIntArray channels = new SparseIntArray();
1891             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1892                 int band = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL;
1893                 int channel = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL;
1894                 switch (in.getName()) {
1895                     case XML_TAG_BAND_CHANNEL:
1896                         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth + 1)) {
1897                             String[] valueName = new String[1];
1898                             Object value = XmlUtil.readCurrentValue(in, valueName);
1899                             if (valueName[0] == null) {
1900                                 throw new XmlPullParserException("Missing value name");
1901                             }
1902                             switch (valueName[0]) {
1903                                 case XML_TAG_BAND:
1904                                     band = (int) value;
1905                                     break;
1906                                 case XML_TAG_CHANNEL:
1907                                     channel = (int) value;
1908                                     break;
1909                                 default:
1910                                     Log.e(TAG, "Unknown value name found: " + valueName[0]);
1911                                     break;
1912                             }
1913                         }
1914                         channels.put(band, channel);
1915                         break;
1916                 }
1917             }
1918             return channels;
1919         }
1920 
1921         /**
1922          * Write the SoftApConfiguration channels data elements
1923          * from the provided SparseIntArray to the XML stream.
1924          *
1925          * @param out       XmlSerializer instance pointing to the XML stream.
1926          * @param channels  SparseIntArray, which includes bands and channels, to be serialized.
1927          */
writeChannelsToXml(XmlSerializer out, SparseIntArray channels)1928         public static void writeChannelsToXml(XmlSerializer out, SparseIntArray channels)
1929                 throws XmlPullParserException, IOException {
1930             for (int i = 0; i < channels.size(); i++) {
1931                 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL);
1932                 XmlUtil.writeNextValue(out, XML_TAG_BAND, channels.keyAt(i));
1933                 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, channels.valueAt(i));
1934                 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL);
1935             }
1936         }
1937 
1938         /**
1939          * Write the SoftApConfiguration data elements to the XML stream.
1940          *
1941          * @param out          XmlSerializer instance pointing to the XML stream.
1942          * @param softApConfig configuration of the Soft AP.
1943          */
writeSoftApConfigurationToXml(@onNull XmlSerializer out, @NonNull SoftApConfiguration softApConfig)1944         public static void writeSoftApConfigurationToXml(@NonNull XmlSerializer out,
1945                 @NonNull SoftApConfiguration softApConfig)
1946                 throws XmlPullParserException, IOException {
1947             XmlUtil.writeNextValue(out, XML_TAG_WIFI_SSID, softApConfig.getWifiSsid().toString());
1948             if (softApConfig.getBssid() != null) {
1949                 XmlUtil.writeNextValue(out, XML_TAG_BSSID, softApConfig.getBssid().toString());
1950             }
1951             if (!SdkLevel.isAtLeastS()) {
1952                 // Band and channel change to store in Tag:BandChannelMap from S.
1953                 XmlUtil.writeNextValue(out, XML_TAG_AP_BAND, softApConfig.getBand());
1954                 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, softApConfig.getChannel());
1955             }
1956             XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, softApConfig.isHiddenSsid());
1957             XmlUtil.writeNextValue(out, XML_TAG_SECURITY_TYPE, softApConfig.getSecurityType());
1958             if (!ApConfigUtil.isNonPasswordAP(softApConfig.getSecurityType())) {
1959                 XmlUtil.writeNextValue(out, XML_TAG_PASSPHRASE,
1960                         softApConfig.getPassphrase());
1961             }
1962 
1963             XmlUtil.writeNextValue(out, XML_TAG_MAX_NUMBER_OF_CLIENTS,
1964                     softApConfig.getMaxNumberOfClients());
1965             XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CONTROL_BY_USER,
1966                     softApConfig.isClientControlByUserEnabled());
1967             XmlUtil.writeNextValue(out, XML_TAG_AUTO_SHUTDOWN_ENABLED,
1968                     softApConfig.isAutoShutdownEnabled());
1969             XmlUtil.writeNextValue(out, XML_TAG_SHUTDOWN_TIMEOUT_MILLIS,
1970                     softApConfig.getShutdownTimeoutMillis());
1971             XmlUtil.writeNextSectionStart(out, XML_TAG_BLOCKED_CLIENT_LIST);
1972             XmlUtil.SoftApConfigurationXmlUtil.writeClientListToXml(out,
1973                     softApConfig.getBlockedClientList());
1974             XmlUtil.writeNextSectionEnd(out, XML_TAG_BLOCKED_CLIENT_LIST);
1975 
1976             XmlUtil.writeNextSectionStart(out, XML_TAG_ALLOWED_CLIENT_LIST);
1977             XmlUtil.SoftApConfigurationXmlUtil.writeClientListToXml(out,
1978                     softApConfig.getAllowedClientList());
1979             XmlUtil.writeNextSectionEnd(out, XML_TAG_ALLOWED_CLIENT_LIST);
1980             if (SdkLevel.isAtLeastS()) {
1981                 XmlUtil.writeNextValue(out, XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED,
1982                         softApConfig.isBridgedModeOpportunisticShutdownEnabled());
1983                 XmlUtil.writeNextValue(out, XML_TAG_MAC_RAMDOMIZATION_SETTING,
1984                         softApConfig.getMacRandomizationSetting());
1985 
1986                 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL_MAP);
1987                 XmlUtil.SoftApConfigurationXmlUtil.writeChannelsToXml(out,
1988                         softApConfig.getChannels());
1989                 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL_MAP);
1990                 XmlUtil.writeNextValue(out, XML_TAG_80211_AX_ENABLED,
1991                         softApConfig.isIeee80211axEnabled());
1992                 XmlUtil.writeNextValue(out, XML_TAG_USER_CONFIGURATION,
1993                         softApConfig.isUserConfiguration());
1994             }
1995             if (SdkLevel.isAtLeastT()) {
1996                 XmlUtil.writeNextValue(out,
1997                         XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS,
1998                         softApConfig.getBridgedModeOpportunisticShutdownTimeoutMillisInternal());
1999                 XmlUtil.writeNextSectionStart(out, XML_TAG_VENDOR_ELEMENTS);
2000                 XmlUtil.SoftApConfigurationXmlUtil.writeVendorElementsSetToXml(out,
2001                         softApConfig.getVendorElementsInternal());
2002                 XmlUtil.writeNextSectionEnd(out, XML_TAG_VENDOR_ELEMENTS);
2003                 XmlUtil.writeNextValue(out, XML_TAG_80211_BE_ENABLED,
2004                         softApConfig.isIeee80211beEnabled());
2005                 if (softApConfig.getPersistentRandomizedMacAddress() != null) {
2006                     XmlUtil.writeNextValue(out, XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS,
2007                             softApConfig.getPersistentRandomizedMacAddress().toString());
2008                 }
2009             }
2010         } // End of writeSoftApConfigurationToXml
2011 
2012         /**
2013          * Returns configuration of the SoftAp from the XML stream.
2014          *
2015          * @param in XmlPullParser instance pointing to the XML stream.
2016          * @param outerTagDepth depth of the outer tag in the XML document.
2017          * @param settingsMigrationDataHolder the class instance of SettingsMigrationDataHolder
2018          */
2019         @Nullable
parseFromXml(XmlPullParser in, int outerTagDepth, SettingsMigrationDataHolder settingsMigrationDataHolder)2020         public static SoftApConfiguration parseFromXml(XmlPullParser in, int outerTagDepth,
2021                 SettingsMigrationDataHolder settingsMigrationDataHolder)
2022                 throws XmlPullParserException, IOException  {
2023             SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder();
2024             int securityType = SoftApConfiguration.SECURITY_TYPE_OPEN;
2025             String passphrase = null;
2026             // SSID may be retrieved from the old encoding (XML_TAG_SSID) or the new encoding
2027             // (XML_TAG_WIFI_SSID).
2028             boolean hasSsid = false;
2029             String bssid = null;
2030             // Note that, during deserialization, we may read the old band encoding (XML_TAG_BAND)
2031             // or the new band encoding (XML_TAG_AP_BAND) that is used after the introduction of the
2032             // 6GHz band. If the old encoding is found, a conversion is done.
2033             int channel = -1;
2034             int apBand = -1;
2035             boolean hasBandChannelMap = false;
2036             List<MacAddress> blockedList = new ArrayList<>();
2037             List<MacAddress> allowedList = new ArrayList<>();
2038             boolean autoShutdownEnabledTagPresent = false;
2039             try {
2040                 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
2041                     if (in.getAttributeValue(null, "name") != null) {
2042                         String[] valueName = new String[1];
2043                         Object value = XmlUtil.readCurrentValue(in, valueName);
2044                         if (TextUtils.isEmpty(valueName[0])) {
2045                             throw new XmlPullParserException("Missing value name");
2046                         }
2047                         switch (valueName[0]) {
2048                             case XML_TAG_SSID:
2049                                 hasSsid = true;
2050                                 softApConfigBuilder.setSsid((String) value);
2051                                 break;
2052                             case XML_TAG_WIFI_SSID:
2053                                 hasSsid = true;
2054                                 final WifiSsid wifiSsid = WifiSsid.fromString((String) value);
2055                                 if (SdkLevel.isAtLeastT()) {
2056                                     softApConfigBuilder.setWifiSsid(wifiSsid);
2057                                 } else {
2058                                     // If the SSID is non-UTF-8, then use WifiManager.UNKNOWN_SSID.
2059                                     // This should not happen since non-UTF-8 SSIDs may only be set
2060                                     // with SoftApConfiguration#Builder#setWifiSsid(WifiSsid),
2061                                     // which is only available in T and above.
2062                                     final CharSequence utf8Ssid = wifiSsid.getUtf8Text();
2063                                     softApConfigBuilder.setSsid(utf8Ssid != null
2064                                             ? utf8Ssid.toString() : WifiManager.UNKNOWN_SSID);
2065                                 }
2066                                 break;
2067                             case XML_TAG_BSSID:
2068                                 bssid = (String) value;
2069                                 softApConfigBuilder.setBssid(MacAddress.fromString(bssid));
2070                                 break;
2071                             case XML_TAG_BAND:
2072                                 apBand = ApConfigUtil.convertWifiConfigBandToSoftApConfigBand(
2073                                         (int) value);
2074                                 break;
2075                             case XML_TAG_AP_BAND:
2076                                 apBand = (int) value;
2077                                 break;
2078                             case XML_TAG_CHANNEL:
2079                                 channel = (int) value;
2080                                 break;
2081                             case XML_TAG_HIDDEN_SSID:
2082                                 softApConfigBuilder.setHiddenSsid((boolean) value);
2083                                 break;
2084                             case XML_TAG_SECURITY_TYPE:
2085                                 securityType = (int) value;
2086                                 break;
2087                             case XML_TAG_WPA2_PASSPHRASE:
2088                             case XML_TAG_PASSPHRASE:
2089                                 passphrase = (String) value;
2090                                 break;
2091                             case XML_TAG_MAX_NUMBER_OF_CLIENTS:
2092                                 softApConfigBuilder.setMaxNumberOfClients((int) value);
2093                                 break;
2094                             case XML_TAG_AUTO_SHUTDOWN_ENABLED:
2095                                 softApConfigBuilder.setAutoShutdownEnabled((boolean) value);
2096                                 autoShutdownEnabledTagPresent = true;
2097                                 break;
2098                             case XML_TAG_SHUTDOWN_TIMEOUT_MILLIS:
2099                                 long shutDownMillis = 0;
2100                                 if (value instanceof Integer) {
2101                                     shutDownMillis = Long.valueOf((int) value);
2102                                 } else if (value instanceof Long) {
2103                                     shutDownMillis = (long) value;
2104                                 }
2105                                 if (shutDownMillis == 0
2106                                         && Compatibility.isChangeEnabled(
2107                                         SoftApConfiguration.REMOVE_ZERO_FOR_TIMEOUT_SETTING)) {
2108                                     shutDownMillis = SoftApConfiguration.DEFAULT_TIMEOUT;
2109                                 }
2110                                 softApConfigBuilder.setShutdownTimeoutMillis(shutDownMillis);
2111                                 break;
2112                             case XML_TAG_CLIENT_CONTROL_BY_USER:
2113                                 softApConfigBuilder.setClientControlByUserEnabled((boolean) value);
2114                                 break;
2115                             case XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED:
2116                                 if (SdkLevel.isAtLeastS()) {
2117                                     softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled(
2118                                             (boolean) value);
2119                                 }
2120                                 break;
2121                             case XML_TAG_MAC_RAMDOMIZATION_SETTING:
2122                                 if (SdkLevel.isAtLeastS()) {
2123                                     softApConfigBuilder.setMacRandomizationSetting((int) value);
2124                                 }
2125                                 break;
2126                             case XML_TAG_80211_AX_ENABLED:
2127                                 if (SdkLevel.isAtLeastS()) {
2128                                     softApConfigBuilder.setIeee80211axEnabled((boolean) value);
2129                                 }
2130                                 break;
2131                             case XML_TAG_80211_BE_ENABLED:
2132                                 if (SdkLevel.isAtLeastT()) {
2133                                     softApConfigBuilder.setIeee80211beEnabled((boolean) value);
2134                                 }
2135                                 break;
2136                             case XML_TAG_USER_CONFIGURATION:
2137                                 if (SdkLevel.isAtLeastS()) {
2138                                     softApConfigBuilder.setUserConfiguration((boolean) value);
2139                                 }
2140                                 break;
2141                             case XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS:
2142                                 if (SdkLevel.isAtLeastT()) {
2143                                     long bridgedTimeout = (long) value;
2144                                     bridgedTimeout = bridgedTimeout == 0
2145                                             ? SoftApConfiguration.DEFAULT_TIMEOUT : bridgedTimeout;
2146                                     softApConfigBuilder
2147                                             .setBridgedModeOpportunisticShutdownTimeoutMillis(
2148                                                     bridgedTimeout);
2149                                 }
2150                                 break;
2151                             case XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS:
2152                                 if (SdkLevel.isAtLeastT()) {
2153                                     softApConfigBuilder.setRandomizedMacAddress(
2154                                             MacAddress.fromString((String) value));
2155                                 }
2156                                 break;
2157                             default:
2158                                 Log.w(TAG, "Ignoring unknown value name " + valueName[0]);
2159                                 break;
2160                         }
2161                     } else {
2162                         String tagName = in.getName();
2163                         List<MacAddress> parseredList;
2164                         if (tagName == null) {
2165                             throw new XmlPullParserException("Unexpected null tag found");
2166                         }
2167                         switch (tagName) {
2168                             case XML_TAG_BLOCKED_CLIENT_LIST:
2169                                 parseredList =
2170                                         XmlUtil.SoftApConfigurationXmlUtil.parseClientListFromXml(
2171                                         in, outerTagDepth + 1);
2172                                 if (parseredList != null) {
2173                                     blockedList = new ArrayList<>(parseredList);
2174                                 }
2175                                 break;
2176                             case XML_TAG_ALLOWED_CLIENT_LIST:
2177                                 parseredList =
2178                                         XmlUtil.SoftApConfigurationXmlUtil.parseClientListFromXml(
2179                                         in, outerTagDepth + 1);
2180                                 if (parseredList != null) {
2181                                     allowedList = new ArrayList<>(parseredList);
2182                                 }
2183                                 break;
2184                             case XML_TAG_BAND_CHANNEL_MAP:
2185                                 if (SdkLevel.isAtLeastS()) {
2186                                     hasBandChannelMap = true;
2187                                     SparseIntArray channels = XmlUtil.SoftApConfigurationXmlUtil
2188                                             .parseChannelsFromXml(in, outerTagDepth + 1);
2189                                     softApConfigBuilder.setChannels(channels);
2190                                 }
2191                                 break;
2192                             case XML_TAG_VENDOR_ELEMENTS:
2193                                 if (SdkLevel.isAtLeastT()) {
2194                                     softApConfigBuilder.setVendorElements(
2195                                             SoftApConfigurationXmlUtil.parseVendorElementsFromXml(
2196                                                     in, outerTagDepth + 1));
2197                                 }
2198                                 break;
2199                             default:
2200                                 Log.w(TAG, "Ignoring unknown tag found: " + tagName);
2201                                 break;
2202                         }
2203                     }
2204                 }
2205                 softApConfigBuilder.setBlockedClientList(blockedList);
2206                 softApConfigBuilder.setAllowedClientList(allowedList);
2207                 if (!hasBandChannelMap) {
2208                     // Set channel and band
2209                     if (channel == 0) {
2210                         softApConfigBuilder.setBand(apBand);
2211                     } else {
2212                         softApConfigBuilder.setChannel(channel, apBand);
2213                     }
2214                 }
2215 
2216                 // We should at least have an SSID restored from store.
2217                 if (!hasSsid) {
2218                     Log.e(TAG, "Failed to parse SSID");
2219                     return null;
2220                 }
2221                 if (!ApConfigUtil.isNonPasswordAP(securityType)) {
2222                     softApConfigBuilder.setPassphrase(passphrase, securityType);
2223                 }
2224                 if (!autoShutdownEnabledTagPresent) {
2225                     // Migrate data out of settings.
2226                     WifiMigration.SettingsMigrationData migrationData =
2227                             settingsMigrationDataHolder.retrieveData();
2228                     if (migrationData == null) {
2229                         Log.e(TAG, "No migration data present");
2230                     } else {
2231                         softApConfigBuilder.setAutoShutdownEnabled(
2232                                 migrationData.isSoftApTimeoutEnabled());
2233                     }
2234                 }
2235                 if (bssid != null && SdkLevel.isAtLeastS()) {
2236                     // Force MAC randomization setting to none when BSSID is configured
2237                     softApConfigBuilder.setMacRandomizationSetting(
2238                             SoftApConfiguration.RANDOMIZATION_NONE);
2239                 }
2240             } catch (IllegalArgumentException e) {
2241                 Log.e(TAG, "Failed to parse configuration " + e);
2242                 return null;
2243             }
2244             return softApConfigBuilder.build();
2245         } // End of parseFromXml
2246     }
2247 }
2248 
2249