1 /*
2  * Copyright 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.annotation.Nullable;
20 import android.util.ArraySet;
21 import android.util.Log;
22 
23 import com.android.server.wifi.WifiConfigStore.StoreData;
24 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
25 import com.android.server.wifi.util.XmlUtil;
26 
27 import org.xmlpull.v1.XmlPullParser;
28 import org.xmlpull.v1.XmlPullParserException;
29 import org.xmlpull.v1.XmlSerializer;
30 
31 import java.io.IOException;
32 import java.util.Collections;
33 import java.util.Set;
34 
35 /**
36  * Config store data for Wifi Wake.
37  */
38 public class WakeupConfigStoreData implements StoreData {
39     private static final String TAG = "WakeupConfigStoreData";
40 
41     private static final String XML_TAG_FEATURE_STATE_SECTION = "FeatureState";
42     private static final String XML_TAG_IS_ACTIVE = "IsActive";
43     private static final String XML_TAG_IS_ONBOARDED = "IsOnboarded";
44     private static final String XML_TAG_NOTIFICATIONS_SHOWN = "NotificationsShown";
45     private static final String XML_TAG_NETWORK_SECTION = "Network";
46     private static final String XML_TAG_SSID = "SSID";
47     private static final String XML_TAG_SECURITY = "Security";
48 
49     private final DataSource<Boolean> mIsActiveDataSource;
50     private final DataSource<Boolean> mIsOnboardedDataSource;
51     private final DataSource<Integer> mNotificationsDataSource;
52     private final DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource;
53     private boolean mHasBeenRead = false;
54 
55     /**
56      * Interface defining a data source for the store data.
57      *
58      * @param <T> Type of data source
59      */
60     public interface DataSource<T> {
61         /**
62          * Returns the data from the data source.
63          */
getData()64         T getData();
65 
66         /**
67          * Updates the data in the data source.
68          *
69          * @param data Data retrieved from the store
70          */
setData(T data)71         void setData(T data);
72     }
73 
74     /**
75      * Creates the config store data with its data sources.
76      *
77      * @param isActiveDataSource Data source for isActive
78      * @param networkDataSource Data source for the locked network list
79      */
WakeupConfigStoreData( DataSource<Boolean> isActiveDataSource, DataSource<Boolean> isOnboardedDataSource, DataSource<Integer> notificationsDataSource, DataSource<Set<ScanResultMatchInfo>> networkDataSource)80     public WakeupConfigStoreData(
81             DataSource<Boolean> isActiveDataSource,
82             DataSource<Boolean> isOnboardedDataSource,
83             DataSource<Integer> notificationsDataSource,
84             DataSource<Set<ScanResultMatchInfo>> networkDataSource) {
85         mIsActiveDataSource = isActiveDataSource;
86         mIsOnboardedDataSource = isOnboardedDataSource;
87         mNotificationsDataSource = notificationsDataSource;
88         mNetworkDataSource = networkDataSource;
89     }
90 
91     /**
92      * Returns whether the user store has been read.
93      */
hasBeenRead()94     public boolean hasBeenRead() {
95         return mHasBeenRead;
96     }
97 
98     @Override
serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)99     public void serializeData(XmlSerializer out,
100             @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
101             throws XmlPullParserException, IOException {
102         writeFeatureState(out);
103 
104         for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) {
105             writeNetwork(out, scanResultMatchInfo);
106         }
107     }
108 
109     /**
110      * Writes the current state of Wifi Wake to an XML output stream.
111      *
112      * @param out XML output stream
113      * @throws XmlPullParserException
114      * @throws IOException
115      */
writeFeatureState(XmlSerializer out)116     private void writeFeatureState(XmlSerializer out)
117             throws IOException, XmlPullParserException {
118         XmlUtil.writeNextSectionStart(out, XML_TAG_FEATURE_STATE_SECTION);
119 
120         XmlUtil.writeNextValue(out, XML_TAG_IS_ACTIVE, mIsActiveDataSource.getData());
121         XmlUtil.writeNextValue(out, XML_TAG_IS_ONBOARDED, mIsOnboardedDataSource.getData());
122         XmlUtil.writeNextValue(out, XML_TAG_NOTIFICATIONS_SHOWN,
123                 mNotificationsDataSource.getData());
124 
125         XmlUtil.writeNextSectionEnd(out, XML_TAG_FEATURE_STATE_SECTION);
126     }
127 
128     /**
129      * Writes a {@link ScanResultMatchInfo} to an XML output stream.
130      *
131      * @param out XML output stream
132      * @param scanResultMatchInfo The ScanResultMatchInfo to serialize
133      * @throws XmlPullParserException
134      * @throws IOException
135      */
writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)136     private void writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)
137             throws XmlPullParserException, IOException {
138         XmlUtil.writeNextSectionStart(out, XML_TAG_NETWORK_SECTION);
139 
140         XmlUtil.writeNextValue(out, XML_TAG_SSID, scanResultMatchInfo.networkSsid);
141         XmlUtil.writeNextValue(out, XML_TAG_SECURITY, scanResultMatchInfo.networkType);
142 
143         XmlUtil.writeNextSectionEnd(out, XML_TAG_NETWORK_SECTION);
144     }
145 
146     @Override
deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)147     public void deserializeData(XmlPullParser in, int outerTagDepth,
148             @WifiConfigStore.Version int version,
149             @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
150             throws XmlPullParserException, IOException {
151         if (!mHasBeenRead) {
152             Log.d(TAG, "WifiWake user data has been read");
153             mHasBeenRead = true;
154         }
155         // Ignore empty reads.
156         if (in == null) {
157             return;
158         }
159 
160         Set<ScanResultMatchInfo> networks = new ArraySet<>();
161 
162         String[] headerName = new String[1];
163         while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) {
164             switch (headerName[0]) {
165                 case XML_TAG_FEATURE_STATE_SECTION:
166                     parseFeatureState(in, outerTagDepth + 1);
167                     break;
168                 case XML_TAG_NETWORK_SECTION:
169                     networks.add(parseNetwork(in, outerTagDepth + 1));
170                     break;
171             }
172         }
173 
174         mNetworkDataSource.setData(networks);
175     }
176 
177     /**
178      * Parses the state of Wifi Wake from an XML input stream and sets the respective data sources.
179      *
180      * @param in XML input stream
181      * @param outerTagDepth XML tag depth of the containing section
182      * @throws IOException
183      * @throws XmlPullParserException
184      */
parseFeatureState(XmlPullParser in, int outerTagDepth)185     private void parseFeatureState(XmlPullParser in, int outerTagDepth)
186             throws IOException, XmlPullParserException {
187         boolean isActive = false;
188         boolean isOnboarded = false;
189         int notificationsShown = 0;
190 
191         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
192             String[] valueName = new String[1];
193             Object value = XmlUtil.readCurrentValue(in, valueName);
194             if (valueName[0] == null) {
195                 throw new XmlPullParserException("Missing value name");
196             }
197             switch (valueName[0]) {
198                 case XML_TAG_IS_ACTIVE:
199                     isActive = (Boolean) value;
200                     break;
201                 case XML_TAG_IS_ONBOARDED:
202                     isOnboarded = (Boolean) value;
203                     break;
204                 case XML_TAG_NOTIFICATIONS_SHOWN:
205                     notificationsShown = (Integer) value;
206                     break;
207                 default:
208                     throw new XmlPullParserException("Unknown value found: " + valueName[0]);
209             }
210         }
211 
212         mIsActiveDataSource.setData(isActive);
213         mIsOnboardedDataSource.setData(isOnboarded);
214         mNotificationsDataSource.setData(notificationsShown);
215     }
216 
217     /**
218      * Parses a {@link ScanResultMatchInfo} from an XML input stream.
219      *
220      * @param in XML input stream
221      * @param outerTagDepth XML tag depth of the containing section
222      * @return The {@link ScanResultMatchInfo}
223      * @throws IOException
224      * @throws XmlPullParserException
225      */
parseNetwork(XmlPullParser in, int outerTagDepth)226     private ScanResultMatchInfo parseNetwork(XmlPullParser in, int outerTagDepth)
227             throws IOException, XmlPullParserException {
228         ScanResultMatchInfo scanResultMatchInfo = new ScanResultMatchInfo();
229         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
230             String[] valueName = new String[1];
231             Object value = XmlUtil.readCurrentValue(in, valueName);
232             if (valueName[0] == null) {
233                 throw new XmlPullParserException("Missing value name");
234             }
235             switch (valueName[0]) {
236                 case XML_TAG_SSID:
237                     scanResultMatchInfo.networkSsid = (String) value;
238                     break;
239                 case XML_TAG_SECURITY:
240                     scanResultMatchInfo.networkType = (int) value;
241                     break;
242                 default:
243                     throw new XmlPullParserException("Unknown tag under " + TAG + ": "
244                             + valueName[0]);
245             }
246         }
247 
248         return scanResultMatchInfo;
249     }
250 
251     @Override
resetData()252     public void resetData() {
253         mNetworkDataSource.setData(Collections.emptySet());
254         mIsActiveDataSource.setData(false);
255         mIsOnboardedDataSource.setData(false);
256         mNotificationsDataSource.setData(0);
257     }
258 
259     @Override
hasNewDataToSerialize()260     public boolean hasNewDataToSerialize() {
261         // always persist.
262         return true;
263     }
264 
265     @Override
getName()266     public String getName() {
267         return TAG;
268     }
269 
270     @Override
getStoreFileId()271     public @WifiConfigStore.StoreFileId int getStoreFileId() {
272         // Shared general store.
273         return WifiConfigStore.STORE_FILE_USER_GENERAL;
274     }
275 }
276