1 /* 2 * Copyright (C) 2016 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.app.ActivityManager; 21 import android.app.admin.DeviceAdminInfo; 22 import android.app.admin.DevicePolicyManagerInternal; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.database.ContentObserver; 29 import android.net.IpConfiguration; 30 import android.net.MacAddress; 31 import android.net.ProxyInfo; 32 import android.net.StaticIpConfiguration; 33 import android.net.wifi.ScanResult; 34 import android.net.wifi.WifiConfiguration; 35 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; 36 import android.net.wifi.WifiEnterpriseConfig; 37 import android.net.wifi.WifiInfo; 38 import android.net.wifi.WifiManager; 39 import android.net.wifi.WifiScanner; 40 import android.os.Handler; 41 import android.os.Looper; 42 import android.os.Process; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.provider.Settings; 46 import android.telephony.TelephonyManager; 47 import android.text.TextUtils; 48 import android.util.ArraySet; 49 import android.util.LocalLog; 50 import android.util.Log; 51 import android.util.Pair; 52 53 import com.android.internal.R; 54 import com.android.internal.annotations.VisibleForTesting; 55 import com.android.server.wifi.hotspot2.PasspointManager; 56 import com.android.server.wifi.util.TelephonyUtil; 57 import com.android.server.wifi.util.WifiPermissionsUtil; 58 import com.android.server.wifi.util.WifiPermissionsWrapper; 59 60 import org.xmlpull.v1.XmlPullParserException; 61 62 import java.io.FileDescriptor; 63 import java.io.IOException; 64 import java.io.PrintWriter; 65 import java.util.ArrayList; 66 import java.util.Arrays; 67 import java.util.BitSet; 68 import java.util.Calendar; 69 import java.util.Collection; 70 import java.util.Collections; 71 import java.util.Comparator; 72 import java.util.HashMap; 73 import java.util.HashSet; 74 import java.util.Iterator; 75 import java.util.List; 76 import java.util.Map; 77 import java.util.Set; 78 79 /** 80 * This class provides the APIs to manage configured Wi-Fi networks. 81 * It deals with the following: 82 * - Maintaining a list of configured networks for quick access. 83 * - Persisting the configurations to store when required. 84 * - Supporting WifiManager Public API calls: 85 * > addOrUpdateNetwork() 86 * > removeNetwork() 87 * > enableNetwork() 88 * > disableNetwork() 89 * - Handle user switching on multi-user devices. 90 * 91 * All network configurations retrieved from this class are copies of the original configuration 92 * stored in the internal database. So, any updates to the retrieved configuration object are 93 * meaningless and will not be reflected in the original database. 94 * This is done on purpose to ensure that only WifiConfigManager can modify configurations stored 95 * in the internal database. Any configuration updates should be triggered with appropriate helper 96 * methods of this class using the configuration's unique networkId. 97 * 98 * NOTE: These API's are not thread safe and should only be used from ClientModeImpl thread. 99 */ 100 public class WifiConfigManager { 101 /** 102 * String used to mask passwords to public interface. 103 */ 104 @VisibleForTesting 105 public static final String PASSWORD_MASK = "*"; 106 /** 107 * Package name for SysUI. This is used to lookup the UID of SysUI which is used to allow 108 * Quick settings to modify network configurations. 109 */ 110 @VisibleForTesting 111 public static final String SYSUI_PACKAGE_NAME = "com.android.systemui"; 112 /** 113 * Network Selection disable reason thresholds. These numbers are used to debounce network 114 * failures before we disable them. 115 * These are indexed using the disable reason constants defined in 116 * {@link android.net.wifi.WifiConfiguration.NetworkSelectionStatus}. 117 */ 118 @VisibleForTesting 119 public static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = { 120 -1, // threshold for NETWORK_SELECTION_ENABLE 121 1, // threshold for DISABLED_BAD_LINK 122 5, // threshold for DISABLED_ASSOCIATION_REJECTION 123 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 124 5, // threshold for DISABLED_DHCP_FAILURE 125 5, // threshold for DISABLED_DNS_FAILURE 126 1, // threshold for DISABLED_NO_INTERNET_TEMPORARY 127 1, // threshold for DISABLED_WPS_START 128 6, // threshold for DISABLED_TLS_VERSION_MISMATCH 129 1, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 130 1, // threshold for DISABLED_NO_INTERNET_PERMANENT 131 1, // threshold for DISABLED_BY_WIFI_MANAGER 132 1, // threshold for DISABLED_BY_USER_SWITCH 133 1, // threshold for DISABLED_BY_WRONG_PASSWORD 134 1 // threshold for DISABLED_AUTHENTICATION_NO_SUBSCRIBED 135 }; 136 /** 137 * Network Selection disable timeout for each kind of error. After the timeout milliseconds, 138 * enable the network again. 139 * These are indexed using the disable reason constants defined in 140 * {@link android.net.wifi.WifiConfiguration.NetworkSelectionStatus}. 141 */ 142 @VisibleForTesting 143 public static final int[] NETWORK_SELECTION_DISABLE_TIMEOUT_MS = { 144 Integer.MAX_VALUE, // threshold for NETWORK_SELECTION_ENABLE 145 15 * 60 * 1000, // threshold for DISABLED_BAD_LINK 146 5 * 60 * 1000, // threshold for DISABLED_ASSOCIATION_REJECTION 147 5 * 60 * 1000, // threshold for DISABLED_AUTHENTICATION_FAILURE 148 5 * 60 * 1000, // threshold for DISABLED_DHCP_FAILURE 149 5 * 60 * 1000, // threshold for DISABLED_DNS_FAILURE 150 10 * 60 * 1000, // threshold for DISABLED_NO_INTERNET_TEMPORARY 151 0 * 60 * 1000, // threshold for DISABLED_WPS_START 152 Integer.MAX_VALUE, // threshold for DISABLED_TLS_VERSION 153 Integer.MAX_VALUE, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 154 Integer.MAX_VALUE, // threshold for DISABLED_NO_INTERNET_PERMANENT 155 Integer.MAX_VALUE, // threshold for DISABLED_BY_WIFI_MANAGER 156 Integer.MAX_VALUE, // threshold for DISABLED_BY_USER_SWITCH 157 Integer.MAX_VALUE, // threshold for DISABLED_BY_WRONG_PASSWORD 158 Integer.MAX_VALUE // threshold for DISABLED_AUTHENTICATION_NO_SUBSCRIBED 159 }; 160 /** 161 * Interface for other modules to listen to the saved network updated 162 * events. 163 */ 164 public interface OnSavedNetworkUpdateListener { 165 /** 166 * Invoked on saved network being added. 167 */ onSavedNetworkAdded(int networkId)168 void onSavedNetworkAdded(int networkId); 169 /** 170 * Invoked on saved network being enabled. 171 */ onSavedNetworkEnabled(int networkId)172 void onSavedNetworkEnabled(int networkId); 173 /** 174 * Invoked on saved network being permanently disabled. 175 */ onSavedNetworkPermanentlyDisabled(int networkId, int disableReason)176 void onSavedNetworkPermanentlyDisabled(int networkId, int disableReason); 177 /** 178 * Invoked on saved network being removed. 179 */ onSavedNetworkRemoved(int networkId)180 void onSavedNetworkRemoved(int networkId); 181 /** 182 * Invoked on saved network being temporarily disabled. 183 */ onSavedNetworkTemporarilyDisabled(int networkId, int disableReason)184 void onSavedNetworkTemporarilyDisabled(int networkId, int disableReason); 185 /** 186 * Invoked on saved network being updated. 187 */ onSavedNetworkUpdated(int networkId)188 void onSavedNetworkUpdated(int networkId); 189 } 190 /** 191 * Max size of scan details to cache in {@link #mScanDetailCaches}. 192 */ 193 @VisibleForTesting 194 public static final int SCAN_CACHE_ENTRIES_MAX_SIZE = 192; 195 /** 196 * Once the size of the scan details in the cache {@link #mScanDetailCaches} exceeds 197 * {@link #SCAN_CACHE_ENTRIES_MAX_SIZE}, trim it down to this value so that we have some 198 * buffer time before the next eviction. 199 */ 200 @VisibleForTesting 201 public static final int SCAN_CACHE_ENTRIES_TRIM_SIZE = 128; 202 /** 203 * Link networks only if they have less than this number of scan cache entries. 204 */ 205 @VisibleForTesting 206 public static final int LINK_CONFIGURATION_MAX_SCAN_CACHE_ENTRIES = 6; 207 /** 208 * Link networks only if the bssid in scan results for the networks match in the first 209 * 16 ASCII chars in the bssid string. For example = "af:de:56;34:15:7" 210 */ 211 @VisibleForTesting 212 public static final int LINK_CONFIGURATION_BSSID_MATCH_LENGTH = 16; 213 /** 214 * Log tag for this class. 215 */ 216 private static final String TAG = "WifiConfigManager"; 217 /** 218 * Maximum age of scan results that can be used for averaging out RSSI value. 219 */ 220 private static final int SCAN_RESULT_MAXIMUM_AGE_MS = 40000; 221 222 /** 223 * Maximum age of frequencies last seen to be included in pno scans. (30 days) 224 */ 225 @VisibleForTesting 226 public static final long MAX_PNO_SCAN_FREQUENCY_AGE_MS = (long) 1000 * 3600 * 24 * 30; 227 228 private static final int WIFI_PNO_FREQUENCY_CULLING_ENABLED_DEFAULT = 1; // 0 = disabled 229 private static final int WIFI_PNO_RECENCY_SORTING_ENABLED_DEFAULT = 1; // 0 = disabled: 230 231 private static final MacAddress DEFAULT_MAC_ADDRESS = 232 MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); 233 234 /** 235 * Expiration timeout for deleted ephemeral ssids. (1 day) 236 */ 237 @VisibleForTesting 238 public static final long DELETED_EPHEMERAL_SSID_EXPIRY_MS = (long) 1000 * 60 * 60 * 24; 239 240 /** 241 * General sorting algorithm of all networks for scanning purposes: 242 * Place the configurations in descending order of their |numAssociation| values. If networks 243 * have the same |numAssociation|, place the configurations with 244 * |lastSeenInQualifiedNetworkSelection| set first. 245 */ 246 private static final WifiConfigurationUtil.WifiConfigurationComparator sScanListComparator = 247 new WifiConfigurationUtil.WifiConfigurationComparator() { 248 @Override 249 public int compareNetworksWithSameStatus(WifiConfiguration a, WifiConfiguration b) { 250 if (a.numAssociation != b.numAssociation) { 251 return Long.compare(b.numAssociation, a.numAssociation); 252 } else { 253 boolean isConfigALastSeen = 254 a.getNetworkSelectionStatus() 255 .getSeenInLastQualifiedNetworkSelection(); 256 boolean isConfigBLastSeen = 257 b.getNetworkSelectionStatus() 258 .getSeenInLastQualifiedNetworkSelection(); 259 return Boolean.compare(isConfigBLastSeen, isConfigALastSeen); 260 } 261 } 262 }; 263 264 /** 265 * List of external dependencies for WifiConfigManager. 266 */ 267 private final Context mContext; 268 private final Clock mClock; 269 private final UserManager mUserManager; 270 private final BackupManagerProxy mBackupManagerProxy; 271 private final TelephonyManager mTelephonyManager; 272 private final WifiKeyStore mWifiKeyStore; 273 private final WifiConfigStore mWifiConfigStore; 274 private final WifiPermissionsUtil mWifiPermissionsUtil; 275 private final WifiPermissionsWrapper mWifiPermissionsWrapper; 276 private final WifiInjector mWifiInjector; 277 278 /** 279 * Local log used for debugging any WifiConfigManager issues. 280 */ 281 private final LocalLog mLocalLog = 282 new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 128 : 256); 283 /** 284 * Map of configured networks with network id as the key. 285 */ 286 private final ConfigurationMap mConfiguredNetworks; 287 /** 288 * Stores a map of NetworkId to ScanDetailCache. 289 */ 290 private final Map<Integer, ScanDetailCache> mScanDetailCaches; 291 /** 292 * Framework keeps a list of ephemeral SSIDs that where deleted by user, 293 * framework knows not to autoconnect again even if the app/scorer recommends it. 294 * The entries are deleted after 24 hours. 295 * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. 296 * 297 * The map stores the SSID and the wall clock time when the network was deleted. 298 */ 299 private final Map<String, Long> mDeletedEphemeralSsidsToTimeMap; 300 301 /** 302 * Framework keeps a mapping from configKey to the randomized MAC address so that 303 * when a user forgets a network and thne adds it back, the same randomized MAC address 304 * will get used. 305 */ 306 private final Map<String, String> mRandomizedMacAddressMapping; 307 308 /** 309 * Flag to indicate if only networks with the same psk should be linked. 310 * TODO(b/30706406): Remove this flag if unused. 311 */ 312 private final boolean mOnlyLinkSameCredentialConfigurations; 313 /** 314 * Number of channels to scan for during partial scans initiated while connected. 315 */ 316 private final int mMaxNumActiveChannelsForPartialScans; 317 318 private final FrameworkFacade mFrameworkFacade; 319 320 /** 321 * Verbose logging flag. Toggled by developer options. 322 */ 323 private boolean mVerboseLoggingEnabled = false; 324 /** 325 * Current logged in user ID. 326 */ 327 private int mCurrentUserId = UserHandle.USER_SYSTEM; 328 /** 329 * Flag to indicate that the new user's store has not yet been read since user switch. 330 * Initialize this flag to |true| to trigger a read on the first user unlock after 331 * bootup. 332 */ 333 private boolean mPendingUnlockStoreRead = true; 334 /** 335 * Flag to indicate if we have performed a read from store at all. This is used to gate 336 * any user unlock/switch operations until we read the store (Will happen if wifi is disabled 337 * when user updates from N to O). 338 */ 339 private boolean mPendingStoreRead = true; 340 /** 341 * Flag to indicate if the user unlock was deferred until the store load occurs. 342 */ 343 private boolean mDeferredUserUnlockRead = false; 344 /** 345 * This is keeping track of the next network ID to be assigned. Any new networks will be 346 * assigned |mNextNetworkId| as network ID. 347 */ 348 private int mNextNetworkId = 0; 349 /** 350 * UID of system UI. This uid is allowed to modify network configurations regardless of which 351 * user is logged in. 352 */ 353 private int mSystemUiUid = -1; 354 /** 355 * This is used to remember which network was selected successfully last by an app. This is set 356 * when an app invokes {@link #enableNetwork(int, boolean, int)} with |disableOthers| flag set. 357 * This is the only way for an app to request connection to a specific network using the 358 * {@link WifiManager} API's. 359 */ 360 private int mLastSelectedNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 361 private long mLastSelectedTimeStamp = 362 WifiConfiguration.NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP; 363 364 // Store data for network list and deleted ephemeral SSID list. Used for serializing 365 // parsing data to/from the config store. 366 private final NetworkListSharedStoreData mNetworkListSharedStoreData; 367 private final NetworkListUserStoreData mNetworkListUserStoreData; 368 private final DeletedEphemeralSsidsStoreData mDeletedEphemeralSsidsStoreData; 369 private final RandomizedMacStoreData mRandomizedMacStoreData; 370 371 // Store the saved network update listener. 372 private OnSavedNetworkUpdateListener mListener = null; 373 374 private boolean mPnoFrequencyCullingEnabled = false; 375 private boolean mPnoRecencySortingEnabled = false; 376 377 378 379 /** 380 * Create new instance of WifiConfigManager. 381 */ WifiConfigManager( Context context, Clock clock, UserManager userManager, TelephonyManager telephonyManager, WifiKeyStore wifiKeyStore, WifiConfigStore wifiConfigStore, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper wifiPermissionsWrapper, WifiInjector wifiInjector, NetworkListSharedStoreData networkListSharedStoreData, NetworkListUserStoreData networkListUserStoreData, DeletedEphemeralSsidsStoreData deletedEphemeralSsidsStoreData, RandomizedMacStoreData randomizedMacStoreData, FrameworkFacade frameworkFacade, Looper looper)382 WifiConfigManager( 383 Context context, Clock clock, UserManager userManager, 384 TelephonyManager telephonyManager, WifiKeyStore wifiKeyStore, 385 WifiConfigStore wifiConfigStore, 386 WifiPermissionsUtil wifiPermissionsUtil, 387 WifiPermissionsWrapper wifiPermissionsWrapper, 388 WifiInjector wifiInjector, 389 NetworkListSharedStoreData networkListSharedStoreData, 390 NetworkListUserStoreData networkListUserStoreData, 391 DeletedEphemeralSsidsStoreData deletedEphemeralSsidsStoreData, 392 RandomizedMacStoreData randomizedMacStoreData, 393 FrameworkFacade frameworkFacade, Looper looper) { 394 mContext = context; 395 mClock = clock; 396 mUserManager = userManager; 397 mBackupManagerProxy = new BackupManagerProxy(); 398 mTelephonyManager = telephonyManager; 399 mWifiKeyStore = wifiKeyStore; 400 mWifiConfigStore = wifiConfigStore; 401 mWifiPermissionsUtil = wifiPermissionsUtil; 402 mWifiPermissionsWrapper = wifiPermissionsWrapper; 403 mWifiInjector = wifiInjector; 404 405 mConfiguredNetworks = new ConfigurationMap(userManager); 406 mScanDetailCaches = new HashMap<>(16, 0.75f); 407 mDeletedEphemeralSsidsToTimeMap = new HashMap<>(); 408 mRandomizedMacAddressMapping = new HashMap<>(); 409 410 // Register store data for network list and deleted ephemeral SSIDs. 411 mNetworkListSharedStoreData = networkListSharedStoreData; 412 mNetworkListUserStoreData = networkListUserStoreData; 413 mDeletedEphemeralSsidsStoreData = deletedEphemeralSsidsStoreData; 414 mRandomizedMacStoreData = randomizedMacStoreData; 415 mWifiConfigStore.registerStoreData(mNetworkListSharedStoreData); 416 mWifiConfigStore.registerStoreData(mNetworkListUserStoreData); 417 mWifiConfigStore.registerStoreData(mDeletedEphemeralSsidsStoreData); 418 mWifiConfigStore.registerStoreData(mRandomizedMacStoreData); 419 420 mOnlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean( 421 R.bool.config_wifi_only_link_same_credential_configurations); 422 mMaxNumActiveChannelsForPartialScans = mContext.getResources().getInteger( 423 R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels); 424 mFrameworkFacade = frameworkFacade; 425 mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor( 426 Settings.Global.WIFI_PNO_FREQUENCY_CULLING_ENABLED), false, 427 new ContentObserver(new Handler(looper)) { 428 @Override 429 public void onChange(boolean selfChange) { 430 updatePnoFrequencyCullingSetting(); 431 } 432 }); 433 updatePnoFrequencyCullingSetting(); 434 mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor( 435 Settings.Global.WIFI_PNO_RECENCY_SORTING_ENABLED), false, 436 new ContentObserver(new Handler(looper)) { 437 @Override 438 public void onChange(boolean selfChange) { 439 updatePnoRecencySortingSetting(); 440 } 441 }); 442 updatePnoRecencySortingSetting(); 443 try { 444 mSystemUiUid = mContext.getPackageManager().getPackageUidAsUser(SYSUI_PACKAGE_NAME, 445 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); 446 } catch (PackageManager.NameNotFoundException e) { 447 Log.e(TAG, "Unable to resolve SystemUI's UID."); 448 } 449 } 450 451 /** 452 * Construct the string to be put in the |creationTime| & |updateTime| elements of 453 * WifiConfiguration from the provided wall clock millis. 454 * 455 * @param wallClockMillis Time in milliseconds to be converted to string. 456 */ 457 @VisibleForTesting createDebugTimeStampString(long wallClockMillis)458 public static String createDebugTimeStampString(long wallClockMillis) { 459 StringBuilder sb = new StringBuilder(); 460 sb.append("time="); 461 Calendar c = Calendar.getInstance(); 462 c.setTimeInMillis(wallClockMillis); 463 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 464 return sb.toString(); 465 } 466 467 @VisibleForTesting getRandomizedMacAddressMappingSize()468 protected int getRandomizedMacAddressMappingSize() { 469 return mRandomizedMacAddressMapping.size(); 470 } 471 472 /** 473 * The persistent randomized MAC address is locally generated for each SSID and does not 474 * change until factory reset of the device. In the initial Q release the per-SSID randomized 475 * MAC is saved on the device, but in an update the storing of randomized MAC is removed. 476 * Instead, the randomized MAC is calculated directly from the SSID and a on device secret. 477 * For backward compatibility, this method first checks the device storage for saved 478 * randomized MAC. If it is not found or the saved MAC is invalid then it will calculate the 479 * randomized MAC directly. 480 * 481 * In the future as devices launched on Q no longer get supported, this method should get 482 * simplified to return the calculated MAC address directly. 483 * @param config the WifiConfiguration to obtain MAC address for. 484 * @return persistent MAC address for this WifiConfiguration 485 */ getPersistentMacAddress(WifiConfiguration config)486 private MacAddress getPersistentMacAddress(WifiConfiguration config) { 487 // mRandomizedMacAddressMapping had been the location to save randomized MAC addresses. 488 String persistentMacString = mRandomizedMacAddressMapping.get( 489 config.getSsidAndSecurityTypeString()); 490 // Use the MAC address stored in the storage if it exists and is valid. Otherwise 491 // use the MAC address calculated from a hash function as the persistent MAC. 492 if (persistentMacString != null) { 493 try { 494 return MacAddress.fromString(persistentMacString); 495 } catch (IllegalArgumentException e) { 496 Log.e(TAG, "Error creating randomized MAC address from stored value."); 497 mRandomizedMacAddressMapping.remove(config.getSsidAndSecurityTypeString()); 498 } 499 } 500 MacAddress result = WifiConfigurationUtil.calculatePersistentMacForConfiguration(config, 501 WifiConfigurationUtil.obtainMacRandHashFunction(Process.WIFI_UID)); 502 if (result == null) { 503 result = WifiConfigurationUtil.calculatePersistentMacForConfiguration(config, 504 WifiConfigurationUtil.obtainMacRandHashFunction(Process.WIFI_UID)); 505 } 506 if (result == null) { 507 Log.wtf(TAG, "Failed to generate MAC address from KeyStore even after retrying. " 508 + "Using locally generated MAC address instead."); 509 result = MacAddress.createRandomUnicastAddress(); 510 } 511 return result; 512 } 513 514 /** 515 * Obtain the persistent MAC address by first reading from an internal database. If non exists 516 * then calculate the persistent MAC using HMAC-SHA256. 517 * Finally set the randomized MAC of the configuration to the randomized MAC obtained. 518 * @param config the WifiConfiguration to make the update 519 * @return the persistent MacAddress or null if the operation is unsuccessful 520 */ setRandomizedMacToPersistentMac(WifiConfiguration config)521 private MacAddress setRandomizedMacToPersistentMac(WifiConfiguration config) { 522 MacAddress persistentMac = getPersistentMacAddress(config); 523 if (persistentMac == null || persistentMac.equals(config.getRandomizedMacAddress())) { 524 return persistentMac; 525 } 526 WifiConfiguration internalConfig = getInternalConfiguredNetwork(config.networkId); 527 internalConfig.setRandomizedMacAddress(persistentMac); 528 return persistentMac; 529 } 530 531 /** 532 * Enable/disable verbose logging in WifiConfigManager & its helper classes. 533 */ enableVerboseLogging(int verbose)534 public void enableVerboseLogging(int verbose) { 535 if (verbose > 0) { 536 mVerboseLoggingEnabled = true; 537 } else { 538 mVerboseLoggingEnabled = false; 539 } 540 mWifiConfigStore.enableVerboseLogging(mVerboseLoggingEnabled); 541 mWifiKeyStore.enableVerboseLogging(mVerboseLoggingEnabled); 542 } 543 updatePnoFrequencyCullingSetting()544 private void updatePnoFrequencyCullingSetting() { 545 int flag = mFrameworkFacade.getIntegerSetting( 546 mContext, Settings.Global.WIFI_PNO_FREQUENCY_CULLING_ENABLED, 547 WIFI_PNO_FREQUENCY_CULLING_ENABLED_DEFAULT); 548 mPnoFrequencyCullingEnabled = (flag == 1); 549 } 550 updatePnoRecencySortingSetting()551 private void updatePnoRecencySortingSetting() { 552 int flag = mFrameworkFacade.getIntegerSetting( 553 mContext, Settings.Global.WIFI_PNO_RECENCY_SORTING_ENABLED, 554 WIFI_PNO_RECENCY_SORTING_ENABLED_DEFAULT); 555 mPnoRecencySortingEnabled = (flag == 1); 556 } 557 558 /** 559 * Helper method to mask all passwords/keys from the provided WifiConfiguration object. This 560 * is needed when the network configurations are being requested via the public WifiManager 561 * API's. 562 * This currently masks the following elements: psk, wepKeys & enterprise config password. 563 */ maskPasswordsInWifiConfiguration(WifiConfiguration configuration)564 private void maskPasswordsInWifiConfiguration(WifiConfiguration configuration) { 565 if (!TextUtils.isEmpty(configuration.preSharedKey)) { 566 configuration.preSharedKey = PASSWORD_MASK; 567 } 568 if (configuration.wepKeys != null) { 569 for (int i = 0; i < configuration.wepKeys.length; i++) { 570 if (!TextUtils.isEmpty(configuration.wepKeys[i])) { 571 configuration.wepKeys[i] = PASSWORD_MASK; 572 } 573 } 574 } 575 if (!TextUtils.isEmpty(configuration.enterpriseConfig.getPassword())) { 576 configuration.enterpriseConfig.setPassword(PASSWORD_MASK); 577 } 578 } 579 580 /** 581 * Helper method to mask randomized MAC address from the provided WifiConfiguration Object. 582 * This is needed when the network configurations are being requested via the public 583 * WifiManager API's. This method puts "02:00:00:00:00:00" as the MAC address. 584 * @param configuration WifiConfiguration to hide the MAC address 585 */ maskRandomizedMacAddressInWifiConfiguration(WifiConfiguration configuration)586 private void maskRandomizedMacAddressInWifiConfiguration(WifiConfiguration configuration) { 587 configuration.setRandomizedMacAddress(DEFAULT_MAC_ADDRESS); 588 } 589 590 /** 591 * Helper method to create a copy of the provided internal WifiConfiguration object to be 592 * passed to external modules. 593 * 594 * @param configuration provided WifiConfiguration object. 595 * @param maskPasswords Mask passwords or not. 596 * @param targetUid Target UID for MAC address reading: -1 = mask all, 0 = mask none, >0 = 597 * mask all but the targetUid (carrier app). 598 * @return Copy of the WifiConfiguration object. 599 */ createExternalWifiConfiguration( WifiConfiguration configuration, boolean maskPasswords, int targetUid)600 private WifiConfiguration createExternalWifiConfiguration( 601 WifiConfiguration configuration, boolean maskPasswords, int targetUid) { 602 WifiConfiguration network = new WifiConfiguration(configuration); 603 if (maskPasswords) { 604 maskPasswordsInWifiConfiguration(network); 605 } 606 if (targetUid != Process.WIFI_UID && targetUid != Process.SYSTEM_UID 607 && targetUid != configuration.creatorUid) { 608 maskRandomizedMacAddressInWifiConfiguration(network); 609 } 610 return network; 611 } 612 613 /** 614 * Fetch the list of currently configured networks maintained in WifiConfigManager. 615 * 616 * This retrieves a copy of the internal configurations maintained by WifiConfigManager and 617 * should be used for any public interfaces. 618 * 619 * @param savedOnly Retrieve only saved networks. 620 * @param maskPasswords Mask passwords or not. 621 * @param targetUid Target UID for MAC address reading: -1 (Invalid UID) = mask all, 622 * WIFI||SYSTEM = mask none, <other> = mask all but the targetUid (carrier 623 * app). 624 * @return List of WifiConfiguration objects representing the networks. 625 */ getConfiguredNetworks( boolean savedOnly, boolean maskPasswords, int targetUid)626 private List<WifiConfiguration> getConfiguredNetworks( 627 boolean savedOnly, boolean maskPasswords, int targetUid) { 628 List<WifiConfiguration> networks = new ArrayList<>(); 629 for (WifiConfiguration config : getInternalConfiguredNetworks()) { 630 if (savedOnly && (config.ephemeral || config.isPasspoint())) { 631 continue; 632 } 633 networks.add(createExternalWifiConfiguration(config, maskPasswords, targetUid)); 634 } 635 return networks; 636 } 637 638 /** 639 * Retrieves the list of all configured networks with passwords masked. 640 * 641 * @return List of WifiConfiguration objects representing the networks. 642 */ getConfiguredNetworks()643 public List<WifiConfiguration> getConfiguredNetworks() { 644 return getConfiguredNetworks(false, true, Process.WIFI_UID); 645 } 646 647 /** 648 * Retrieves the list of all configured networks with the passwords in plaintext. 649 * 650 * WARNING: Don't use this to pass network configurations to external apps. Should only be 651 * sent to system apps/wifi stack, when there is a need for passwords in plaintext. 652 * TODO: Need to understand the current use case of this API. 653 * 654 * @return List of WifiConfiguration objects representing the networks. 655 */ getConfiguredNetworksWithPasswords()656 public List<WifiConfiguration> getConfiguredNetworksWithPasswords() { 657 return getConfiguredNetworks(false, false, Process.WIFI_UID); 658 } 659 660 /** 661 * Retrieves the list of all configured networks with the passwords masked. 662 * 663 * @return List of WifiConfiguration objects representing the networks. 664 */ getSavedNetworks(int targetUid)665 public List<WifiConfiguration> getSavedNetworks(int targetUid) { 666 return getConfiguredNetworks(true, true, targetUid); 667 } 668 669 /** 670 * Retrieves the configured network corresponding to the provided networkId with password 671 * masked. 672 * 673 * @param networkId networkId of the requested network. 674 * @return WifiConfiguration object if found, null otherwise. 675 */ getConfiguredNetwork(int networkId)676 public WifiConfiguration getConfiguredNetwork(int networkId) { 677 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 678 if (config == null) { 679 return null; 680 } 681 // Create a new configuration object with the passwords masked to send out to the external 682 // world. 683 return createExternalWifiConfiguration(config, true, Process.WIFI_UID); 684 } 685 686 /** 687 * Retrieves the configured network corresponding to the provided config key with password 688 * masked. 689 * 690 * @param configKey configKey of the requested network. 691 * @return WifiConfiguration object if found, null otherwise. 692 */ getConfiguredNetwork(String configKey)693 public WifiConfiguration getConfiguredNetwork(String configKey) { 694 WifiConfiguration config = getInternalConfiguredNetwork(configKey); 695 if (config == null) { 696 return null; 697 } 698 // Create a new configuration object with the passwords masked to send out to the external 699 // world. 700 return createExternalWifiConfiguration(config, true, Process.WIFI_UID); 701 } 702 703 /** 704 * Retrieves the configured network corresponding to the provided networkId with password 705 * in plaintext. 706 * 707 * WARNING: Don't use this to pass network configurations to external apps. Should only be 708 * sent to system apps/wifi stack, when there is a need for passwords in plaintext. 709 * 710 * @param networkId networkId of the requested network. 711 * @return WifiConfiguration object if found, null otherwise. 712 */ getConfiguredNetworkWithPassword(int networkId)713 public WifiConfiguration getConfiguredNetworkWithPassword(int networkId) { 714 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 715 if (config == null) { 716 return null; 717 } 718 // Create a new configuration object without the passwords masked to send out to the 719 // external world. 720 return createExternalWifiConfiguration(config, false, Process.WIFI_UID); 721 } 722 723 /** 724 * Retrieves the configured network corresponding to the provided networkId 725 * without any masking. 726 * 727 * WARNING: Don't use this to pass network configurations except in the wifi stack, when 728 * there is a need for passwords and randomized MAC address. 729 * 730 * @param networkId networkId of the requested network. 731 * @return Copy of WifiConfiguration object if found, null otherwise. 732 */ getConfiguredNetworkWithoutMasking(int networkId)733 public WifiConfiguration getConfiguredNetworkWithoutMasking(int networkId) { 734 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 735 if (config == null) { 736 return null; 737 } 738 return new WifiConfiguration(config); 739 } 740 741 /** 742 * Helper method to retrieve all the internal WifiConfiguration objects corresponding to all 743 * the networks in our database. 744 */ getInternalConfiguredNetworks()745 private Collection<WifiConfiguration> getInternalConfiguredNetworks() { 746 return mConfiguredNetworks.valuesForCurrentUser(); 747 } 748 749 /** 750 * Helper method to retrieve the internal WifiConfiguration object corresponding to the 751 * provided configuration in our database. 752 * This first attempts to find the network using the provided network ID in configuration, 753 * else it attempts to find a matching configuration using the configKey. 754 */ getInternalConfiguredNetwork(WifiConfiguration config)755 private WifiConfiguration getInternalConfiguredNetwork(WifiConfiguration config) { 756 WifiConfiguration internalConfig = mConfiguredNetworks.getForCurrentUser(config.networkId); 757 if (internalConfig != null) { 758 return internalConfig; 759 } 760 internalConfig = mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 761 if (internalConfig == null) { 762 Log.e(TAG, "Cannot find network with networkId " + config.networkId 763 + " or configKey " + config.configKey()); 764 } 765 return internalConfig; 766 } 767 768 /** 769 * Helper method to retrieve the internal WifiConfiguration object corresponding to the 770 * provided network ID in our database. 771 */ getInternalConfiguredNetwork(int networkId)772 private WifiConfiguration getInternalConfiguredNetwork(int networkId) { 773 if (networkId == WifiConfiguration.INVALID_NETWORK_ID) { 774 return null; 775 } 776 WifiConfiguration internalConfig = mConfiguredNetworks.getForCurrentUser(networkId); 777 if (internalConfig == null) { 778 Log.e(TAG, "Cannot find network with networkId " + networkId); 779 } 780 return internalConfig; 781 } 782 783 /** 784 * Helper method to retrieve the internal WifiConfiguration object corresponding to the 785 * provided configKey in our database. 786 */ getInternalConfiguredNetwork(String configKey)787 private WifiConfiguration getInternalConfiguredNetwork(String configKey) { 788 WifiConfiguration internalConfig = 789 mConfiguredNetworks.getByConfigKeyForCurrentUser(configKey); 790 if (internalConfig == null) { 791 Log.e(TAG, "Cannot find network with configKey " + configKey); 792 } 793 return internalConfig; 794 } 795 796 /** 797 * Method to send out the configured networks change broadcast when a single network 798 * configuration is changed. 799 * 800 * @param network WifiConfiguration corresponding to the network that was changed. 801 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 802 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 803 */ sendConfiguredNetworkChangedBroadcast( WifiConfiguration network, int reason)804 private void sendConfiguredNetworkChangedBroadcast( 805 WifiConfiguration network, int reason) { 806 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 807 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 808 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 809 // Create a new WifiConfiguration with passwords masked before we send it out. 810 WifiConfiguration broadcastNetwork = new WifiConfiguration(network); 811 maskPasswordsInWifiConfiguration(broadcastNetwork); 812 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, broadcastNetwork); 813 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 814 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 815 } 816 817 /** 818 * Method to send out the configured networks change broadcast when multiple network 819 * configurations are changed. 820 */ sendConfiguredNetworksChangedBroadcast()821 private void sendConfiguredNetworksChangedBroadcast() { 822 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 823 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 824 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 825 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 826 } 827 828 /** 829 * Checks if |uid| has permission to modify the provided configuration. 830 * 831 * @param config WifiConfiguration object corresponding to the network to be modified. 832 * @param uid UID of the app requesting the modification. 833 */ canModifyNetwork(WifiConfiguration config, int uid)834 private boolean canModifyNetwork(WifiConfiguration config, int uid) { 835 // System internals can always update networks; they're typically only 836 // making meteredHint or meteredOverride changes 837 if (uid == Process.SYSTEM_UID) { 838 return true; 839 } 840 841 // Passpoint configurations are generated and managed by PasspointManager. They can be 842 // added by either PasspointNetworkEvaluator (for auto connection) or Settings app 843 // (for manual connection), and need to be removed once the connection is completed. 844 // Since it is "owned" by us, so always allow us to modify them. 845 if (config.isPasspoint() && uid == Process.WIFI_UID) { 846 return true; 847 } 848 849 // EAP-SIM/AKA/AKA' network needs framework to update the anonymous identity provided 850 // by authenticator back to the WifiConfiguration object. 851 // Since it is "owned" by us, so always allow us to modify them. 852 if (config.enterpriseConfig != null 853 && uid == Process.WIFI_UID 854 && TelephonyUtil.isSimEapMethod(config.enterpriseConfig.getEapMethod())) { 855 return true; 856 } 857 858 final DevicePolicyManagerInternal dpmi = 859 mWifiPermissionsWrapper.getDevicePolicyManagerInternal(); 860 861 final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid, 862 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 863 864 // If |uid| corresponds to the device owner, allow all modifications. 865 if (isUidDeviceOwner) { 866 return true; 867 } 868 869 final boolean isCreator = (config.creatorUid == uid); 870 871 // Check if device has DPM capability. If it has and |dpmi| is still null, then we 872 // treat this case with suspicion and bail out. 873 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) 874 && dpmi == null) { 875 Log.w(TAG, "Error retrieving DPMI service."); 876 return false; 877 } 878 879 // WiFi config lockdown related logic. At this point we know uid is NOT a Device Owner. 880 final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy( 881 config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 882 if (!isConfigEligibleForLockdown) { 883 return isCreator || mWifiPermissionsUtil.checkNetworkSettingsPermission(uid); 884 } 885 886 final ContentResolver resolver = mContext.getContentResolver(); 887 final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver, 888 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; 889 return !isLockdownFeatureEnabled 890 && mWifiPermissionsUtil.checkNetworkSettingsPermission(uid); 891 } 892 893 /** 894 * Check if the given UID belongs to the current foreground user. This is 895 * used to prevent apps running in background users from modifying network 896 * configurations. 897 * <p> 898 * UIDs belonging to system internals (such as SystemUI) are always allowed, 899 * since they always run as {@link UserHandle#USER_SYSTEM}. 900 * 901 * @param uid uid of the app. 902 * @return true if the given UID belongs to the current foreground user, 903 * otherwise false. 904 */ doesUidBelongToCurrentUser(int uid)905 private boolean doesUidBelongToCurrentUser(int uid) { 906 if (uid == android.os.Process.SYSTEM_UID || uid == mSystemUiUid) { 907 return true; 908 } else { 909 return WifiConfigurationUtil.doesUidBelongToAnyProfile( 910 uid, mUserManager.getProfiles(mCurrentUserId)); 911 } 912 } 913 914 /** 915 * Copy over public elements from an external WifiConfiguration object to the internal 916 * configuration object if element has been set in the provided external WifiConfiguration. 917 * The only exception is the hidden |IpConfiguration| parameters, these need to be copied over 918 * for every update. 919 * 920 * This method updates all elements that are common to both network addition & update. 921 * The following fields of {@link WifiConfiguration} are not copied from external configs: 922 * > networkId - These are allocated by Wi-Fi stack internally for any new configurations. 923 * > status - The status needs to be explicitly updated using 924 * {@link WifiManager#enableNetwork(int, boolean)} or 925 * {@link WifiManager#disableNetwork(int)}. 926 * 927 * @param internalConfig WifiConfiguration object in our internal map. 928 * @param externalConfig WifiConfiguration object provided from the external API. 929 */ mergeWithInternalWifiConfiguration( WifiConfiguration internalConfig, WifiConfiguration externalConfig)930 private void mergeWithInternalWifiConfiguration( 931 WifiConfiguration internalConfig, WifiConfiguration externalConfig) { 932 if (externalConfig.SSID != null) { 933 internalConfig.SSID = externalConfig.SSID; 934 } 935 if (externalConfig.BSSID != null) { 936 internalConfig.BSSID = externalConfig.BSSID.toLowerCase(); 937 } 938 internalConfig.hiddenSSID = externalConfig.hiddenSSID; 939 internalConfig.requirePMF = externalConfig.requirePMF; 940 941 if (externalConfig.preSharedKey != null 942 && !externalConfig.preSharedKey.equals(PASSWORD_MASK)) { 943 internalConfig.preSharedKey = externalConfig.preSharedKey; 944 } 945 // Modify only wep keys are present in the provided configuration. This is a little tricky 946 // because there is no easy way to tell if the app is actually trying to null out the 947 // existing keys or not. 948 if (externalConfig.wepKeys != null) { 949 boolean hasWepKey = false; 950 for (int i = 0; i < internalConfig.wepKeys.length; i++) { 951 if (externalConfig.wepKeys[i] != null 952 && !externalConfig.wepKeys[i].equals(PASSWORD_MASK)) { 953 internalConfig.wepKeys[i] = externalConfig.wepKeys[i]; 954 hasWepKey = true; 955 } 956 } 957 if (hasWepKey) { 958 internalConfig.wepTxKeyIndex = externalConfig.wepTxKeyIndex; 959 } 960 } 961 if (externalConfig.FQDN != null) { 962 internalConfig.FQDN = externalConfig.FQDN; 963 } 964 if (externalConfig.providerFriendlyName != null) { 965 internalConfig.providerFriendlyName = externalConfig.providerFriendlyName; 966 } 967 if (externalConfig.roamingConsortiumIds != null) { 968 internalConfig.roamingConsortiumIds = externalConfig.roamingConsortiumIds.clone(); 969 } 970 971 // Copy over all the auth/protocol/key mgmt parameters if set. 972 if (externalConfig.allowedAuthAlgorithms != null 973 && !externalConfig.allowedAuthAlgorithms.isEmpty()) { 974 internalConfig.allowedAuthAlgorithms = 975 (BitSet) externalConfig.allowedAuthAlgorithms.clone(); 976 } 977 if (externalConfig.allowedProtocols != null 978 && !externalConfig.allowedProtocols.isEmpty()) { 979 internalConfig.allowedProtocols = (BitSet) externalConfig.allowedProtocols.clone(); 980 } 981 if (externalConfig.allowedKeyManagement != null 982 && !externalConfig.allowedKeyManagement.isEmpty()) { 983 internalConfig.allowedKeyManagement = 984 (BitSet) externalConfig.allowedKeyManagement.clone(); 985 } 986 if (externalConfig.allowedPairwiseCiphers != null 987 && !externalConfig.allowedPairwiseCiphers.isEmpty()) { 988 internalConfig.allowedPairwiseCiphers = 989 (BitSet) externalConfig.allowedPairwiseCiphers.clone(); 990 } 991 if (externalConfig.allowedGroupCiphers != null 992 && !externalConfig.allowedGroupCiphers.isEmpty()) { 993 internalConfig.allowedGroupCiphers = 994 (BitSet) externalConfig.allowedGroupCiphers.clone(); 995 } 996 if (externalConfig.allowedGroupManagementCiphers != null 997 && !externalConfig.allowedGroupManagementCiphers.isEmpty()) { 998 internalConfig.allowedGroupManagementCiphers = 999 (BitSet) externalConfig.allowedGroupManagementCiphers.clone(); 1000 } 1001 // allowedSuiteBCiphers is set internally according to the certificate type 1002 1003 // Copy over the |IpConfiguration| parameters if set. 1004 if (externalConfig.getIpConfiguration() != null) { 1005 IpConfiguration.IpAssignment ipAssignment = externalConfig.getIpAssignment(); 1006 if (ipAssignment != IpConfiguration.IpAssignment.UNASSIGNED) { 1007 internalConfig.setIpAssignment(ipAssignment); 1008 if (ipAssignment == IpConfiguration.IpAssignment.STATIC) { 1009 internalConfig.setStaticIpConfiguration( 1010 new StaticIpConfiguration(externalConfig.getStaticIpConfiguration())); 1011 } 1012 } 1013 IpConfiguration.ProxySettings proxySettings = externalConfig.getProxySettings(); 1014 if (proxySettings != IpConfiguration.ProxySettings.UNASSIGNED) { 1015 internalConfig.setProxySettings(proxySettings); 1016 if (proxySettings == IpConfiguration.ProxySettings.PAC 1017 || proxySettings == IpConfiguration.ProxySettings.STATIC) { 1018 internalConfig.setHttpProxy(new ProxyInfo(externalConfig.getHttpProxy())); 1019 } 1020 } 1021 } 1022 1023 // Copy over the |WifiEnterpriseConfig| parameters if set. 1024 if (externalConfig.enterpriseConfig != null) { 1025 internalConfig.enterpriseConfig.copyFromExternal( 1026 externalConfig.enterpriseConfig, PASSWORD_MASK); 1027 } 1028 1029 // Copy over any metered information. 1030 internalConfig.meteredHint = externalConfig.meteredHint; 1031 internalConfig.meteredOverride = externalConfig.meteredOverride; 1032 1033 // Copy over macRandomizationSetting 1034 internalConfig.macRandomizationSetting = externalConfig.macRandomizationSetting; 1035 } 1036 1037 /** 1038 * Set all the exposed defaults in the newly created WifiConfiguration object. 1039 * These fields have a default value advertised in our public documentation. The only exception 1040 * is the hidden |IpConfiguration| parameters, these have a default value even though they're 1041 * hidden. 1042 * 1043 * @param configuration provided WifiConfiguration object. 1044 */ setDefaultsInWifiConfiguration(WifiConfiguration configuration)1045 private void setDefaultsInWifiConfiguration(WifiConfiguration configuration) { 1046 configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 1047 1048 configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN); 1049 configuration.allowedProtocols.set(WifiConfiguration.Protocol.WPA); 1050 1051 configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 1052 configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); 1053 1054 configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); 1055 configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); 1056 1057 configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); 1058 configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); 1059 configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); 1060 configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104); 1061 1062 configuration.setIpAssignment(IpConfiguration.IpAssignment.DHCP); 1063 configuration.setProxySettings(IpConfiguration.ProxySettings.NONE); 1064 1065 configuration.status = WifiConfiguration.Status.DISABLED; 1066 configuration.getNetworkSelectionStatus().setNetworkSelectionStatus( 1067 NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED); 1068 configuration.getNetworkSelectionStatus().setNetworkSelectionDisableReason( 1069 NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER); 1070 } 1071 1072 /** 1073 * Create a new internal WifiConfiguration object by copying over parameters from the provided 1074 * external configuration and set defaults for the appropriate parameters. 1075 * 1076 * @param externalConfig WifiConfiguration object provided from the external API. 1077 * @return New WifiConfiguration object with parameters merged from the provided external 1078 * configuration. 1079 */ createNewInternalWifiConfigurationFromExternal( WifiConfiguration externalConfig, int uid, @Nullable String packageName)1080 private WifiConfiguration createNewInternalWifiConfigurationFromExternal( 1081 WifiConfiguration externalConfig, int uid, @Nullable String packageName) { 1082 WifiConfiguration newInternalConfig = new WifiConfiguration(); 1083 1084 // First allocate a new network ID for the configuration. 1085 newInternalConfig.networkId = mNextNetworkId++; 1086 1087 // First set defaults in the new configuration created. 1088 setDefaultsInWifiConfiguration(newInternalConfig); 1089 1090 // Copy over all the public elements from the provided configuration. 1091 mergeWithInternalWifiConfiguration(newInternalConfig, externalConfig); 1092 1093 // Copy over the hidden configuration parameters. These are the only parameters used by 1094 // system apps to indicate some property about the network being added. 1095 // These are only copied over for network additions and ignored for network updates. 1096 newInternalConfig.requirePMF = externalConfig.requirePMF; 1097 newInternalConfig.noInternetAccessExpected = externalConfig.noInternetAccessExpected; 1098 newInternalConfig.ephemeral = externalConfig.ephemeral; 1099 newInternalConfig.osu = externalConfig.osu; 1100 newInternalConfig.trusted = externalConfig.trusted; 1101 newInternalConfig.fromWifiNetworkSuggestion = externalConfig.fromWifiNetworkSuggestion; 1102 newInternalConfig.fromWifiNetworkSpecifier = externalConfig.fromWifiNetworkSpecifier; 1103 newInternalConfig.useExternalScores = externalConfig.useExternalScores; 1104 newInternalConfig.shared = externalConfig.shared; 1105 newInternalConfig.updateIdentifier = externalConfig.updateIdentifier; 1106 1107 // Add debug information for network addition. 1108 newInternalConfig.creatorUid = newInternalConfig.lastUpdateUid = uid; 1109 newInternalConfig.creatorName = newInternalConfig.lastUpdateName = 1110 packageName != null ? packageName : mContext.getPackageManager().getNameForUid(uid); 1111 newInternalConfig.creationTime = newInternalConfig.updateTime = 1112 createDebugTimeStampString(mClock.getWallClockMillis()); 1113 MacAddress randomizedMac = getPersistentMacAddress(newInternalConfig); 1114 if (randomizedMac != null) { 1115 newInternalConfig.setRandomizedMacAddress(randomizedMac); 1116 } 1117 return newInternalConfig; 1118 } 1119 1120 /** 1121 * Create a new internal WifiConfiguration object by copying over parameters from the provided 1122 * external configuration to a copy of the existing internal WifiConfiguration object. 1123 * 1124 * @param internalConfig WifiConfiguration object in our internal map. 1125 * @param externalConfig WifiConfiguration object provided from the external API. 1126 * @return Copy of existing WifiConfiguration object with parameters merged from the provided 1127 * configuration. 1128 */ updateExistingInternalWifiConfigurationFromExternal( WifiConfiguration internalConfig, WifiConfiguration externalConfig, int uid, @Nullable String packageName)1129 private WifiConfiguration updateExistingInternalWifiConfigurationFromExternal( 1130 WifiConfiguration internalConfig, WifiConfiguration externalConfig, int uid, 1131 @Nullable String packageName) { 1132 WifiConfiguration newInternalConfig = new WifiConfiguration(internalConfig); 1133 1134 // Copy over all the public elements from the provided configuration. 1135 mergeWithInternalWifiConfiguration(newInternalConfig, externalConfig); 1136 1137 // Add debug information for network update. 1138 newInternalConfig.lastUpdateUid = uid; 1139 newInternalConfig.lastUpdateName = 1140 packageName != null ? packageName : mContext.getPackageManager().getNameForUid(uid); 1141 newInternalConfig.updateTime = createDebugTimeStampString(mClock.getWallClockMillis()); 1142 1143 return newInternalConfig; 1144 } 1145 1146 /** 1147 * Add a network or update a network configuration to our database. 1148 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1149 * network configuration. Otherwise, the networkId should refer to an existing configuration. 1150 * 1151 * @param config provided WifiConfiguration object. 1152 * @param uid UID of the app requesting the network addition/modification. 1153 * @param packageName Package name of the app requesting the network addition/modification. 1154 * @return NetworkUpdateResult object representing status of the update. 1155 */ addOrUpdateNetworkInternal(WifiConfiguration config, int uid, @Nullable String packageName)1156 private NetworkUpdateResult addOrUpdateNetworkInternal(WifiConfiguration config, int uid, 1157 @Nullable String packageName) { 1158 if (mVerboseLoggingEnabled) { 1159 Log.v(TAG, "Adding/Updating network " + config.getPrintableSsid()); 1160 } 1161 WifiConfiguration newInternalConfig = null; 1162 1163 // First check if we already have a network with the provided network id or configKey. 1164 WifiConfiguration existingInternalConfig = getInternalConfiguredNetwork(config); 1165 // No existing network found. So, potentially a network add. 1166 if (existingInternalConfig == null) { 1167 if (!WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)) { 1168 Log.e(TAG, "Cannot add network with invalid config"); 1169 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1170 } 1171 newInternalConfig = 1172 createNewInternalWifiConfigurationFromExternal(config, uid, packageName); 1173 // Since the original config provided may have had an empty 1174 // {@link WifiConfiguration#allowedKeyMgmt} field, check again if we already have a 1175 // network with the the same configkey. 1176 existingInternalConfig = getInternalConfiguredNetwork(newInternalConfig.configKey()); 1177 } 1178 // Existing network found. So, a network update. 1179 if (existingInternalConfig != null) { 1180 if (!WifiConfigurationUtil.validate( 1181 config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE)) { 1182 Log.e(TAG, "Cannot update network with invalid config"); 1183 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1184 } 1185 // Check for the app's permission before we let it update this network. 1186 if (!canModifyNetwork(existingInternalConfig, uid)) { 1187 Log.e(TAG, "UID " + uid + " does not have permission to update configuration " 1188 + config.configKey()); 1189 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1190 } 1191 newInternalConfig = 1192 updateExistingInternalWifiConfigurationFromExternal( 1193 existingInternalConfig, config, uid, packageName); 1194 } 1195 1196 // Only add networks with proxy settings if the user has permission to 1197 if (WifiConfigurationUtil.hasProxyChanged(existingInternalConfig, newInternalConfig) 1198 && !canModifyProxySettings(uid)) { 1199 Log.e(TAG, "UID " + uid + " does not have permission to modify proxy Settings " 1200 + config.configKey() + ". Must have NETWORK_SETTINGS," 1201 + " or be device or profile owner."); 1202 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1203 } 1204 1205 if (WifiConfigurationUtil.hasMacRandomizationSettingsChanged(existingInternalConfig, 1206 newInternalConfig) && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 1207 && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) { 1208 Log.e(TAG, "UID " + uid + " does not have permission to modify MAC randomization " 1209 + "Settings " + config.getSsidAndSecurityTypeString() + ". Must have " 1210 + "NETWORK_SETTINGS or NETWORK_SETUP_WIZARD."); 1211 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1212 } 1213 1214 // Update the keys for saved enterprise networks. For Passpoint, the certificates 1215 // and keys are installed at the time the provider is installed. For suggestion enterprise 1216 // network the certificates and keys are installed at the time the suggestion is added 1217 if (!config.isPasspoint() && !config.fromWifiNetworkSuggestion && config.isEnterprise()) { 1218 if (!mWifiKeyStore.updateNetworkKeys(newInternalConfig, existingInternalConfig)) { 1219 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1220 } 1221 } 1222 1223 boolean newNetwork = (existingInternalConfig == null); 1224 // This is needed to inform IpClient about any IP configuration changes. 1225 boolean hasIpChanged = 1226 newNetwork || WifiConfigurationUtil.hasIpChanged( 1227 existingInternalConfig, newInternalConfig); 1228 boolean hasProxyChanged = 1229 newNetwork || WifiConfigurationUtil.hasProxyChanged( 1230 existingInternalConfig, newInternalConfig); 1231 // Reset the |hasEverConnected| flag if the credential parameters changed in this update. 1232 boolean hasCredentialChanged = 1233 newNetwork || WifiConfigurationUtil.hasCredentialChanged( 1234 existingInternalConfig, newInternalConfig); 1235 if (hasCredentialChanged) { 1236 newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false); 1237 } 1238 1239 // Add it to our internal map. This will replace any existing network configuration for 1240 // updates. 1241 try { 1242 mConfiguredNetworks.put(newInternalConfig); 1243 } catch (IllegalArgumentException e) { 1244 Log.e(TAG, "Failed to add network to config map", e); 1245 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1246 } 1247 1248 if (mDeletedEphemeralSsidsToTimeMap.remove(config.SSID) != null) { 1249 if (mVerboseLoggingEnabled) { 1250 Log.v(TAG, "Removed from ephemeral blacklist: " + config.SSID); 1251 } 1252 } 1253 1254 // Stage the backup of the SettingsProvider package which backs this up. 1255 mBackupManagerProxy.notifyDataChanged(); 1256 1257 NetworkUpdateResult result = 1258 new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged); 1259 result.setIsNewNetwork(newNetwork); 1260 result.setNetworkId(newInternalConfig.networkId); 1261 1262 localLog("addOrUpdateNetworkInternal: added/updated config." 1263 + " netId=" + newInternalConfig.networkId 1264 + " configKey=" + newInternalConfig.configKey() 1265 + " uid=" + Integer.toString(newInternalConfig.creatorUid) 1266 + " name=" + newInternalConfig.creatorName); 1267 return result; 1268 } 1269 1270 /** 1271 * Add a network or update a network configuration to our database. 1272 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1273 * network configuration. Otherwise, the networkId should refer to an existing configuration. 1274 * 1275 * @param config provided WifiConfiguration object. 1276 * @param uid UID of the app requesting the network addition/modification. 1277 * @param packageName Package name of the app requesting the network addition/modification. 1278 * @return NetworkUpdateResult object representing status of the update. 1279 */ addOrUpdateNetwork(WifiConfiguration config, int uid, @Nullable String packageName)1280 public NetworkUpdateResult addOrUpdateNetwork(WifiConfiguration config, int uid, 1281 @Nullable String packageName) { 1282 if (!doesUidBelongToCurrentUser(uid)) { 1283 Log.e(TAG, "UID " + uid + " not visible to the current user"); 1284 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1285 } 1286 if (config == null) { 1287 Log.e(TAG, "Cannot add/update network with null config"); 1288 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1289 } 1290 if (mPendingStoreRead) { 1291 Log.e(TAG, "Cannot add/update network before store is read!"); 1292 return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID); 1293 } 1294 if (!config.isEphemeral()) { 1295 // Removes the existing ephemeral network if it exists to add this configuration. 1296 WifiConfiguration existingConfig = getConfiguredNetwork(config.configKey()); 1297 if (existingConfig != null && existingConfig.isEphemeral()) { 1298 // In this case, new connection for this config won't happen because same 1299 // network is already registered as an ephemeral network. 1300 // Clear the Ephemeral Network to address the situation. 1301 removeNetwork(existingConfig.networkId, mSystemUiUid); 1302 } 1303 } 1304 1305 NetworkUpdateResult result = addOrUpdateNetworkInternal(config, uid, packageName); 1306 if (!result.isSuccess()) { 1307 Log.e(TAG, "Failed to add/update network " + config.getPrintableSsid()); 1308 return result; 1309 } 1310 WifiConfiguration newConfig = getInternalConfiguredNetwork(result.getNetworkId()); 1311 sendConfiguredNetworkChangedBroadcast( 1312 newConfig, 1313 result.isNewNetwork() 1314 ? WifiManager.CHANGE_REASON_ADDED 1315 : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1316 // Unless the added network is ephemeral or Passpoint, persist the network update/addition. 1317 if (!config.ephemeral && !config.isPasspoint()) { 1318 saveToStore(true); 1319 if (mListener != null) { 1320 if (result.isNewNetwork()) { 1321 mListener.onSavedNetworkAdded(newConfig.networkId); 1322 } else { 1323 mListener.onSavedNetworkUpdated(newConfig.networkId); 1324 } 1325 } 1326 } 1327 return result; 1328 1329 } 1330 1331 /** 1332 * Add a network or update a network configuration to our database. 1333 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1334 * network configuration. Otherwise, the networkId should refer to an existing configuration. 1335 * 1336 * @param config provided WifiConfiguration object. 1337 * @param uid UID of the app requesting the network addition/modification. 1338 * @return NetworkUpdateResult object representing status of the update. 1339 */ addOrUpdateNetwork(WifiConfiguration config, int uid)1340 public NetworkUpdateResult addOrUpdateNetwork(WifiConfiguration config, int uid) { 1341 return addOrUpdateNetwork(config, uid, null); 1342 } 1343 1344 /** 1345 * Removes the specified network configuration from our database. 1346 * 1347 * @param config provided WifiConfiguration object. 1348 * @param uid UID of the app requesting the network deletion. 1349 * @return true if successful, false otherwise. 1350 */ removeNetworkInternal(WifiConfiguration config, int uid)1351 private boolean removeNetworkInternal(WifiConfiguration config, int uid) { 1352 if (mVerboseLoggingEnabled) { 1353 Log.v(TAG, "Removing network " + config.getPrintableSsid()); 1354 } 1355 // Remove any associated enterprise keys for saved enterprise networks. Passpoint network 1356 // will remove the enterprise keys when provider is uninstalled. Suggestion enterprise 1357 // networks will remove the enterprise keys when suggestion is removed. 1358 if (!config.isPasspoint() && !config.fromWifiNetworkSuggestion && config.isEnterprise()) { 1359 mWifiKeyStore.removeKeys(config.enterpriseConfig); 1360 } 1361 1362 removeConnectChoiceFromAllNetworks(config.configKey()); 1363 mConfiguredNetworks.remove(config.networkId); 1364 mScanDetailCaches.remove(config.networkId); 1365 // Stage the backup of the SettingsProvider package which backs this up. 1366 mBackupManagerProxy.notifyDataChanged(); 1367 1368 localLog("removeNetworkInternal: removed config." 1369 + " netId=" + config.networkId 1370 + " configKey=" + config.configKey() 1371 + " uid=" + Integer.toString(uid) 1372 + " name=" + mContext.getPackageManager().getNameForUid(uid)); 1373 return true; 1374 } 1375 1376 /** 1377 * Removes the specified network configuration from our database. 1378 * 1379 * @param networkId network ID of the provided network. 1380 * @param uid UID of the app requesting the network deletion. 1381 * @return true if successful, false otherwise. 1382 */ removeNetwork(int networkId, int uid)1383 public boolean removeNetwork(int networkId, int uid) { 1384 if (!doesUidBelongToCurrentUser(uid)) { 1385 Log.e(TAG, "UID " + uid + " not visible to the current user"); 1386 return false; 1387 } 1388 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1389 if (config == null) { 1390 return false; 1391 } 1392 if (!canModifyNetwork(config, uid)) { 1393 Log.e(TAG, "UID " + uid + " does not have permission to delete configuration " 1394 + config.configKey()); 1395 return false; 1396 } 1397 if (!removeNetworkInternal(config, uid)) { 1398 Log.e(TAG, "Failed to remove network " + config.getPrintableSsid()); 1399 return false; 1400 } 1401 if (networkId == mLastSelectedNetworkId) { 1402 clearLastSelectedNetwork(); 1403 } 1404 sendConfiguredNetworkChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 1405 // Unless the removed network is ephemeral or Passpoint, persist the network removal. 1406 if (!config.ephemeral && !config.isPasspoint()) { 1407 saveToStore(true); 1408 if (mListener != null) mListener.onSavedNetworkRemoved(networkId); 1409 } 1410 return true; 1411 } 1412 getCreatorPackageName(WifiConfiguration config)1413 private String getCreatorPackageName(WifiConfiguration config) { 1414 String creatorName = config.creatorName; 1415 // getNameForUid (Stored in WifiConfiguration.creatorName) returns a concatenation of name 1416 // and uid for shared UIDs ("name:uid"). 1417 if (!creatorName.contains(":")) { 1418 return creatorName; // regular app not using shared UID. 1419 } 1420 // Separate the package name from the string for app using shared UID. 1421 return creatorName.substring(0, creatorName.indexOf(":")); 1422 } 1423 1424 /** 1425 * Remove all networks associated with an application. 1426 * 1427 * @param app Application info of the package of networks to remove. 1428 * @return the {@link Set} of networks that were removed by this call. Networks which matched 1429 * but failed to remove are omitted from this set. 1430 */ removeNetworksForApp(ApplicationInfo app)1431 public Set<Integer> removeNetworksForApp(ApplicationInfo app) { 1432 if (app == null || app.packageName == null) { 1433 return Collections.<Integer>emptySet(); 1434 } 1435 Log.d(TAG, "Remove all networks for app " + app); 1436 Set<Integer> removedNetworks = new ArraySet<>(); 1437 WifiConfiguration[] copiedConfigs = 1438 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1439 for (WifiConfiguration config : copiedConfigs) { 1440 if (app.uid != config.creatorUid 1441 || !app.packageName.equals(getCreatorPackageName(config))) { 1442 continue; 1443 } 1444 localLog("Removing network " + config.SSID 1445 + ", application \"" + app.packageName + "\" uninstalled" 1446 + " from user " + UserHandle.getUserId(app.uid)); 1447 if (removeNetwork(config.networkId, mSystemUiUid)) { 1448 removedNetworks.add(config.networkId); 1449 } 1450 } 1451 return removedNetworks; 1452 } 1453 1454 /** 1455 * Remove all networks associated with a user. 1456 * 1457 * @param userId The identifier of the user which is being removed. 1458 * @return the {@link Set} of networks that were removed by this call. Networks which matched 1459 * but failed to remove are omitted from this set. 1460 */ removeNetworksForUser(int userId)1461 Set<Integer> removeNetworksForUser(int userId) { 1462 Log.d(TAG, "Remove all networks for user " + userId); 1463 Set<Integer> removedNetworks = new ArraySet<>(); 1464 WifiConfiguration[] copiedConfigs = 1465 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1466 for (WifiConfiguration config : copiedConfigs) { 1467 if (userId != UserHandle.getUserId(config.creatorUid)) { 1468 continue; 1469 } 1470 localLog("Removing network " + config.SSID + ", user " + userId + " removed"); 1471 if (removeNetwork(config.networkId, mSystemUiUid)) { 1472 removedNetworks.add(config.networkId); 1473 } 1474 } 1475 return removedNetworks; 1476 } 1477 1478 /** 1479 * Iterates through the internal list of configured networks and removes any ephemeral or 1480 * passpoint network configurations which are transient in nature. 1481 * 1482 * @return true if a network was removed, false otherwise. 1483 */ removeAllEphemeralOrPasspointConfiguredNetworks()1484 public boolean removeAllEphemeralOrPasspointConfiguredNetworks() { 1485 if (mVerboseLoggingEnabled) { 1486 Log.v(TAG, "Removing all passpoint or ephemeral configured networks"); 1487 } 1488 boolean didRemove = false; 1489 WifiConfiguration[] copiedConfigs = 1490 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1491 for (WifiConfiguration config : copiedConfigs) { 1492 if (config.isPasspoint()) { 1493 Log.d(TAG, "Removing passpoint network config " + config.configKey()); 1494 removeNetwork(config.networkId, mSystemUiUid); 1495 didRemove = true; 1496 } else if (config.ephemeral) { 1497 Log.d(TAG, "Removing ephemeral network config " + config.configKey()); 1498 removeNetwork(config.networkId, mSystemUiUid); 1499 didRemove = true; 1500 } 1501 } 1502 return didRemove; 1503 } 1504 1505 /** 1506 * Removes the passpoint network configuration matched with {@code fqdn} provided. 1507 * 1508 * @param fqdn Fully Qualified Domain Name to remove. 1509 * @return true if a network was removed, false otherwise. 1510 */ removePasspointConfiguredNetwork(String fqdn)1511 public boolean removePasspointConfiguredNetwork(String fqdn) { 1512 WifiConfiguration[] copiedConfigs = 1513 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1514 for (WifiConfiguration config : copiedConfigs) { 1515 if (config.isPasspoint() && TextUtils.equals(fqdn, config.FQDN)) { 1516 Log.d(TAG, "Removing passpoint network config " + config.configKey()); 1517 removeNetwork(config.networkId, mSystemUiUid); 1518 return true; 1519 } 1520 } 1521 return false; 1522 } 1523 1524 /** 1525 * Helper method to mark a network enabled for network selection. 1526 */ setNetworkSelectionEnabled(WifiConfiguration config)1527 private void setNetworkSelectionEnabled(WifiConfiguration config) { 1528 NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 1529 status.setNetworkSelectionStatus( 1530 NetworkSelectionStatus.NETWORK_SELECTION_ENABLED); 1531 status.setDisableTime( 1532 NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1533 status.setNetworkSelectionDisableReason(NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1534 1535 // Clear out all the disable reason counters. 1536 status.clearDisableReasonCounter(); 1537 if (mListener != null) mListener.onSavedNetworkEnabled(config.networkId); 1538 } 1539 1540 /** 1541 * Helper method to mark a network temporarily disabled for network selection. 1542 */ setNetworkSelectionTemporarilyDisabled( WifiConfiguration config, int disableReason)1543 private void setNetworkSelectionTemporarilyDisabled( 1544 WifiConfiguration config, int disableReason) { 1545 NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 1546 status.setNetworkSelectionStatus( 1547 NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED); 1548 // Only need a valid time filled in for temporarily disabled networks. 1549 status.setDisableTime(mClock.getElapsedSinceBootMillis()); 1550 status.setNetworkSelectionDisableReason(disableReason); 1551 if (mListener != null) { 1552 mListener.onSavedNetworkTemporarilyDisabled(config.networkId, disableReason); 1553 } 1554 } 1555 1556 /** 1557 * Helper method to mark a network permanently disabled for network selection. 1558 */ setNetworkSelectionPermanentlyDisabled( WifiConfiguration config, int disableReason)1559 private void setNetworkSelectionPermanentlyDisabled( 1560 WifiConfiguration config, int disableReason) { 1561 NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 1562 status.setNetworkSelectionStatus( 1563 NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED); 1564 status.setDisableTime( 1565 NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1566 status.setNetworkSelectionDisableReason(disableReason); 1567 if (mListener != null) { 1568 mListener.onSavedNetworkPermanentlyDisabled(config.networkId, disableReason); 1569 } 1570 } 1571 1572 /** 1573 * Helper method to set the publicly exposed status for the network and send out the network 1574 * status change broadcast. 1575 */ setNetworkStatus(WifiConfiguration config, int status)1576 private void setNetworkStatus(WifiConfiguration config, int status) { 1577 config.status = status; 1578 sendConfiguredNetworkChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1579 } 1580 1581 /** 1582 * Sets a network's status (both internal and public) according to the update reason and 1583 * its current state. 1584 * 1585 * This updates the network's {@link WifiConfiguration#mNetworkSelectionStatus} field and the 1586 * public {@link WifiConfiguration#status} field if the network is either enabled or 1587 * permanently disabled. 1588 * 1589 * @param config network to be updated. 1590 * @param reason reason code for update. 1591 * @return true if the input configuration has been updated, false otherwise. 1592 */ setNetworkSelectionStatus(WifiConfiguration config, int reason)1593 private boolean setNetworkSelectionStatus(WifiConfiguration config, int reason) { 1594 NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1595 if (reason < 0 || reason >= NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX) { 1596 Log.e(TAG, "Invalid Network disable reason " + reason); 1597 return false; 1598 } 1599 if (reason == NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1600 setNetworkSelectionEnabled(config); 1601 setNetworkStatus(config, WifiConfiguration.Status.ENABLED); 1602 } else if (reason < NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) { 1603 setNetworkSelectionTemporarilyDisabled(config, reason); 1604 } else { 1605 setNetworkSelectionPermanentlyDisabled(config, reason); 1606 setNetworkStatus(config, WifiConfiguration.Status.DISABLED); 1607 } 1608 localLog("setNetworkSelectionStatus: configKey=" + config.configKey() 1609 + " networkStatus=" + networkStatus.getNetworkStatusString() + " disableReason=" 1610 + networkStatus.getNetworkDisableReasonString() + " at=" 1611 + createDebugTimeStampString(mClock.getWallClockMillis())); 1612 saveToStore(false); 1613 return true; 1614 } 1615 1616 /** 1617 * Update a network's status (both internal and public) according to the update reason and 1618 * its current state. 1619 * 1620 * @param config network to be updated. 1621 * @param reason reason code for update. 1622 * @return true if the input configuration has been updated, false otherwise. 1623 */ updateNetworkSelectionStatus(WifiConfiguration config, int reason)1624 private boolean updateNetworkSelectionStatus(WifiConfiguration config, int reason) { 1625 NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1626 if (reason != NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1627 1628 // Do not update SSID blacklist with information if this is the only 1629 // SSID be observed. By ignoring it we will cause additional failures 1630 // which will trigger Watchdog. 1631 if (reason == NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION 1632 || reason == NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE 1633 || reason == NetworkSelectionStatus.DISABLED_DHCP_FAILURE) { 1634 if (mWifiInjector.getWifiLastResortWatchdog().shouldIgnoreSsidUpdate()) { 1635 if (mVerboseLoggingEnabled) { 1636 Log.v(TAG, "Ignore update network selection status " 1637 + "since Watchdog trigger is activated"); 1638 } 1639 return false; 1640 } 1641 } 1642 1643 networkStatus.incrementDisableReasonCounter(reason); 1644 // For network disable reasons, we should only update the status if we cross the 1645 // threshold. 1646 int disableReasonCounter = networkStatus.getDisableReasonCounter(reason); 1647 int disableReasonThreshold = NETWORK_SELECTION_DISABLE_THRESHOLD[reason]; 1648 if (disableReasonCounter < disableReasonThreshold) { 1649 if (mVerboseLoggingEnabled) { 1650 Log.v(TAG, "Disable counter for network " + config.getPrintableSsid() 1651 + " for reason " 1652 + NetworkSelectionStatus.getNetworkDisableReasonString(reason) + " is " 1653 + networkStatus.getDisableReasonCounter(reason) + " and threshold is " 1654 + disableReasonThreshold); 1655 } 1656 return true; 1657 } 1658 } 1659 return setNetworkSelectionStatus(config, reason); 1660 } 1661 1662 /** 1663 * Update a network's status (both internal and public) according to the update reason and 1664 * its current state. 1665 * 1666 * Each network has 2 status: 1667 * 1. NetworkSelectionStatus: This is internal selection status of the network. This is used 1668 * for temporarily disabling a network for Network Selector. 1669 * 2. Status: This is the exposed status for a network. This is mostly set by 1670 * the public API's {@link WifiManager#enableNetwork(int, boolean)} & 1671 * {@link WifiManager#disableNetwork(int)}. 1672 * 1673 * @param networkId network ID of the network that needs the update. 1674 * @param reason reason to update the network. 1675 * @return true if the input configuration has been updated, false otherwise. 1676 */ updateNetworkSelectionStatus(int networkId, int reason)1677 public boolean updateNetworkSelectionStatus(int networkId, int reason) { 1678 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1679 if (config == null) { 1680 return false; 1681 } 1682 return updateNetworkSelectionStatus(config, reason); 1683 } 1684 1685 /** 1686 * Update whether a network is currently not recommended by {@link RecommendedNetworkEvaluator}. 1687 * 1688 * @param networkId network ID of the network to be updated 1689 * @param notRecommended whether this network is not recommended 1690 * @return true if the network is updated, false otherwise 1691 */ updateNetworkNotRecommended(int networkId, boolean notRecommended)1692 public boolean updateNetworkNotRecommended(int networkId, boolean notRecommended) { 1693 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1694 if (config == null) { 1695 return false; 1696 } 1697 1698 config.getNetworkSelectionStatus().setNotRecommended(notRecommended); 1699 if (mVerboseLoggingEnabled) { 1700 localLog("updateNetworkRecommendation: configKey=" + config.configKey() 1701 + " notRecommended=" + notRecommended); 1702 } 1703 saveToStore(false); 1704 return true; 1705 } 1706 1707 /** 1708 * Attempt to re-enable a network for network selection, if this network was either: 1709 * a) Previously temporarily disabled, but its disable timeout has expired, or 1710 * b) Previously disabled because of a user switch, but is now visible to the current 1711 * user. 1712 * 1713 * @param config configuration for the network to be re-enabled for network selection. The 1714 * network corresponding to the config must be visible to the current user. 1715 * @return true if the network identified by {@param config} was re-enabled for qualified 1716 * network selection, false otherwise. 1717 */ tryEnableNetwork(WifiConfiguration config)1718 private boolean tryEnableNetwork(WifiConfiguration config) { 1719 NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1720 if (networkStatus.isNetworkTemporaryDisabled()) { 1721 long timeDifferenceMs = 1722 mClock.getElapsedSinceBootMillis() - networkStatus.getDisableTime(); 1723 int disableReason = networkStatus.getNetworkSelectionDisableReason(); 1724 long disableTimeoutMs = NETWORK_SELECTION_DISABLE_TIMEOUT_MS[disableReason]; 1725 if (timeDifferenceMs >= disableTimeoutMs) { 1726 return updateNetworkSelectionStatus( 1727 config, NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1728 } 1729 } else if (networkStatus.isDisabledByReason( 1730 NetworkSelectionStatus.DISABLED_DUE_TO_USER_SWITCH)) { 1731 return updateNetworkSelectionStatus( 1732 config, NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1733 } 1734 return false; 1735 } 1736 1737 /** 1738 * Attempt to re-enable a network for network selection, if this network was either: 1739 * a) Previously temporarily disabled, but its disable timeout has expired, or 1740 * b) Previously disabled because of a user switch, but is now visible to the current 1741 * user. 1742 * 1743 * @param networkId the id of the network to be checked for possible unblock (due to timeout) 1744 * @return true if the network identified by {@param networkId} was re-enabled for qualified 1745 * network selection, false otherwise. 1746 */ tryEnableNetwork(int networkId)1747 public boolean tryEnableNetwork(int networkId) { 1748 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1749 if (config == null) { 1750 return false; 1751 } 1752 return tryEnableNetwork(config); 1753 } 1754 1755 /** 1756 * Enable a network using the public {@link WifiManager#enableNetwork(int, boolean)} API. 1757 * 1758 * @param networkId network ID of the network that needs the update. 1759 * @param disableOthers Whether to disable all other networks or not. This is used to indicate 1760 * that the app requested connection to a specific network. 1761 * @param uid uid of the app requesting the update. 1762 * @return true if it succeeds, false otherwise 1763 */ enableNetwork(int networkId, boolean disableOthers, int uid)1764 public boolean enableNetwork(int networkId, boolean disableOthers, int uid) { 1765 if (mVerboseLoggingEnabled) { 1766 Log.v(TAG, "Enabling network " + networkId + " (disableOthers " + disableOthers + ")"); 1767 } 1768 if (!doesUidBelongToCurrentUser(uid)) { 1769 Log.e(TAG, "UID " + uid + " not visible to the current user"); 1770 return false; 1771 } 1772 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1773 if (config == null) { 1774 return false; 1775 } 1776 // Set the "last selected" flag even if the app does not have permissions to modify this 1777 // network config. Apps are allowed to connect to networks even if they don't have 1778 // permission to modify it. 1779 if (disableOthers) { 1780 setLastSelectedNetwork(networkId); 1781 } 1782 if (!canModifyNetwork(config, uid)) { 1783 Log.e(TAG, "UID " + uid + " does not have permission to update configuration " 1784 + config.configKey()); 1785 return false; 1786 } 1787 if (!updateNetworkSelectionStatus( 1788 networkId, WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE)) { 1789 return false; 1790 } 1791 saveToStore(true); 1792 return true; 1793 } 1794 1795 /** 1796 * Disable a network using the public {@link WifiManager#disableNetwork(int)} API. 1797 * 1798 * @param networkId network ID of the network that needs the update. 1799 * @param uid uid of the app requesting the update. 1800 * @return true if it succeeds, false otherwise 1801 */ disableNetwork(int networkId, int uid)1802 public boolean disableNetwork(int networkId, int uid) { 1803 if (mVerboseLoggingEnabled) { 1804 Log.v(TAG, "Disabling network " + networkId); 1805 } 1806 if (!doesUidBelongToCurrentUser(uid)) { 1807 Log.e(TAG, "UID " + uid + " not visible to the current user"); 1808 return false; 1809 } 1810 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1811 if (config == null) { 1812 return false; 1813 } 1814 // Reset the "last selected" flag even if the app does not have permissions to modify this 1815 // network config. 1816 if (networkId == mLastSelectedNetworkId) { 1817 clearLastSelectedNetwork(); 1818 } 1819 if (!canModifyNetwork(config, uid)) { 1820 Log.e(TAG, "UID " + uid + " does not have permission to update configuration " 1821 + config.configKey()); 1822 return false; 1823 } 1824 if (!updateNetworkSelectionStatus( 1825 networkId, NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER)) { 1826 return false; 1827 } 1828 saveToStore(true); 1829 return true; 1830 } 1831 1832 /** 1833 * Updates the last connected UID for the provided configuration. 1834 * 1835 * @param networkId network ID corresponding to the network. 1836 * @param uid uid of the app requesting the connection. 1837 * @return true if the network was found, false otherwise. 1838 */ updateLastConnectUid(int networkId, int uid)1839 public boolean updateLastConnectUid(int networkId, int uid) { 1840 if (mVerboseLoggingEnabled) { 1841 Log.v(TAG, "Update network last connect UID for " + networkId); 1842 } 1843 if (!doesUidBelongToCurrentUser(uid)) { 1844 Log.e(TAG, "UID " + uid + " not visible to the current user"); 1845 return false; 1846 } 1847 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1848 if (config == null) { 1849 return false; 1850 } 1851 config.lastConnectUid = uid; 1852 return true; 1853 } 1854 1855 /** 1856 * Updates a network configuration after a successful connection to it. 1857 * 1858 * This method updates the following WifiConfiguration elements: 1859 * 1. Set the |lastConnected| timestamp. 1860 * 2. Increment |numAssociation| counter. 1861 * 3. Clear the disable reason counters in the associated |NetworkSelectionStatus|. 1862 * 4. Set the hasEverConnected| flag in the associated |NetworkSelectionStatus|. 1863 * 5. Sets the status of network as |CURRENT|. 1864 * 1865 * @param networkId network ID corresponding to the network. 1866 * @return true if the network was found, false otherwise. 1867 */ updateNetworkAfterConnect(int networkId)1868 public boolean updateNetworkAfterConnect(int networkId) { 1869 if (mVerboseLoggingEnabled) { 1870 Log.v(TAG, "Update network after connect for " + networkId); 1871 } 1872 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1873 if (config == null) { 1874 return false; 1875 } 1876 config.lastConnected = mClock.getWallClockMillis(); 1877 config.numAssociation++; 1878 config.getNetworkSelectionStatus().clearDisableReasonCounter(); 1879 config.getNetworkSelectionStatus().setHasEverConnected(true); 1880 setNetworkStatus(config, WifiConfiguration.Status.CURRENT); 1881 saveToStore(false); 1882 return true; 1883 } 1884 1885 /** 1886 * Updates a network configuration after disconnection from it. 1887 * 1888 * This method updates the following WifiConfiguration elements: 1889 * 1. Set the |lastDisConnected| timestamp. 1890 * 2. Sets the status of network back to |ENABLED|. 1891 * 1892 * @param networkId network ID corresponding to the network. 1893 * @return true if the network was found, false otherwise. 1894 */ updateNetworkAfterDisconnect(int networkId)1895 public boolean updateNetworkAfterDisconnect(int networkId) { 1896 if (mVerboseLoggingEnabled) { 1897 Log.v(TAG, "Update network after disconnect for " + networkId); 1898 } 1899 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1900 if (config == null) { 1901 return false; 1902 } 1903 config.lastDisconnected = mClock.getWallClockMillis(); 1904 // If the network hasn't been disabled, mark it back as 1905 // enabled after disconnection. 1906 if (config.status == WifiConfiguration.Status.CURRENT) { 1907 setNetworkStatus(config, WifiConfiguration.Status.ENABLED); 1908 } 1909 saveToStore(false); 1910 return true; 1911 } 1912 1913 /** 1914 * Set default GW MAC address for the provided network. 1915 * 1916 * @param networkId network ID corresponding to the network. 1917 * @param macAddress MAC address of the gateway to be set. 1918 * @return true if the network was found, false otherwise. 1919 */ setNetworkDefaultGwMacAddress(int networkId, String macAddress)1920 public boolean setNetworkDefaultGwMacAddress(int networkId, String macAddress) { 1921 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1922 if (config == null) { 1923 return false; 1924 } 1925 config.defaultGwMacAddress = macAddress; 1926 return true; 1927 } 1928 1929 /** 1930 * Set randomized MAC address for the provided network. 1931 * 1932 * @param networkId network ID corresponding to the network. 1933 * @param macAddress Randomized MAC address to be used for network connection. 1934 * @return true if the network was found, false otherwise. 1935 */ setNetworkRandomizedMacAddress(int networkId, MacAddress macAddress)1936 public boolean setNetworkRandomizedMacAddress(int networkId, MacAddress macAddress) { 1937 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1938 if (config == null) { 1939 return false; 1940 } 1941 config.setRandomizedMacAddress(macAddress); 1942 return true; 1943 } 1944 1945 /** 1946 * Clear the {@link NetworkSelectionStatus#mCandidate}, 1947 * {@link NetworkSelectionStatus#mCandidateScore} & 1948 * {@link NetworkSelectionStatus#mSeenInLastQualifiedNetworkSelection} for the provided network. 1949 * 1950 * This is invoked by Network Selector at the start of every selection procedure to clear all 1951 * configured networks' scan-result-candidates. 1952 * 1953 * @param networkId network ID corresponding to the network. 1954 * @return true if the network was found, false otherwise. 1955 */ clearNetworkCandidateScanResult(int networkId)1956 public boolean clearNetworkCandidateScanResult(int networkId) { 1957 if (mVerboseLoggingEnabled) { 1958 Log.v(TAG, "Clear network candidate scan result for " + networkId); 1959 } 1960 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1961 if (config == null) { 1962 return false; 1963 } 1964 config.getNetworkSelectionStatus().setCandidate(null); 1965 config.getNetworkSelectionStatus().setCandidateScore(Integer.MIN_VALUE); 1966 config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(false); 1967 return true; 1968 } 1969 1970 /** 1971 * Set the {@link NetworkSelectionStatus#mCandidate}, 1972 * {@link NetworkSelectionStatus#mCandidateScore} & 1973 * {@link NetworkSelectionStatus#mSeenInLastQualifiedNetworkSelection} for the provided network. 1974 * 1975 * This is invoked by Network Selector when it sees a network during network selection procedure 1976 * to set the scan result candidate. 1977 * 1978 * @param networkId network ID corresponding to the network. 1979 * @param scanResult Candidate ScanResult associated with this network. 1980 * @param score Score assigned to the candidate. 1981 * @return true if the network was found, false otherwise. 1982 */ setNetworkCandidateScanResult(int networkId, ScanResult scanResult, int score)1983 public boolean setNetworkCandidateScanResult(int networkId, ScanResult scanResult, int score) { 1984 if (mVerboseLoggingEnabled) { 1985 Log.v(TAG, "Set network candidate scan result " + scanResult + " for " + networkId); 1986 } 1987 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 1988 if (config == null) { 1989 Log.e(TAG, "Cannot find network for " + networkId); 1990 return false; 1991 } 1992 config.getNetworkSelectionStatus().setCandidate(scanResult); 1993 config.getNetworkSelectionStatus().setCandidateScore(score); 1994 config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(true); 1995 return true; 1996 } 1997 1998 /** 1999 * Iterate through all the saved networks and remove the provided configuration from the 2000 * {@link NetworkSelectionStatus#mConnectChoice} from them. 2001 * 2002 * This is invoked when a network is removed from our records. 2003 * 2004 * @param connectChoiceConfigKey ConfigKey corresponding to the network that is being removed. 2005 */ removeConnectChoiceFromAllNetworks(String connectChoiceConfigKey)2006 private void removeConnectChoiceFromAllNetworks(String connectChoiceConfigKey) { 2007 if (mVerboseLoggingEnabled) { 2008 Log.v(TAG, "Removing connect choice from all networks " + connectChoiceConfigKey); 2009 } 2010 if (connectChoiceConfigKey == null) { 2011 return; 2012 } 2013 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2014 WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 2015 String connectChoice = status.getConnectChoice(); 2016 if (TextUtils.equals(connectChoice, connectChoiceConfigKey)) { 2017 Log.d(TAG, "remove connect choice:" + connectChoice + " from " + config.SSID 2018 + " : " + config.networkId); 2019 clearNetworkConnectChoice(config.networkId); 2020 } 2021 } 2022 } 2023 2024 /** 2025 * Clear the {@link NetworkSelectionStatus#mConnectChoice} & 2026 * {@link NetworkSelectionStatus#mConnectChoiceTimestamp} for the provided network. 2027 * 2028 * @param networkId network ID corresponding to the network. 2029 * @return true if the network was found, false otherwise. 2030 */ clearNetworkConnectChoice(int networkId)2031 public boolean clearNetworkConnectChoice(int networkId) { 2032 if (mVerboseLoggingEnabled) { 2033 Log.v(TAG, "Clear network connect choice for " + networkId); 2034 } 2035 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2036 if (config == null) { 2037 return false; 2038 } 2039 config.getNetworkSelectionStatus().setConnectChoice(null); 2040 config.getNetworkSelectionStatus().setConnectChoiceTimestamp( 2041 NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 2042 saveToStore(false); 2043 return true; 2044 } 2045 2046 /** 2047 * Set the {@link NetworkSelectionStatus#mConnectChoice} & 2048 * {@link NetworkSelectionStatus#mConnectChoiceTimestamp} for the provided network. 2049 * 2050 * This is invoked by Network Selector when the user overrides the currently connected network 2051 * choice. 2052 * 2053 * @param networkId network ID corresponding to the network. 2054 * @param connectChoiceConfigKey ConfigKey corresponding to the network which was chosen over 2055 * this network. 2056 * @param timestamp timestamp at which the choice was made. 2057 * @return true if the network was found, false otherwise. 2058 */ setNetworkConnectChoice( int networkId, String connectChoiceConfigKey, long timestamp)2059 public boolean setNetworkConnectChoice( 2060 int networkId, String connectChoiceConfigKey, long timestamp) { 2061 if (mVerboseLoggingEnabled) { 2062 Log.v(TAG, "Set network connect choice " + connectChoiceConfigKey + " for " + networkId); 2063 } 2064 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2065 if (config == null) { 2066 return false; 2067 } 2068 config.getNetworkSelectionStatus().setConnectChoice(connectChoiceConfigKey); 2069 config.getNetworkSelectionStatus().setConnectChoiceTimestamp(timestamp); 2070 saveToStore(false); 2071 return true; 2072 } 2073 2074 /** 2075 * Increments the number of no internet access reports in the provided network. 2076 * 2077 * @param networkId network ID corresponding to the network. 2078 * @return true if the network was found, false otherwise. 2079 */ incrementNetworkNoInternetAccessReports(int networkId)2080 public boolean incrementNetworkNoInternetAccessReports(int networkId) { 2081 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2082 if (config == null) { 2083 return false; 2084 } 2085 config.numNoInternetAccessReports++; 2086 return true; 2087 } 2088 2089 /** 2090 * Sets the internet access is validated or not in the provided network. 2091 * 2092 * @param networkId network ID corresponding to the network. 2093 * @param validated Whether access is validated or not. 2094 * @return true if the network was found, false otherwise. 2095 */ setNetworkValidatedInternetAccess(int networkId, boolean validated)2096 public boolean setNetworkValidatedInternetAccess(int networkId, boolean validated) { 2097 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2098 if (config == null) { 2099 return false; 2100 } 2101 config.validatedInternetAccess = validated; 2102 config.numNoInternetAccessReports = 0; 2103 saveToStore(false); 2104 return true; 2105 } 2106 2107 /** 2108 * Sets whether the internet access is expected or not in the provided network. 2109 * 2110 * @param networkId network ID corresponding to the network. 2111 * @param expected Whether access is expected or not. 2112 * @return true if the network was found, false otherwise. 2113 */ setNetworkNoInternetAccessExpected(int networkId, boolean expected)2114 public boolean setNetworkNoInternetAccessExpected(int networkId, boolean expected) { 2115 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2116 if (config == null) { 2117 return false; 2118 } 2119 config.noInternetAccessExpected = expected; 2120 return true; 2121 } 2122 2123 /** 2124 * Helper method to clear out the {@link #mNextNetworkId} user/app network selection. This 2125 * is done when either the corresponding network is either removed or disabled. 2126 */ clearLastSelectedNetwork()2127 private void clearLastSelectedNetwork() { 2128 if (mVerboseLoggingEnabled) { 2129 Log.v(TAG, "Clearing last selected network"); 2130 } 2131 mLastSelectedNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2132 mLastSelectedTimeStamp = NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP; 2133 } 2134 2135 /** 2136 * Helper method to mark a network as the last selected one by an app/user. This is set 2137 * when an app invokes {@link #enableNetwork(int, boolean, int)} with |disableOthers| flag set. 2138 * This is used by network selector to assign a special bonus during network selection. 2139 */ setLastSelectedNetwork(int networkId)2140 private void setLastSelectedNetwork(int networkId) { 2141 if (mVerboseLoggingEnabled) { 2142 Log.v(TAG, "Setting last selected network to " + networkId); 2143 } 2144 mLastSelectedNetworkId = networkId; 2145 mLastSelectedTimeStamp = mClock.getElapsedSinceBootMillis(); 2146 } 2147 2148 /** 2149 * Retrieve the network Id corresponding to the last network that was explicitly selected by 2150 * an app/user. 2151 * 2152 * @return network Id corresponding to the last selected network. 2153 */ getLastSelectedNetwork()2154 public int getLastSelectedNetwork() { 2155 return mLastSelectedNetworkId; 2156 } 2157 2158 /** 2159 * Retrieve the configKey corresponding to the last network that was explicitly selected by 2160 * an app/user. 2161 * 2162 * @return network Id corresponding to the last selected network. 2163 */ getLastSelectedNetworkConfigKey()2164 public String getLastSelectedNetworkConfigKey() { 2165 if (mLastSelectedNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 2166 return ""; 2167 } 2168 WifiConfiguration config = getInternalConfiguredNetwork(mLastSelectedNetworkId); 2169 if (config == null) { 2170 return ""; 2171 } 2172 return config.configKey(); 2173 } 2174 2175 /** 2176 * Retrieve the time stamp at which a network was explicitly selected by an app/user. 2177 * 2178 * @return timestamp in milliseconds from boot when this was set. 2179 */ getLastSelectedTimeStamp()2180 public long getLastSelectedTimeStamp() { 2181 return mLastSelectedTimeStamp; 2182 } 2183 2184 /** 2185 * Helper method to get the scan detail cache entry {@link #mScanDetailCaches} for the provided 2186 * network. 2187 * 2188 * @param networkId network ID corresponding to the network. 2189 * @return existing {@link ScanDetailCache} entry if one exists or null. 2190 */ getScanDetailCacheForNetwork(int networkId)2191 public ScanDetailCache getScanDetailCacheForNetwork(int networkId) { 2192 return mScanDetailCaches.get(networkId); 2193 } 2194 2195 /** 2196 * Helper method to get or create a scan detail cache entry {@link #mScanDetailCaches} for 2197 * the provided network. 2198 * 2199 * @param config configuration corresponding to the the network. 2200 * @return existing {@link ScanDetailCache} entry if one exists or a new instance created for 2201 * this network. 2202 */ getOrCreateScanDetailCacheForNetwork(WifiConfiguration config)2203 private ScanDetailCache getOrCreateScanDetailCacheForNetwork(WifiConfiguration config) { 2204 if (config == null) return null; 2205 ScanDetailCache cache = getScanDetailCacheForNetwork(config.networkId); 2206 if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { 2207 cache = new ScanDetailCache( 2208 config, SCAN_CACHE_ENTRIES_MAX_SIZE, SCAN_CACHE_ENTRIES_TRIM_SIZE); 2209 mScanDetailCaches.put(config.networkId, cache); 2210 } 2211 return cache; 2212 } 2213 2214 /** 2215 * Saves the provided ScanDetail into the corresponding scan detail cache entry 2216 * {@link #mScanDetailCaches} for the provided network. 2217 * 2218 * @param config configuration corresponding to the the network. 2219 * @param scanDetail new scan detail instance to be saved into the cache. 2220 */ saveToScanDetailCacheForNetwork( WifiConfiguration config, ScanDetail scanDetail)2221 private void saveToScanDetailCacheForNetwork( 2222 WifiConfiguration config, ScanDetail scanDetail) { 2223 ScanResult scanResult = scanDetail.getScanResult(); 2224 2225 ScanDetailCache scanDetailCache = getOrCreateScanDetailCacheForNetwork(config); 2226 if (scanDetailCache == null) { 2227 Log.e(TAG, "Could not allocate scan cache for " + config.getPrintableSsid()); 2228 return; 2229 } 2230 2231 // Adding a new BSSID 2232 if (config.ephemeral) { 2233 // For an ephemeral Wi-Fi config, the ScanResult should be considered 2234 // untrusted. 2235 scanResult.untrusted = true; 2236 } 2237 2238 // Add the scan detail to this network's scan detail cache. 2239 scanDetailCache.put(scanDetail); 2240 2241 // Since we added a scan result to this configuration, re-attempt linking. 2242 // TODO: Do we really need to do this after every scan result? 2243 attemptNetworkLinking(config); 2244 } 2245 2246 /** 2247 * Retrieves a configured network corresponding to the provided scan detail if one exists. 2248 * 2249 * @param scanDetail ScanDetail instance to use for looking up the network. 2250 * @return WifiConfiguration object representing the network corresponding to the scanDetail, 2251 * null if none exists. 2252 */ getConfiguredNetworkForScanDetail(ScanDetail scanDetail)2253 public WifiConfiguration getConfiguredNetworkForScanDetail(ScanDetail scanDetail) { 2254 ScanResult scanResult = scanDetail.getScanResult(); 2255 if (scanResult == null) { 2256 Log.e(TAG, "No scan result found in scan detail"); 2257 return null; 2258 } 2259 WifiConfiguration config = null; 2260 try { 2261 config = mConfiguredNetworks.getByScanResultForCurrentUser(scanResult); 2262 } catch (IllegalArgumentException e) { 2263 Log.e(TAG, "Failed to lookup network from config map", e); 2264 } 2265 if (config != null) { 2266 if (mVerboseLoggingEnabled) { 2267 Log.v(TAG, "getSavedNetworkFromScanDetail Found " + config.configKey() 2268 + " for " + scanResult.SSID + "[" + scanResult.capabilities + "]"); 2269 } 2270 } 2271 return config; 2272 } 2273 2274 /** 2275 * Retrieves a configured network corresponding to the provided scan detail if one exists and 2276 * caches the provided |scanDetail| into the corresponding scan detail cache entry 2277 * {@link #mScanDetailCaches} for the retrieved network. 2278 * 2279 * @param scanDetail input a scanDetail from the scan result 2280 * @return WifiConfiguration object representing the network corresponding to the scanDetail, 2281 * null if none exists. 2282 */ getConfiguredNetworkForScanDetailAndCache(ScanDetail scanDetail)2283 public WifiConfiguration getConfiguredNetworkForScanDetailAndCache(ScanDetail scanDetail) { 2284 WifiConfiguration network = getConfiguredNetworkForScanDetail(scanDetail); 2285 if (network == null) { 2286 return null; 2287 } 2288 saveToScanDetailCacheForNetwork(network, scanDetail); 2289 // Cache DTIM values parsed from the beacon frame Traffic Indication Map (TIM) 2290 // Information Element (IE), into the associated WifiConfigurations. Most of the 2291 // time there is no TIM IE in the scan result (Probe Response instead of Beacon 2292 // Frame), these scanResult DTIM's are negative and ignored. 2293 // Used for metrics collection. 2294 if (scanDetail.getNetworkDetail() != null 2295 && scanDetail.getNetworkDetail().getDtimInterval() > 0) { 2296 network.dtimInterval = scanDetail.getNetworkDetail().getDtimInterval(); 2297 } 2298 return createExternalWifiConfiguration(network, true, Process.WIFI_UID); 2299 } 2300 2301 /** 2302 * Update the scan detail cache associated with current connected network with latest 2303 * RSSI value in the provided WifiInfo. 2304 * This is invoked when we get an RSSI poll update after connection. 2305 * 2306 * @param info WifiInfo instance pointing to the current connected network. 2307 */ updateScanDetailCacheFromWifiInfo(WifiInfo info)2308 public void updateScanDetailCacheFromWifiInfo(WifiInfo info) { 2309 WifiConfiguration config = getInternalConfiguredNetwork(info.getNetworkId()); 2310 ScanDetailCache scanDetailCache = getScanDetailCacheForNetwork(info.getNetworkId()); 2311 if (config != null && scanDetailCache != null) { 2312 ScanDetail scanDetail = scanDetailCache.getScanDetail(info.getBSSID()); 2313 if (scanDetail != null) { 2314 ScanResult result = scanDetail.getScanResult(); 2315 long previousSeen = result.seen; 2316 int previousRssi = result.level; 2317 // Update the scan result 2318 scanDetail.setSeen(); 2319 result.level = info.getRssi(); 2320 // Average the RSSI value 2321 long maxAge = SCAN_RESULT_MAXIMUM_AGE_MS; 2322 long age = result.seen - previousSeen; 2323 if (previousSeen > 0 && age > 0 && age < maxAge / 2) { 2324 // Average the RSSI with previously seen instances of this scan result 2325 double alpha = 0.5 - (double) age / (double) maxAge; 2326 result.level = (int) ((double) result.level * (1 - alpha) 2327 + (double) previousRssi * alpha); 2328 } 2329 if (mVerboseLoggingEnabled) { 2330 Log.v(TAG, "Updating scan detail cache freq=" + result.frequency 2331 + " BSSID=" + result.BSSID 2332 + " RSSI=" + result.level 2333 + " for " + config.configKey()); 2334 } 2335 } 2336 } 2337 } 2338 2339 /** 2340 * Save the ScanDetail to the ScanDetailCache of the given network. This is used 2341 * by {@link com.android.server.wifi.hotspot2.PasspointNetworkEvaluator} for caching 2342 * ScanDetail for newly created {@link WifiConfiguration} for Passpoint network. 2343 * 2344 * @param networkId The ID of the network to save ScanDetail to 2345 * @param scanDetail The ScanDetail to cache 2346 */ updateScanDetailForNetwork(int networkId, ScanDetail scanDetail)2347 public void updateScanDetailForNetwork(int networkId, ScanDetail scanDetail) { 2348 WifiConfiguration network = getInternalConfiguredNetwork(networkId); 2349 if (network == null) { 2350 return; 2351 } 2352 saveToScanDetailCacheForNetwork(network, scanDetail); 2353 } 2354 2355 /** 2356 * Helper method to check if the 2 provided networks can be linked or not. 2357 * Networks are considered for linking if: 2358 * 1. Share the same GW MAC address. 2359 * 2. Scan results for the networks have AP's with MAC address which differ only in the last 2360 * nibble. 2361 * 2362 * @param network1 WifiConfiguration corresponding to network 1. 2363 * @param network2 WifiConfiguration corresponding to network 2. 2364 * @param scanDetailCache1 ScanDetailCache entry for network 1. 2365 * @param scanDetailCache1 ScanDetailCache entry for network 2. 2366 * @return true if the networks should be linked, false if the networks should be unlinked. 2367 */ shouldNetworksBeLinked( WifiConfiguration network1, WifiConfiguration network2, ScanDetailCache scanDetailCache1, ScanDetailCache scanDetailCache2)2368 private boolean shouldNetworksBeLinked( 2369 WifiConfiguration network1, WifiConfiguration network2, 2370 ScanDetailCache scanDetailCache1, ScanDetailCache scanDetailCache2) { 2371 // TODO (b/30706406): Link networks only with same passwords if the 2372 // |mOnlyLinkSameCredentialConfigurations| flag is set. 2373 if (mOnlyLinkSameCredentialConfigurations) { 2374 if (!TextUtils.equals(network1.preSharedKey, network2.preSharedKey)) { 2375 if (mVerboseLoggingEnabled) { 2376 Log.v(TAG, "shouldNetworksBeLinked unlink due to password mismatch"); 2377 } 2378 return false; 2379 } 2380 } 2381 if (network1.defaultGwMacAddress != null && network2.defaultGwMacAddress != null) { 2382 // If both default GW are known, link only if they are equal 2383 if (network1.defaultGwMacAddress.equals(network2.defaultGwMacAddress)) { 2384 if (mVerboseLoggingEnabled) { 2385 Log.v(TAG, "shouldNetworksBeLinked link due to same gw " + network2.SSID 2386 + " and " + network1.SSID + " GW " + network1.defaultGwMacAddress); 2387 } 2388 return true; 2389 } 2390 } else { 2391 // We do not know BOTH default gateways hence we will try to link 2392 // hoping that WifiConfigurations are indeed behind the same gateway. 2393 // once both WifiConfiguration have been tried and thus once both default gateways 2394 // are known we will revisit the choice of linking them. 2395 if (scanDetailCache1 != null && scanDetailCache2 != null) { 2396 for (String abssid : scanDetailCache1.keySet()) { 2397 for (String bbssid : scanDetailCache2.keySet()) { 2398 if (abssid.regionMatches( 2399 true, 0, bbssid, 0, LINK_CONFIGURATION_BSSID_MATCH_LENGTH)) { 2400 // If first 16 ASCII characters of BSSID matches, 2401 // we assume this is a DBDC. 2402 if (mVerboseLoggingEnabled) { 2403 Log.v(TAG, "shouldNetworksBeLinked link due to DBDC BSSID match " 2404 + network2.SSID + " and " + network1.SSID 2405 + " bssida " + abssid + " bssidb " + bbssid); 2406 } 2407 return true; 2408 } 2409 } 2410 } 2411 } 2412 } 2413 return false; 2414 } 2415 2416 /** 2417 * Helper methods to link 2 networks together. 2418 * 2419 * @param network1 WifiConfiguration corresponding to network 1. 2420 * @param network2 WifiConfiguration corresponding to network 2. 2421 */ linkNetworks(WifiConfiguration network1, WifiConfiguration network2)2422 private void linkNetworks(WifiConfiguration network1, WifiConfiguration network2) { 2423 if (mVerboseLoggingEnabled) { 2424 Log.v(TAG, "linkNetworks will link " + network2.configKey() 2425 + " and " + network1.configKey()); 2426 } 2427 if (network2.linkedConfigurations == null) { 2428 network2.linkedConfigurations = new HashMap<>(); 2429 } 2430 if (network1.linkedConfigurations == null) { 2431 network1.linkedConfigurations = new HashMap<>(); 2432 } 2433 // TODO (b/30638473): This needs to become a set instead of map, but it will need 2434 // public interface changes and need some migration of existing store data. 2435 network2.linkedConfigurations.put(network1.configKey(), 1); 2436 network1.linkedConfigurations.put(network2.configKey(), 1); 2437 } 2438 2439 /** 2440 * Helper methods to unlink 2 networks from each other. 2441 * 2442 * @param network1 WifiConfiguration corresponding to network 1. 2443 * @param network2 WifiConfiguration corresponding to network 2. 2444 */ unlinkNetworks(WifiConfiguration network1, WifiConfiguration network2)2445 private void unlinkNetworks(WifiConfiguration network1, WifiConfiguration network2) { 2446 if (network2.linkedConfigurations != null 2447 && (network2.linkedConfigurations.get(network1.configKey()) != null)) { 2448 if (mVerboseLoggingEnabled) { 2449 Log.v(TAG, "unlinkNetworks un-link " + network1.configKey() 2450 + " from " + network2.configKey()); 2451 } 2452 network2.linkedConfigurations.remove(network1.configKey()); 2453 } 2454 if (network1.linkedConfigurations != null 2455 && (network1.linkedConfigurations.get(network2.configKey()) != null)) { 2456 if (mVerboseLoggingEnabled) { 2457 Log.v(TAG, "unlinkNetworks un-link " + network2.configKey() 2458 + " from " + network1.configKey()); 2459 } 2460 network1.linkedConfigurations.remove(network2.configKey()); 2461 } 2462 } 2463 2464 /** 2465 * This method runs through all the saved networks and checks if the provided network can be 2466 * linked with any of them. 2467 * 2468 * @param config WifiConfiguration object corresponding to the network that needs to be 2469 * checked for potential links. 2470 */ attemptNetworkLinking(WifiConfiguration config)2471 private void attemptNetworkLinking(WifiConfiguration config) { 2472 // Only link WPA_PSK config. 2473 if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 2474 return; 2475 } 2476 ScanDetailCache scanDetailCache = getScanDetailCacheForNetwork(config.networkId); 2477 // Ignore configurations with large number of BSSIDs. 2478 if (scanDetailCache != null 2479 && scanDetailCache.size() > LINK_CONFIGURATION_MAX_SCAN_CACHE_ENTRIES) { 2480 return; 2481 } 2482 for (WifiConfiguration linkConfig : getInternalConfiguredNetworks()) { 2483 if (linkConfig.configKey().equals(config.configKey())) { 2484 continue; 2485 } 2486 if (linkConfig.ephemeral) { 2487 continue; 2488 } 2489 // Network Selector will be allowed to dynamically jump from a linked configuration 2490 // to another, hence only link configurations that have WPA_PSK security type. 2491 if (!linkConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 2492 continue; 2493 } 2494 ScanDetailCache linkScanDetailCache = 2495 getScanDetailCacheForNetwork(linkConfig.networkId); 2496 // Ignore configurations with large number of BSSIDs. 2497 if (linkScanDetailCache != null 2498 && linkScanDetailCache.size() > LINK_CONFIGURATION_MAX_SCAN_CACHE_ENTRIES) { 2499 continue; 2500 } 2501 // Check if the networks should be linked/unlinked. 2502 if (shouldNetworksBeLinked( 2503 config, linkConfig, scanDetailCache, linkScanDetailCache)) { 2504 linkNetworks(config, linkConfig); 2505 } else { 2506 unlinkNetworks(config, linkConfig); 2507 } 2508 } 2509 } 2510 2511 /** 2512 * Helper method to fetch list of channels for a network from the associated ScanResult's cache 2513 * and add it to the provided channel as long as the size of the set is less than 2514 * |maxChannelSetSize|. 2515 * 2516 * @param channelSet Channel set holding all the channels for the network. 2517 * @param scanDetailCache ScanDetailCache entry associated with the network. 2518 * @param nowInMillis current timestamp to be used for age comparison. 2519 * @param ageInMillis only consider scan details whose timestamps are earlier than this 2520 * value. 2521 * @param maxChannelSetSize Maximum number of channels to be added to the set. 2522 * @return false if the list is full, true otherwise. 2523 */ addToChannelSetForNetworkFromScanDetailCache( Set<Integer> channelSet, ScanDetailCache scanDetailCache, long nowInMillis, long ageInMillis, int maxChannelSetSize)2524 private boolean addToChannelSetForNetworkFromScanDetailCache( 2525 Set<Integer> channelSet, ScanDetailCache scanDetailCache, 2526 long nowInMillis, long ageInMillis, int maxChannelSetSize) { 2527 if (scanDetailCache != null && scanDetailCache.size() > 0) { 2528 for (ScanDetail scanDetail : scanDetailCache.values()) { 2529 ScanResult result = scanDetail.getScanResult(); 2530 boolean valid = (nowInMillis - result.seen) < ageInMillis; 2531 if (mVerboseLoggingEnabled) { 2532 Log.v(TAG, "fetchChannelSetForNetwork has " + result.BSSID + " freq " 2533 + result.frequency + " age " + (nowInMillis - result.seen) 2534 + " ?=" + valid); 2535 } 2536 if (valid) { 2537 channelSet.add(result.frequency); 2538 } 2539 if (channelSet.size() >= maxChannelSetSize) { 2540 return false; 2541 } 2542 } 2543 } 2544 return true; 2545 } 2546 2547 /** 2548 * Retrieve a set of channels on which AP's for the provided network was seen using the 2549 * internal ScanResult's cache {@link #mScanDetailCaches}. This is used for initiating partial 2550 * scans for the currently connected network. 2551 * 2552 * @param networkId network ID corresponding to the network. 2553 * @param ageInMillis only consider scan details whose timestamps are earlier than this value. 2554 * @param homeChannelFreq frequency of the currently connected network. 2555 * @return Set containing the frequencies on which this network was found, null if the network 2556 * was not found or there are no associated scan details in the cache. 2557 */ fetchChannelSetForNetworkForPartialScan(int networkId, long ageInMillis, int homeChannelFreq)2558 public Set<Integer> fetchChannelSetForNetworkForPartialScan(int networkId, long ageInMillis, 2559 int homeChannelFreq) { 2560 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2561 if (config == null) { 2562 return null; 2563 } 2564 ScanDetailCache scanDetailCache = getScanDetailCacheForNetwork(networkId); 2565 if (scanDetailCache == null && config.linkedConfigurations == null) { 2566 Log.i(TAG, "No scan detail and linked configs associated with networkId " + networkId); 2567 return null; 2568 } 2569 if (mVerboseLoggingEnabled) { 2570 StringBuilder dbg = new StringBuilder(); 2571 dbg.append("fetchChannelSetForNetworkForPartialScan ageInMillis ") 2572 .append(ageInMillis) 2573 .append(" for ") 2574 .append(config.configKey()) 2575 .append(" max ") 2576 .append(mMaxNumActiveChannelsForPartialScans); 2577 if (scanDetailCache != null) { 2578 dbg.append(" bssids " + scanDetailCache.size()); 2579 } 2580 if (config.linkedConfigurations != null) { 2581 dbg.append(" linked " + config.linkedConfigurations.size()); 2582 } 2583 Log.v(TAG, dbg.toString()); 2584 } 2585 Set<Integer> channelSet = new HashSet<>(); 2586 2587 // First add the currently connected network channel. 2588 if (homeChannelFreq > 0) { 2589 channelSet.add(homeChannelFreq); 2590 if (channelSet.size() >= mMaxNumActiveChannelsForPartialScans) { 2591 return channelSet; 2592 } 2593 } 2594 2595 long nowInMillis = mClock.getWallClockMillis(); 2596 2597 // Then get channels for the network. 2598 if (!addToChannelSetForNetworkFromScanDetailCache( 2599 channelSet, scanDetailCache, nowInMillis, ageInMillis, 2600 mMaxNumActiveChannelsForPartialScans)) { 2601 return channelSet; 2602 } 2603 2604 // Lastly get channels for linked networks. 2605 if (config.linkedConfigurations != null) { 2606 for (String configKey : config.linkedConfigurations.keySet()) { 2607 WifiConfiguration linkedConfig = getInternalConfiguredNetwork(configKey); 2608 if (linkedConfig == null) { 2609 continue; 2610 } 2611 ScanDetailCache linkedScanDetailCache = 2612 getScanDetailCacheForNetwork(linkedConfig.networkId); 2613 if (!addToChannelSetForNetworkFromScanDetailCache( 2614 channelSet, linkedScanDetailCache, nowInMillis, ageInMillis, 2615 mMaxNumActiveChannelsForPartialScans)) { 2616 break; 2617 } 2618 } 2619 } 2620 return channelSet; 2621 } 2622 2623 /** 2624 * Retrieve a set of channels on which AP's for the provided network was seen using the 2625 * internal ScanResult's cache {@link #mScanDetailCaches}. This is used to reduced the list 2626 * of frequencies for pno scans. 2627 * 2628 * @param networkId network ID corresponding to the network. 2629 * @param ageInMillis only consider scan details whose timestamps are earlier than this. 2630 * @return Set containing the frequencies on which this network was found, null if the network 2631 * was not found or there are no associated scan details in the cache. 2632 */ fetchChannelSetForNetworkForPnoScan(int networkId, long ageInMillis)2633 private Set<Integer> fetchChannelSetForNetworkForPnoScan(int networkId, long ageInMillis) { 2634 WifiConfiguration config = getInternalConfiguredNetwork(networkId); 2635 if (config == null) { 2636 return null; 2637 } 2638 ScanDetailCache scanDetailCache = getScanDetailCacheForNetwork(networkId); 2639 if (scanDetailCache == null) { 2640 return null; 2641 } 2642 if (mVerboseLoggingEnabled) { 2643 Log.v(TAG, new StringBuilder("fetchChannelSetForNetworkForPnoScan ageInMillis ") 2644 .append(ageInMillis) 2645 .append(" for ") 2646 .append(config.configKey()) 2647 .append(" bssids " + scanDetailCache.size()) 2648 .toString()); 2649 } 2650 Set<Integer> channelSet = new HashSet<>(); 2651 long nowInMillis = mClock.getWallClockMillis(); 2652 2653 // Add channels for the network to the output. 2654 addToChannelSetForNetworkFromScanDetailCache(channelSet, scanDetailCache, nowInMillis, 2655 ageInMillis, Integer.MAX_VALUE); 2656 return channelSet; 2657 } 2658 2659 /** 2660 * Retrieves a list of all the saved networks before enabling disconnected/connected PNO. 2661 * 2662 * PNO network list sent to the firmware has limited size. If there are a lot of saved 2663 * networks, this list will be truncated and we might end up not sending the networks 2664 * with the highest chance of connecting to the firmware. 2665 * So, re-sort the network list based on the frequency of connection to those networks 2666 * and whether it was last seen in the scan results. 2667 * 2668 * @return list of networks in the order of priority. 2669 */ retrievePnoNetworkList()2670 public List<WifiScanner.PnoSettings.PnoNetwork> retrievePnoNetworkList() { 2671 List<WifiScanner.PnoSettings.PnoNetwork> pnoList = new ArrayList<>(); 2672 List<WifiConfiguration> networks = new ArrayList<>(getInternalConfiguredNetworks()); 2673 // Remove any permanently or temporarily disabled networks. 2674 Iterator<WifiConfiguration> iter = networks.iterator(); 2675 while (iter.hasNext()) { 2676 WifiConfiguration config = iter.next(); 2677 if (config.ephemeral || config.isPasspoint() 2678 || config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled() 2679 || config.getNetworkSelectionStatus().isNetworkTemporaryDisabled()) { 2680 iter.remove(); 2681 } 2682 } 2683 if (networks.isEmpty()) { 2684 return pnoList; 2685 } 2686 2687 // Sort the networks with the most frequent ones at the front of the network list. 2688 Collections.sort(networks, sScanListComparator); 2689 if (mPnoRecencySortingEnabled) { 2690 // Find the most recently connected network and add it to the front of the network list. 2691 WifiConfiguration lastConnectedNetwork = 2692 networks.stream() 2693 .max(Comparator.comparing( 2694 (WifiConfiguration config) -> config.lastConnected)) 2695 .get(); 2696 if (lastConnectedNetwork.lastConnected != 0) { 2697 int lastConnectedNetworkIdx = networks.indexOf(lastConnectedNetwork); 2698 networks.remove(lastConnectedNetworkIdx); 2699 networks.add(0, lastConnectedNetwork); 2700 } 2701 } 2702 for (WifiConfiguration config : networks) { 2703 WifiScanner.PnoSettings.PnoNetwork pnoNetwork = 2704 WifiConfigurationUtil.createPnoNetwork(config); 2705 pnoList.add(pnoNetwork); 2706 if (!mPnoFrequencyCullingEnabled) { 2707 continue; 2708 } 2709 Set<Integer> channelSet = fetchChannelSetForNetworkForPnoScan(config.networkId, 2710 MAX_PNO_SCAN_FREQUENCY_AGE_MS); 2711 if (channelSet != null) { 2712 pnoNetwork.frequencies = channelSet.stream() 2713 .mapToInt(Integer::intValue) 2714 .toArray(); 2715 } 2716 if (mVerboseLoggingEnabled) { 2717 Log.v(TAG, "retrievePnoNetworkList " + pnoNetwork.ssid + ":" 2718 + Arrays.toString(pnoNetwork.frequencies)); 2719 } 2720 } 2721 return pnoList; 2722 } 2723 2724 /** 2725 * Retrieves a list of all the saved hidden networks for scans. 2726 * 2727 * Hidden network list sent to the firmware has limited size. If there are a lot of saved 2728 * networks, this list will be truncated and we might end up not sending the networks 2729 * with the highest chance of connecting to the firmware. 2730 * So, re-sort the network list based on the frequency of connection to those networks 2731 * and whether it was last seen in the scan results. 2732 * 2733 * @return list of networks in the order of priority. 2734 */ retrieveHiddenNetworkList()2735 public List<WifiScanner.ScanSettings.HiddenNetwork> retrieveHiddenNetworkList() { 2736 List<WifiScanner.ScanSettings.HiddenNetwork> hiddenList = new ArrayList<>(); 2737 List<WifiConfiguration> networks = new ArrayList<>(getInternalConfiguredNetworks()); 2738 // Remove any permanently disabled networks or non hidden networks. 2739 Iterator<WifiConfiguration> iter = networks.iterator(); 2740 while (iter.hasNext()) { 2741 WifiConfiguration config = iter.next(); 2742 if (!config.hiddenSSID) { 2743 iter.remove(); 2744 } 2745 } 2746 Collections.sort(networks, sScanListComparator); 2747 // The most frequently connected network has the highest priority now. 2748 for (WifiConfiguration config : networks) { 2749 hiddenList.add( 2750 new WifiScanner.ScanSettings.HiddenNetwork(config.SSID)); 2751 } 2752 return hiddenList; 2753 } 2754 2755 /** 2756 * Check if the provided ephemeral network was deleted by the user or not. This call also clears 2757 * the SSID from the deleted ephemeral network map, if the duration has expired the 2758 * timeout specified by {@link #DELETED_EPHEMERAL_SSID_EXPIRY_MS}. 2759 * 2760 * @param ssid caller must ensure that the SSID passed thru this API match 2761 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 2762 * @return true if network was deleted, false otherwise. 2763 */ wasEphemeralNetworkDeleted(String ssid)2764 public boolean wasEphemeralNetworkDeleted(String ssid) { 2765 if (!mDeletedEphemeralSsidsToTimeMap.containsKey(ssid)) { 2766 return false; 2767 } 2768 long deletedTimeInMs = mDeletedEphemeralSsidsToTimeMap.get(ssid); 2769 long nowInMs = mClock.getWallClockMillis(); 2770 // Clear the ssid from the map if the age > |DELETED_EPHEMERAL_SSID_EXPIRY_MS|. 2771 if (nowInMs - deletedTimeInMs > DELETED_EPHEMERAL_SSID_EXPIRY_MS) { 2772 mDeletedEphemeralSsidsToTimeMap.remove(ssid); 2773 return false; 2774 } 2775 return true; 2776 } 2777 2778 /** 2779 * Disable an ephemeral or Passpoint SSID for the purpose of network selection. 2780 * 2781 * The network will be re-enabled when: 2782 * a) The user creates a network for that SSID and then forgets. 2783 * b) The time specified by {@link #DELETED_EPHEMERAL_SSID_EXPIRY_MS} expires after the disable. 2784 * 2785 * @param ssid caller must ensure that the SSID passed thru this API match 2786 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 2787 * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can 2788 * disconnect if this is the current network. 2789 */ disableEphemeralNetwork(String ssid)2790 public WifiConfiguration disableEphemeralNetwork(String ssid) { 2791 if (ssid == null) { 2792 return null; 2793 } 2794 WifiConfiguration foundConfig = null; 2795 for (WifiConfiguration config : getInternalConfiguredNetworks()) { 2796 if ((config.ephemeral || config.isPasspoint()) && TextUtils.equals(config.SSID, ssid)) { 2797 foundConfig = config; 2798 break; 2799 } 2800 } 2801 if (foundConfig == null) return null; 2802 // Store the ssid & the wall clock time at which the network was disabled. 2803 mDeletedEphemeralSsidsToTimeMap.put(ssid, mClock.getWallClockMillis()); 2804 Log.d(TAG, "Forget ephemeral SSID " + ssid + " num=" 2805 + mDeletedEphemeralSsidsToTimeMap.size()); 2806 if (foundConfig.ephemeral) { 2807 Log.d(TAG, "Found ephemeral config in disableEphemeralNetwork: " 2808 + foundConfig.networkId); 2809 } else if (foundConfig.isPasspoint()) { 2810 Log.d(TAG, "Found Passpoint config in disableEphemeralNetwork: " 2811 + foundConfig.networkId + ", FQDN: " + foundConfig.FQDN); 2812 } 2813 removeConnectChoiceFromAllNetworks(foundConfig.configKey()); 2814 return foundConfig; 2815 } 2816 2817 /** 2818 * Clear all deleted ephemeral networks. 2819 */ 2820 @VisibleForTesting clearDeletedEphemeralNetworks()2821 public void clearDeletedEphemeralNetworks() { 2822 mDeletedEphemeralSsidsToTimeMap.clear(); 2823 } 2824 2825 /** 2826 * Resets all sim networks state. 2827 */ resetSimNetworks()2828 public void resetSimNetworks() { 2829 if (mVerboseLoggingEnabled) localLog("resetSimNetworks"); 2830 for (WifiConfiguration config : getInternalConfiguredNetworks()) { 2831 if (!TelephonyUtil.isSimConfig(config)) { 2832 continue; 2833 } 2834 if (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) { 2835 Pair<String, String> currentIdentity = TelephonyUtil.getSimIdentity( 2836 mTelephonyManager, new TelephonyUtil(), config, 2837 mWifiInjector.getCarrierNetworkConfig()); 2838 if (mVerboseLoggingEnabled) { 2839 Log.d(TAG, "New identity for config " + config + ": " + currentIdentity); 2840 } 2841 // Update the loaded config 2842 if (currentIdentity == null) { 2843 Log.d(TAG, "Identity is null"); 2844 } else { 2845 config.enterpriseConfig.setIdentity(currentIdentity.first); 2846 } 2847 // do not reset anonymous identity since it may be dependent on user-entry 2848 // (i.e. cannot re-request on every reboot/SIM re-entry) 2849 } else { 2850 // reset identity as well: supplicant will ask us for it 2851 config.enterpriseConfig.setIdentity(""); 2852 if (!TelephonyUtil.isAnonymousAtRealmIdentity( 2853 config.enterpriseConfig.getAnonymousIdentity())) { 2854 config.enterpriseConfig.setAnonymousIdentity(""); 2855 } 2856 } 2857 } 2858 } 2859 2860 /** 2861 * Helper method to perform the following operations during user switch/unlock: 2862 * - Remove private networks of the old user. 2863 * - Load from the new user store file. 2864 * - Save the store files again to migrate any user specific networks from the shared store 2865 * to user store. 2866 * This method assumes the user store is visible (i.e CE storage is unlocked). So, the caller 2867 * should ensure that the stores are accessible before invocation. 2868 * 2869 * @param userId The identifier of the new foreground user, after the unlock or switch. 2870 */ handleUserUnlockOrSwitch(int userId)2871 private void handleUserUnlockOrSwitch(int userId) { 2872 if (mVerboseLoggingEnabled) { 2873 Log.v(TAG, "Loading from store after user switch/unlock for " + userId); 2874 } 2875 // Switch out the user store file. 2876 if (loadFromUserStoreAfterUnlockOrSwitch(userId)) { 2877 saveToStore(true); 2878 mPendingUnlockStoreRead = false; 2879 } 2880 } 2881 2882 /** 2883 * Handles the switch to a different foreground user: 2884 * - Flush the current state to the old user's store file. 2885 * - Switch the user specific store file. 2886 * - Reload the networks from the store files (shared & user). 2887 * - Write the store files to move any user specific private networks from shared store to user 2888 * store. 2889 * 2890 * Need to be called when {@link com.android.server.SystemService#onSwitchUser(int)} is invoked. 2891 * 2892 * @param userId The identifier of the new foreground user, after the switch. 2893 * @return List of network ID's of all the private networks of the old user which will be 2894 * removed from memory. 2895 */ handleUserSwitch(int userId)2896 public Set<Integer> handleUserSwitch(int userId) { 2897 if (mVerboseLoggingEnabled) { 2898 Log.v(TAG, "Handling user switch for " + userId); 2899 } 2900 if (userId == mCurrentUserId) { 2901 Log.w(TAG, "User already in foreground " + userId); 2902 return new HashSet<>(); 2903 } 2904 if (mPendingStoreRead) { 2905 Log.w(TAG, "User switch before store is read!"); 2906 mConfiguredNetworks.setNewUser(userId); 2907 mCurrentUserId = userId; 2908 // Reset any state from previous user unlock. 2909 mDeferredUserUnlockRead = false; 2910 // Cannot read data from new user's CE store file before they log-in. 2911 mPendingUnlockStoreRead = true; 2912 return new HashSet<>(); 2913 } 2914 if (mUserManager.isUserUnlockingOrUnlocked(mCurrentUserId)) { 2915 saveToStore(true); 2916 } 2917 // Remove any private networks of the old user before switching the userId. 2918 Set<Integer> removedNetworkIds = clearInternalUserData(mCurrentUserId); 2919 mConfiguredNetworks.setNewUser(userId); 2920 mCurrentUserId = userId; 2921 2922 if (mUserManager.isUserUnlockingOrUnlocked(mCurrentUserId)) { 2923 handleUserUnlockOrSwitch(mCurrentUserId); 2924 } else { 2925 // Cannot read data from new user's CE store file before they log-in. 2926 mPendingUnlockStoreRead = true; 2927 Log.i(TAG, "Waiting for user unlock to load from store"); 2928 } 2929 return removedNetworkIds; 2930 } 2931 2932 /** 2933 * Handles the unlock of foreground user. This maybe needed to read the store file if the user's 2934 * CE storage is not visible when {@link #handleUserSwitch(int)} is invoked. 2935 * 2936 * Need to be called when {@link com.android.server.SystemService#onUnlockUser(int)} is invoked. 2937 * 2938 * @param userId The identifier of the user that unlocked. 2939 */ handleUserUnlock(int userId)2940 public void handleUserUnlock(int userId) { 2941 if (mVerboseLoggingEnabled) { 2942 Log.v(TAG, "Handling user unlock for " + userId); 2943 } 2944 if (userId != mCurrentUserId) { 2945 Log.e(TAG, "Ignore user unlock for non current user " + userId); 2946 return; 2947 } 2948 if (mPendingStoreRead) { 2949 Log.w(TAG, "Ignore user unlock until store is read!"); 2950 mDeferredUserUnlockRead = true; 2951 return; 2952 } 2953 if (mPendingUnlockStoreRead) { 2954 handleUserUnlockOrSwitch(mCurrentUserId); 2955 } 2956 } 2957 2958 /** 2959 * Handles the stop of foreground user. This is needed to write the store file to flush 2960 * out any pending data before the user's CE store storage is unavailable. 2961 * 2962 * Need to be called when {@link com.android.server.SystemService#onStopUser(int)} is invoked. 2963 * 2964 * @param userId The identifier of the user that stopped. 2965 */ handleUserStop(int userId)2966 public void handleUserStop(int userId) { 2967 if (mVerboseLoggingEnabled) { 2968 Log.v(TAG, "Handling user stop for " + userId); 2969 } 2970 if (userId == mCurrentUserId && mUserManager.isUserUnlockingOrUnlocked(mCurrentUserId)) { 2971 saveToStore(true); 2972 clearInternalUserData(mCurrentUserId); 2973 } 2974 } 2975 2976 /** 2977 * Helper method to clear internal databases. 2978 * This method clears the: 2979 * - List of configured networks. 2980 * - Map of scan detail caches. 2981 * - List of deleted ephemeral networks. 2982 */ clearInternalData()2983 private void clearInternalData() { 2984 localLog("clearInternalData: Clearing all internal data"); 2985 mConfiguredNetworks.clear(); 2986 mDeletedEphemeralSsidsToTimeMap.clear(); 2987 mRandomizedMacAddressMapping.clear(); 2988 mScanDetailCaches.clear(); 2989 clearLastSelectedNetwork(); 2990 } 2991 2992 /** 2993 * Helper method to clear internal databases of the specified user. 2994 * This method clears the: 2995 * - Private configured configured networks of the specified user. 2996 * - Map of scan detail caches. 2997 * - List of deleted ephemeral networks. 2998 * 2999 * @param userId The identifier of the current foreground user, before the switch. 3000 * @return List of network ID's of all the private networks of the old user which will be 3001 * removed from memory. 3002 */ clearInternalUserData(int userId)3003 private Set<Integer> clearInternalUserData(int userId) { 3004 localLog("clearInternalUserData: Clearing user internal data for " + userId); 3005 Set<Integer> removedNetworkIds = new HashSet<>(); 3006 // Remove any private networks of the old user before switching the userId. 3007 for (WifiConfiguration config : getInternalConfiguredNetworks()) { 3008 if (!config.shared && WifiConfigurationUtil.doesUidBelongToAnyProfile( 3009 config.creatorUid, mUserManager.getProfiles(userId))) { 3010 removedNetworkIds.add(config.networkId); 3011 localLog("clearInternalUserData: removed config." 3012 + " netId=" + config.networkId 3013 + " configKey=" + config.configKey()); 3014 mConfiguredNetworks.remove(config.networkId); 3015 } 3016 } 3017 mDeletedEphemeralSsidsToTimeMap.clear(); 3018 mScanDetailCaches.clear(); 3019 clearLastSelectedNetwork(); 3020 return removedNetworkIds; 3021 } 3022 3023 /** 3024 * Helper function to populate the internal (in-memory) data from the retrieved shared store 3025 * (file) data. 3026 * 3027 * @param configurations list of configurations retrieved from store. 3028 */ loadInternalDataFromSharedStore( List<WifiConfiguration> configurations, Map<String, String> macAddressMapping)3029 private void loadInternalDataFromSharedStore( 3030 List<WifiConfiguration> configurations, 3031 Map<String, String> macAddressMapping) { 3032 for (WifiConfiguration configuration : configurations) { 3033 configuration.networkId = mNextNetworkId++; 3034 if (mVerboseLoggingEnabled) { 3035 Log.v(TAG, "Adding network from shared store " + configuration.configKey()); 3036 } 3037 try { 3038 mConfiguredNetworks.put(configuration); 3039 } catch (IllegalArgumentException e) { 3040 Log.e(TAG, "Failed to add network to config map", e); 3041 } 3042 } 3043 mRandomizedMacAddressMapping.putAll(macAddressMapping); 3044 } 3045 3046 /** 3047 * Helper function to populate the internal (in-memory) data from the retrieved user store 3048 * (file) data. 3049 * 3050 * @param configurations list of configurations retrieved from store. 3051 * @param deletedEphemeralSsidsToTimeMap map of ssid's representing the ephemeral networks 3052 * deleted by the user to the wall clock time at which 3053 * it was deleted. 3054 */ loadInternalDataFromUserStore( List<WifiConfiguration> configurations, Map<String, Long> deletedEphemeralSsidsToTimeMap)3055 private void loadInternalDataFromUserStore( 3056 List<WifiConfiguration> configurations, 3057 Map<String, Long> deletedEphemeralSsidsToTimeMap) { 3058 for (WifiConfiguration configuration : configurations) { 3059 configuration.networkId = mNextNetworkId++; 3060 if (mVerboseLoggingEnabled) { 3061 Log.v(TAG, "Adding network from user store " + configuration.configKey()); 3062 } 3063 try { 3064 mConfiguredNetworks.put(configuration); 3065 } catch (IllegalArgumentException e) { 3066 Log.e(TAG, "Failed to add network to config map", e); 3067 } 3068 } 3069 mDeletedEphemeralSsidsToTimeMap.putAll(deletedEphemeralSsidsToTimeMap); 3070 } 3071 3072 /** 3073 * Assign randomized MAC addresses for configured networks. 3074 * This is needed to generate persistent randomized MAC address for existing networks when 3075 * a device updates to Q+ for the first time since we are not calling addOrUpdateNetwork when 3076 * we load configuration at boot. 3077 */ generateRandomizedMacAddresses()3078 private void generateRandomizedMacAddresses() { 3079 for (WifiConfiguration config : getInternalConfiguredNetworks()) { 3080 if (DEFAULT_MAC_ADDRESS.equals(config.getRandomizedMacAddress())) { 3081 setRandomizedMacToPersistentMac(config); 3082 } 3083 } 3084 } 3085 3086 /** 3087 * Helper function to populate the internal (in-memory) data from the retrieved stores (file) 3088 * data. 3089 * This method: 3090 * 1. Clears all existing internal data. 3091 * 2. Sends out the networks changed broadcast after loading all the data. 3092 * 3093 * @param sharedConfigurations list of network configurations retrieved from shared store. 3094 * @param userConfigurations list of network configurations retrieved from user store. 3095 * @param deletedEphemeralSsidsToTimeMap map of ssid's representing the ephemeral networks 3096 * deleted by the user to the wall clock time at which 3097 * it was deleted. 3098 */ loadInternalData( List<WifiConfiguration> sharedConfigurations, List<WifiConfiguration> userConfigurations, Map<String, Long> deletedEphemeralSsidsToTimeMap, Map<String, String> macAddressMapping)3099 private void loadInternalData( 3100 List<WifiConfiguration> sharedConfigurations, 3101 List<WifiConfiguration> userConfigurations, 3102 Map<String, Long> deletedEphemeralSsidsToTimeMap, 3103 Map<String, String> macAddressMapping) { 3104 // Clear out all the existing in-memory lists and load the lists from what was retrieved 3105 // from the config store. 3106 clearInternalData(); 3107 loadInternalDataFromSharedStore(sharedConfigurations, macAddressMapping); 3108 loadInternalDataFromUserStore(userConfigurations, deletedEphemeralSsidsToTimeMap); 3109 generateRandomizedMacAddresses(); 3110 if (mConfiguredNetworks.sizeForAllUsers() == 0) { 3111 Log.w(TAG, "No stored networks found."); 3112 } 3113 // reset identity & anonymous identity for networks using SIM-based authentication 3114 // on load (i.e. boot) so that if the user changed SIMs while the device was powered off, 3115 // we do not reuse stale credentials that would lead to authentication failure. 3116 resetSimNetworks(); 3117 sendConfiguredNetworksChangedBroadcast(); 3118 mPendingStoreRead = false; 3119 } 3120 3121 /** 3122 * Read the config store and load the in-memory lists from the store data retrieved and sends 3123 * out the networks changed broadcast. 3124 * 3125 * This reads all the network configurations from: 3126 * 1. Shared WifiConfigStore.xml 3127 * 2. User WifiConfigStore.xml 3128 * 3129 * @return true on success or not needed (fresh install), false otherwise. 3130 */ loadFromStore()3131 public boolean loadFromStore() { 3132 // If the user unlock comes in before we load from store, which means the user store have 3133 // not been setup yet for the current user. Setup the user store before the read so that 3134 // configurations for the current user will also being loaded. 3135 if (mDeferredUserUnlockRead) { 3136 Log.i(TAG, "Handling user unlock before loading from store."); 3137 List<WifiConfigStore.StoreFile> userStoreFiles = 3138 WifiConfigStore.createUserFiles(mCurrentUserId); 3139 if (userStoreFiles == null) { 3140 Log.wtf(TAG, "Failed to create user store files"); 3141 return false; 3142 } 3143 mWifiConfigStore.setUserStores(userStoreFiles); 3144 mDeferredUserUnlockRead = false; 3145 } 3146 try { 3147 mWifiConfigStore.read(); 3148 } catch (IOException e) { 3149 Log.wtf(TAG, "Reading from new store failed. All saved networks are lost!", e); 3150 return false; 3151 } catch (XmlPullParserException e) { 3152 Log.wtf(TAG, "XML deserialization of store failed. All saved networks are lost!", e); 3153 return false; 3154 } 3155 loadInternalData(mNetworkListSharedStoreData.getConfigurations(), 3156 mNetworkListUserStoreData.getConfigurations(), 3157 mDeletedEphemeralSsidsStoreData.getSsidToTimeMap(), 3158 mRandomizedMacStoreData.getMacMapping()); 3159 return true; 3160 } 3161 3162 /** 3163 * Read the user config store and load the in-memory lists from the store data retrieved and 3164 * sends out the networks changed broadcast. 3165 * This should be used for all user switches/unlocks to only load networks from the user 3166 * specific store and avoid reloading the shared networks. 3167 * 3168 * This reads all the network configurations from: 3169 * 1. User WifiConfigStore.xml 3170 * 3171 * @param userId The identifier of the foreground user. 3172 * @return true on success, false otherwise. 3173 */ loadFromUserStoreAfterUnlockOrSwitch(int userId)3174 private boolean loadFromUserStoreAfterUnlockOrSwitch(int userId) { 3175 try { 3176 List<WifiConfigStore.StoreFile> userStoreFiles = 3177 WifiConfigStore.createUserFiles(userId); 3178 if (userStoreFiles == null) { 3179 Log.e(TAG, "Failed to create user store files"); 3180 return false; 3181 } 3182 mWifiConfigStore.switchUserStoresAndRead(userStoreFiles); 3183 } catch (IOException e) { 3184 Log.wtf(TAG, "Reading from new store failed. All saved private networks are lost!", e); 3185 return false; 3186 } catch (XmlPullParserException e) { 3187 Log.wtf(TAG, "XML deserialization of store failed. All saved private networks are" + 3188 "lost!", e); 3189 return false; 3190 } 3191 loadInternalDataFromUserStore(mNetworkListUserStoreData.getConfigurations(), 3192 mDeletedEphemeralSsidsStoreData.getSsidToTimeMap()); 3193 return true; 3194 } 3195 3196 /** 3197 * Save the current snapshot of the in-memory lists to the config store. 3198 * 3199 * @param forceWrite Whether the write needs to be forced or not. 3200 * @return Whether the write was successful or not, this is applicable only for force writes. 3201 */ saveToStore(boolean forceWrite)3202 public boolean saveToStore(boolean forceWrite) { 3203 if (mPendingStoreRead) { 3204 Log.e(TAG, "Cannot save to store before store is read!"); 3205 return false; 3206 } 3207 ArrayList<WifiConfiguration> sharedConfigurations = new ArrayList<>(); 3208 ArrayList<WifiConfiguration> userConfigurations = new ArrayList<>(); 3209 // List of network IDs for legacy Passpoint configuration to be removed. 3210 List<Integer> legacyPasspointNetId = new ArrayList<>(); 3211 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 3212 // Ignore ephemeral networks and non-legacy Passpoint configurations. 3213 if (config.ephemeral || (config.isPasspoint() && !config.isLegacyPasspointConfig)) { 3214 continue; 3215 } 3216 3217 // Migrate the legacy Passpoint configurations owned by the current user to 3218 // {@link PasspointManager}. 3219 if (config.isLegacyPasspointConfig && WifiConfigurationUtil.doesUidBelongToAnyProfile( 3220 config.creatorUid, mUserManager.getProfiles(mCurrentUserId))) { 3221 legacyPasspointNetId.add(config.networkId); 3222 // Migrate the legacy Passpoint configuration and add it to PasspointManager. 3223 if (!PasspointManager.addLegacyPasspointConfig(config)) { 3224 Log.e(TAG, "Failed to migrate legacy Passpoint config: " + config.FQDN); 3225 } 3226 // This will prevent adding |config| to the |sharedConfigurations|. 3227 continue; 3228 } 3229 3230 // We push all shared networks & private networks not belonging to the current 3231 // user to the shared store. Ideally, private networks for other users should 3232 // not even be in memory, 3233 // But, this logic is in place to deal with store migration from N to O 3234 // because all networks were previously stored in a central file. We cannot 3235 // write these private networks to the user specific store until the corresponding 3236 // user logs in. 3237 if (config.shared || !WifiConfigurationUtil.doesUidBelongToAnyProfile( 3238 config.creatorUid, mUserManager.getProfiles(mCurrentUserId))) { 3239 sharedConfigurations.add(config); 3240 } else { 3241 userConfigurations.add(config); 3242 } 3243 } 3244 3245 // Remove the configurations for migrated Passpoint configurations. 3246 for (int networkId : legacyPasspointNetId) { 3247 mConfiguredNetworks.remove(networkId); 3248 } 3249 3250 // Setup store data for write. 3251 mNetworkListSharedStoreData.setConfigurations(sharedConfigurations); 3252 mNetworkListUserStoreData.setConfigurations(userConfigurations); 3253 mDeletedEphemeralSsidsStoreData.setSsidToTimeMap(mDeletedEphemeralSsidsToTimeMap); 3254 mRandomizedMacStoreData.setMacMapping(mRandomizedMacAddressMapping); 3255 3256 try { 3257 mWifiConfigStore.write(forceWrite); 3258 } catch (IOException e) { 3259 Log.wtf(TAG, "Writing to store failed. Saved networks maybe lost!", e); 3260 return false; 3261 } catch (XmlPullParserException e) { 3262 Log.wtf(TAG, "XML serialization for store failed. Saved networks maybe lost!", e); 3263 return false; 3264 } 3265 return true; 3266 } 3267 3268 /** 3269 * Helper method for logging into local log buffer. 3270 */ localLog(String s)3271 private void localLog(String s) { 3272 if (mLocalLog != null) { 3273 mLocalLog.log(s); 3274 } 3275 } 3276 3277 /** 3278 * Dump the local log buffer and other internal state of WifiConfigManager. 3279 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)3280 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3281 pw.println("Dump of WifiConfigManager"); 3282 pw.println("WifiConfigManager - Log Begin ----"); 3283 mLocalLog.dump(fd, pw, args); 3284 pw.println("WifiConfigManager - Log End ----"); 3285 pw.println("WifiConfigManager - Configured networks Begin ----"); 3286 for (WifiConfiguration network : getInternalConfiguredNetworks()) { 3287 pw.println(network); 3288 } 3289 pw.println("WifiConfigManager - Configured networks End ----"); 3290 pw.println("WifiConfigManager - Next network ID to be allocated " + mNextNetworkId); 3291 pw.println("WifiConfigManager - Last selected network ID " + mLastSelectedNetworkId); 3292 pw.println("WifiConfigManager - PNO scan frequency culling enabled = " 3293 + mPnoFrequencyCullingEnabled); 3294 pw.println("WifiConfigManager - PNO scan recency sorting enabled = " 3295 + mPnoRecencySortingEnabled); 3296 mWifiConfigStore.dump(fd, pw, args); 3297 } 3298 3299 /** 3300 * Returns true if the given uid has permission to add, update or remove proxy settings 3301 */ canModifyProxySettings(int uid)3302 private boolean canModifyProxySettings(int uid) { 3303 final DevicePolicyManagerInternal dpmi = 3304 mWifiPermissionsWrapper.getDevicePolicyManagerInternal(); 3305 final boolean isUidProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid, 3306 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); 3307 final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid, 3308 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 3309 final boolean hasNetworkSettingsPermission = 3310 mWifiPermissionsUtil.checkNetworkSettingsPermission(uid); 3311 final boolean hasNetworkSetupWizardPermission = 3312 mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid); 3313 // If |uid| corresponds to the device owner, allow all modifications. 3314 if (isUidDeviceOwner || isUidProfileOwner || hasNetworkSettingsPermission 3315 || hasNetworkSetupWizardPermission) { 3316 return true; 3317 } 3318 if (mVerboseLoggingEnabled) { 3319 Log.v(TAG, "UID: " + uid + " cannot modify WifiConfiguration proxy settings." 3320 + " hasNetworkSettings=" + hasNetworkSettingsPermission 3321 + " hasNetworkSetupWizard=" + hasNetworkSetupWizardPermission 3322 + " DeviceOwner=" + isUidDeviceOwner 3323 + " ProfileOwner=" + isUidProfileOwner); 3324 } 3325 return false; 3326 } 3327 3328 /** 3329 * Set the saved network update event listener 3330 */ setOnSavedNetworkUpdateListener(OnSavedNetworkUpdateListener listener)3331 public void setOnSavedNetworkUpdateListener(OnSavedNetworkUpdateListener listener) { 3332 mListener = listener; 3333 } 3334 3335 /** 3336 * Set extra failure reason for given config. Used to surface extra failure details to the UI 3337 * @param netId The network ID of the config to set the extra failure reason for 3338 * @param reason the WifiConfiguration.ExtraFailureReason failure code representing the most 3339 * recent failure reason 3340 */ setRecentFailureAssociationStatus(int netId, int reason)3341 public void setRecentFailureAssociationStatus(int netId, int reason) { 3342 WifiConfiguration config = getInternalConfiguredNetwork(netId); 3343 if (config == null) { 3344 return; 3345 } 3346 config.recentFailure.setAssociationStatus(reason); 3347 } 3348 3349 /** 3350 * @param netId The network ID of the config to clear the extra failure reason from 3351 */ clearRecentFailureReason(int netId)3352 public void clearRecentFailureReason(int netId) { 3353 WifiConfiguration config = getInternalConfiguredNetwork(netId); 3354 if (config == null) { 3355 return; 3356 } 3357 config.recentFailure.clear(); 3358 } 3359 } 3360