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