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