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.net.wifi.SecurityParams; 21 import android.util.ArraySet; 22 import android.util.Log; 23 24 import com.android.server.wifi.WifiConfigStore.StoreData; 25 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 26 import com.android.server.wifi.util.XmlUtil; 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.Collections; 34 import java.util.Set; 35 36 /** 37 * Config store data for Wifi Wake. 38 */ 39 public class WakeupConfigStoreData implements StoreData { 40 private static final String TAG = "WakeupConfigStoreData"; 41 42 private static final String XML_TAG_FEATURE_STATE_SECTION = "FeatureState"; 43 private static final String XML_TAG_IS_ACTIVE = "IsActive"; 44 private static final String XML_TAG_IS_ONBOARDED = "IsOnboarded"; 45 private static final String XML_TAG_NOTIFICATIONS_SHOWN = "NotificationsShown"; 46 private static final String XML_TAG_NETWORK_SECTION = "Network"; 47 private static final String XML_TAG_SSID = "SSID"; 48 private static final String XML_TAG_SECURITY = "Security"; 49 private static final String XML_TAG_SECURITY_PARAMS_LIST = "SecurityParamsList"; 50 private static final String XML_TAG_SECURITY_PARAMS = "SecurityParams"; 51 private static final String XML_TAG_SECURITY_TYPE = "SecurityType"; 52 private static final String XML_TAG_SAE_IS_H2E_ONLY_MODE = "SaeIsH2eOnlyMode"; 53 private static final String XML_TAG_SAE_IS_PK_ONLY_MODE = "SaeIsPkOnlyMode"; 54 private static final String XML_TAG_IS_ADDED_BY_AUTO_UPGRADE = "IsAddedByAutoUpgrade"; 55 56 private final DataSource<Boolean> mIsActiveDataSource; 57 private final DataSource<Boolean> mIsOnboardedDataSource; 58 private final DataSource<Integer> mNotificationsDataSource; 59 private final DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource; 60 private boolean mHasBeenRead = false; 61 62 /** 63 * Interface defining a data source for the store data. 64 * 65 * @param <T> Type of data source 66 */ 67 public interface DataSource<T> { 68 /** 69 * Returns the data from the data source. 70 */ getData()71 T getData(); 72 73 /** 74 * Updates the data in the data source. 75 * 76 * @param data Data retrieved from the store 77 */ setData(T data)78 void setData(T data); 79 } 80 81 /** 82 * Creates the config store data with its data sources. 83 * 84 * @param isActiveDataSource Data source for isActive 85 * @param networkDataSource Data source for the locked network list 86 */ WakeupConfigStoreData( DataSource<Boolean> isActiveDataSource, DataSource<Boolean> isOnboardedDataSource, DataSource<Integer> notificationsDataSource, DataSource<Set<ScanResultMatchInfo>> networkDataSource)87 public WakeupConfigStoreData( 88 DataSource<Boolean> isActiveDataSource, 89 DataSource<Boolean> isOnboardedDataSource, 90 DataSource<Integer> notificationsDataSource, 91 DataSource<Set<ScanResultMatchInfo>> networkDataSource) { 92 mIsActiveDataSource = isActiveDataSource; 93 mIsOnboardedDataSource = isOnboardedDataSource; 94 mNotificationsDataSource = notificationsDataSource; 95 mNetworkDataSource = networkDataSource; 96 } 97 98 /** 99 * Returns whether the user store has been read. 100 */ hasBeenRead()101 public boolean hasBeenRead() { 102 return mHasBeenRead; 103 } 104 105 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)106 public void serializeData(XmlSerializer out, 107 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 108 throws XmlPullParserException, IOException { 109 writeFeatureState(out); 110 111 for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) { 112 writeNetwork(out, scanResultMatchInfo); 113 } 114 } 115 116 /** 117 * Writes the current state of Wifi Wake to an XML output stream. 118 * 119 * @param out XML output stream 120 * @throws XmlPullParserException 121 * @throws IOException 122 */ writeFeatureState(XmlSerializer out)123 private void writeFeatureState(XmlSerializer out) 124 throws IOException, XmlPullParserException { 125 XmlUtil.writeNextSectionStart(out, XML_TAG_FEATURE_STATE_SECTION); 126 127 XmlUtil.writeNextValue(out, XML_TAG_IS_ACTIVE, mIsActiveDataSource.getData()); 128 XmlUtil.writeNextValue(out, XML_TAG_IS_ONBOARDED, mIsOnboardedDataSource.getData()); 129 XmlUtil.writeNextValue(out, XML_TAG_NOTIFICATIONS_SHOWN, 130 mNotificationsDataSource.getData()); 131 132 XmlUtil.writeNextSectionEnd(out, XML_TAG_FEATURE_STATE_SECTION); 133 } 134 writeSecurityParamsList( XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)135 private void writeSecurityParamsList( 136 XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo) 137 throws XmlPullParserException, IOException { 138 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS_LIST); 139 for (SecurityParams params: scanResultMatchInfo.securityParamsList) { 140 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS); 141 XmlUtil.writeNextValue( 142 out, XML_TAG_SECURITY_TYPE, 143 params.getSecurityType()); 144 XmlUtil.writeNextValue( 145 out, XML_TAG_SAE_IS_H2E_ONLY_MODE, 146 params.isSaeH2eOnlyMode()); 147 XmlUtil.writeNextValue( 148 out, XML_TAG_SAE_IS_PK_ONLY_MODE, 149 params.isSaePkOnlyMode()); 150 XmlUtil.writeNextValue( 151 out, XML_TAG_IS_ADDED_BY_AUTO_UPGRADE, 152 params.isAddedByAutoUpgrade()); 153 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS); 154 } 155 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS_LIST); 156 } 157 158 /** 159 * Writes a {@link ScanResultMatchInfo} to an XML output stream. 160 * 161 * @param out XML output stream 162 * @param scanResultMatchInfo The ScanResultMatchInfo to serialize 163 * @throws XmlPullParserException 164 * @throws IOException 165 */ writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)166 private void writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo) 167 throws XmlPullParserException, IOException { 168 XmlUtil.writeNextSectionStart(out, XML_TAG_NETWORK_SECTION); 169 170 XmlUtil.writeNextValue(out, XML_TAG_SSID, scanResultMatchInfo.networkSsid); 171 writeSecurityParamsList(out, scanResultMatchInfo); 172 173 XmlUtil.writeNextSectionEnd(out, XML_TAG_NETWORK_SECTION); 174 } 175 176 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)177 public void deserializeData(XmlPullParser in, int outerTagDepth, 178 @WifiConfigStore.Version int version, 179 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 180 throws XmlPullParserException, IOException { 181 if (!mHasBeenRead) { 182 Log.d(TAG, "WifiWake user data has been read"); 183 mHasBeenRead = true; 184 } 185 // Ignore empty reads. 186 if (in == null) { 187 return; 188 } 189 190 Set<ScanResultMatchInfo> networks = new ArraySet<>(); 191 192 String[] headerName = new String[1]; 193 while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) { 194 switch (headerName[0]) { 195 case XML_TAG_FEATURE_STATE_SECTION: 196 parseFeatureState(in, outerTagDepth + 1); 197 break; 198 case XML_TAG_NETWORK_SECTION: 199 networks.add(parseNetwork(in, outerTagDepth + 1)); 200 break; 201 } 202 } 203 204 mNetworkDataSource.setData(networks); 205 } 206 207 /** 208 * Parses the state of Wifi Wake from an XML input stream and sets the respective data sources. 209 * 210 * @param in XML input stream 211 * @param outerTagDepth XML tag depth of the containing section 212 * @throws IOException 213 * @throws XmlPullParserException 214 */ parseFeatureState(XmlPullParser in, int outerTagDepth)215 private void parseFeatureState(XmlPullParser in, int outerTagDepth) 216 throws IOException, XmlPullParserException { 217 boolean isActive = false; 218 boolean isOnboarded = false; 219 int notificationsShown = 0; 220 221 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 222 String[] valueName = new String[1]; 223 Object value = XmlUtil.readCurrentValue(in, valueName); 224 if (valueName[0] == null) { 225 throw new XmlPullParserException("Missing value name"); 226 } 227 switch (valueName[0]) { 228 case XML_TAG_IS_ACTIVE: 229 isActive = (Boolean) value; 230 break; 231 case XML_TAG_IS_ONBOARDED: 232 isOnboarded = (Boolean) value; 233 break; 234 case XML_TAG_NOTIFICATIONS_SHOWN: 235 notificationsShown = (Integer) value; 236 break; 237 default: 238 Log.w(TAG, "Unknown value found: " + valueName[0]); 239 break; 240 } 241 } 242 243 mIsActiveDataSource.setData(isActive); 244 mIsOnboardedDataSource.setData(isOnboarded); 245 mNotificationsDataSource.setData(notificationsShown); 246 } 247 parseSecurityParams(XmlPullParser in, int outerTagDepth)248 private SecurityParams parseSecurityParams(XmlPullParser in, int outerTagDepth) 249 throws IOException, XmlPullParserException { 250 SecurityParams params = null; 251 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 252 String[] valueName = new String[1]; 253 Object value = XmlUtil.readCurrentValue(in, valueName); 254 String tagName = valueName[0]; 255 if (tagName == null) { 256 throw new XmlPullParserException("Missing value name"); 257 } 258 switch (tagName) { 259 case XML_TAG_SECURITY_TYPE: 260 params = SecurityParams.createSecurityParamsBySecurityType((int) value); 261 break; 262 case XML_TAG_SAE_IS_H2E_ONLY_MODE: 263 if (null == params) { 264 throw new XmlPullParserException("Missing security type."); 265 } 266 params.enableSaeH2eOnlyMode((boolean) value); 267 break; 268 case XML_TAG_SAE_IS_PK_ONLY_MODE: 269 if (null == params) { 270 throw new XmlPullParserException("Missing security type."); 271 } 272 params.enableSaePkOnlyMode((boolean) value); 273 break; 274 case XML_TAG_IS_ADDED_BY_AUTO_UPGRADE: 275 if (null == params) { 276 throw new XmlPullParserException("Missing security type."); 277 } 278 params.setIsAddedByAutoUpgrade((boolean) value); 279 break; 280 } 281 } 282 return params; 283 } 284 parseSecurityParamsList( XmlPullParser in, int outerTagDepth, ScanResultMatchInfo scanResultMatchInfo)285 private void parseSecurityParamsList( 286 XmlPullParser in, int outerTagDepth, ScanResultMatchInfo scanResultMatchInfo) 287 throws IOException, XmlPullParserException { 288 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 289 switch (in.getName()) { 290 case XML_TAG_SECURITY_PARAMS: 291 SecurityParams params = parseSecurityParams(in, outerTagDepth + 1); 292 if (null != params) { 293 scanResultMatchInfo.securityParamsList.add(params); 294 } 295 break; 296 } 297 } 298 299 } 300 301 /** 302 * Parses a {@link ScanResultMatchInfo} from an XML input stream. 303 * 304 * @param in XML input stream 305 * @param outerTagDepth XML tag depth of the containing section 306 * @return The {@link ScanResultMatchInfo} 307 * @throws IOException 308 * @throws XmlPullParserException 309 */ parseNetwork(XmlPullParser in, int outerTagDepth)310 private ScanResultMatchInfo parseNetwork(XmlPullParser in, int outerTagDepth) 311 throws IOException, XmlPullParserException { 312 ScanResultMatchInfo scanResultMatchInfo = new ScanResultMatchInfo(); 313 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 314 if (in.getAttributeValue(null, "name") == null) { 315 String tagName = in.getName(); 316 if (tagName == null) { 317 throw new XmlPullParserException("Unexpected null tag found"); 318 } 319 switch (tagName) { 320 case XML_TAG_SECURITY_PARAMS_LIST: 321 parseSecurityParamsList(in, outerTagDepth + 1, scanResultMatchInfo); 322 break; 323 } 324 continue; 325 } 326 327 String[] valueName = new String[1]; 328 Object value = XmlUtil.readCurrentValue(in, valueName); 329 if (valueName[0] == null) { 330 throw new XmlPullParserException("Missing value name"); 331 } 332 switch (valueName[0]) { 333 case XML_TAG_SSID: 334 scanResultMatchInfo.networkSsid = (String) value; 335 break; 336 case XML_TAG_SECURITY: 337 // Migrate data from R to S. 338 scanResultMatchInfo.securityParamsList.add( 339 SecurityParams.createSecurityParamsBySecurityType((int) value)); 340 break; 341 default: 342 Log.w(TAG, "Ignoring unknown tag under " + TAG + ": " + valueName[0]); 343 break; 344 } 345 } 346 347 return scanResultMatchInfo; 348 } 349 350 @Override resetData()351 public void resetData() { 352 mNetworkDataSource.setData(Collections.emptySet()); 353 mIsActiveDataSource.setData(false); 354 mIsOnboardedDataSource.setData(false); 355 mNotificationsDataSource.setData(0); 356 } 357 358 @Override hasNewDataToSerialize()359 public boolean hasNewDataToSerialize() { 360 // always persist. 361 return true; 362 } 363 364 @Override getName()365 public String getName() { 366 return TAG; 367 } 368 369 @Override getStoreFileId()370 public @WifiConfigStore.StoreFileId int getStoreFileId() { 371 // Shared general store. 372 return WifiConfigStore.STORE_FILE_USER_GENERAL; 373 } 374 } 375