• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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