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