• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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;
18 
19 import android.content.Context;
20 import android.net.IpConfiguration;
21 import android.net.wifi.WifiConfiguration;
22 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
23 import android.net.wifi.WifiEnterpriseConfig;
24 import android.os.Process;
25 import android.util.Log;
26 import android.util.Pair;
27 
28 import com.android.server.wifi.util.XmlUtil;
29 import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil;
30 import com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil;
31 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil;
32 import com.android.server.wifi.util.XmlUtil.WifiEnterpriseConfigXmlUtil;
33 
34 import org.xmlpull.v1.XmlPullParser;
35 import org.xmlpull.v1.XmlPullParserException;
36 import org.xmlpull.v1.XmlSerializer;
37 
38 import java.io.IOException;
39 import java.util.ArrayList;
40 import java.util.List;
41 
42 /**
43  * This class performs serialization and parsing of XML data block that contain the list of WiFi
44  * network configurations (XML block data inside <NetworkList> tag).
45  */
46 public abstract class NetworkListStoreData implements WifiConfigStore.StoreData {
47     private static final String TAG = "NetworkListStoreData";
48 
49     private static final String XML_TAG_SECTION_HEADER_NETWORK_LIST = "NetworkList";
50     private static final String XML_TAG_SECTION_HEADER_NETWORK = "Network";
51     private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration";
52     private static final String XML_TAG_SECTION_HEADER_NETWORK_STATUS = "NetworkStatus";
53     private static final String XML_TAG_SECTION_HEADER_IP_CONFIGURATION = "IpConfiguration";
54     private static final String XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION =
55             "WifiEnterpriseConfiguration";
56 
57     private final Context mContext;
58 
59     /**
60      * List of saved shared networks visible to all the users to be stored in the store file.
61      */
62     private List<WifiConfiguration> mConfigurations;
63 
NetworkListStoreData(Context context)64     NetworkListStoreData(Context context) {
65         mContext = context;
66     }
67 
68     @Override
serializeData(XmlSerializer out)69     public void serializeData(XmlSerializer out)
70             throws XmlPullParserException, IOException {
71         serializeNetworkList(out, mConfigurations);
72     }
73 
74     @Override
deserializeData(XmlPullParser in, int outerTagDepth)75     public void deserializeData(XmlPullParser in, int outerTagDepth)
76             throws XmlPullParserException, IOException {
77         // Ignore empty reads.
78         if (in == null) {
79             return;
80         }
81         mConfigurations = parseNetworkList(in, outerTagDepth);
82     }
83 
84     @Override
resetData()85     public void resetData() {
86         mConfigurations = null;
87     }
88 
89     @Override
hasNewDataToSerialize()90     public boolean hasNewDataToSerialize() {
91         // always persist.
92         return true;
93     }
94 
95     @Override
getName()96     public String getName() {
97         return XML_TAG_SECTION_HEADER_NETWORK_LIST;
98     }
99 
setConfigurations(List<WifiConfiguration> configs)100     public void setConfigurations(List<WifiConfiguration> configs) {
101         mConfigurations = configs;
102     }
103 
104     /**
105      * An empty list will be returned if no shared configurations.
106      *
107      * @return List of {@link WifiConfiguration}
108      */
getConfigurations()109     public List<WifiConfiguration> getConfigurations() {
110         if (mConfigurations == null) {
111             return new ArrayList<WifiConfiguration>();
112         }
113         return mConfigurations;
114     }
115 
116     /**
117      * Serialize the list of {@link WifiConfiguration} to an output stream in XML format.
118      *
119      * @param out The output stream to serialize the data to
120      * @param networkList The network list to serialize
121      * @throws XmlPullParserException
122      * @throws IOException
123      */
serializeNetworkList(XmlSerializer out, List<WifiConfiguration> networkList)124     private void serializeNetworkList(XmlSerializer out, List<WifiConfiguration> networkList)
125             throws XmlPullParserException, IOException {
126         if (networkList == null) {
127             return;
128         }
129         for (WifiConfiguration network : networkList) {
130             serializeNetwork(out, network);
131         }
132     }
133 
134     /**
135      * Serialize a {@link WifiConfiguration} to an output stream in XML format.
136      * @param out
137      * @param config
138      * @throws XmlPullParserException
139      * @throws IOException
140      */
serializeNetwork(XmlSerializer out, WifiConfiguration config)141     private void serializeNetwork(XmlSerializer out, WifiConfiguration config)
142             throws XmlPullParserException, IOException {
143         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK);
144 
145         // Serialize WifiConfiguration.
146         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
147         WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, config);
148         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
149 
150         // Serialize network selection status.
151         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS);
152         NetworkSelectionStatusXmlUtil.writeToXml(out, config.getNetworkSelectionStatus());
153         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS);
154 
155         // Serialize IP configuration.
156         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
157         IpConfigurationXmlUtil.writeToXml(out, config.getIpConfiguration());
158         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
159 
160         // Serialize enterprise configuration for enterprise networks.
161         if (config.enterpriseConfig != null
162                 && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) {
163             XmlUtil.writeNextSectionStart(
164                     out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
165             WifiEnterpriseConfigXmlUtil.writeToXml(out, config.enterpriseConfig);
166             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
167         }
168 
169         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK);
170     }
171 
172     /**
173      * Parse a list of {@link WifiConfiguration} from an input stream in XML format.
174      *
175      * @param in The input stream to read from
176      * @param outerTagDepth The XML tag depth of the outer XML block
177      * @return List of {@link WifiConfiguration}
178      * @throws XmlPullParserException
179      * @throws IOException
180      */
parseNetworkList(XmlPullParser in, int outerTagDepth)181     private List<WifiConfiguration> parseNetworkList(XmlPullParser in, int outerTagDepth)
182             throws XmlPullParserException, IOException {
183         List<WifiConfiguration> networkList = new ArrayList<>();
184         while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_NETWORK,
185                 outerTagDepth)) {
186             // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are
187             // fatal and should abort the entire loading process.
188             try {
189                 WifiConfiguration config = parseNetwork(in, outerTagDepth + 1);
190                 networkList.add(config);
191             } catch (RuntimeException e) {
192                 // Failed to parse this network, skip it.
193                 Log.e(TAG, "Failed to parse network config. Skipping...", e);
194             }
195         }
196         return networkList;
197     }
198 
199     /**
200      * Parse a {@link WifiConfiguration} from an input stream in XML format.
201      *
202      * @param in The input stream to read from
203      * @param outerTagDepth The XML tag depth of the outer XML block
204      * @return {@link WifiConfiguration}
205      * @throws XmlPullParserException
206      * @throws IOException
207      */
parseNetwork(XmlPullParser in, int outerTagDepth)208     private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth)
209             throws XmlPullParserException, IOException {
210         Pair<String, WifiConfiguration> parsedConfig = null;
211         NetworkSelectionStatus status = null;
212         IpConfiguration ipConfiguration = null;
213         WifiEnterpriseConfig enterpriseConfig = null;
214 
215         String[] headerName = new String[1];
216         while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) {
217             switch (headerName[0]) {
218                 case XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION:
219                     if (parsedConfig != null) {
220                         throw new XmlPullParserException("Detected duplicate tag for: "
221                                 + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
222                     }
223                     parsedConfig = WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
224                     break;
225                 case XML_TAG_SECTION_HEADER_NETWORK_STATUS:
226                     if (status != null) {
227                         throw new XmlPullParserException("Detected duplicate tag for: "
228                                 + XML_TAG_SECTION_HEADER_NETWORK_STATUS);
229                     }
230                     status = NetworkSelectionStatusXmlUtil.parseFromXml(in, outerTagDepth + 1);
231                     break;
232                 case XML_TAG_SECTION_HEADER_IP_CONFIGURATION:
233                     if (ipConfiguration != null) {
234                         throw new XmlPullParserException("Detected duplicate tag for: "
235                                 + XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
236                     }
237                     ipConfiguration = IpConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
238                     break;
239                 case XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION:
240                     if (enterpriseConfig != null) {
241                         throw new XmlPullParserException("Detected duplicate tag for: "
242                                 + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
243                     }
244                     enterpriseConfig =
245                             WifiEnterpriseConfigXmlUtil.parseFromXml(in, outerTagDepth + 1);
246                     break;
247                 default:
248                     throw new XmlPullParserException("Unknown tag under "
249                             + XML_TAG_SECTION_HEADER_NETWORK + ": " + headerName[0]);
250             }
251         }
252         if (parsedConfig == null || parsedConfig.first == null || parsedConfig.second == null) {
253             throw new XmlPullParserException("XML parsing of wifi configuration failed");
254         }
255         String configKeyParsed = parsedConfig.first;
256         WifiConfiguration configuration = parsedConfig.second;
257         String configKeyCalculated = configuration.configKey();
258         if (!configKeyParsed.equals(configKeyCalculated)) {
259             throw new XmlPullParserException(
260                     "Configuration key does not match. Retrieved: " + configKeyParsed
261                             + ", Calculated: " + configKeyCalculated);
262         }
263         // Set creatorUid/creatorName for networks which don't have it set to valid value.
264         String creatorName = mContext.getPackageManager().getNameForUid(configuration.creatorUid);
265         if (creatorName == null) {
266             Log.e(TAG, "Invalid creatorUid for saved network " + configuration.configKey()
267                     + ", creatorUid=" + configuration.creatorUid);
268             configuration.creatorUid = Process.SYSTEM_UID;
269             configuration.creatorName =
270                     mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID);
271         } else if (!creatorName.equals(configuration.creatorName)) {
272             Log.w(TAG, "Invalid creatorName for saved network " + configuration.configKey()
273                     + ", creatorUid=" + configuration.creatorUid
274                     + ", creatorName=" + configuration.creatorName);
275             configuration.creatorName = creatorName;
276         }
277 
278         configuration.setNetworkSelectionStatus(status);
279         configuration.setIpConfiguration(ipConfiguration);
280         if (enterpriseConfig != null) {
281             configuration.enterpriseConfig = enterpriseConfig;
282         }
283         return configuration;
284     }
285 }
286 
287