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