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 static com.android.server.wifi.WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION; 20 21 import android.annotation.Nullable; 22 import android.net.wifi.WifiConfiguration; 23 import android.net.wifi.WifiEnterpriseConfig; 24 import android.net.wifi.WifiNetworkSuggestion; 25 import android.net.wifi.hotspot2.PasspointConfiguration; 26 import android.os.Process; 27 import android.telephony.TelephonyManager; 28 import android.util.Log; 29 import android.util.Pair; 30 31 import com.android.server.wifi.WifiNetworkSuggestionsManager.ExtendedWifiNetworkSuggestion; 32 import com.android.server.wifi.WifiNetworkSuggestionsManager.PerAppInfo; 33 import com.android.server.wifi.hotspot2.PasspointXmlUtils; 34 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 35 import com.android.server.wifi.util.XmlUtil; 36 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; 37 38 import org.xmlpull.v1.XmlPullParser; 39 import org.xmlpull.v1.XmlPullParserException; 40 import org.xmlpull.v1.XmlSerializer; 41 42 import java.io.IOException; 43 import java.util.Collection; 44 import java.util.Collections; 45 import java.util.HashMap; 46 import java.util.Map; 47 import java.util.Map.Entry; 48 49 /** 50 * This class performs serialization and parsing of XML data block that contain the list of WiFi 51 * network suggestions. 52 */ 53 public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { 54 private static final String TAG = "NetworkSuggestionStoreData"; 55 56 private static final String XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_MAP = 57 "NetworkSuggestionMap"; 58 private static final String XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP = 59 "NetworkSuggestionPerApp"; 60 private static final String XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION = "NetworkSuggestion"; 61 private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration"; 62 private static final String XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION = 63 "WifiEnterpriseConfiguration"; 64 private static final String XML_TAG_IS_APP_INTERACTION_REQUIRED = "IsAppInteractionRequired"; 65 private static final String XML_TAG_IS_USER_INTERACTION_REQUIRED = "IsUserInteractionRequired"; 66 private static final String XML_TAG_IS_USER_ALLOWED_TO_MANUALLY_CONNECT = 67 "IsUserAllowedToManuallyConnect"; 68 private static final String XML_TAG_IS_INITIALIZED_AUTO_JOIN = "InitializedAutoJoinEnabled"; 69 private static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled"; 70 private static final String XML_TAG_SUGGESTOR_UID = "SuggestorUid"; 71 private static final String XML_TAG_SUGGESTOR_PACKAGE_NAME = "SuggestorPackageName"; 72 private static final String XML_TAG_SUGGESTOR_FEATURE_ID = "SuggestorFeatureId"; 73 private static final String XML_TAG_SUGGESTOR_HAS_USER_APPROVED = "SuggestorHasUserApproved"; 74 private static final String XML_TAG_SUGGESTOR_CARRIER_ID = "SuggestorCarrierId"; 75 private static final String XML_TAG_SUGGESTOR_MAX_SIZE = "SuggestorMaxSize"; 76 private static final String XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION = 77 "PasspointConfiguration"; 78 private static final String XML_TAG_PRIORITY_GROUP = "PriorityGroup"; 79 private static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice"; 80 private static final String XML_TAG_CONNECT_CHOICE_RSSI = "ConnectChoiceRssi"; 81 82 /** 83 * Interface define the data source for the network suggestions store data. 84 */ 85 public interface DataSource { 86 /** 87 * Retrieve the network suggestion list from the data source to serialize them to disk. 88 * 89 * @return Map of package name to {@link PerAppInfo} 90 */ toSerialize()91 Map<String, PerAppInfo> toSerialize(); 92 93 /** 94 * Set the network suggestions list in the data source after serializing them from disk. 95 * 96 * @param networkSuggestions Map of package name to {@link PerAppInfo} 97 */ fromDeserialized(Map<String, PerAppInfo> networkSuggestions)98 void fromDeserialized(Map<String, PerAppInfo> networkSuggestions); 99 100 /** 101 * Clear internal data structure in preparation for user switch or initial store read. 102 */ reset()103 void reset(); 104 105 /** 106 * Indicates whether there is new data to serialize. 107 */ hasNewDataToSerialize()108 boolean hasNewDataToSerialize(); 109 } 110 111 private final DataSource mDataSource; 112 NetworkSuggestionStoreData(DataSource dataSource)113 public NetworkSuggestionStoreData(DataSource dataSource) { 114 mDataSource = dataSource; 115 } 116 117 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)118 public void serializeData(XmlSerializer out, 119 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 120 throws XmlPullParserException, IOException { 121 serializeNetworkSuggestionsMap(out, mDataSource.toSerialize(), encryptionUtil); 122 } 123 124 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)125 public void deserializeData(XmlPullParser in, int outerTagDepth, 126 @WifiConfigStore.Version int version, 127 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 128 throws XmlPullParserException, IOException { 129 if (in == null) { 130 mDataSource.fromDeserialized(Collections.EMPTY_MAP); 131 return; 132 } 133 mDataSource.fromDeserialized( 134 parseNetworkSuggestionsMap(in, outerTagDepth, version, encryptionUtil)); 135 } 136 137 @Override resetData()138 public void resetData() { 139 mDataSource.reset(); 140 } 141 142 @Override hasNewDataToSerialize()143 public boolean hasNewDataToSerialize() { 144 return mDataSource.hasNewDataToSerialize(); 145 } 146 147 @Override getName()148 public String getName() { 149 return XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_MAP; 150 } 151 152 @Override getStoreFileId()153 public @WifiConfigStore.StoreFileId int getStoreFileId() { 154 return WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS; 155 } 156 157 /** 158 * Serialize the map of package name to network suggestions to an output stream in XML format. 159 * 160 * @throws XmlPullParserException 161 * @throws IOException 162 */ serializeNetworkSuggestionsMap( XmlSerializer out, final Map<String, PerAppInfo> networkSuggestionsMap, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)163 private void serializeNetworkSuggestionsMap( 164 XmlSerializer out, final Map<String, PerAppInfo> networkSuggestionsMap, 165 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 166 throws XmlPullParserException, IOException { 167 if (networkSuggestionsMap == null) { 168 return; 169 } 170 for (Entry<String, PerAppInfo> entry : networkSuggestionsMap.entrySet()) { 171 String packageName = entry.getValue().packageName; 172 String featureId = entry.getValue().featureId; 173 boolean hasUserApproved = entry.getValue().hasUserApproved; 174 int maxSize = entry.getValue().maxSize; 175 int uid = entry.getValue().uid; 176 int carrierId = entry.getValue().carrierId; 177 Collection<ExtendedWifiNetworkSuggestion> networkSuggestions = 178 entry.getValue().extNetworkSuggestions.values(); 179 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP); 180 XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_PACKAGE_NAME, packageName); 181 XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_FEATURE_ID, featureId); 182 XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_HAS_USER_APPROVED, hasUserApproved); 183 XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_MAX_SIZE, maxSize); 184 XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_UID, uid); 185 XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_CARRIER_ID, carrierId); 186 serializeExtNetworkSuggestions(out, networkSuggestions, encryptionUtil); 187 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP); 188 } 189 } 190 191 /** 192 * Serialize the set of network suggestions to an output stream in XML format. 193 * 194 * @throws XmlPullParserException 195 * @throws IOException 196 */ serializeExtNetworkSuggestions(XmlSerializer out, final Collection<ExtendedWifiNetworkSuggestion> extNetworkSuggestions, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)197 private void serializeExtNetworkSuggestions(XmlSerializer out, 198 final Collection<ExtendedWifiNetworkSuggestion> extNetworkSuggestions, 199 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 200 throws XmlPullParserException, IOException { 201 for (ExtendedWifiNetworkSuggestion extNetworkSuggestion : extNetworkSuggestions) { 202 serializeNetworkSuggestion(out, extNetworkSuggestion, encryptionUtil); 203 } 204 } 205 206 /** 207 * Serialize a {@link ExtendedWifiNetworkSuggestion} to an output stream in XML format. 208 * 209 * @throws XmlPullParserException 210 * @throws IOException 211 */ serializeNetworkSuggestion(XmlSerializer out, final ExtendedWifiNetworkSuggestion extSuggestion, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)212 private void serializeNetworkSuggestion(XmlSerializer out, 213 final ExtendedWifiNetworkSuggestion extSuggestion, 214 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 215 throws XmlPullParserException, IOException { 216 WifiNetworkSuggestion suggestion = extSuggestion.wns; 217 218 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION); 219 220 // Serialize WifiConfiguration. 221 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); 222 WifiConfigurationXmlUtil.writeToXmlForConfigStore( 223 out, suggestion.wifiConfiguration, encryptionUtil); 224 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); 225 // Serialize enterprise configuration for enterprise networks. 226 if (suggestion.wifiConfiguration.enterpriseConfig != null 227 && suggestion.wifiConfiguration.enterpriseConfig.getEapMethod() 228 != WifiEnterpriseConfig.Eap.NONE) { 229 XmlUtil.writeNextSectionStart( 230 out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); 231 XmlUtil.WifiEnterpriseConfigXmlUtil.writeToXml( 232 out, suggestion.wifiConfiguration.enterpriseConfig, encryptionUtil); 233 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); 234 } 235 if (suggestion.passpointConfiguration != null) { 236 XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION); 237 PasspointXmlUtils.serializePasspointConfiguration(out, 238 suggestion.passpointConfiguration); 239 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION); 240 } 241 242 // Serialize other fields 243 XmlUtil.writeNextValue(out, XML_TAG_IS_APP_INTERACTION_REQUIRED, 244 suggestion.isAppInteractionRequired); 245 XmlUtil.writeNextValue(out, XML_TAG_IS_USER_INTERACTION_REQUIRED, 246 suggestion.isUserInteractionRequired); 247 XmlUtil.writeNextValue(out, XML_TAG_IS_USER_ALLOWED_TO_MANUALLY_CONNECT, 248 suggestion.isUserAllowedToManuallyConnect); 249 XmlUtil.writeNextValue(out, XML_TAG_IS_INITIALIZED_AUTO_JOIN, 250 suggestion.isInitialAutoJoinEnabled); 251 XmlUtil.writeNextValue(out, XML_TAG_IS_AUTO_JOIN, 252 extSuggestion.isAutojoinEnabled); 253 XmlUtil.writeNextValue(out, XML_TAG_PRIORITY_GROUP, suggestion.priorityGroup); 254 XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, extSuggestion.connectChoice); 255 XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE_RSSI, extSuggestion.connectChoiceRssi); 256 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION); 257 } 258 259 /** 260 * Parse a map of package name to network suggestions from an input stream in XML format. 261 * 262 * @throws XmlPullParserException 263 * @throws IOException 264 */ parseNetworkSuggestionsMap(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)265 private Map<String, PerAppInfo> parseNetworkSuggestionsMap(XmlPullParser in, int outerTagDepth, 266 @WifiConfigStore.Version int version, 267 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 268 throws XmlPullParserException, IOException { 269 Map<String, PerAppInfo> networkSuggestionsMap = new HashMap<>(); 270 while (XmlUtil.gotoNextSectionWithNameOrEnd( 271 in, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP, outerTagDepth)) { 272 // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are 273 // fatal and should abort the entire loading process. 274 try { 275 PerAppInfo perAppInfo = null; 276 String packageName = null; 277 String featureId = null; 278 boolean hasUserApproved = false; 279 int maxSize = -1; 280 int uid = Process.INVALID_UID; 281 int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 282 // Loop through and parse out all the elements from the stream within this section. 283 while (XmlUtil.nextElementWithin(in, outerTagDepth + 1)) { 284 if (in.getAttributeValue(null, "name") != null) { 285 // Value elements. 286 String[] valueName = new String[1]; 287 Object value = XmlUtil.readCurrentValue(in, valueName); 288 switch (valueName[0]) { 289 case XML_TAG_SUGGESTOR_PACKAGE_NAME: 290 packageName = (String) value; 291 break; 292 case XML_TAG_SUGGESTOR_FEATURE_ID: 293 featureId = (String) value; 294 break; 295 case XML_TAG_SUGGESTOR_HAS_USER_APPROVED: 296 hasUserApproved = (boolean) value; 297 break; 298 case XML_TAG_SUGGESTOR_MAX_SIZE: 299 maxSize = (int) value; 300 break; 301 case XML_TAG_SUGGESTOR_UID: 302 uid = (int) value; 303 break; 304 case XML_TAG_SUGGESTOR_CARRIER_ID: 305 carrierId = (int) value; 306 break; 307 default: 308 Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); 309 break; 310 } 311 } else { 312 String tagName = in.getName(); 313 if (tagName == null) { 314 throw new XmlPullParserException("Unexpected null under " 315 + XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP); 316 } 317 // Create the PerAppInfo struct before parsing individual network 318 // suggestions in the block. 319 if (perAppInfo == null) { 320 if (packageName == null) { 321 throw new XmlPullParserException( 322 "XML parsing of PerAppInfo failed"); 323 } 324 perAppInfo = new PerAppInfo(uid, packageName, featureId); 325 perAppInfo.hasUserApproved = hasUserApproved; 326 perAppInfo.maxSize = maxSize; 327 perAppInfo.carrierId = carrierId; 328 } 329 switch (tagName) { 330 case XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION: 331 ExtendedWifiNetworkSuggestion ewns = parseNetworkSuggestion(in, 332 outerTagDepth + 2, version, encryptionUtil, perAppInfo); 333 perAppInfo.extNetworkSuggestions.put(ewns.hashCode(), ewns); 334 break; 335 default: 336 Log.w(TAG, "Ignoring unknown tag under " 337 + XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP + ": " 338 + in.getName()); 339 break; 340 } 341 } 342 } 343 // If app has no suggestions, create perAppInfo here. 344 if (perAppInfo == null) { 345 if (packageName == null) { 346 throw new XmlPullParserException( 347 "XML parsing of PerAppInfo failed"); 348 } 349 perAppInfo = new PerAppInfo(uid, packageName, featureId); 350 perAppInfo.hasUserApproved = hasUserApproved; 351 perAppInfo.maxSize = maxSize; 352 } 353 // Store this app info in the map. 354 networkSuggestionsMap.put(packageName, perAppInfo); 355 } catch (RuntimeException e) { 356 // Failed to parse this network, skip it. 357 Log.e(TAG, "Failed to parse network suggestion. Skipping...", e); 358 } 359 } 360 return networkSuggestionsMap; 361 } 362 363 /** 364 * Parse a {@link ExtendedWifiNetworkSuggestion} from an input stream in XML format. 365 * 366 * @throws XmlPullParserException 367 * @throws IOException 368 */ parseNetworkSuggestion(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, PerAppInfo perAppInfo)369 private ExtendedWifiNetworkSuggestion parseNetworkSuggestion(XmlPullParser in, 370 int outerTagDepth, @WifiConfigStore.Version int version, 371 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, PerAppInfo perAppInfo) 372 throws XmlPullParserException, IOException { 373 Pair<String, WifiConfiguration> parsedConfig = null; 374 WifiEnterpriseConfig enterpriseConfig = null; 375 PasspointConfiguration passpointConfiguration = null; 376 boolean isAppInteractionRequired = false; 377 boolean isUserInteractionRequired = false; 378 boolean isUserAllowedToManuallyConnect = false; // Backward compatibility. 379 boolean isInitializedAutoJoinEnabled = true; // backward compat 380 boolean isAutoJoinEnabled = true; // backward compat 381 boolean isNetworkUntrusted = false; 382 int priorityGroup = WifiNetworkSuggestionsManager.DEFAULT_PRIORITY_GROUP; 383 int suggestorUid = Process.INVALID_UID; 384 String connectChoice = null; 385 int connectChoiceRssi = 0; 386 387 // Loop through and parse out all the elements from the stream within this section. 388 while (XmlUtil.nextElementWithin(in, outerTagDepth)) { 389 if (in.getAttributeValue(null, "name") != null) { 390 // Value elements. 391 String[] valueName = new String[1]; 392 Object value = XmlUtil.readCurrentValue(in, valueName); 393 switch (valueName[0]) { 394 case XML_TAG_IS_APP_INTERACTION_REQUIRED: 395 isAppInteractionRequired = (boolean) value; 396 break; 397 case XML_TAG_IS_USER_INTERACTION_REQUIRED: 398 isUserInteractionRequired = (boolean) value; 399 break; 400 case XML_TAG_IS_USER_ALLOWED_TO_MANUALLY_CONNECT: 401 isUserAllowedToManuallyConnect = (boolean) value; 402 break; 403 case XML_TAG_IS_INITIALIZED_AUTO_JOIN: 404 isInitializedAutoJoinEnabled = (boolean) value; 405 break; 406 case XML_TAG_IS_AUTO_JOIN: 407 isAutoJoinEnabled = (boolean) value; 408 break; 409 case XML_TAG_SUGGESTOR_UID: 410 // Only needed for migration of data from Q to R. 411 suggestorUid = (int) value; 412 break; 413 case XML_TAG_PRIORITY_GROUP: 414 priorityGroup = (int) value; 415 break; 416 case XML_TAG_CONNECT_CHOICE: 417 connectChoice = (String) value; 418 break; 419 case XML_TAG_CONNECT_CHOICE_RSSI: 420 connectChoiceRssi = (int) value; 421 break; 422 default: 423 Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]); 424 break; 425 } 426 } else { 427 String tagName = in.getName(); 428 if (tagName == null) { 429 throw new XmlPullParserException("Unexpected null under " 430 + XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION); 431 } 432 switch (tagName) { 433 case XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION: 434 if (parsedConfig != null) { 435 throw new XmlPullParserException("Detected duplicate tag for: " 436 + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); 437 } 438 parsedConfig = WifiConfigurationXmlUtil.parseFromXml( 439 in, outerTagDepth + 1, 440 version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, 441 encryptionUtil, true); 442 break; 443 case XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION: 444 if (enterpriseConfig != null) { 445 throw new XmlPullParserException("Detected duplicate tag for: " 446 + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); 447 } 448 enterpriseConfig = XmlUtil.WifiEnterpriseConfigXmlUtil.parseFromXml( 449 in, outerTagDepth + 1, 450 version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, 451 encryptionUtil); 452 break; 453 case XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION: 454 if (passpointConfiguration != null) { 455 throw new XmlPullParserException("Detected duplicate tag for: " 456 + XML_TAG_SECTION_HEADER_PASSPOINT_CONFIGURATION); 457 } 458 passpointConfiguration = PasspointXmlUtils 459 .deserializePasspointConfiguration(in, outerTagDepth + 1); 460 break; 461 default: 462 Log.w(TAG, "Ignoring unknown tag under " 463 + XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION + ": " + in.getName()); 464 break; 465 } 466 } 467 } 468 if (parsedConfig == null || parsedConfig.second == null) { 469 throw new XmlPullParserException("XML parsing of wifi configuration failed"); 470 } 471 // Note: In R, we migrated the uid/package name storage from individual 472 // ExtWifiNetworkSuggestion to the top level PerAppInfo. This block of code helps 473 // with migration of data for devices upgrading from Q to R. 474 perAppInfo.setUid(suggestorUid); 475 WifiConfiguration wifiConfiguration = parsedConfig.second; 476 if (passpointConfiguration != null) { 477 wifiConfiguration.setPasspointUniqueId(passpointConfiguration.getUniqueId()); 478 } 479 if (enterpriseConfig != null) { 480 wifiConfiguration.enterpriseConfig = enterpriseConfig; 481 } 482 ExtendedWifiNetworkSuggestion ewns = ExtendedWifiNetworkSuggestion 483 .fromWns(new WifiNetworkSuggestion(wifiConfiguration, passpointConfiguration, 484 isAppInteractionRequired, isUserInteractionRequired, 485 isUserAllowedToManuallyConnect, isInitializedAutoJoinEnabled, 486 priorityGroup), perAppInfo, isAutoJoinEnabled); 487 ewns.connectChoice = connectChoice; 488 ewns.connectChoiceRssi = connectChoiceRssi; 489 return ewns; 490 } 491 } 492 493