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