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