1 /* 2 * Copyright (C) 2018 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.annotation.Nullable; 20 import android.net.MacAddress; 21 import android.util.Log; 22 23 import com.android.server.wifi.WifiNetworkFactory.AccessPoint; 24 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 25 import com.android.server.wifi.util.XmlUtil; 26 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; 27 28 import org.xmlpull.v1.XmlPullParser; 29 import org.xmlpull.v1.XmlPullParserException; 30 import org.xmlpull.v1.XmlSerializer; 31 32 import java.io.IOException; 33 import java.util.HashMap; 34 import java.util.LinkedHashSet; 35 import java.util.Map; 36 import java.util.Map.Entry; 37 import java.util.Set; 38 39 /** 40 * This class performs serialization and parsing of XML data block that contain the list of WiFi 41 * network request approvals. 42 */ 43 public class NetworkRequestStoreData implements WifiConfigStore.StoreData { 44 private static final String TAG = "NetworkRequestStoreData"; 45 46 private static final String XML_TAG_SECTION_HEADER_NETWORK_REQUEST_MAP = 47 "NetworkRequestMap"; 48 private static final String XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP = 49 "ApprovedAccessPointsPerApp"; 50 private static final String XML_TAG_REQUESTOR_PACKAGE_NAME = "RequestorPackageName"; 51 private static final String XML_TAG_SECTION_HEADER_ACCESS_POINT = "AccessPoint"; 52 private static final String XML_TAG_ACCESS_POINT_SSID = WifiConfigurationXmlUtil.XML_TAG_SSID; 53 private static final String XML_TAG_ACCESS_POINT_BSSID = WifiConfigurationXmlUtil.XML_TAG_BSSID; 54 private static final String XML_TAG_ACCESS_POINT_NETWORK_TYPE = "NetworkType"; 55 56 /** 57 * Interface define the data source for the network requests store data. 58 */ 59 public interface DataSource { 60 /** 61 * Retrieve the approved access points from the data source to serialize them to disk. 62 * 63 * @return Map of package name to a set of {@link AccessPoint} 64 */ toSerialize()65 Map<String, Set<AccessPoint>> toSerialize(); 66 67 /** 68 * Set the approved access points in the data source after serializing them from disk. 69 * 70 * @param approvedAccessPoints Map of package name to {@link AccessPoint} 71 */ fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPoints)72 void fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPoints); 73 74 /** 75 * Clear internal data structure in preparation for user switch or initial store read. 76 */ reset()77 void reset(); 78 79 /** 80 * Indicates whether there is new data to serialize. 81 */ hasNewDataToSerialize()82 boolean hasNewDataToSerialize(); 83 } 84 85 private final DataSource mDataSource; 86 NetworkRequestStoreData(DataSource dataSource)87 public NetworkRequestStoreData(DataSource dataSource) { 88 mDataSource = dataSource; 89 } 90 91 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)92 public void serializeData(XmlSerializer out, 93 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 94 throws XmlPullParserException, IOException { 95 serializeApprovedAccessPointsMap(out, mDataSource.toSerialize()); 96 } 97 98 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)99 public void deserializeData(XmlPullParser in, int outerTagDepth, 100 @WifiConfigStore.Version int version, 101 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 102 throws XmlPullParserException, IOException { 103 // Ignore empty reads. 104 if (in == null) { 105 return; 106 } 107 mDataSource.fromDeserialized(parseApprovedAccessPointsMap(in, outerTagDepth)); 108 } 109 110 @Override resetData()111 public void resetData() { 112 mDataSource.reset(); 113 } 114 115 @Override hasNewDataToSerialize()116 public boolean hasNewDataToSerialize() { 117 return mDataSource.hasNewDataToSerialize(); 118 } 119 120 @Override getName()121 public String getName() { 122 return XML_TAG_SECTION_HEADER_NETWORK_REQUEST_MAP; 123 } 124 125 @Override getStoreFileId()126 public @WifiConfigStore.StoreFileId int getStoreFileId() { 127 return WifiConfigStore.STORE_FILE_USER_GENERAL; 128 } 129 130 /** 131 * Serialize the map of package name to approved access points to an output stream in XML 132 * format. 133 * 134 * @throws XmlPullParserException 135 * @throws IOException 136 */ serializeApprovedAccessPointsMap( XmlSerializer out, final Map<String, Set<AccessPoint>> approvedAccessPointsMap)137 private void serializeApprovedAccessPointsMap( 138 XmlSerializer out, final Map<String, Set<AccessPoint>> approvedAccessPointsMap) 139 throws XmlPullParserException, IOException { 140 if (approvedAccessPointsMap == null) { 141 return; 142 } 143 for (Entry<String, Set<AccessPoint>> entry : approvedAccessPointsMap.entrySet()) { 144 String packageName = entry.getKey(); 145 XmlUtil.writeNextSectionStart(out, 146 XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP); 147 XmlUtil.writeNextValue(out, XML_TAG_REQUESTOR_PACKAGE_NAME, packageName); 148 serializeApprovedAccessPoints(out, entry.getValue()); 149 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP); 150 } 151 } 152 153 /** 154 * Serialize the set of approved access points to an output stream in XML format. 155 * 156 * @throws XmlPullParserException 157 * @throws IOException 158 */ serializeApprovedAccessPoints( XmlSerializer out, final Set<AccessPoint> approvedAccessPoints)159 private void serializeApprovedAccessPoints( 160 XmlSerializer out, final Set<AccessPoint> approvedAccessPoints) 161 throws XmlPullParserException, IOException { 162 for (AccessPoint approvedAccessPoint : approvedAccessPoints) { 163 serializeApprovedAccessPoint(out, approvedAccessPoint); 164 } 165 } 166 167 /** 168 * Serialize a {@link AccessPoint} to an output stream in XML format. 169 * 170 * @throws XmlPullParserException 171 * @throws IOException 172 */ serializeApprovedAccessPoint(XmlSerializer out, AccessPoint approvedAccessPoint)173 private void serializeApprovedAccessPoint(XmlSerializer out, 174 AccessPoint approvedAccessPoint) 175 throws XmlPullParserException, IOException { 176 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_ACCESS_POINT); 177 XmlUtil.writeNextValue(out, XML_TAG_ACCESS_POINT_SSID, approvedAccessPoint.ssid); 178 XmlUtil.writeNextValue(out, XML_TAG_ACCESS_POINT_BSSID, 179 approvedAccessPoint.bssid.toString()); 180 XmlUtil.writeNextValue(out, XML_TAG_ACCESS_POINT_NETWORK_TYPE, 181 approvedAccessPoint.networkType); 182 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_ACCESS_POINT); 183 } 184 185 /** 186 * Parse a map of package name to approved access point from an input stream in XML format. 187 * 188 * @throws XmlPullParserException 189 * @throws IOException 190 */ parseApprovedAccessPointsMap(XmlPullParser in, int outerTagDepth)191 private Map<String, Set<AccessPoint>> parseApprovedAccessPointsMap(XmlPullParser in, 192 int outerTagDepth) 193 throws XmlPullParserException, IOException { 194 Map<String, Set<AccessPoint>> approvedAccessPointsMap = new HashMap<>(); 195 while (XmlUtil.gotoNextSectionWithNameOrEnd( 196 in, XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP, outerTagDepth)) { 197 // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are 198 // fatal and should abort the entire loading process. 199 try { 200 String packageName = 201 (String) XmlUtil.readNextValueWithName(in, XML_TAG_REQUESTOR_PACKAGE_NAME); 202 Set<AccessPoint> approvedAccessPoints = 203 parseApprovedAccessPoints(in, outerTagDepth + 1); 204 approvedAccessPointsMap.put(packageName, approvedAccessPoints); 205 } catch (RuntimeException e) { 206 // Failed to parse this network, skip it. 207 Log.e(TAG, "Failed to parse network suggestion. Skipping...", e); 208 } 209 } 210 return approvedAccessPointsMap; 211 } 212 213 /** 214 * Parse a set of approved access points from an input stream in XML format. 215 * 216 * @throws XmlPullParserException 217 * @throws IOException 218 */ parseApprovedAccessPoints(XmlPullParser in, int outerTagDepth)219 private Set<AccessPoint> parseApprovedAccessPoints(XmlPullParser in, int outerTagDepth) 220 throws XmlPullParserException, IOException { 221 Set<AccessPoint> approvedAccessPoints = new LinkedHashSet<>(); 222 while (XmlUtil.gotoNextSectionWithNameOrEnd( 223 in, XML_TAG_SECTION_HEADER_ACCESS_POINT, outerTagDepth)) { 224 // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are 225 // fatal and should abort the entire loading process. 226 try { 227 AccessPoint approvedAccessPoint = 228 parseApprovedAccessPoint(in, outerTagDepth + 1); 229 approvedAccessPoints.add(approvedAccessPoint); 230 } catch (RuntimeException e) { 231 // Failed to parse this network, skip it. 232 Log.e(TAG, "Failed to parse network suggestion. Skipping...", e); 233 } 234 } 235 return approvedAccessPoints; 236 } 237 238 /** 239 * Parse a {@link AccessPoint} from an input stream in XML format. 240 * 241 * @throws XmlPullParserException 242 * @throws IOException 243 */ parseApprovedAccessPoint(XmlPullParser in, int outerTagDepth)244 private AccessPoint parseApprovedAccessPoint(XmlPullParser in, int outerTagDepth) 245 throws XmlPullParserException, IOException { 246 String ssid = null; 247 MacAddress bssid = null; 248 int networkType = -1; 249 250 // Loop through and parse out all the elements from the stream within this section. 251 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 252 String[] valueName = new String[1]; 253 Object value = XmlUtil.readCurrentValue(in, valueName); 254 if (valueName[0] == null) { 255 throw new XmlPullParserException("Missing value name"); 256 } 257 switch (valueName[0]) { 258 case XML_TAG_ACCESS_POINT_SSID: 259 ssid = (String) value; 260 break; 261 case XML_TAG_ACCESS_POINT_BSSID: 262 bssid = MacAddress.fromString((String) value); 263 break; 264 case XML_TAG_ACCESS_POINT_NETWORK_TYPE: 265 networkType = (int) value; 266 break; 267 default: 268 Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); 269 break; 270 } 271 } 272 if (ssid == null) { 273 throw new XmlPullParserException("XML parsing of ssid failed"); 274 } 275 if (bssid == null) { 276 throw new XmlPullParserException("XML parsing of bssid failed"); 277 } 278 if (networkType == -1) { 279 throw new XmlPullParserException("XML parsing of network type failed"); 280 } 281 return new AccessPoint(ssid, bssid, networkType); 282 } 283 } 284 285