WifiConfigManager.java revision 936d25cfe7a682337e9a9c39412650c9ae3ff312
1/* 2 * Copyright (C) 2010 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 static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 20 21import android.app.admin.DeviceAdminInfo; 22import android.app.admin.DevicePolicyManagerInternal; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.ApplicationInfo; 27import android.content.pm.PackageManager; 28import android.content.pm.UserInfo; 29import android.net.IpConfiguration; 30import android.net.IpConfiguration.IpAssignment; 31import android.net.IpConfiguration.ProxySettings; 32import android.net.NetworkInfo.DetailedState; 33import android.net.ProxyInfo; 34import android.net.StaticIpConfiguration; 35import android.net.wifi.PasspointManagementObjectDefinition; 36import android.net.wifi.ScanResult; 37import android.net.wifi.WifiConfiguration; 38import android.net.wifi.WifiConfiguration.KeyMgmt; 39import android.net.wifi.WifiConfiguration.Status; 40import android.net.wifi.WifiEnterpriseConfig; 41import android.net.wifi.WifiInfo; 42import android.net.wifi.WifiManager; 43import android.net.wifi.WifiScanner; 44import android.net.wifi.WpsInfo; 45import android.net.wifi.WpsResult; 46import android.os.Environment; 47import android.os.RemoteException; 48import android.os.SystemClock; 49import android.os.UserHandle; 50import android.os.UserManager; 51import android.provider.Settings; 52import android.security.KeyStore; 53import android.text.TextUtils; 54import android.util.ArraySet; 55import android.util.LocalLog; 56import android.util.Log; 57import android.util.SparseArray; 58 59import com.android.internal.R; 60import com.android.server.LocalServices; 61import com.android.server.net.DelayedDiskWrite; 62import com.android.server.net.IpConfigStore; 63import com.android.server.wifi.anqp.ANQPElement; 64import com.android.server.wifi.anqp.ANQPFactory; 65import com.android.server.wifi.anqp.Constants; 66import com.android.server.wifi.hotspot2.ANQPData; 67import com.android.server.wifi.hotspot2.AnqpCache; 68import com.android.server.wifi.hotspot2.IconEvent; 69import com.android.server.wifi.hotspot2.NetworkDetail; 70import com.android.server.wifi.hotspot2.PasspointMatch; 71import com.android.server.wifi.hotspot2.SupplicantBridge; 72import com.android.server.wifi.hotspot2.Utils; 73import com.android.server.wifi.hotspot2.omadm.PasspointManagementObjectManager; 74import com.android.server.wifi.hotspot2.pps.Credential; 75import com.android.server.wifi.hotspot2.pps.HomeSP; 76 77import org.xml.sax.SAXException; 78 79import java.io.BufferedReader; 80import java.io.DataOutputStream; 81import java.io.File; 82import java.io.FileDescriptor; 83import java.io.FileNotFoundException; 84import java.io.FileReader; 85import java.io.IOException; 86import java.io.PrintWriter; 87import java.security.cert.X509Certificate; 88import java.text.DateFormat; 89import java.util.ArrayList; 90import java.util.BitSet; 91import java.util.Calendar; 92import java.util.Collection; 93import java.util.Collections; 94import java.util.Comparator; 95import java.util.Date; 96import java.util.HashMap; 97import java.util.HashSet; 98import java.util.Iterator; 99import java.util.List; 100import java.util.Map; 101import java.util.Objects; 102import java.util.Set; 103import java.util.concurrent.ConcurrentHashMap; 104import java.util.concurrent.atomic.AtomicBoolean; 105import java.util.concurrent.atomic.AtomicInteger; 106import java.util.zip.CRC32; 107import java.util.zip.Checksum; 108 109 110/** 111 * This class provides the API to manage configured 112 * wifi networks. The API is not thread safe is being 113 * used only from WifiStateMachine. 114 * 115 * It deals with the following 116 * - Add/update/remove a WifiConfiguration 117 * The configuration contains two types of information. 118 * = IP and proxy configuration that is handled by WifiConfigManager and 119 * is saved to disk on any change. 120 * 121 * The format of configuration file is as follows: 122 * <version> 123 * <netA_key1><netA_value1><netA_key2><netA_value2>...<EOS> 124 * <netB_key1><netB_value1><netB_key2><netB_value2>...<EOS> 125 * .. 126 * 127 * (key, value) pairs for a given network are grouped together and can 128 * be in any order. A EOS at the end of a set of (key, value) pairs 129 * indicates that the next set of (key, value) pairs are for a new 130 * network. A network is identified by a unique ID_KEY. If there is no 131 * ID_KEY in the (key, value) pairs, the data is discarded. 132 * 133 * An invalid version on read would result in discarding the contents of 134 * the file. On the next write, the latest version is written to file. 135 * 136 * Any failures during read or write to the configuration file are ignored 137 * without reporting to the user since the likelihood of these errors are 138 * low and the impact on connectivity is low. 139 * 140 * = SSID & security details that is pushed to the supplicant. 141 * supplicant saves these details to the disk on calling 142 * saveConfigCommand(). 143 * 144 * We have two kinds of APIs exposed: 145 * > public API calls that provide fine grained control 146 * - enableNetwork, disableNetwork, addOrUpdateNetwork(), 147 * removeNetwork(). For these calls, the config is not persisted 148 * to the disk. (TODO: deprecate these calls in WifiManager) 149 * > The new API calls - selectNetwork(), saveNetwork() & forgetNetwork(). 150 * These calls persist the supplicant config to disk. 151 * 152 * - Maintain a list of configured networks for quick access 153 * 154 */ 155public class WifiConfigManager { 156 private static boolean sVDBG = false; 157 private static boolean sVVDBG = false; 158 public static final String TAG = "WifiConfigManager"; 159 public static final int MAX_TX_PACKET_FOR_FULL_SCANS = 8; 160 public static final int MAX_RX_PACKET_FOR_FULL_SCANS = 16; 161 public static final int MAX_TX_PACKET_FOR_PARTIAL_SCANS = 40; 162 public static final int MAX_RX_PACKET_FOR_PARTIAL_SCANS = 80; 163 public static final boolean ROAM_ON_ANY = false; 164 public static final int MAX_NUM_SCAN_CACHE_ENTRIES = 128; 165 private static final boolean DBG = true; 166 private static final String PPS_FILE = "/data/misc/wifi/PerProviderSubscription.conf"; 167 private static final String IP_CONFIG_FILE = 168 Environment.getDataDirectory() + "/misc/wifi/ipconfig.txt"; 169 170 // The Wifi verbose log is provided as a way to persist the verbose logging settings 171 // for testing purpose. 172 // It is not intended for normal use. 173 private static final String WIFI_VERBOSE_LOGS_KEY = "WIFI_VERBOSE_LOGS"; 174 175 // As we keep deleted PSK WifiConfiguration for a while, the PSK of 176 // those deleted WifiConfiguration is set to this random unused PSK 177 private static final String DELETED_CONFIG_PSK = "Mjkd86jEMGn79KhKll298Uu7-deleted"; 178 179 /** 180 * The maximum number of times we will retry a connection to an access point 181 * for which we have failed in acquiring an IP address from DHCP. A value of 182 * N means that we will make N+1 connection attempts in all. 183 * <p> 184 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 185 * value if a Settings value is not present. 186 */ 187 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 188 189 /** 190 * The threshold for each kind of error. If a network continuously encounter the same error more 191 * than the threshold times, this network will be disabled. -1 means unavailable. 192 */ 193 private static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = { 194 -1, // threshold for NETWORK_SELECTION_ENABLE 195 1, // threshold for DISABLED_BAD_LINK (deprecated) 196 5, // threshold for DISABLED_ASSOCIATION_REJECTION 197 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 198 5, // threshold for DISABLED_DHCP_FAILURE 199 5, // threshold for DISABLED_DNS_FAILURE 200 6, // threshold for DISABLED_TLS_VERSION_MISMATCH 201 1, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 202 1, // threshold for DISABLED_NO_INTERNET 203 1 // threshold for DISABLED_BY_WIFI_MANAGER 204 }; 205 206 /** 207 * Timeout for each kind of error. After the timeout minutes, unblock the network again. 208 */ 209 private static final int[] NETWORK_SELECTION_DISABLE_TIMEOUT = { 210 Integer.MAX_VALUE, // threshold for NETWORK_SELECTION_ENABLE 211 15, // threshold for DISABLED_BAD_LINK (deprecated) 212 5, // threshold for DISABLED_ASSOCIATION_REJECTION 213 5, // threshold for DISABLED_AUTHENTICATION_FAILURE 214 5, // threshold for DISABLED_DHCP_FAILURE 215 5, // threshold for DISABLED_DNS_FAILURE 216 Integer.MAX_VALUE, // threshold for DISABLED_TLS_VERSION 217 Integer.MAX_VALUE, // threshold for DISABLED_AUTHENTICATION_NO_CREDENTIALS 218 Integer.MAX_VALUE, // threshold for DISABLED_NO_INTERNET 219 Integer.MAX_VALUE // threshold for DISABLED_BY_WIFI_MANAGER 220 }; 221 222 public final AtomicBoolean mEnableAutoJoinWhenAssociated = new AtomicBoolean(); 223 public final AtomicBoolean mEnableChipWakeUpWhenAssociated = new AtomicBoolean(true); 224 public final AtomicBoolean mEnableRssiPollWhenAssociated = new AtomicBoolean(true); 225 public final AtomicInteger mThresholdSaturatedRssi5 = new AtomicInteger(); 226 public final AtomicInteger mThresholdQualifiedRssi24 = new AtomicInteger(); 227 public final AtomicInteger mEnableVerboseLogging = new AtomicInteger(0); 228 public final AtomicInteger mAlwaysEnableScansWhileAssociated = new AtomicInteger(0); 229 public final AtomicInteger mMaxNumActiveChannelsForPartialScans = new AtomicInteger(); 230 231 public boolean mEnableLinkDebouncing; 232 public boolean mEnableWifiCellularHandoverUserTriggeredAdjustment; 233 public int mNetworkSwitchingBlackListPeriodMs; 234 public int mBadLinkSpeed24; 235 public int mBadLinkSpeed5; 236 public int mGoodLinkSpeed24; 237 public int mGoodLinkSpeed5; 238 239 // These fields are non-final for testing. 240 public AtomicInteger mThresholdQualifiedRssi5 = new AtomicInteger(); 241 public AtomicInteger mThresholdMinimumRssi5 = new AtomicInteger(); 242 public AtomicInteger mThresholdSaturatedRssi24 = new AtomicInteger(); 243 public AtomicInteger mThresholdMinimumRssi24 = new AtomicInteger(); 244 public AtomicInteger mCurrentNetworkBoost = new AtomicInteger(); 245 public AtomicInteger mBandAward5Ghz = new AtomicInteger(); 246 247 // Indicates whether the system is capable of 802.11r fast BSS transition. 248 private boolean mSystemSupportsFastBssTransition = false; 249 250 /** 251 * Framework keeps a list of ephemeral SSIDs that where deleted by user, 252 * so as, framework knows not to autojoin again those SSIDs based on scorer input. 253 * The list is never cleared up. 254 * 255 * The SSIDs are encoded in a String as per definition of WifiConfiguration.SSID field. 256 */ 257 public Set<String> mDeletedEphemeralSSIDs = new HashSet<String>(); 258 259 /* configured networks with network id as the key */ 260 private final ConfigurationMap mConfiguredNetworks; 261 262 /* 263 * Stores whether carrier networks are configured. 264 * This information is provided externally from the CarrierConfig. 265 */ 266 private boolean mHasCarrierConfiguredNetworks; 267 268 private final LocalLog mLocalLog; 269 private final KeyStore mKeyStore; 270 private final WifiNetworkHistory mWifiNetworkHistory; 271 private final WifiConfigStore mWifiConfigStore; 272 private final AnqpCache mAnqpCache; 273 private final SupplicantBridge mSupplicantBridge; 274 private final SupplicantBridgeCallbacks mSupplicantBridgeCallbacks; 275 private final PasspointManagementObjectManager mMOManager; 276 private final boolean mEnableOsuQueries; 277 private final SIMAccessor mSIMAccessor; 278 private final UserManager mUserManager; 279 private final Object mActiveScanDetailLock = new Object(); 280 281 private Context mContext; 282 private FrameworkFacade mFacade; 283 private Clock mClock; 284 private IpConfigStore mIpconfigStore; 285 private DelayedDiskWrite mWriter; 286 private boolean mOnlyLinkSameCredentialConfigurations; 287 private boolean mShowNetworks = false; 288 private int mCurrentUserId = UserHandle.USER_SYSTEM; 289 290 /* Stores a map of NetworkId to ScanCache */ 291 private ConcurrentHashMap<Integer, ScanDetailCache> mScanDetailCaches; 292 293 /* Tracks the highest priority of configured networks */ 294 private int mLastPriority = -1; 295 296 /** 297 * The mLastSelectedConfiguration is used to remember which network 298 * was selected last by the user. 299 * The connection to this network may not be successful, as well 300 * the selection (i.e. network priority) might not be persisted. 301 * WiFi state machine is the only object that sets this variable. 302 */ 303 private String mLastSelectedConfiguration = null; 304 private long mLastSelectedTimeStamp = 305 WifiConfiguration.NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP; 306 307 /* 308 * Lost config list, whenever we read a config from networkHistory.txt that was not in 309 * wpa_supplicant.conf 310 */ 311 private HashSet<String> mLostConfigsDbg = new HashSet<String>(); 312 313 private ScanDetail mActiveScanDetail; // ScanDetail associated with active network 314 315 private class SupplicantBridgeCallbacks implements SupplicantBridge.SupplicantBridgeCallbacks { 316 @Override 317 public void notifyANQPResponse(ScanDetail scanDetail, 318 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 319 updateAnqpCache(scanDetail, anqpElements); 320 if (anqpElements == null || anqpElements.isEmpty()) { 321 return; 322 } 323 scanDetail.propagateANQPInfo(anqpElements); 324 325 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, false); 326 Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() + " pass 2 matches: " 327 + toMatchString(matches)); 328 329 cacheScanResultForPasspointConfigs(scanDetail, matches, null); 330 } 331 @Override 332 public void notifyIconFailed(long bssid) { 333 Intent intent = new Intent(WifiManager.PASSPOINT_ICON_RECEIVED_ACTION); 334 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 335 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_BSSID, bssid); 336 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 337 } 338 339 } 340 341 WifiConfigManager(Context context, WifiNative wifiNative, FrameworkFacade facade, Clock clock, 342 UserManager userManager, KeyStore keyStore) { 343 mContext = context; 344 mFacade = facade; 345 mClock = clock; 346 mKeyStore = keyStore; 347 mUserManager = userManager; 348 349 if (mShowNetworks) { 350 mLocalLog = wifiNative.getLocalLog(); 351 } else { 352 mLocalLog = null; 353 } 354 355 mOnlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean( 356 R.bool.config_wifi_only_link_same_credential_configurations); 357 mMaxNumActiveChannelsForPartialScans.set(mContext.getResources().getInteger( 358 R.integer.config_wifi_framework_associated_partial_scan_max_num_active_channels)); 359 mEnableLinkDebouncing = mContext.getResources().getBoolean( 360 R.bool.config_wifi_enable_disconnection_debounce); 361 mBandAward5Ghz.set(mContext.getResources().getInteger( 362 R.integer.config_wifi_framework_5GHz_preference_boost_factor)); 363 mThresholdMinimumRssi5.set(mContext.getResources().getInteger( 364 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz)); 365 mThresholdQualifiedRssi5.set(mContext.getResources().getInteger( 366 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz)); 367 mThresholdSaturatedRssi5.set(mContext.getResources().getInteger( 368 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz)); 369 mThresholdMinimumRssi24.set(mContext.getResources().getInteger( 370 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz)); 371 mThresholdQualifiedRssi24.set(mContext.getResources().getInteger( 372 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz)); 373 mThresholdSaturatedRssi24.set(mContext.getResources().getInteger( 374 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)); 375 mEnableWifiCellularHandoverUserTriggeredAdjustment = mContext.getResources().getBoolean( 376 R.bool.config_wifi_framework_cellular_handover_enable_user_triggered_adjustment); 377 mBadLinkSpeed24 = mContext.getResources().getInteger( 378 R.integer.config_wifi_framework_wifi_score_bad_link_speed_24); 379 mBadLinkSpeed5 = mContext.getResources().getInteger( 380 R.integer.config_wifi_framework_wifi_score_bad_link_speed_5); 381 mGoodLinkSpeed24 = mContext.getResources().getInteger( 382 R.integer.config_wifi_framework_wifi_score_good_link_speed_24); 383 mGoodLinkSpeed5 = mContext.getResources().getInteger( 384 R.integer.config_wifi_framework_wifi_score_good_link_speed_5); 385 mEnableAutoJoinWhenAssociated.set(mContext.getResources().getBoolean( 386 R.bool.config_wifi_framework_enable_associated_network_selection)); 387 mCurrentNetworkBoost.set(mContext.getResources().getInteger( 388 R.integer.config_wifi_framework_current_network_boost)); 389 mNetworkSwitchingBlackListPeriodMs = mContext.getResources().getInteger( 390 R.integer.config_wifi_network_switching_blacklist_time); 391 mSystemSupportsFastBssTransition = mContext.getResources().getBoolean( 392 R.bool.config_wifi_fast_bss_transition_enabled); 393 394 boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled); 395 Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled")); 396 397 mConfiguredNetworks = new ConfigurationMap(userManager); 398 mMOManager = new PasspointManagementObjectManager(new File(PPS_FILE), hs2on); 399 mEnableOsuQueries = true; 400 mAnqpCache = new AnqpCache(mClock); 401 mSupplicantBridgeCallbacks = new SupplicantBridgeCallbacks(); 402 mSupplicantBridge = new SupplicantBridge(wifiNative, mSupplicantBridgeCallbacks); 403 mScanDetailCaches = new ConcurrentHashMap<>(16, 0.75f, 2); 404 mSIMAccessor = new SIMAccessor(mContext); 405 mWriter = new DelayedDiskWrite(); 406 mIpconfigStore = new IpConfigStore(mWriter); 407 mWifiNetworkHistory = new WifiNetworkHistory(context, mLocalLog, mWriter); 408 mWifiConfigStore = 409 new WifiConfigStore(context, wifiNative, mKeyStore, mLocalLog, mShowNetworks, true); 410 } 411 412 public void trimANQPCache(boolean all) { 413 mAnqpCache.clear(all, DBG); 414 } 415 416 void enableVerboseLogging(int verbose) { 417 mEnableVerboseLogging.set(verbose); 418 if (verbose > 0) { 419 sVDBG = true; 420 mShowNetworks = true; 421 } else { 422 sVDBG = false; 423 } 424 if (verbose > 1) { 425 sVVDBG = true; 426 } else { 427 sVVDBG = false; 428 } 429 } 430 431 /** 432 * Fetch the list of configured networks 433 * and enable all stored networks in supplicant. 434 */ 435 void loadAndEnableAllNetworks() { 436 if (DBG) log("Loading config and enabling all networks "); 437 loadConfiguredNetworks(); 438 enableAllNetworks(); 439 } 440 441 int getConfiguredNetworksSize() { 442 return mConfiguredNetworks.sizeForCurrentUser(); 443 } 444 445 /** 446 * Fetch the list of currently saved networks (i.e. all configured networks, excluding 447 * ephemeral networks). 448 * @param pskMap Map of preSharedKeys, keyed by the configKey of the configuration the 449 * preSharedKeys belong to 450 * @return List of networks 451 */ 452 private List<WifiConfiguration> getSavedNetworks(Map<String, String> pskMap) { 453 List<WifiConfiguration> networks = new ArrayList<>(); 454 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 455 WifiConfiguration newConfig = new WifiConfiguration(config); 456 // When updating this condition, update WifiStateMachine's CONNECT_NETWORK handler to 457 // correctly handle updating existing configs that are filtered out here. 458 if (config.ephemeral) { 459 // Do not enumerate and return this configuration to anyone (e.g. WiFi Picker); 460 // treat it as unknown instead. This configuration can still be retrieved 461 // directly by its key or networkId. 462 continue; 463 } 464 465 if (pskMap != null && config.allowedKeyManagement != null 466 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 467 && pskMap.containsKey(config.configKey(true))) { 468 newConfig.preSharedKey = pskMap.get(config.configKey(true)); 469 } 470 networks.add(newConfig); 471 } 472 return networks; 473 } 474 475 /** 476 * This function returns all configuration, and is used for debug and creating bug reports. 477 */ 478 private List<WifiConfiguration> getAllConfiguredNetworks() { 479 List<WifiConfiguration> networks = new ArrayList<>(); 480 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 481 WifiConfiguration newConfig = new WifiConfiguration(config); 482 networks.add(newConfig); 483 } 484 return networks; 485 } 486 487 /** 488 * Fetch the list of currently saved networks (i.e. all configured networks, excluding 489 * ephemeral networks). 490 * @return List of networks 491 */ 492 public List<WifiConfiguration> getSavedNetworks() { 493 return getSavedNetworks(null); 494 } 495 496 /** 497 * Check if Carrier networks have ben configured. 498 * @return true if carrier networks are present else false. 499 */ 500 public boolean hasCarrierNetworks() { 501 return mHasCarrierConfiguredNetworks; 502 } 503 504 /** 505 * Set true/false depending on whether Carrier networks have been configured. 506 * @param hasCarrierNetworks if Carrier networks have been configured. 507 */ 508 public void setHasCarrierNetworks(boolean hasCarrierNetworks) { 509 mHasCarrierConfiguredNetworks = hasCarrierNetworks; 510 } 511 512 /** 513 * Fetch the list of currently saved networks (i.e. all configured networks, excluding 514 * ephemeral networks), filled with real preSharedKeys. 515 * @return List of networks 516 */ 517 List<WifiConfiguration> getPrivilegedSavedNetworks() { 518 Map<String, String> pskMap = getCredentialsByConfigKeyMap(); 519 List<WifiConfiguration> configurations = getSavedNetworks(pskMap); 520 for (WifiConfiguration configuration : configurations) { 521 try { 522 configuration 523 .setPasspointManagementObjectTree(mMOManager.getMOTree(configuration.FQDN)); 524 } catch (IOException ioe) { 525 Log.w(TAG, "Failed to parse MO from " + configuration.FQDN + ": " + ioe); 526 } 527 } 528 return configurations; 529 } 530 531 /** 532 * Fetch the list of networkId's which are hidden in current user's configuration. 533 * @return List of networkIds 534 */ 535 public Set<Integer> getHiddenConfiguredNetworkIds() { 536 return mConfiguredNetworks.getHiddenNetworkIdsForCurrentUser(); 537 } 538 539 /** 540 * Find matching network for this scanResult 541 */ 542 WifiConfiguration getMatchingConfig(ScanResult scanResult) { 543 if (scanResult == null) { 544 return null; 545 } 546 for (Map.Entry entry : mScanDetailCaches.entrySet()) { 547 Integer netId = (Integer) entry.getKey(); 548 ScanDetailCache cache = (ScanDetailCache) entry.getValue(); 549 WifiConfiguration config = getWifiConfiguration(netId); 550 if (config == null) { 551 continue; 552 } 553 if (cache.get(scanResult.BSSID) != null) { 554 return config; 555 } 556 } 557 558 return null; 559 } 560 561 /** 562 * Fetch the preSharedKeys for all networks. 563 * @return a map from configKey to preSharedKey. 564 */ 565 private Map<String, String> getCredentialsByConfigKeyMap() { 566 return readNetworkVariablesFromSupplicantFile("psk"); 567 } 568 569 /** 570 * Fetch the list of currently saved networks (i.e. all configured networks, excluding 571 * ephemeral networks) that were recently seen. 572 * 573 * @param scanResultAgeMs The maximum age (in ms) of scan results for which we calculate the 574 * RSSI values 575 * @param copy If true, the returned list will contain copies of the configurations for the 576 * saved networks. Otherwise, the returned list will contain references to these 577 * configurations. 578 * @return List of networks 579 */ 580 List<WifiConfiguration> getRecentSavedNetworks(int scanResultAgeMs, boolean copy) { 581 List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 582 583 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 584 if (config.ephemeral) { 585 // Do not enumerate and return this configuration to anyone (e.g. WiFi Picker); 586 // treat it as unknown instead. This configuration can still be retrieved 587 // directly by its key or networkId. 588 continue; 589 } 590 591 // Calculate the RSSI for scan results that are more recent than scanResultAgeMs. 592 ScanDetailCache cache = getScanDetailCache(config); 593 if (cache == null) { 594 continue; 595 } 596 config.setVisibility(cache.getVisibility(scanResultAgeMs)); 597 if (config.visibility == null) { 598 continue; 599 } 600 if (config.visibility.rssi5 == WifiConfiguration.INVALID_RSSI 601 && config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) { 602 continue; 603 } 604 if (copy) { 605 networks.add(new WifiConfiguration(config)); 606 } else { 607 networks.add(config); 608 } 609 } 610 return networks; 611 } 612 613 /** 614 * Update the configuration and BSSID with latest RSSI value. 615 */ 616 void updateConfiguration(WifiInfo info) { 617 WifiConfiguration config = getWifiConfiguration(info.getNetworkId()); 618 if (config != null && getScanDetailCache(config) != null) { 619 ScanDetail scanDetail = getScanDetailCache(config).getScanDetail(info.getBSSID()); 620 if (scanDetail != null) { 621 ScanResult result = scanDetail.getScanResult(); 622 long previousSeen = result.seen; 623 int previousRssi = result.level; 624 625 // Update the scan result 626 scanDetail.setSeen(); 627 result.level = info.getRssi(); 628 629 // Average the RSSI value 630 result.averageRssi(previousRssi, previousSeen, 631 WifiQualifiedNetworkSelector.SCAN_RESULT_MAXIMUNM_AGE); 632 if (sVDBG) { 633 logd("updateConfiguration freq=" + result.frequency 634 + " BSSID=" + result.BSSID 635 + " RSSI=" + result.level 636 + " " + config.configKey()); 637 } 638 } 639 } 640 } 641 642 /** 643 * get the Wificonfiguration for this netId 644 * 645 * @return Wificonfiguration 646 */ 647 public WifiConfiguration getWifiConfiguration(int netId) { 648 return mConfiguredNetworks.getForCurrentUser(netId); 649 } 650 651 /** 652 * Get the Wificonfiguration for this key 653 * @return Wificonfiguration 654 */ 655 public WifiConfiguration getWifiConfiguration(String key) { 656 return mConfiguredNetworks.getByConfigKeyForCurrentUser(key); 657 } 658 659 /** 660 * Enable all networks (if disabled time expire) and save config. This will be a no-op if the 661 * list of configured networks indicates all networks as being enabled 662 */ 663 void enableAllNetworks() { 664 boolean networkEnabledStateChanged = false; 665 666 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 667 if (config != null && !config.ephemeral 668 && !config.getNetworkSelectionStatus().isNetworkEnabled()) { 669 if (tryEnableQualifiedNetwork(config)) { 670 networkEnabledStateChanged = true; 671 } 672 } 673 } 674 675 if (networkEnabledStateChanged) { 676 saveConfig(); 677 sendConfiguredNetworksChangedBroadcast(); 678 } 679 } 680 681 private boolean setNetworkPriorityNative(WifiConfiguration config, int priority) { 682 return mWifiConfigStore.setNetworkPriority(config, priority); 683 } 684 685 private boolean setSSIDNative(WifiConfiguration config, String ssid) { 686 return mWifiConfigStore.setNetworkSSID(config, ssid); 687 } 688 689 public boolean updateLastConnectUid(WifiConfiguration config, int uid) { 690 if (config != null) { 691 if (config.lastConnectUid != uid) { 692 config.lastConnectUid = uid; 693 return true; 694 } 695 } 696 return false; 697 } 698 699 /** 700 * Selects the specified network for connection. This involves 701 * updating the priority of all the networks and enabling the given 702 * network while disabling others. 703 * 704 * Selecting a network will leave the other networks disabled and 705 * a call to enableAllNetworks() needs to be issued upon a connection 706 * or a failure event from supplicant 707 * 708 * @param config network to select for connection 709 * @param updatePriorities makes config highest priority network 710 * @return false if the network id is invalid 711 */ 712 boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) { 713 if (sVDBG) localLogNetwork("selectNetwork", config.networkId); 714 if (config.networkId == INVALID_NETWORK_ID) return false; 715 if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, 716 mUserManager.getProfiles(mCurrentUserId))) { 717 loge("selectNetwork " + Integer.toString(config.networkId) + ": Network config is not " 718 + "visible to current user."); 719 return false; 720 } 721 722 // Reset the priority of each network at start or if it goes too high. 723 if (mLastPriority == -1 || mLastPriority > 1000000) { 724 if (updatePriorities) { 725 for (WifiConfiguration config2 : mConfiguredNetworks.valuesForCurrentUser()) { 726 if (config2.networkId != INVALID_NETWORK_ID) { 727 setNetworkPriorityNative(config2, 0); 728 } 729 } 730 } 731 mLastPriority = 0; 732 } 733 734 // Set to the highest priority and save the configuration. 735 if (updatePriorities) { 736 setNetworkPriorityNative(config, ++mLastPriority); 737 } 738 739 if (config.isPasspoint()) { 740 // Set the SSID for the underlying WPA supplicant network entry corresponding to this 741 // Passpoint profile to the SSID of the BSS selected by QNS. |config.SSID| is set by 742 // selectQualifiedNetwork.selectQualifiedNetwork(), when the qualified network selected 743 // is a Passpoint network. 744 logd("Setting SSID for WPA supplicant network " + config.networkId + " to " 745 + config.SSID); 746 setSSIDNative(config, config.SSID); 747 } 748 749 mWifiConfigStore.enableHS20(config.isPasspoint()); 750 751 if (updatePriorities) { 752 saveConfig(); 753 } 754 755 updateLastConnectUid(config, uid); 756 757 writeKnownNetworkHistory(); 758 759 /* Enable the given network while disabling all other networks */ 760 selectNetworkWithoutBroadcast(config.networkId); 761 762 /* Avoid saving the config & sending a broadcast to prevent settings 763 * from displaying a disabled list of networks */ 764 return true; 765 } 766 767 /** 768 * Add/update the specified configuration and save config 769 * 770 * @param config WifiConfiguration to be saved 771 * @return network update result 772 */ 773 NetworkUpdateResult saveNetwork(WifiConfiguration config, int uid) { 774 WifiConfiguration conf; 775 776 // A new network cannot have null SSID 777 if (config == null || (config.networkId == INVALID_NETWORK_ID && config.SSID == null)) { 778 return new NetworkUpdateResult(INVALID_NETWORK_ID); 779 } 780 781 if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, 782 mUserManager.getProfiles(mCurrentUserId))) { 783 return new NetworkUpdateResult(INVALID_NETWORK_ID); 784 } 785 786 if (sVDBG) localLogNetwork("WifiConfigManager: saveNetwork netId", config.networkId); 787 if (sVDBG) { 788 logd("WifiConfigManager saveNetwork," 789 + " size=" + Integer.toString(mConfiguredNetworks.sizeForAllUsers()) 790 + " (for all users)" 791 + " SSID=" + config.SSID 792 + " Uid=" + Integer.toString(config.creatorUid) 793 + "/" + Integer.toString(config.lastUpdateUid)); 794 } 795 796 if (mDeletedEphemeralSSIDs.remove(config.SSID)) { 797 if (sVDBG) { 798 logd("WifiConfigManager: removed from ephemeral blacklist: " + config.SSID); 799 } 800 // NOTE: This will be flushed to disk as part of the addOrUpdateNetworkNative call 801 // below, since we're creating/modifying a config. 802 } 803 804 boolean newNetwork = (config.networkId == INVALID_NETWORK_ID); 805 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 806 int netId = result.getNetworkId(); 807 808 if (sVDBG) localLogNetwork("WifiConfigManager: saveNetwork got it back netId=", netId); 809 810 conf = mConfiguredNetworks.getForCurrentUser(netId); 811 if (conf != null) { 812 if (!conf.getNetworkSelectionStatus().isNetworkEnabled()) { 813 if (sVDBG) localLog("WifiConfigManager: re-enabling: " + conf.SSID); 814 815 // reenable autojoin, since new information has been provided 816 updateNetworkSelectionStatus(netId, 817 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 818 } 819 if (sVDBG) { 820 logd("WifiConfigManager: saveNetwork got config back netId=" 821 + Integer.toString(netId) 822 + " uid=" + Integer.toString(config.creatorUid)); 823 } 824 } 825 826 saveConfig(); 827 sendConfiguredNetworksChangedBroadcast( 828 conf, 829 result.isNewNetwork() 830 ? WifiManager.CHANGE_REASON_ADDED 831 : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 832 return result; 833 } 834 835 void noteRoamingFailure(WifiConfiguration config, int reason) { 836 if (config == null) return; 837 config.lastRoamingFailure = mClock.currentTimeMillis(); 838 config.roamingFailureBlackListTimeMilli = 839 2 * (config.roamingFailureBlackListTimeMilli + 1000); 840 if (config.roamingFailureBlackListTimeMilli > mNetworkSwitchingBlackListPeriodMs) { 841 config.roamingFailureBlackListTimeMilli = mNetworkSwitchingBlackListPeriodMs; 842 } 843 config.lastRoamingFailureReason = reason; 844 } 845 846 void saveWifiConfigBSSID(WifiConfiguration config, String bssid) { 847 mWifiConfigStore.setNetworkBSSID(config, bssid); 848 } 849 850 851 void updateStatus(int netId, DetailedState state) { 852 if (netId != INVALID_NETWORK_ID) { 853 WifiConfiguration config = mConfiguredNetworks.getForAllUsers(netId); 854 if (config == null) return; 855 switch (state) { 856 case CONNECTED: 857 config.status = Status.CURRENT; 858 //we successfully connected, hence remove the blacklist 859 updateNetworkSelectionStatus(netId, 860 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 861 break; 862 case DISCONNECTED: 863 //If network is already disabled, keep the status 864 if (config.status == Status.CURRENT) { 865 config.status = Status.ENABLED; 866 } 867 break; 868 default: 869 //do nothing, retain the existing state 870 break; 871 } 872 } 873 } 874 875 876 /** 877 * Disable an ephemeral SSID for the purpose of auto-joining thru scored. 878 * This SSID will never be scored anymore. 879 * The only way to "un-disable it" is if the user create a network for that SSID and then 880 * forget it. 881 * 882 * @param ssid caller must ensure that the SSID passed thru this API match 883 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 884 * @return the {@link WifiConfiguration} corresponding to this SSID, if any, so that we can 885 * disconnect if this is the current network. 886 */ 887 WifiConfiguration disableEphemeralNetwork(String ssid) { 888 if (ssid == null) { 889 return null; 890 } 891 892 WifiConfiguration foundConfig = mConfiguredNetworks.getEphemeralForCurrentUser(ssid); 893 894 mDeletedEphemeralSSIDs.add(ssid); 895 logd("Forget ephemeral SSID " + ssid + " num=" + mDeletedEphemeralSSIDs.size()); 896 897 if (foundConfig != null) { 898 logd("Found ephemeral config in disableEphemeralNetwork: " + foundConfig.networkId); 899 } 900 901 writeKnownNetworkHistory(); 902 return foundConfig; 903 } 904 905 /** 906 * Forget the specified network and save config 907 * 908 * @param netId network to forget 909 * @return {@code true} if it succeeds, {@code false} otherwise 910 */ 911 boolean forgetNetwork(int netId) { 912 if (mShowNetworks) localLogNetwork("forgetNetwork", netId); 913 if (!removeNetwork(netId)) { 914 loge("Failed to forget network " + netId); 915 return false; 916 } 917 saveConfig(); 918 writeKnownNetworkHistory(); 919 return true; 920 } 921 922 /** 923 * Add/update a network. Note that there is no saveConfig operation. 924 * This function is retained for compatibility with the public 925 * API. The more powerful saveNetwork() is used by the 926 * state machine 927 * 928 * @param config wifi configuration to add/update 929 * @return network Id 930 */ 931 int addOrUpdateNetwork(WifiConfiguration config, int uid) { 932 if (config == null || !WifiConfigurationUtil.isVisibleToAnyProfile(config, 933 mUserManager.getProfiles(mCurrentUserId))) { 934 return WifiConfiguration.INVALID_NETWORK_ID; 935 } 936 937 if (mShowNetworks) localLogNetwork("addOrUpdateNetwork id=", config.networkId); 938 if (config.isPasspoint()) { 939 /* create a temporary SSID with providerFriendlyName */ 940 Long csum = getChecksum(config.FQDN); 941 config.SSID = csum.toString(); 942 config.enterpriseConfig.setDomainSuffixMatch(config.FQDN); 943 } 944 945 NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid); 946 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 947 WifiConfiguration conf = mConfiguredNetworks.getForCurrentUser(result.getNetworkId()); 948 if (conf != null) { 949 sendConfiguredNetworksChangedBroadcast( 950 conf, 951 result.isNewNetwork 952 ? WifiManager.CHANGE_REASON_ADDED 953 : WifiManager.CHANGE_REASON_CONFIG_CHANGE); 954 } 955 } 956 957 return result.getNetworkId(); 958 } 959 960 public int addPasspointManagementObject(String managementObject) { 961 try { 962 mMOManager.addSP(managementObject); 963 return 0; 964 } catch (IOException | SAXException e) { 965 return -1; 966 } 967 } 968 969 public int modifyPasspointMo(String fqdn, List<PasspointManagementObjectDefinition> mos) { 970 try { 971 return mMOManager.modifySP(fqdn, mos); 972 } catch (IOException | SAXException e) { 973 return -1; 974 } 975 } 976 977 public boolean queryPasspointIcon(long bssid, String fileName) { 978 return mSupplicantBridge.doIconQuery(bssid, fileName); 979 } 980 981 public int matchProviderWithCurrentNetwork(String fqdn) { 982 ScanDetail scanDetail = null; 983 synchronized (mActiveScanDetailLock) { 984 scanDetail = mActiveScanDetail; 985 } 986 if (scanDetail == null) { 987 return PasspointMatch.None.ordinal(); 988 } 989 HomeSP homeSP = mMOManager.getHomeSP(fqdn); 990 if (homeSP == null) { 991 return PasspointMatch.None.ordinal(); 992 } 993 994 ANQPData anqpData = mAnqpCache.getEntry(scanDetail.getNetworkDetail()); 995 996 Map<Constants.ANQPElementType, ANQPElement> anqpElements = 997 anqpData != null ? anqpData.getANQPElements() : null; 998 999 return homeSP.match(scanDetail.getNetworkDetail(), anqpElements, mSIMAccessor).ordinal(); 1000 } 1001 1002 /** 1003 * General PnoNetwork list sorting algorithm: 1004 * 1, Place the fully enabled networks first. Among the fully enabled networks, 1005 * sort them in the oder determined by the return of |compareConfigurations| method 1006 * implementation. 1007 * 2. Next place all the temporarily disabled networks. Among the temporarily disabled 1008 * networks, sort them in the order determined by the return of |compareConfigurations| method 1009 * implementation. 1010 * 3. Place the permanently disabled networks last. The order among permanently disabled 1011 * networks doesn't matter. 1012 */ 1013 private static class PnoListComparator implements Comparator<WifiConfiguration> { 1014 1015 public final int ENABLED_NETWORK_SCORE = 3; 1016 public final int TEMPORARY_DISABLED_NETWORK_SCORE = 2; 1017 public final int PERMANENTLY_DISABLED_NETWORK_SCORE = 1; 1018 1019 @Override 1020 public int compare(WifiConfiguration a, WifiConfiguration b) { 1021 int configAScore = getPnoNetworkSortScore(a); 1022 int configBScore = getPnoNetworkSortScore(b); 1023 if (configAScore == configBScore) { 1024 return compareConfigurations(a, b); 1025 } else { 1026 return Integer.compare(configBScore, configAScore); 1027 } 1028 } 1029 1030 // This needs to be implemented by the connected/disconnected PNO list comparator. 1031 public int compareConfigurations(WifiConfiguration a, WifiConfiguration b) { 1032 return 0; 1033 } 1034 1035 /** 1036 * Returns an integer representing a score for each configuration. The scores are assigned 1037 * based on the status of the configuration. The scores are assigned according to the order: 1038 * Fully enabled network > Temporarily disabled network > Permanently disabled network. 1039 */ 1040 private int getPnoNetworkSortScore(WifiConfiguration config) { 1041 if (config.getNetworkSelectionStatus().isNetworkEnabled()) { 1042 return ENABLED_NETWORK_SCORE; 1043 } else if (config.getNetworkSelectionStatus().isNetworkTemporaryDisabled()) { 1044 return TEMPORARY_DISABLED_NETWORK_SCORE; 1045 } else { 1046 return PERMANENTLY_DISABLED_NETWORK_SCORE; 1047 } 1048 } 1049 } 1050 1051 /** 1052 * Disconnected PnoNetwork list sorting algorithm: 1053 * Place the configurations in descending order of their |numAssociation| values. If networks 1054 * have the same |numAssociation|, then sort them in descending order of their |priority| 1055 * values. 1056 */ 1057 private static final PnoListComparator sDisconnectedPnoListComparator = 1058 new PnoListComparator() { 1059 @Override 1060 public int compareConfigurations(WifiConfiguration a, WifiConfiguration b) { 1061 if (a.numAssociation != b.numAssociation) { 1062 return Long.compare(b.numAssociation, a.numAssociation); 1063 } else { 1064 return Integer.compare(b.priority, a.priority); 1065 } 1066 } 1067 }; 1068 1069 /** 1070 * Retrieves an updated list of priorities for all the saved networks before 1071 * enabling disconnected PNO (wpa_supplicant based PNO). 1072 * 1073 * wpa_supplicant uses the priority of networks to build the list of SSID's to monitor 1074 * during PNO. If there are a lot of saved networks, this list will be truncated and we 1075 * might end up not connecting to the networks we use most frequently. So, We want the networks 1076 * to be re-sorted based on the relative |numAssociation| values. 1077 * 1078 * @return list of networks with updated priorities. 1079 */ 1080 public ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrieveDisconnectedPnoNetworkList() { 1081 return retrievePnoNetworkList(sDisconnectedPnoListComparator); 1082 } 1083 1084 /** 1085 * Connected PnoNetwork list sorting algorithm: 1086 * Place the configurations with |lastSeenInQualifiedNetworkSelection| set first. If networks 1087 * have the same value, then sort them in descending order of their |numAssociation| 1088 * values. 1089 */ 1090 private static final PnoListComparator sConnectedPnoListComparator = 1091 new PnoListComparator() { 1092 @Override 1093 public int compareConfigurations(WifiConfiguration a, WifiConfiguration b) { 1094 boolean isConfigALastSeen = 1095 a.getNetworkSelectionStatus().getSeenInLastQualifiedNetworkSelection(); 1096 boolean isConfigBLastSeen = 1097 b.getNetworkSelectionStatus().getSeenInLastQualifiedNetworkSelection(); 1098 if (isConfigALastSeen != isConfigBLastSeen) { 1099 return Boolean.compare(isConfigBLastSeen, isConfigALastSeen); 1100 } else { 1101 return Long.compare(b.numAssociation, a.numAssociation); 1102 } 1103 } 1104 }; 1105 1106 /** 1107 * Retrieves an updated list of priorities for all the saved networks before 1108 * enabling connected PNO (HAL based ePno). 1109 * 1110 * @return list of networks with updated priorities. 1111 */ 1112 public ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrieveConnectedPnoNetworkList() { 1113 return retrievePnoNetworkList(sConnectedPnoListComparator); 1114 } 1115 1116 /** 1117 * Create a PnoNetwork object from the provided WifiConfiguration. 1118 * @param config Configuration corresponding to the network. 1119 * @param newPriority New priority to be assigned to the network. 1120 */ 1121 private static WifiScanner.PnoSettings.PnoNetwork createPnoNetworkFromWifiConfiguration( 1122 WifiConfiguration config, int newPriority) { 1123 WifiScanner.PnoSettings.PnoNetwork pnoNetwork = 1124 new WifiScanner.PnoSettings.PnoNetwork(config.SSID); 1125 pnoNetwork.networkId = config.networkId; 1126 pnoNetwork.priority = newPriority; 1127 if (config.hiddenSSID) { 1128 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN; 1129 } 1130 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_A_BAND; 1131 pnoNetwork.flags |= WifiScanner.PnoSettings.PnoNetwork.FLAG_G_BAND; 1132 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 1133 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_PSK; 1134 } else if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) 1135 || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) { 1136 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_EAPOL; 1137 } else { 1138 pnoNetwork.authBitField |= WifiScanner.PnoSettings.PnoNetwork.AUTH_CODE_OPEN; 1139 } 1140 return pnoNetwork; 1141 } 1142 1143 /** 1144 * Retrieves an updated list of priorities for all the saved networks before 1145 * enabling/disabling PNO. 1146 * 1147 * @param pnoListComparator The comparator to use for sorting networks 1148 * @return list of networks with updated priorities. 1149 */ 1150 private ArrayList<WifiScanner.PnoSettings.PnoNetwork> retrievePnoNetworkList( 1151 PnoListComparator pnoListComparator) { 1152 ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoList = new ArrayList<>(); 1153 ArrayList<WifiConfiguration> wifiConfigurations = 1154 new ArrayList<>(mConfiguredNetworks.valuesForCurrentUser()); 1155 // Remove any permanently disabled networks. 1156 Iterator<WifiConfiguration> iter = wifiConfigurations.iterator(); 1157 while (iter.hasNext()) { 1158 WifiConfiguration config = iter.next(); 1159 if (config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()) { 1160 iter.remove(); 1161 } 1162 } 1163 Collections.sort(wifiConfigurations, pnoListComparator); 1164 // Let's use the network list size as the highest priority and then go down from there. 1165 // So, the most frequently connected network has the highest priority now. 1166 int priority = wifiConfigurations.size(); 1167 for (WifiConfiguration config : wifiConfigurations) { 1168 pnoList.add(createPnoNetworkFromWifiConfiguration(config, priority)); 1169 priority--; 1170 } 1171 return pnoList; 1172 } 1173 1174 /** 1175 * Remove a network. Note that there is no saveConfig operation. 1176 * This function is retained for compatibility with the public 1177 * API. The more powerful forgetNetwork() is used by the 1178 * state machine for network removal 1179 * 1180 * @param netId network to be removed 1181 * @return {@code true} if it succeeds, {@code false} otherwise 1182 */ 1183 boolean removeNetwork(int netId) { 1184 if (mShowNetworks) localLogNetwork("removeNetwork", netId); 1185 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1186 if (!removeConfigAndSendBroadcastIfNeeded(config)) { 1187 return false; 1188 } 1189 if (config.isPasspoint()) { 1190 writePasspointConfigs(config.FQDN, null); 1191 } 1192 return true; 1193 } 1194 1195 private static Long getChecksum(String source) { 1196 Checksum csum = new CRC32(); 1197 csum.update(source.getBytes(), 0, source.getBytes().length); 1198 return csum.getValue(); 1199 } 1200 1201 private boolean removeConfigWithoutBroadcast(WifiConfiguration config) { 1202 if (config == null) { 1203 return false; 1204 } 1205 if (!mWifiConfigStore.removeNetwork(config)) { 1206 loge("Failed to remove network " + config.networkId); 1207 return false; 1208 } 1209 if (config.configKey().equals(mLastSelectedConfiguration)) { 1210 mLastSelectedConfiguration = null; 1211 } 1212 mConfiguredNetworks.remove(config.networkId); 1213 mScanDetailCaches.remove(config.networkId); 1214 return true; 1215 } 1216 1217 private boolean removeConfigAndSendBroadcastIfNeeded(WifiConfiguration config) { 1218 if (!removeConfigWithoutBroadcast(config)) { 1219 return false; 1220 } 1221 String key = config.configKey(); 1222 if (sVDBG) { 1223 logd("removeNetwork " + " key=" + key + " config.id=" + config.networkId); 1224 } 1225 writeIpAndProxyConfigurations(); 1226 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED); 1227 if (!config.ephemeral) { 1228 removeUserSelectionPreference(key); 1229 } 1230 writeKnownNetworkHistory(); 1231 return true; 1232 } 1233 1234 private void removeUserSelectionPreference(String configKey) { 1235 if (DBG) { 1236 Log.d(TAG, "removeUserSelectionPreference: key is " + configKey); 1237 } 1238 if (configKey == null) { 1239 return; 1240 } 1241 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 1242 WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus(); 1243 String connectChoice = status.getConnectChoice(); 1244 if (connectChoice != null && connectChoice.equals(configKey)) { 1245 Log.d(TAG, "remove connect choice:" + connectChoice + " from " + config.SSID 1246 + " : " + config.networkId); 1247 status.setConnectChoice(null); 1248 status.setConnectChoiceTimestamp(WifiConfiguration.NetworkSelectionStatus 1249 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1250 } 1251 } 1252 } 1253 1254 /* 1255 * Remove all networks associated with an application 1256 * 1257 * @param app Application info of the package of networks to remove. 1258 * @return the {@link Set} of networks that were removed by this call. Networks which matched 1259 * but failed to remove are omitted from this set. 1260 */ 1261 public Set<Integer> removeNetworksForApp(ApplicationInfo app) { 1262 if (app == null || app.packageName == null) { 1263 return Collections.<Integer>emptySet(); 1264 } 1265 1266 Log.d(TAG, "Remove all networks for app " + app); 1267 Set<Integer> removedNetworks = new ArraySet<>(); 1268 WifiConfiguration[] copiedConfigs = 1269 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1270 for (WifiConfiguration config : copiedConfigs) { 1271 if (app.uid != config.creatorUid || !app.packageName.equals(config.creatorName)) { 1272 continue; 1273 } 1274 localLog("Removing network " + config.SSID 1275 + ", application \"" + app.packageName + "\" uninstalled" 1276 + " from user " + UserHandle.getUserId(app.uid)); 1277 if (removeNetwork(config.networkId)) { 1278 removedNetworks.add(config.networkId); 1279 } 1280 } 1281 saveConfig(); 1282 return removedNetworks; 1283 } 1284 1285 /** 1286 * Remove all networks associated with a user. 1287 * 1288 * @param userId The identifier of the user which is being removed. 1289 * @return the {@link Set} of networks that were removed by this call. Networks which matched 1290 * but failed to remove are omitted from this set. 1291 */ 1292 Set<Integer> removeNetworksForUser(int userId) { 1293 Log.d(TAG, "Remove all networks for user " + userId); 1294 Set<Integer> removedNetworks = new ArraySet<>(); 1295 WifiConfiguration[] copiedConfigs = 1296 mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]); 1297 for (WifiConfiguration config : copiedConfigs) { 1298 if (userId != UserHandle.getUserId(config.creatorUid)) { 1299 continue; 1300 } 1301 localLog("Removing network " + config.SSID + ", user " + userId + " removed"); 1302 if (removeNetwork(config.networkId)) { 1303 removedNetworks.add(config.networkId); 1304 } 1305 } 1306 return removedNetworks; 1307 } 1308 1309 /** 1310 * Enable a network. Note that there is no saveConfig operation. 1311 * This function is retained for compatibility with the public 1312 * API. The more powerful selectNetwork()/saveNetwork() is used by the 1313 * state machine for connecting to a network 1314 * 1315 * @param config network to be enabled 1316 * @return {@code true} if it succeeds, {@code false} otherwise 1317 */ 1318 boolean enableNetwork(WifiConfiguration config, boolean disableOthers, int uid) { 1319 if (config == null) { 1320 return false; 1321 } 1322 1323 updateNetworkSelectionStatus( 1324 config, WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1325 setLatestUserSelectedConfiguration(config); 1326 boolean ret = true; 1327 if (disableOthers) { 1328 ret = selectNetworkWithoutBroadcast(config.networkId); 1329 if (sVDBG) { 1330 localLogNetwork("enableNetwork(disableOthers=true, uid=" + uid + ") ", 1331 config.networkId); 1332 } 1333 updateLastConnectUid(config, uid); 1334 writeKnownNetworkHistory(); 1335 sendConfiguredNetworksChangedBroadcast(); 1336 } else { 1337 if (sVDBG) localLogNetwork("enableNetwork(disableOthers=false) ", config.networkId); 1338 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1339 } 1340 return ret; 1341 } 1342 1343 boolean selectNetworkWithoutBroadcast(int netId) { 1344 return mWifiConfigStore.selectNetwork( 1345 mConfiguredNetworks.getForCurrentUser(netId), 1346 mConfiguredNetworks.valuesForCurrentUser()); 1347 } 1348 1349 /** 1350 * Disable a network in wpa_supplicant. 1351 */ 1352 boolean disableNetworkNative(WifiConfiguration config) { 1353 return mWifiConfigStore.disableNetwork(config); 1354 } 1355 1356 /** 1357 * Disable all networks in wpa_supplicant. 1358 */ 1359 void disableAllNetworksNative() { 1360 mWifiConfigStore.disableAllNetworks(mConfiguredNetworks.valuesForCurrentUser()); 1361 } 1362 1363 /** 1364 * Disable a network. Note that there is no saveConfig operation. 1365 * @param netId network to be disabled 1366 * @return {@code true} if it succeeds, {@code false} otherwise 1367 */ 1368 boolean disableNetwork(int netId) { 1369 return mWifiConfigStore.disableNetwork(mConfiguredNetworks.getForCurrentUser(netId)); 1370 } 1371 1372 /** 1373 * Update a network according to the update reason and its current state 1374 * @param netId The network ID of the network need update 1375 * @param reason The reason to update the network 1376 * @return false if no change made to the input configure file, can due to error or need not 1377 * true the input config file has been changed 1378 */ 1379 boolean updateNetworkSelectionStatus(int netId, int reason) { 1380 WifiConfiguration config = getWifiConfiguration(netId); 1381 return updateNetworkSelectionStatus(config, reason); 1382 } 1383 1384 /** 1385 * Update a network according to the update reason and its current state 1386 * @param config the network need update 1387 * @param reason The reason to update the network 1388 * @return false if no change made to the input configure file, can due to error or need not 1389 * true the input config file has been changed 1390 */ 1391 boolean updateNetworkSelectionStatus(WifiConfiguration config, int reason) { 1392 if (config == null) { 1393 return false; 1394 } 1395 1396 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1397 if (reason == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1398 updateNetworkStatus(config, WifiConfiguration.NetworkSelectionStatus 1399 .NETWORK_SELECTION_ENABLE); 1400 localLog("Enable network:" + config.configKey()); 1401 return true; 1402 } 1403 1404 networkStatus.incrementDisableReasonCounter(reason); 1405 if (DBG) { 1406 localLog("Network:" + config.SSID + "disable counter of " 1407 + WifiConfiguration.NetworkSelectionStatus.getNetworkDisableReasonString(reason) 1408 + " is: " + networkStatus.getDisableReasonCounter(reason) + "and threshold is: " 1409 + NETWORK_SELECTION_DISABLE_THRESHOLD[reason]); 1410 } 1411 1412 if (networkStatus.getDisableReasonCounter(reason) 1413 >= NETWORK_SELECTION_DISABLE_THRESHOLD[reason]) { 1414 return updateNetworkStatus(config, reason); 1415 } 1416 return true; 1417 } 1418 1419 /** 1420 * Check the config. If it is temporarily disabled, check the disable time is expired or not, If 1421 * expired, enabled it again for qualified network selection. 1422 * @param networkId the id of the network to be checked for possible unblock (due to timeout) 1423 * @return true if network status has been changed 1424 * false network status is not changed 1425 */ 1426 public boolean tryEnableQualifiedNetwork(int networkId) { 1427 WifiConfiguration config = getWifiConfiguration(networkId); 1428 if (config == null) { 1429 localLog("updateQualifiedNetworkstatus invalid network."); 1430 return false; 1431 } 1432 return tryEnableQualifiedNetwork(config); 1433 } 1434 1435 /** 1436 * Check the config. If it is temporarily disabled, check the disable is expired or not, If 1437 * expired, enabled it again for qualified network selection. 1438 * @param config network to be checked for possible unblock (due to timeout) 1439 * @return true if network status has been changed 1440 * false network status is not changed 1441 */ 1442 private boolean tryEnableQualifiedNetwork(WifiConfiguration config) { 1443 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1444 if (networkStatus.isNetworkTemporaryDisabled()) { 1445 //time difference in minutes 1446 long timeDifference = 1447 (mClock.elapsedRealtime() - networkStatus.getDisableTime()) / 1000 / 60; 1448 if (timeDifference < 0 || timeDifference 1449 >= NETWORK_SELECTION_DISABLE_TIMEOUT[ 1450 networkStatus.getNetworkSelectionDisableReason()]) { 1451 updateNetworkSelectionStatus(config.networkId, 1452 networkStatus.NETWORK_SELECTION_ENABLE); 1453 return true; 1454 } 1455 } 1456 return false; 1457 } 1458 1459 /** 1460 * Update a network's status. Note that there is no saveConfig operation. 1461 * @param config network to be updated 1462 * @param reason reason code for updated 1463 * @return false if no change made to the input configure file, can due to error or need not 1464 * true the input config file has been changed 1465 */ 1466 boolean updateNetworkStatus(WifiConfiguration config, int reason) { 1467 localLog("updateNetworkStatus:" + (config == null ? null : config.SSID)); 1468 if (config == null) { 1469 return false; 1470 } 1471 1472 WifiConfiguration.NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); 1473 if (reason < 0 || reason >= WifiConfiguration.NetworkSelectionStatus 1474 .NETWORK_SELECTION_DISABLED_MAX) { 1475 localLog("Invalid Network disable reason:" + reason); 1476 return false; 1477 } 1478 1479 if (reason == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) { 1480 if (networkStatus.isNetworkEnabled()) { 1481 if (DBG) { 1482 localLog("Need not change Qualified network Selection status since" 1483 + " already enabled"); 1484 } 1485 return false; 1486 } 1487 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1488 .NETWORK_SELECTION_ENABLED); 1489 networkStatus.setNetworkSelectionDisableReason(reason); 1490 networkStatus.setDisableTime( 1491 WifiConfiguration.NetworkSelectionStatus 1492 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); 1493 networkStatus.clearDisableReasonCounter(); 1494 String disableTime = DateFormat.getDateTimeInstance().format(new Date()); 1495 if (DBG) { 1496 localLog("Re-enable network: " + config.SSID + " at " + disableTime); 1497 } 1498 sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1499 } else { 1500 //disable the network 1501 if (networkStatus.isNetworkPermanentlyDisabled()) { 1502 //alreay permanent disable 1503 if (DBG) { 1504 localLog("Do nothing. Alreay permanent disabled! " 1505 + WifiConfiguration.NetworkSelectionStatus 1506 .getNetworkDisableReasonString(reason)); 1507 } 1508 return false; 1509 } else if (networkStatus.isNetworkTemporaryDisabled() 1510 && reason < WifiConfiguration.NetworkSelectionStatus 1511 .DISABLED_TLS_VERSION_MISMATCH) { 1512 //alreay temporarily disable 1513 if (DBG) { 1514 localLog("Do nothing. Already temporarily disabled! " 1515 + WifiConfiguration.NetworkSelectionStatus 1516 .getNetworkDisableReasonString(reason)); 1517 } 1518 return false; 1519 } 1520 1521 if (networkStatus.isNetworkEnabled()) { 1522 disableNetworkNative(config); 1523 sendConfiguredNetworksChangedBroadcast(config, 1524 WifiManager.CHANGE_REASON_CONFIG_CHANGE); 1525 localLog("Disable network " + config.SSID + " reason:" 1526 + WifiConfiguration.NetworkSelectionStatus 1527 .getNetworkDisableReasonString(reason)); 1528 } 1529 if (reason < WifiConfiguration.NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) { 1530 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1531 .NETWORK_SELECTION_TEMPORARY_DISABLED); 1532 networkStatus.setDisableTime(mClock.elapsedRealtime()); 1533 } else { 1534 networkStatus.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus 1535 .NETWORK_SELECTION_PERMANENTLY_DISABLED); 1536 } 1537 networkStatus.setNetworkSelectionDisableReason(reason); 1538 if (DBG) { 1539 String disableTime = DateFormat.getDateTimeInstance().format(new Date()); 1540 localLog("Network:" + config.SSID + "Configure new status:" 1541 + networkStatus.getNetworkStatusString() + " with reason:" 1542 + networkStatus.getNetworkDisableReasonString() + " at: " + disableTime); 1543 } 1544 } 1545 return true; 1546 } 1547 1548 /** 1549 * Save the configured networks in supplicant to disk 1550 * @return {@code true} if it succeeds, {@code false} otherwise 1551 */ 1552 boolean saveConfig() { 1553 return mWifiConfigStore.saveConfig(); 1554 } 1555 1556 /** 1557 * Start WPS pin method configuration with pin obtained 1558 * from the access point 1559 * @param config WPS configuration 1560 * @return Wps result containing status and pin 1561 */ 1562 WpsResult startWpsWithPinFromAccessPoint(WpsInfo config) { 1563 return mWifiConfigStore.startWpsWithPinFromAccessPoint( 1564 config, mConfiguredNetworks.valuesForCurrentUser()); 1565 } 1566 1567 /** 1568 * Start WPS pin method configuration with obtained 1569 * from the device 1570 * @return WpsResult indicating status and pin 1571 */ 1572 WpsResult startWpsWithPinFromDevice(WpsInfo config) { 1573 return mWifiConfigStore.startWpsWithPinFromDevice( 1574 config, mConfiguredNetworks.valuesForCurrentUser()); 1575 } 1576 1577 /** 1578 * Start WPS push button configuration 1579 * @param config WPS configuration 1580 * @return WpsResult indicating status and pin 1581 */ 1582 WpsResult startWpsPbc(WpsInfo config) { 1583 return mWifiConfigStore.startWpsPbc( 1584 config, mConfiguredNetworks.valuesForCurrentUser()); 1585 } 1586 1587 /** 1588 * Fetch the static IP configuration for a given network id 1589 */ 1590 StaticIpConfiguration getStaticIpConfiguration(int netId) { 1591 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1592 if (config != null) { 1593 return config.getStaticIpConfiguration(); 1594 } 1595 return null; 1596 } 1597 1598 /** 1599 * Set the static IP configuration for a given network id 1600 */ 1601 void setStaticIpConfiguration(int netId, StaticIpConfiguration staticIpConfiguration) { 1602 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1603 if (config != null) { 1604 config.setStaticIpConfiguration(staticIpConfiguration); 1605 } 1606 } 1607 1608 /** 1609 * set default GW MAC address 1610 */ 1611 void setDefaultGwMacAddress(int netId, String macAddress) { 1612 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1613 if (config != null) { 1614 //update defaultGwMacAddress 1615 config.defaultGwMacAddress = macAddress; 1616 } 1617 } 1618 1619 1620 /** 1621 * Fetch the proxy properties for a given network id 1622 * @param netId id 1623 * @return ProxyInfo for the network id 1624 */ 1625 ProxyInfo getProxyProperties(int netId) { 1626 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1627 if (config != null) { 1628 return config.getHttpProxy(); 1629 } 1630 return null; 1631 } 1632 1633 /** 1634 * Return if the specified network is using static IP 1635 * @param netId id 1636 * @return {@code true} if using static ip for netId 1637 */ 1638 boolean isUsingStaticIp(int netId) { 1639 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1640 if (config != null && config.getIpAssignment() == IpAssignment.STATIC) { 1641 return true; 1642 } 1643 return false; 1644 } 1645 1646 boolean isEphemeral(int netId) { 1647 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1648 return config != null && config.ephemeral; 1649 } 1650 1651 boolean getMeteredHint(int netId) { 1652 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId); 1653 return config != null && config.meteredHint; 1654 } 1655 1656 /** 1657 * Should be called when a single network configuration is made. 1658 * @param network The network configuration that changed. 1659 * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED, 1660 * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE. 1661 */ 1662 private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network, 1663 int reason) { 1664 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1665 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1666 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false); 1667 intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network); 1668 intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason); 1669 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1670 } 1671 1672 /** 1673 * Should be called when multiple network configuration changes are made. 1674 */ 1675 private void sendConfiguredNetworksChangedBroadcast() { 1676 Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); 1677 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1678 intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true); 1679 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1680 } 1681 1682 void loadConfiguredNetworks() { 1683 1684 final Map<String, WifiConfiguration> configs = new HashMap<>(); 1685 final SparseArray<Map<String, String>> networkExtras = new SparseArray<>(); 1686 mLastPriority = mWifiConfigStore.loadNetworks(configs, networkExtras); 1687 1688 readNetworkHistory(configs); 1689 readPasspointConfig(configs, networkExtras); 1690 1691 // We are only now updating mConfiguredNetworks for two reasons: 1692 // 1) The information required to compute configKeys is spread across wpa_supplicant.conf 1693 // and networkHistory.txt. Thus, we had to load both files first. 1694 // 2) mConfiguredNetworks caches a Passpoint network's FQDN the moment the network is added. 1695 // Thus, we had to load the FQDNs first. 1696 mConfiguredNetworks.clear(); 1697 mScanDetailCaches.clear(); 1698 for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) { 1699 final String configKey = entry.getKey(); 1700 final WifiConfiguration config = entry.getValue(); 1701 if (!configKey.equals(config.configKey())) { 1702 if (mShowNetworks) { 1703 log("Ignoring network " + config.networkId + " because the configKey loaded " 1704 + "from wpa_supplicant.conf is not valid."); 1705 } 1706 mWifiConfigStore.removeNetwork(config); 1707 continue; 1708 } 1709 mConfiguredNetworks.put(config); 1710 } 1711 1712 readIpAndProxyConfigurations(); 1713 1714 sendConfiguredNetworksChangedBroadcast(); 1715 1716 if (mShowNetworks) { 1717 localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.sizeForAllUsers() 1718 + " networks (for all users)"); 1719 } 1720 1721 if (mConfiguredNetworks.sizeForAllUsers() == 0) { 1722 // no networks? Lets log if the file contents 1723 logKernelTime(); 1724 logContents(WifiConfigStore.SUPPLICANT_CONFIG_FILE); 1725 logContents(WifiConfigStore.SUPPLICANT_CONFIG_FILE_BACKUP); 1726 logContents(WifiNetworkHistory.NETWORK_HISTORY_CONFIG_FILE); 1727 } 1728 } 1729 1730 private void logContents(String file) { 1731 localLogAndLogcat("--- Begin " + file + " ---"); 1732 BufferedReader reader = null; 1733 try { 1734 reader = new BufferedReader(new FileReader(file)); 1735 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 1736 localLogAndLogcat(line); 1737 } 1738 } catch (FileNotFoundException e) { 1739 localLog("Could not open " + file + ", " + e); 1740 Log.w(TAG, "Could not open " + file + ", " + e); 1741 } catch (IOException e) { 1742 localLog("Could not read " + file + ", " + e); 1743 Log.w(TAG, "Could not read " + file + ", " + e); 1744 } finally { 1745 try { 1746 if (reader != null) { 1747 reader.close(); 1748 } 1749 } catch (IOException e) { 1750 // Just ignore the fact that we couldn't close 1751 } 1752 } 1753 localLogAndLogcat("--- End " + file + " Contents ---"); 1754 } 1755 1756 private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) { 1757 return mWifiConfigStore.readNetworkVariablesFromSupplicantFile(key); 1758 } 1759 1760 private String readNetworkVariableFromSupplicantFile(String configKey, String key) { 1761 long start = SystemClock.elapsedRealtimeNanos(); 1762 Map<String, String> data = mWifiConfigStore.readNetworkVariablesFromSupplicantFile(key); 1763 long end = SystemClock.elapsedRealtimeNanos(); 1764 1765 if (sVDBG) { 1766 localLog("readNetworkVariableFromSupplicantFile configKey=[" + configKey + "] key=" 1767 + key + " duration=" + (long) (end - start)); 1768 } 1769 return data.get(configKey); 1770 } 1771 1772 boolean needsUnlockedKeyStore() { 1773 1774 // Any network using certificates to authenticate access requires 1775 // unlocked key store; unless the certificates can be stored with 1776 // hardware encryption 1777 1778 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 1779 1780 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) 1781 && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 1782 1783 if (needsSoftwareBackedKeyStore(config.enterpriseConfig)) { 1784 return true; 1785 } 1786 } 1787 } 1788 1789 return false; 1790 } 1791 1792 void readPasspointConfig(Map<String, WifiConfiguration> configs, 1793 SparseArray<Map<String, String>> networkExtras) { 1794 List<HomeSP> homeSPs; 1795 try { 1796 homeSPs = mMOManager.loadAllSPs(); 1797 } catch (IOException e) { 1798 loge("Could not read " + PPS_FILE + " : " + e); 1799 return; 1800 } 1801 1802 int matchedConfigs = 0; 1803 for (HomeSP homeSp : homeSPs) { 1804 String fqdn = homeSp.getFQDN(); 1805 Log.d(TAG, "Looking for " + fqdn); 1806 for (WifiConfiguration config : configs.values()) { 1807 Log.d(TAG, "Testing " + config.SSID); 1808 1809 if (config.enterpriseConfig == null) { 1810 continue; 1811 } 1812 final String configFqdn = 1813 networkExtras.get(config.networkId).get(WifiConfigStore.ID_STRING_KEY_FQDN); 1814 if (configFqdn != null && configFqdn.equals(fqdn)) { 1815 Log.d(TAG, "Matched " + configFqdn + " with " + config.networkId); 1816 ++matchedConfigs; 1817 config.FQDN = fqdn; 1818 config.providerFriendlyName = homeSp.getFriendlyName(); 1819 1820 HashSet<Long> roamingConsortiumIds = homeSp.getRoamingConsortiums(); 1821 config.roamingConsortiumIds = new long[roamingConsortiumIds.size()]; 1822 int i = 0; 1823 for (long id : roamingConsortiumIds) { 1824 config.roamingConsortiumIds[i] = id; 1825 i++; 1826 } 1827 IMSIParameter imsiParameter = homeSp.getCredential().getImsi(); 1828 config.enterpriseConfig.setPlmn( 1829 imsiParameter != null ? imsiParameter.toString() : null); 1830 config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm()); 1831 } 1832 } 1833 } 1834 1835 Log.d(TAG, "loaded " + matchedConfigs + " passpoint configs"); 1836 } 1837 1838 public void writePasspointConfigs(final String fqdn, final HomeSP homeSP) { 1839 mWriter.write(PPS_FILE, new DelayedDiskWrite.Writer() { 1840 @Override 1841 public void onWriteCalled(DataOutputStream out) throws IOException { 1842 try { 1843 if (homeSP != null) { 1844 mMOManager.addSP(homeSP); 1845 } else { 1846 mMOManager.removeSP(fqdn); 1847 } 1848 } catch (IOException e) { 1849 loge("Could not write " + PPS_FILE + " : " + e); 1850 } 1851 } 1852 }, false); 1853 } 1854 1855 /** 1856 * Write network history, WifiConfigurations and mScanDetailCaches to file. 1857 */ 1858 private void readNetworkHistory(Map<String, WifiConfiguration> configs) { 1859 mWifiNetworkHistory.readNetworkHistory(configs, 1860 mScanDetailCaches, 1861 mDeletedEphemeralSSIDs); 1862 } 1863 1864 /** 1865 * Read Network history from file, merge it into mConfiguredNetowrks and mScanDetailCaches 1866 */ 1867 public void writeKnownNetworkHistory() { 1868 final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); 1869 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 1870 networks.add(new WifiConfiguration(config)); 1871 } 1872 mWifiNetworkHistory.writeKnownNetworkHistory(networks, 1873 mScanDetailCaches, 1874 mDeletedEphemeralSSIDs); 1875 } 1876 1877 public void setAndEnableLastSelectedConfiguration(int netId) { 1878 if (sVDBG) { 1879 logd("setLastSelectedConfiguration " + Integer.toString(netId)); 1880 } 1881 if (netId == WifiConfiguration.INVALID_NETWORK_ID) { 1882 mLastSelectedConfiguration = null; 1883 mLastSelectedTimeStamp = -1; 1884 } else { 1885 WifiConfiguration selected = getWifiConfiguration(netId); 1886 if (selected == null) { 1887 mLastSelectedConfiguration = null; 1888 mLastSelectedTimeStamp = -1; 1889 } else { 1890 mLastSelectedConfiguration = selected.configKey(); 1891 mLastSelectedTimeStamp = mClock.elapsedRealtime(); 1892 updateNetworkSelectionStatus(netId, 1893 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 1894 if (sVDBG) { 1895 logd("setLastSelectedConfiguration now: " + mLastSelectedConfiguration); 1896 } 1897 } 1898 } 1899 } 1900 1901 public void setLatestUserSelectedConfiguration(WifiConfiguration network) { 1902 if (network != null) { 1903 mLastSelectedConfiguration = network.configKey(); 1904 mLastSelectedTimeStamp = mClock.elapsedRealtime(); 1905 } 1906 } 1907 1908 public String getLastSelectedConfiguration() { 1909 return mLastSelectedConfiguration; 1910 } 1911 1912 public long getLastSelectedTimeStamp() { 1913 return mLastSelectedTimeStamp; 1914 } 1915 1916 public boolean isLastSelectedConfiguration(WifiConfiguration config) { 1917 return (mLastSelectedConfiguration != null 1918 && config != null 1919 && mLastSelectedConfiguration.equals(config.configKey())); 1920 } 1921 1922 private void writeIpAndProxyConfigurations() { 1923 final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>(); 1924 for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { 1925 if (!config.ephemeral) { 1926 networks.put(configKey(config), config.getIpConfiguration()); 1927 } 1928 } 1929 1930 mIpconfigStore.writeIpAndProxyConfigurations(IP_CONFIG_FILE, networks); 1931 } 1932 1933 private void readIpAndProxyConfigurations() { 1934 SparseArray<IpConfiguration> networks = 1935 mIpconfigStore.readIpAndProxyConfigurations(IP_CONFIG_FILE); 1936 1937 if (networks == null || networks.size() == 0) { 1938 // IpConfigStore.readIpAndProxyConfigurations has already logged an error. 1939 return; 1940 } 1941 1942 for (int i = 0; i < networks.size(); i++) { 1943 int id = networks.keyAt(i); 1944 WifiConfiguration config = mConfiguredNetworks.getByConfigKeyIDForAllUsers(id); 1945 // This is the only place the map is looked up through a (dangerous) hash-value! 1946 1947 if (config == null || config.ephemeral) { 1948 logd("configuration found for missing network, nid=" + id 1949 + ", ignored, networks.size=" + Integer.toString(networks.size())); 1950 } else { 1951 config.setIpConfiguration(networks.valueAt(i)); 1952 } 1953 } 1954 } 1955 1956 private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config, int uid) { 1957 /* 1958 * If the supplied networkId is INVALID_NETWORK_ID, we create a new empty 1959 * network configuration. Otherwise, the networkId should 1960 * refer to an existing configuration. 1961 */ 1962 1963 if (sVDBG) localLog("addOrUpdateNetworkNative " + config.getPrintableSsid()); 1964 if (config.isPasspoint() && !mMOManager.isEnabled()) { 1965 Log.e(TAG, "Passpoint is not enabled"); 1966 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1967 } 1968 1969 boolean newNetwork = false; 1970 boolean existingMO = false; 1971 WifiConfiguration currentConfig; 1972 // networkId of INVALID_NETWORK_ID means we want to create a new network 1973 if (config.networkId == INVALID_NETWORK_ID) { 1974 // Try to fetch the existing config using configKey 1975 currentConfig = mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 1976 if (currentConfig != null) { 1977 config.networkId = currentConfig.networkId; 1978 } else { 1979 if (mMOManager.getHomeSP(config.FQDN) != null) { 1980 logd("addOrUpdateNetworkNative passpoint " + config.FQDN 1981 + " was found, but no network Id"); 1982 existingMO = true; 1983 } 1984 newNetwork = true; 1985 } 1986 } else { 1987 // Fetch the existing config using networkID 1988 currentConfig = mConfiguredNetworks.getForCurrentUser(config.networkId); 1989 } 1990 1991 // originalConfig is used to check for credential and config changes that would cause 1992 // HasEverConnected to be set to false. 1993 WifiConfiguration originalConfig = new WifiConfiguration(currentConfig); 1994 1995 if (!mWifiConfigStore.addOrUpdateNetwork(config, currentConfig, 1996 mSystemSupportsFastBssTransition)) { 1997 return new NetworkUpdateResult(INVALID_NETWORK_ID); 1998 } 1999 int netId = config.networkId; 2000 String savedConfigKey = config.configKey(); 2001 2002 /* An update of the network variables requires reading them 2003 * back from the supplicant to update mConfiguredNetworks. 2004 * This is because some of the variables (SSID, wep keys & 2005 * passphrases) reflect different values when read back than 2006 * when written. For example, wep key is stored as * irrespective 2007 * of the value sent to the supplicant. 2008 */ 2009 if (currentConfig == null) { 2010 currentConfig = new WifiConfiguration(); 2011 currentConfig.setIpAssignment(IpAssignment.DHCP); 2012 currentConfig.setProxySettings(ProxySettings.NONE); 2013 currentConfig.networkId = netId; 2014 if (config != null) { 2015 // Carry over the creation parameters 2016 currentConfig.selfAdded = config.selfAdded; 2017 currentConfig.didSelfAdd = config.didSelfAdd; 2018 currentConfig.ephemeral = config.ephemeral; 2019 currentConfig.meteredHint = config.meteredHint; 2020 currentConfig.useExternalScores = config.useExternalScores; 2021 currentConfig.lastConnectUid = config.lastConnectUid; 2022 currentConfig.lastUpdateUid = config.lastUpdateUid; 2023 currentConfig.creatorUid = config.creatorUid; 2024 currentConfig.creatorName = config.creatorName; 2025 currentConfig.lastUpdateName = config.lastUpdateName; 2026 currentConfig.peerWifiConfiguration = config.peerWifiConfiguration; 2027 currentConfig.FQDN = config.FQDN; 2028 currentConfig.providerFriendlyName = config.providerFriendlyName; 2029 currentConfig.roamingConsortiumIds = config.roamingConsortiumIds; 2030 currentConfig.validatedInternetAccess = config.validatedInternetAccess; 2031 currentConfig.numNoInternetAccessReports = config.numNoInternetAccessReports; 2032 currentConfig.updateTime = config.updateTime; 2033 currentConfig.creationTime = config.creationTime; 2034 currentConfig.shared = config.shared; 2035 currentConfig.isCarrierNetwork = config.isCarrierNetwork; 2036 } 2037 if (DBG) { 2038 log("created new config netId=" + Integer.toString(netId) 2039 + " uid=" + Integer.toString(currentConfig.creatorUid) 2040 + " name=" + currentConfig.creatorName); 2041 } 2042 } 2043 2044 /* save HomeSP object for passpoint networks */ 2045 HomeSP homeSP = null; 2046 2047 if (!existingMO && config.isPasspoint()) { 2048 try { 2049 if (config.updateIdentifier == null) { // Only create an MO for r1 networks 2050 Credential credential = 2051 new Credential(config.enterpriseConfig, mKeyStore, !newNetwork); 2052 HashSet<Long> roamingConsortiumIds = new HashSet<Long>(); 2053 for (Long roamingConsortiumId : config.roamingConsortiumIds) { 2054 roamingConsortiumIds.add(roamingConsortiumId); 2055 } 2056 2057 homeSP = new HomeSP(Collections.<String, Long>emptyMap(), config.FQDN, 2058 roamingConsortiumIds, Collections.<String>emptySet(), 2059 Collections.<Long>emptySet(), Collections.<Long>emptyList(), 2060 config.providerFriendlyName, null, credential); 2061 2062 log("created a homeSP object for " + config.networkId + ":" + config.SSID); 2063 } 2064 2065 /* fix enterprise config properties for passpoint */ 2066 currentConfig.enterpriseConfig.setRealm(config.enterpriseConfig.getRealm()); 2067 currentConfig.enterpriseConfig.setPlmn(config.enterpriseConfig.getPlmn()); 2068 } catch (IOException ioe) { 2069 Log.e(TAG, "Failed to create Passpoint config: " + ioe); 2070 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2071 } 2072 } 2073 2074 if (uid != WifiConfiguration.UNKNOWN_UID) { 2075 if (newNetwork) { 2076 currentConfig.creatorUid = uid; 2077 } else { 2078 currentConfig.lastUpdateUid = uid; 2079 } 2080 } 2081 2082 // For debug, record the time the configuration was modified 2083 StringBuilder sb = new StringBuilder(); 2084 sb.append("time="); 2085 Calendar c = Calendar.getInstance(); 2086 c.setTimeInMillis(mClock.currentTimeMillis()); 2087 sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 2088 2089 if (newNetwork) { 2090 currentConfig.creationTime = sb.toString(); 2091 } else { 2092 currentConfig.updateTime = sb.toString(); 2093 } 2094 2095 if (currentConfig.status == WifiConfiguration.Status.ENABLED) { 2096 // Make sure autojoin remain in sync with user modifying the configuration 2097 updateNetworkSelectionStatus(currentConfig.networkId, 2098 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); 2099 } 2100 2101 if (currentConfig.configKey().equals(getLastSelectedConfiguration()) 2102 && currentConfig.ephemeral) { 2103 // Make the config non-ephemeral since the user just explicitly clicked it. 2104 currentConfig.ephemeral = false; 2105 if (DBG) { 2106 log("remove ephemeral status netId=" + Integer.toString(netId) 2107 + " " + currentConfig.configKey()); 2108 } 2109 } 2110 2111 if (sVDBG) log("will read network variables netId=" + Integer.toString(netId)); 2112 2113 readNetworkVariables(currentConfig); 2114 // When we read back the config from wpa_supplicant, some of the default values are set 2115 // which could change the configKey. 2116 if (!savedConfigKey.equals(currentConfig.configKey())) { 2117 if (!mWifiConfigStore.saveNetworkMetadata(currentConfig)) { 2118 loge("Failed to set network metadata. Removing config " + config.networkId); 2119 mWifiConfigStore.removeNetwork(config); 2120 return new NetworkUpdateResult(INVALID_NETWORK_ID); 2121 } 2122 } 2123 2124 boolean passwordChanged = false; 2125 // check passed in config to see if it has more than a password set. 2126 if (!newNetwork && config.preSharedKey != null && !config.preSharedKey.equals("*")) { 2127 passwordChanged = true; 2128 } 2129 2130 if (newNetwork || passwordChanged || wasCredentialChange(originalConfig, currentConfig)) { 2131 currentConfig.getNetworkSelectionStatus().setHasEverConnected(false); 2132 } 2133 2134 // Persist configuration paramaters that are not saved by supplicant. 2135 if (config.lastUpdateName != null) { 2136 currentConfig.lastUpdateName = config.lastUpdateName; 2137 } 2138 if (config.lastUpdateUid != WifiConfiguration.UNKNOWN_UID) { 2139 currentConfig.lastUpdateUid = config.lastUpdateUid; 2140 } 2141 2142 mConfiguredNetworks.put(currentConfig); 2143 2144 NetworkUpdateResult result = 2145 writeIpAndProxyConfigurationsOnChange(currentConfig, config, newNetwork); 2146 result.setIsNewNetwork(newNetwork); 2147 result.setNetworkId(netId); 2148 2149 if (homeSP != null) { 2150 writePasspointConfigs(null, homeSP); 2151 } 2152 2153 saveConfig(); 2154 writeKnownNetworkHistory(); 2155 2156 return result; 2157 } 2158 2159 private boolean wasBitSetUpdated(BitSet originalBitSet, BitSet currentBitSet) { 2160 if (originalBitSet != null && currentBitSet != null) { 2161 // both configs have values set, check if they are different 2162 if (!originalBitSet.equals(currentBitSet)) { 2163 // the BitSets are different 2164 return true; 2165 } 2166 } else if (originalBitSet != null || currentBitSet != null) { 2167 return true; 2168 } 2169 return false; 2170 } 2171 2172 private boolean wasCredentialChange(WifiConfiguration originalConfig, 2173 WifiConfiguration currentConfig) { 2174 // Check if any core WifiConfiguration parameters changed that would impact new connections 2175 if (originalConfig == null) { 2176 return true; 2177 } 2178 2179 if (wasBitSetUpdated(originalConfig.allowedKeyManagement, 2180 currentConfig.allowedKeyManagement)) { 2181 return true; 2182 } 2183 2184 if (wasBitSetUpdated(originalConfig.allowedProtocols, currentConfig.allowedProtocols)) { 2185 return true; 2186 } 2187 2188 if (wasBitSetUpdated(originalConfig.allowedAuthAlgorithms, 2189 currentConfig.allowedAuthAlgorithms)) { 2190 return true; 2191 } 2192 2193 if (wasBitSetUpdated(originalConfig.allowedPairwiseCiphers, 2194 currentConfig.allowedPairwiseCiphers)) { 2195 return true; 2196 } 2197 2198 if (wasBitSetUpdated(originalConfig.allowedGroupCiphers, 2199 currentConfig.allowedGroupCiphers)) { 2200 return true; 2201 } 2202 2203 if (originalConfig.wepKeys != null && currentConfig.wepKeys != null) { 2204 if (originalConfig.wepKeys.length == currentConfig.wepKeys.length) { 2205 for (int i = 0; i < originalConfig.wepKeys.length; i++) { 2206 if (!Objects.equals(originalConfig.wepKeys[i], currentConfig.wepKeys[i])) { 2207 return true; 2208 } 2209 } 2210 } else { 2211 return true; 2212 } 2213 } 2214 2215 if (originalConfig.hiddenSSID != currentConfig.hiddenSSID) { 2216 return true; 2217 } 2218 2219 if (originalConfig.requirePMF != currentConfig.requirePMF) { 2220 return true; 2221 } 2222 2223 if (wasEnterpriseConfigChange(originalConfig.enterpriseConfig, 2224 currentConfig.enterpriseConfig)) { 2225 return true; 2226 } 2227 return false; 2228 } 2229 2230 2231 protected boolean wasEnterpriseConfigChange(WifiEnterpriseConfig originalEnterpriseConfig, 2232 WifiEnterpriseConfig currentEnterpriseConfig) { 2233 if (originalEnterpriseConfig != null && currentEnterpriseConfig != null) { 2234 if (originalEnterpriseConfig.getEapMethod() != currentEnterpriseConfig.getEapMethod()) { 2235 return true; 2236 } 2237 2238 if (originalEnterpriseConfig.getPhase2Method() 2239 != currentEnterpriseConfig.getPhase2Method()) { 2240 return true; 2241 } 2242 2243 X509Certificate[] originalCaCerts = originalEnterpriseConfig.getCaCertificates(); 2244 X509Certificate[] currentCaCerts = currentEnterpriseConfig.getCaCertificates(); 2245 2246 if (originalCaCerts != null && currentCaCerts != null) { 2247 if (originalCaCerts.length == currentCaCerts.length) { 2248 for (int i = 0; i < originalCaCerts.length; i++) { 2249 if (!originalCaCerts[i].equals(currentCaCerts[i])) { 2250 return true; 2251 } 2252 } 2253 } else { 2254 // number of aliases is different, so the configs are different 2255 return true; 2256 } 2257 } else { 2258 // one of the enterprise configs may have aliases 2259 if (originalCaCerts != null || currentCaCerts != null) { 2260 return true; 2261 } 2262 } 2263 } else { 2264 // One of the configs may have an enterpriseConfig 2265 if (originalEnterpriseConfig != null || currentEnterpriseConfig != null) { 2266 return true; 2267 } 2268 } 2269 return false; 2270 } 2271 2272 public WifiConfiguration getWifiConfigForHomeSP(HomeSP homeSP) { 2273 WifiConfiguration config = mConfiguredNetworks.getByFQDNForCurrentUser(homeSP.getFQDN()); 2274 if (config == null) { 2275 Log.e(TAG, "Could not find network for homeSP " + homeSP.getFQDN()); 2276 } 2277 return config; 2278 } 2279 2280 public HomeSP getHomeSPForConfig(WifiConfiguration config) { 2281 WifiConfiguration storedConfig = mConfiguredNetworks.getForCurrentUser(config.networkId); 2282 return storedConfig != null && storedConfig.isPasspoint() 2283 ? mMOManager.getHomeSP(storedConfig.FQDN) 2284 : null; 2285 } 2286 2287 public ScanDetailCache getScanDetailCache(WifiConfiguration config) { 2288 if (config == null) return null; 2289 ScanDetailCache cache = mScanDetailCaches.get(config.networkId); 2290 if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { 2291 cache = new ScanDetailCache(config); 2292 mScanDetailCaches.put(config.networkId, cache); 2293 } 2294 return cache; 2295 } 2296 2297 /** 2298 * This function run thru the Saved WifiConfigurations and check if some should be linked. 2299 * @param config 2300 */ 2301 public void linkConfiguration(WifiConfiguration config) { 2302 if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, 2303 mUserManager.getProfiles(mCurrentUserId))) { 2304 logd("linkConfiguration: Attempting to link config " + config.configKey() 2305 + " that is not visible to the current user."); 2306 return; 2307 } 2308 2309 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 6) { 2310 // Ignore configurations with large number of BSSIDs 2311 return; 2312 } 2313 if (!config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 2314 // Only link WPA_PSK config 2315 return; 2316 } 2317 for (WifiConfiguration link : mConfiguredNetworks.valuesForCurrentUser()) { 2318 boolean doLink = false; 2319 2320 if (link.configKey().equals(config.configKey())) { 2321 continue; 2322 } 2323 2324 if (link.ephemeral) { 2325 continue; 2326 } 2327 2328 // Autojoin will be allowed to dynamically jump from a linked configuration 2329 // to another, hence only link configurations that have equivalent level of security 2330 if (!link.allowedKeyManagement.equals(config.allowedKeyManagement)) { 2331 continue; 2332 } 2333 2334 ScanDetailCache linkedScanDetailCache = getScanDetailCache(link); 2335 if (linkedScanDetailCache != null && linkedScanDetailCache.size() > 6) { 2336 // Ignore configurations with large number of BSSIDs 2337 continue; 2338 } 2339 2340 if (config.defaultGwMacAddress != null && link.defaultGwMacAddress != null) { 2341 // If both default GW are known, link only if they are equal 2342 if (config.defaultGwMacAddress.equals(link.defaultGwMacAddress)) { 2343 if (sVDBG) { 2344 logd("linkConfiguration link due to same gw " + link.SSID 2345 + " and " + config.SSID + " GW " + config.defaultGwMacAddress); 2346 } 2347 doLink = true; 2348 } 2349 } else { 2350 // We do not know BOTH default gateways hence we will try to link 2351 // hoping that WifiConfigurations are indeed behind the same gateway. 2352 // once both WifiConfiguration have been tried and thus once both efault gateways 2353 // are known we will revisit the choice of linking them 2354 if ((getScanDetailCache(config) != null) 2355 && (getScanDetailCache(config).size() <= 6)) { 2356 2357 for (String abssid : getScanDetailCache(config).keySet()) { 2358 for (String bbssid : linkedScanDetailCache.keySet()) { 2359 if (sVVDBG) { 2360 logd("linkConfiguration try to link due to DBDC BSSID match " 2361 + link.SSID + " and " + config.SSID + " bssida " + abssid 2362 + " bssidb " + bbssid); 2363 } 2364 if (abssid.regionMatches(true, 0, bbssid, 0, 16)) { 2365 // If first 16 ascii characters of BSSID matches, 2366 // we assume this is a DBDC 2367 doLink = true; 2368 } 2369 } 2370 } 2371 } 2372 } 2373 2374 if (doLink && mOnlyLinkSameCredentialConfigurations) { 2375 String apsk = 2376 readNetworkVariableFromSupplicantFile(link.configKey(), "psk"); 2377 String bpsk = 2378 readNetworkVariableFromSupplicantFile(config.configKey(), "psk"); 2379 if (apsk == null || bpsk == null 2380 || TextUtils.isEmpty(apsk) || TextUtils.isEmpty(apsk) 2381 || apsk.equals("*") || apsk.equals(DELETED_CONFIG_PSK) 2382 || !apsk.equals(bpsk)) { 2383 doLink = false; 2384 } 2385 } 2386 2387 if (doLink) { 2388 if (sVDBG) { 2389 logd("linkConfiguration: will link " + link.configKey() 2390 + " and " + config.configKey()); 2391 } 2392 if (link.linkedConfigurations == null) { 2393 link.linkedConfigurations = new HashMap<String, Integer>(); 2394 } 2395 if (config.linkedConfigurations == null) { 2396 config.linkedConfigurations = new HashMap<String, Integer>(); 2397 } 2398 if (link.linkedConfigurations.get(config.configKey()) == null) { 2399 link.linkedConfigurations.put(config.configKey(), Integer.valueOf(1)); 2400 } 2401 if (config.linkedConfigurations.get(link.configKey()) == null) { 2402 config.linkedConfigurations.put(link.configKey(), Integer.valueOf(1)); 2403 } 2404 } else { 2405 if (link.linkedConfigurations != null 2406 && (link.linkedConfigurations.get(config.configKey()) != null)) { 2407 if (sVDBG) { 2408 logd("linkConfiguration: un-link " + config.configKey() 2409 + " from " + link.configKey()); 2410 } 2411 link.linkedConfigurations.remove(config.configKey()); 2412 } 2413 if (config.linkedConfigurations != null 2414 && (config.linkedConfigurations.get(link.configKey()) != null)) { 2415 if (sVDBG) { 2416 logd("linkConfiguration: un-link " + link.configKey() 2417 + " from " + config.configKey()); 2418 } 2419 config.linkedConfigurations.remove(link.configKey()); 2420 } 2421 } 2422 } 2423 } 2424 2425 public HashSet<Integer> makeChannelList(WifiConfiguration config, int age) { 2426 if (config == null) { 2427 return null; 2428 } 2429 long now_ms = mClock.currentTimeMillis(); 2430 2431 HashSet<Integer> channels = new HashSet<Integer>(); 2432 2433 //get channels for this configuration, if there are at least 2 BSSIDs 2434 if (getScanDetailCache(config) == null && config.linkedConfigurations == null) { 2435 return null; 2436 } 2437 2438 if (sVDBG) { 2439 StringBuilder dbg = new StringBuilder(); 2440 dbg.append("makeChannelList age=" + Integer.toString(age) 2441 + " for " + config.configKey() 2442 + " max=" + mMaxNumActiveChannelsForPartialScans); 2443 if (getScanDetailCache(config) != null) { 2444 dbg.append(" bssids=" + getScanDetailCache(config).size()); 2445 } 2446 if (config.linkedConfigurations != null) { 2447 dbg.append(" linked=" + config.linkedConfigurations.size()); 2448 } 2449 logd(dbg.toString()); 2450 } 2451 2452 int numChannels = 0; 2453 if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 0) { 2454 for (ScanDetail scanDetail : getScanDetailCache(config).values()) { 2455 ScanResult result = scanDetail.getScanResult(); 2456 //TODO : cout active and passive channels separately 2457 if (numChannels > mMaxNumActiveChannelsForPartialScans.get()) { 2458 break; 2459 } 2460 if (sVDBG) { 2461 boolean test = (now_ms - result.seen) < age; 2462 logd("has " + result.BSSID + " freq=" + Integer.toString(result.frequency) 2463 + " age=" + Long.toString(now_ms - result.seen) + " ?=" + test); 2464 } 2465 if (((now_ms - result.seen) < age)) { 2466 channels.add(result.frequency); 2467 numChannels++; 2468 } 2469 } 2470 } 2471 2472 //get channels for linked configurations 2473 if (config.linkedConfigurations != null) { 2474 for (String key : config.linkedConfigurations.keySet()) { 2475 WifiConfiguration linked = getWifiConfiguration(key); 2476 if (linked == null) { 2477 continue; 2478 } 2479 if (getScanDetailCache(linked) == null) { 2480 continue; 2481 } 2482 for (ScanDetail scanDetail : getScanDetailCache(linked).values()) { 2483 ScanResult result = scanDetail.getScanResult(); 2484 if (sVDBG) { 2485 logd("has link: " + result.BSSID 2486 + " freq=" + Integer.toString(result.frequency) 2487 + " age=" + Long.toString(now_ms - result.seen)); 2488 } 2489 if (numChannels > mMaxNumActiveChannelsForPartialScans.get()) { 2490 break; 2491 } 2492 if (((now_ms - result.seen) < age)) { 2493 channels.add(result.frequency); 2494 numChannels++; 2495 } 2496 } 2497 } 2498 } 2499 return channels; 2500 } 2501 2502 private Map<HomeSP, PasspointMatch> matchPasspointNetworks(ScanDetail scanDetail) { 2503 // Nothing to do if no Hotspot 2.0 provider is configured. 2504 if (!mMOManager.isConfigured()) { 2505 return null; 2506 } 2507 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2508 if (!networkDetail.hasInterworking()) { 2509 return null; 2510 } 2511 updateAnqpCache(scanDetail, networkDetail.getANQPElements()); 2512 2513 Map<HomeSP, PasspointMatch> matches = matchNetwork(scanDetail, true); 2514 Log.d(Utils.hs2LogTag(getClass()), scanDetail.getSSID() 2515 + " pass 1 matches: " + toMatchString(matches)); 2516 return matches; 2517 } 2518 2519 private Map<HomeSP, PasspointMatch> matchNetwork(ScanDetail scanDetail, boolean query) { 2520 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2521 2522 ANQPData anqpData = mAnqpCache.getEntry(networkDetail); 2523 2524 Map<Constants.ANQPElementType, ANQPElement> anqpElements = 2525 anqpData != null ? anqpData.getANQPElements() : null; 2526 2527 boolean queried = !query; 2528 Collection<HomeSP> homeSPs = mMOManager.getLoadedSPs().values(); 2529 Map<HomeSP, PasspointMatch> matches = new HashMap<>(homeSPs.size()); 2530 Log.d(Utils.hs2LogTag(getClass()), "match nwk " + scanDetail.toKeyString() 2531 + ", anqp " + (anqpData != null ? "present" : "missing") 2532 + ", query " + query + ", home sps: " + homeSPs.size()); 2533 2534 for (HomeSP homeSP : homeSPs) { 2535 PasspointMatch match = homeSP.match(networkDetail, anqpElements, mSIMAccessor); 2536 2537 Log.d(Utils.hs2LogTag(getClass()), " -- " 2538 + homeSP.getFQDN() + ": match " + match + ", queried " + queried); 2539 2540 if ((match == PasspointMatch.Incomplete || mEnableOsuQueries) && !queried) { 2541 boolean matchSet = match == PasspointMatch.Incomplete; 2542 boolean osu = mEnableOsuQueries; 2543 List<Constants.ANQPElementType> querySet = 2544 ANQPFactory.buildQueryList(networkDetail, matchSet, osu); 2545 if (networkDetail.queriable(querySet)) { 2546 querySet = mAnqpCache.initiate(networkDetail, querySet); 2547 if (querySet != null) { 2548 mSupplicantBridge.startANQP(scanDetail, querySet); 2549 } 2550 } 2551 queried = true; 2552 } 2553 matches.put(homeSP, match); 2554 } 2555 return matches; 2556 } 2557 2558 public Map<Constants.ANQPElementType, ANQPElement> getANQPData(NetworkDetail network) { 2559 ANQPData data = mAnqpCache.getEntry(network); 2560 return data != null ? data.getANQPElements() : null; 2561 } 2562 2563 public SIMAccessor getSIMAccessor() { 2564 return mSIMAccessor; 2565 } 2566 2567 public void notifyANQPDone(Long bssid, boolean success) { 2568 mSupplicantBridge.notifyANQPDone(bssid, success); 2569 } 2570 2571 public void notifyIconReceived(IconEvent iconEvent) { 2572 Intent intent = new Intent(WifiManager.PASSPOINT_ICON_RECEIVED_ACTION); 2573 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2574 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_BSSID, iconEvent.getBSSID()); 2575 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_FILE, iconEvent.getFileName()); 2576 try { 2577 intent.putExtra(WifiManager.EXTRA_PASSPOINT_ICON_DATA, 2578 mSupplicantBridge.retrieveIcon(iconEvent)); 2579 } catch (IOException ioe) { 2580 /* Simply omit the icon data as a failure indication */ 2581 } 2582 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2583 2584 } 2585 2586 private void updateAnqpCache(ScanDetail scanDetail, 2587 Map<Constants.ANQPElementType, ANQPElement> anqpElements) { 2588 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2589 2590 if (anqpElements == null) { 2591 // Try to pull cached data if query failed. 2592 ANQPData data = mAnqpCache.getEntry(networkDetail); 2593 if (data != null) { 2594 scanDetail.propagateANQPInfo(data.getANQPElements()); 2595 } 2596 return; 2597 } 2598 2599 mAnqpCache.update(networkDetail, anqpElements); 2600 } 2601 2602 private static String toMatchString(Map<HomeSP, PasspointMatch> matches) { 2603 StringBuilder sb = new StringBuilder(); 2604 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 2605 sb.append(' ').append(entry.getKey().getFQDN()).append("->").append(entry.getValue()); 2606 } 2607 return sb.toString(); 2608 } 2609 2610 private void cacheScanResultForPasspointConfigs(ScanDetail scanDetail, 2611 Map<HomeSP, PasspointMatch> matches, 2612 List<WifiConfiguration> associatedWifiConfigurations) { 2613 2614 for (Map.Entry<HomeSP, PasspointMatch> entry : matches.entrySet()) { 2615 PasspointMatch match = entry.getValue(); 2616 if (match == PasspointMatch.HomeProvider || match == PasspointMatch.RoamingProvider) { 2617 WifiConfiguration config = getWifiConfigForHomeSP(entry.getKey()); 2618 if (config != null) { 2619 cacheScanResultForConfig(config, scanDetail, entry.getValue()); 2620 if (associatedWifiConfigurations != null) { 2621 associatedWifiConfigurations.add(config); 2622 } 2623 } else { 2624 Log.w(Utils.hs2LogTag(getClass()), "Failed to find config for '" 2625 + entry.getKey().getFQDN() + "'"); 2626 /* perhaps the configuration was deleted?? */ 2627 } 2628 } 2629 } 2630 } 2631 2632 private void cacheScanResultForConfig( 2633 WifiConfiguration config, ScanDetail scanDetail, PasspointMatch passpointMatch) { 2634 2635 ScanResult scanResult = scanDetail.getScanResult(); 2636 2637 ScanDetailCache scanDetailCache = getScanDetailCache(config); 2638 if (scanDetailCache == null) { 2639 Log.w(TAG, "Could not allocate scan cache for " + config.SSID); 2640 return; 2641 } 2642 2643 // Adding a new BSSID 2644 ScanResult result = scanDetailCache.get(scanResult.BSSID); 2645 if (result != null) { 2646 // transfer the black list status 2647 scanResult.blackListTimestamp = result.blackListTimestamp; 2648 scanResult.numIpConfigFailures = result.numIpConfigFailures; 2649 scanResult.numConnection = result.numConnection; 2650 scanResult.isAutoJoinCandidate = result.isAutoJoinCandidate; 2651 } 2652 2653 if (config.ephemeral) { 2654 // For an ephemeral Wi-Fi config, the ScanResult should be considered 2655 // untrusted. 2656 scanResult.untrusted = true; 2657 } 2658 2659 if (scanDetailCache.size() > (MAX_NUM_SCAN_CACHE_ENTRIES + 64)) { 2660 long now_dbg = 0; 2661 if (sVVDBG) { 2662 logd(" Will trim config " + config.configKey() 2663 + " size " + scanDetailCache.size()); 2664 2665 for (ScanDetail sd : scanDetailCache.values()) { 2666 logd(" " + sd.getBSSIDString() + " " + sd.getSeen()); 2667 } 2668 now_dbg = SystemClock.elapsedRealtimeNanos(); 2669 } 2670 // Trim the scan result cache to MAX_NUM_SCAN_CACHE_ENTRIES entries max 2671 // Since this operation is expensive, make sure it is not performed 2672 // until the cache has grown significantly above the trim treshold 2673 scanDetailCache.trim(MAX_NUM_SCAN_CACHE_ENTRIES); 2674 if (sVVDBG) { 2675 long diff = SystemClock.elapsedRealtimeNanos() - now_dbg; 2676 logd(" Finished trimming config, time(ns) " + diff); 2677 for (ScanDetail sd : scanDetailCache.values()) { 2678 logd(" " + sd.getBSSIDString() + " " + sd.getSeen()); 2679 } 2680 } 2681 } 2682 2683 // Add the scan result to this WifiConfiguration 2684 if (passpointMatch != null) { 2685 scanDetailCache.put(scanDetail, passpointMatch, getHomeSPForConfig(config)); 2686 } else { 2687 scanDetailCache.put(scanDetail); 2688 } 2689 2690 // Since we added a scan result to this configuration, re-attempt linking 2691 linkConfiguration(config); 2692 } 2693 2694 private boolean isEncryptionWep(String encryption) { 2695 return encryption.contains("WEP"); 2696 } 2697 2698 private boolean isEncryptionPsk(String encryption) { 2699 return encryption.contains("PSK"); 2700 } 2701 2702 private boolean isEncryptionEap(String encryption) { 2703 return encryption.contains("EAP"); 2704 } 2705 2706 public boolean isOpenNetwork(String encryption) { 2707 if (!isEncryptionWep(encryption) && !isEncryptionPsk(encryption) 2708 && !isEncryptionEap(encryption)) { 2709 return true; 2710 } 2711 return false; 2712 } 2713 2714 public boolean isOpenNetwork(ScanResult scan) { 2715 String scanResultEncrypt = scan.capabilities; 2716 return isOpenNetwork(scanResultEncrypt); 2717 } 2718 2719 public boolean isOpenNetwork(WifiConfiguration config) { 2720 String configEncrypt = config.configKey(); 2721 return isOpenNetwork(configEncrypt); 2722 } 2723 2724 /** 2725 * Get saved WifiConfiguration associated with a scan detail. 2726 * @param scanDetail input a scanDetail from the scan result 2727 * @return WifiConfiguration WifiConfiguration associated with this scanDetail, null if none 2728 */ 2729 public List<WifiConfiguration> getSavedNetworkFromScanDetail(ScanDetail scanDetail) { 2730 ScanResult scanResult = scanDetail.getScanResult(); 2731 if (scanResult == null) { 2732 return null; 2733 } 2734 List<WifiConfiguration> savedWifiConfigurations = new ArrayList<>(); 2735 String ssid = "\"" + scanResult.SSID + "\""; 2736 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2737 if (config.SSID == null || !config.SSID.equals(ssid)) { 2738 continue; 2739 } 2740 if (DBG) { 2741 localLog("getSavedNetworkFromScanDetail(): try " + config.configKey() 2742 + " SSID=" + config.SSID + " " + scanResult.SSID + " " 2743 + scanResult.capabilities); 2744 } 2745 String scanResultEncrypt = scanResult.capabilities; 2746 String configEncrypt = config.configKey(); 2747 if (isEncryptionWep(scanResultEncrypt) && isEncryptionWep(configEncrypt) 2748 || (isEncryptionPsk(scanResultEncrypt) && isEncryptionPsk(configEncrypt)) 2749 || (isEncryptionEap(scanResultEncrypt) && isEncryptionEap(configEncrypt)) 2750 || (isOpenNetwork(scanResultEncrypt) && isOpenNetwork(configEncrypt))) { 2751 savedWifiConfigurations.add(config); 2752 } 2753 } 2754 return savedWifiConfigurations; 2755 } 2756 2757 /** 2758 * Create a mapping between the scandetail and the Wificonfiguration it associated with 2759 * because Passpoint, one BSSID can associated with multiple SSIDs 2760 * @param scanDetail input a scanDetail from the scan result 2761 * @param isConnectingOrConnected input a boolean to indicate if WiFi is connecting or conncted 2762 * This is used for avoiding ANQP request 2763 * @return List<WifiConfiguration> a list of WifiConfigurations associated to this scanDetail 2764 */ 2765 public List<WifiConfiguration> updateSavedNetworkWithNewScanDetail(ScanDetail scanDetail, 2766 boolean isConnectingOrConnected) { 2767 ScanResult scanResult = scanDetail.getScanResult(); 2768 if (scanResult == null) { 2769 return null; 2770 } 2771 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 2772 List<WifiConfiguration> associatedWifiConfigurations = new ArrayList<>(); 2773 if (networkDetail.hasInterworking() && !isConnectingOrConnected) { 2774 Map<HomeSP, PasspointMatch> matches = matchPasspointNetworks(scanDetail); 2775 if (matches != null) { 2776 cacheScanResultForPasspointConfigs(scanDetail, matches, 2777 associatedWifiConfigurations); 2778 //Do not return here. A BSSID can belong to both passpoint network and non-passpoint 2779 //Network 2780 } 2781 } 2782 List<WifiConfiguration> savedConfigurations = getSavedNetworkFromScanDetail(scanDetail); 2783 if (savedConfigurations != null) { 2784 for (WifiConfiguration config : savedConfigurations) { 2785 cacheScanResultForConfig(config, scanDetail, null); 2786 associatedWifiConfigurations.add(config); 2787 } 2788 } 2789 if (associatedWifiConfigurations.size() == 0) { 2790 return null; 2791 } else { 2792 return associatedWifiConfigurations; 2793 } 2794 } 2795 2796 /** 2797 * Handles the switch to a different foreground user: 2798 * - Removes all ephemeral networks 2799 * - Disables private network configurations belonging to the previous foreground user 2800 * - Enables private network configurations belonging to the new foreground user 2801 * 2802 * @param userId The identifier of the new foreground user, after the switch. 2803 * 2804 * TODO(b/26785736): Terminate background users if the new foreground user has one or more 2805 * private network configurations. 2806 */ 2807 public void handleUserSwitch(int userId) { 2808 mCurrentUserId = userId; 2809 Set<WifiConfiguration> ephemeralConfigs = new HashSet<>(); 2810 for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) { 2811 if (config.ephemeral) { 2812 ephemeralConfigs.add(config); 2813 } 2814 } 2815 if (!ephemeralConfigs.isEmpty()) { 2816 for (WifiConfiguration config : ephemeralConfigs) { 2817 removeConfigWithoutBroadcast(config); 2818 } 2819 saveConfig(); 2820 writeKnownNetworkHistory(); 2821 } 2822 2823 final List<WifiConfiguration> hiddenConfigurations = 2824 mConfiguredNetworks.handleUserSwitch(mCurrentUserId); 2825 for (WifiConfiguration network : hiddenConfigurations) { 2826 disableNetworkNative(network); 2827 } 2828 enableAllNetworks(); 2829 2830 // TODO(b/26785746): This broadcast is unnecessary if either of the following is true: 2831 // * The user switch did not change the list of visible networks 2832 // * The user switch revealed additional networks that were temporarily disabled and got 2833 // re-enabled now (because enableAllNetworks() sent the same broadcast already). 2834 sendConfiguredNetworksChangedBroadcast(); 2835 } 2836 2837 public int getCurrentUserId() { 2838 return mCurrentUserId; 2839 } 2840 2841 public boolean isCurrentUserProfile(int userId) { 2842 if (userId == mCurrentUserId) { 2843 return true; 2844 } 2845 final UserInfo parent = mUserManager.getProfileParent(userId); 2846 return parent != null && parent.id == mCurrentUserId; 2847 } 2848 2849 /* Compare current and new configuration and write to file on change */ 2850 private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange( 2851 WifiConfiguration currentConfig, 2852 WifiConfiguration newConfig, 2853 boolean isNewNetwork) { 2854 boolean ipChanged = false; 2855 boolean proxyChanged = false; 2856 2857 switch (newConfig.getIpAssignment()) { 2858 case STATIC: 2859 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 2860 ipChanged = true; 2861 } else { 2862 ipChanged = !Objects.equals( 2863 currentConfig.getStaticIpConfiguration(), 2864 newConfig.getStaticIpConfiguration()); 2865 } 2866 break; 2867 case DHCP: 2868 if (currentConfig.getIpAssignment() != newConfig.getIpAssignment()) { 2869 ipChanged = true; 2870 } 2871 break; 2872 case UNASSIGNED: 2873 /* Ignore */ 2874 break; 2875 default: 2876 loge("Ignore invalid ip assignment during write"); 2877 break; 2878 } 2879 2880 switch (newConfig.getProxySettings()) { 2881 case STATIC: 2882 case PAC: 2883 ProxyInfo newHttpProxy = newConfig.getHttpProxy(); 2884 ProxyInfo currentHttpProxy = currentConfig.getHttpProxy(); 2885 2886 if (newHttpProxy != null) { 2887 proxyChanged = !newHttpProxy.equals(currentHttpProxy); 2888 } else { 2889 proxyChanged = (currentHttpProxy != null); 2890 } 2891 break; 2892 case NONE: 2893 if (currentConfig.getProxySettings() != newConfig.getProxySettings()) { 2894 proxyChanged = true; 2895 } 2896 break; 2897 case UNASSIGNED: 2898 /* Ignore */ 2899 break; 2900 default: 2901 loge("Ignore invalid proxy configuration during write"); 2902 break; 2903 } 2904 2905 if (ipChanged) { 2906 currentConfig.setIpAssignment(newConfig.getIpAssignment()); 2907 currentConfig.setStaticIpConfiguration(newConfig.getStaticIpConfiguration()); 2908 log("IP config changed SSID = " + currentConfig.SSID); 2909 if (currentConfig.getStaticIpConfiguration() != null) { 2910 log(" static configuration: " 2911 + currentConfig.getStaticIpConfiguration().toString()); 2912 } 2913 } 2914 2915 if (proxyChanged) { 2916 currentConfig.setProxySettings(newConfig.getProxySettings()); 2917 currentConfig.setHttpProxy(newConfig.getHttpProxy()); 2918 log("proxy changed SSID = " + currentConfig.SSID); 2919 if (currentConfig.getHttpProxy() != null) { 2920 log(" proxyProperties: " + currentConfig.getHttpProxy().toString()); 2921 } 2922 } 2923 2924 if (ipChanged || proxyChanged || isNewNetwork) { 2925 if (sVDBG) { 2926 logd("writeIpAndProxyConfigurationsOnChange: " + currentConfig.SSID + " -> " 2927 + newConfig.SSID + " path: " + IP_CONFIG_FILE); 2928 } 2929 writeIpAndProxyConfigurations(); 2930 } 2931 return new NetworkUpdateResult(ipChanged, proxyChanged); 2932 } 2933 2934 /** 2935 * Read the variables from the supplicant daemon that are needed to 2936 * fill in the WifiConfiguration object. 2937 * 2938 * @param config the {@link WifiConfiguration} object to be filled in. 2939 */ 2940 private void readNetworkVariables(WifiConfiguration config) { 2941 mWifiConfigStore.readNetworkVariables(config); 2942 } 2943 2944 /* return the allowed key management based on a scan result */ 2945 2946 public WifiConfiguration wifiConfigurationFromScanResult(ScanResult result) { 2947 2948 WifiConfiguration config = new WifiConfiguration(); 2949 2950 config.SSID = "\"" + result.SSID + "\""; 2951 2952 if (sVDBG) { 2953 logd("WifiConfiguration from scan results " 2954 + config.SSID + " cap " + result.capabilities); 2955 } 2956 2957 if (result.capabilities.contains("PSK") || result.capabilities.contains("EAP") 2958 || result.capabilities.contains("WEP")) { 2959 if (result.capabilities.contains("PSK")) { 2960 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 2961 } 2962 2963 if (result.capabilities.contains("EAP")) { 2964 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 2965 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 2966 } 2967 2968 if (result.capabilities.contains("WEP")) { 2969 config.allowedKeyManagement.set(KeyMgmt.NONE); 2970 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 2971 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 2972 } 2973 } else { 2974 config.allowedKeyManagement.set(KeyMgmt.NONE); 2975 } 2976 2977 return config; 2978 } 2979 2980 public WifiConfiguration wifiConfigurationFromScanResult(ScanDetail scanDetail) { 2981 ScanResult result = scanDetail.getScanResult(); 2982 return wifiConfigurationFromScanResult(result); 2983 } 2984 2985 /* Returns a unique for a given configuration */ 2986 private static int configKey(WifiConfiguration config) { 2987 String key = config.configKey(); 2988 return key.hashCode(); 2989 } 2990 2991 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2992 pw.println("Dump of WifiConfigManager"); 2993 pw.println("mLastPriority " + mLastPriority); 2994 pw.println("Configured networks"); 2995 for (WifiConfiguration conf : getAllConfiguredNetworks()) { 2996 pw.println(conf); 2997 } 2998 pw.println(); 2999 if (mLostConfigsDbg != null && mLostConfigsDbg.size() > 0) { 3000 pw.println("LostConfigs: "); 3001 for (String s : mLostConfigsDbg) { 3002 pw.println(s); 3003 } 3004 } 3005 3006 if (mMOManager.isConfigured()) { 3007 pw.println("Begin dump of ANQP Cache"); 3008 mAnqpCache.dump(pw); 3009 pw.println("End dump of ANQP Cache"); 3010 } 3011 } 3012 3013 public String getConfigFile() { 3014 return IP_CONFIG_FILE; 3015 } 3016 3017 protected void logd(String s) { 3018 Log.d(TAG, s); 3019 } 3020 3021 protected void loge(String s) { 3022 loge(s, false); 3023 } 3024 3025 protected void loge(String s, boolean stack) { 3026 if (stack) { 3027 Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3028 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 3029 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 3030 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 3031 } else { 3032 Log.e(TAG, s); 3033 } 3034 } 3035 3036 private void logKernelTime() { 3037 long kernelTimeMs = System.nanoTime() / (1000 * 1000); 3038 StringBuilder builder = new StringBuilder(); 3039 builder.append("kernel time = ") 3040 .append(kernelTimeMs / 1000) 3041 .append(".") 3042 .append(kernelTimeMs % 1000) 3043 .append("\n"); 3044 localLog(builder.toString()); 3045 } 3046 3047 protected void log(String s) { 3048 Log.d(TAG, s); 3049 } 3050 3051 private void localLog(String s) { 3052 if (mLocalLog != null) { 3053 mLocalLog.log(s); 3054 } 3055 } 3056 3057 private void localLogAndLogcat(String s) { 3058 localLog(s); 3059 Log.d(TAG, s); 3060 } 3061 3062 private void localLogNetwork(String s, int netId) { 3063 if (mLocalLog == null) { 3064 return; 3065 } 3066 3067 WifiConfiguration config; 3068 synchronized (mConfiguredNetworks) { // !!! Useless synchronization 3069 config = mConfiguredNetworks.getForAllUsers(netId); 3070 } 3071 3072 if (config != null) { 3073 mLocalLog.log(s + " " + config.getPrintableSsid() + " " + netId 3074 + " status=" + config.status 3075 + " key=" + config.configKey()); 3076 } else { 3077 mLocalLog.log(s + " " + netId); 3078 } 3079 } 3080 3081 static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) { 3082 String client = config.getClientCertificateAlias(); 3083 if (!TextUtils.isEmpty(client)) { 3084 // a valid client certificate is configured 3085 3086 // BUGBUG: keyStore.get() never returns certBytes; because it is not 3087 // taking WIFI_UID as a parameter. It always looks for certificate 3088 // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that 3089 // all certificates need software keystore until we get the get() API 3090 // fixed. 3091 3092 return true; 3093 } 3094 3095 /* 3096 try { 3097 3098 if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials 3099 .USER_CERTIFICATE + client); 3100 3101 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 3102 if (factory == null) { 3103 Slog.e(TAG, "Error getting certificate factory"); 3104 return; 3105 } 3106 3107 byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); 3108 if (certBytes != null) { 3109 Certificate cert = (X509Certificate) factory.generateCertificate( 3110 new ByteArrayInputStream(certBytes)); 3111 3112 if (cert != null) { 3113 mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); 3114 3115 if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials 3116 .USER_CERTIFICATE + client); 3117 if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : 3118 "does not need" ) + " software key store"); 3119 } else { 3120 Slog.d(TAG, "could not generate certificate"); 3121 } 3122 } else { 3123 Slog.e(TAG, "Could not load client certificate " + Credentials 3124 .USER_CERTIFICATE + client); 3125 mNeedsSoftwareKeystore = true; 3126 } 3127 3128 } catch(CertificateException e) { 3129 Slog.e(TAG, "Could not read certificates"); 3130 mCaCert = null; 3131 mClientCertificate = null; 3132 } 3133 */ 3134 3135 return false; 3136 } 3137 3138 /** 3139 * Resets all sim networks from the network list. 3140 */ 3141 public void resetSimNetworks() { 3142 mWifiConfigStore.resetSimNetworks(mConfiguredNetworks.valuesForCurrentUser()); 3143 } 3144 3145 boolean isNetworkConfigured(WifiConfiguration config) { 3146 // Check if either we have a network Id or a WifiConfiguration 3147 // matching the one we are trying to add. 3148 3149 if (config.networkId != INVALID_NETWORK_ID) { 3150 return (mConfiguredNetworks.getForCurrentUser(config.networkId) != null); 3151 } 3152 3153 return (mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()) != null); 3154 } 3155 3156 /** 3157 * Checks if uid has access to modify the configuration corresponding to networkId. 3158 * 3159 * The conditions checked are, in descending priority order: 3160 * - Disallow modification if the the configuration is not visible to the uid. 3161 * - Allow modification if the uid represents the Device Owner app. 3162 * - Allow modification if both of the following are true: 3163 * - The uid represents the configuration's creator or an app holding OVERRIDE_CONFIG_WIFI. 3164 * - The modification is only for administrative annotation (e.g. when connecting) or the 3165 * configuration is not lockdown eligible (which currently means that it was not last 3166 * updated by the DO). 3167 * - Allow modification if configuration lockdown is explicitly disabled and the uid represents 3168 * an app holding OVERRIDE_CONFIG_WIFI. 3169 * - In all other cases, disallow modification. 3170 */ 3171 boolean canModifyNetwork(int uid, int networkId, boolean onlyAnnotate) { 3172 WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(networkId); 3173 3174 if (config == null) { 3175 loge("canModifyNetwork: cannot find config networkId " + networkId); 3176 return false; 3177 } 3178 3179 final DevicePolicyManagerInternal dpmi = LocalServices.getService( 3180 DevicePolicyManagerInternal.class); 3181 3182 final boolean isUidDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(uid, 3183 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 3184 3185 if (isUidDeviceOwner) { 3186 return true; 3187 } 3188 3189 final boolean isCreator = (config.creatorUid == uid); 3190 3191 if (onlyAnnotate) { 3192 return isCreator || checkConfigOverridePermission(uid); 3193 } 3194 3195 // Check if device has DPM capability. If it has and dpmi is still null, then we 3196 // treat this case with suspicion and bail out. 3197 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) 3198 && dpmi == null) { 3199 return false; 3200 } 3201 3202 // WiFi config lockdown related logic. At this point we know uid NOT to be a Device Owner. 3203 3204 final boolean isConfigEligibleForLockdown = dpmi != null && dpmi.isActiveAdminWithPolicy( 3205 config.creatorUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 3206 if (!isConfigEligibleForLockdown) { 3207 return isCreator || checkConfigOverridePermission(uid); 3208 } 3209 3210 final ContentResolver resolver = mContext.getContentResolver(); 3211 final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver, 3212 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; 3213 return !isLockdownFeatureEnabled && checkConfigOverridePermission(uid); 3214 } 3215 3216 /** 3217 * Saves the network and set the candidate. 3218 * @param config WifiConfiguration to save. 3219 * @param scanResult ScanResult to be used as the network selection candidate. 3220 * @return WifiConfiguration that was saved and with the status updated. 3221 */ 3222 public WifiConfiguration saveNetworkAndSetCandidate(WifiConfiguration config, 3223 ScanResult scanResult) { 3224 saveNetwork(config, WifiConfiguration.UNKNOWN_UID); 3225 3226 config.getNetworkSelectionStatus().setCandidate(scanResult); 3227 return config; 3228 } 3229 3230 3231 /** 3232 * Get the Scan Result candidate. 3233 * @param config WifiConfiguration to get status for. 3234 * @return scanResult which is the selection candidate. 3235 */ 3236 public ScanResult getScanResultCandidate(WifiConfiguration config) { 3237 if (config == null) { 3238 return null; 3239 } 3240 return config.getNetworkSelectionStatus().getCandidate(); 3241 } 3242 3243 /** 3244 * Checks if uid has access to modify config. 3245 */ 3246 boolean canModifyNetwork(int uid, WifiConfiguration config, boolean onlyAnnotate) { 3247 if (config == null) { 3248 loge("canModifyNetowrk recieved null configuration"); 3249 return false; 3250 } 3251 3252 // Resolve the correct network id. 3253 int netid; 3254 if (config.networkId != INVALID_NETWORK_ID) { 3255 netid = config.networkId; 3256 } else { 3257 WifiConfiguration test = 3258 mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()); 3259 if (test == null) { 3260 return false; 3261 } else { 3262 netid = test.networkId; 3263 } 3264 } 3265 3266 return canModifyNetwork(uid, netid, onlyAnnotate); 3267 } 3268 3269 boolean checkConfigOverridePermission(int uid) { 3270 try { 3271 return (mFacade.checkUidPermission( 3272 android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid) 3273 == PackageManager.PERMISSION_GRANTED); 3274 } catch (RemoteException e) { 3275 return false; 3276 } 3277 } 3278 3279 int getMaxDhcpRetries() { 3280 return mFacade.getIntegerSetting(mContext, 3281 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 3282 DEFAULT_MAX_DHCP_RETRIES); 3283 } 3284 3285 void clearBssidBlacklist() { 3286 mWifiConfigStore.clearBssidBlacklist(); 3287 } 3288 3289 void blackListBssid(String bssid) { 3290 mWifiConfigStore.blackListBssid(bssid); 3291 } 3292 3293 public boolean isBssidBlacklisted(String bssid) { 3294 return mWifiConfigStore.isBssidBlacklisted(bssid); 3295 } 3296 3297 public boolean getEnableAutoJoinWhenAssociated() { 3298 return mEnableAutoJoinWhenAssociated.get(); 3299 } 3300 3301 public void setEnableAutoJoinWhenAssociated(boolean enabled) { 3302 mEnableAutoJoinWhenAssociated.set(enabled); 3303 } 3304 3305 public void setActiveScanDetail(ScanDetail activeScanDetail) { 3306 synchronized (mActiveScanDetailLock) { 3307 mActiveScanDetail = activeScanDetail; 3308 } 3309 } 3310 3311 /** 3312 * Check if the provided ephemeral network was deleted by the user or not. 3313 * @param ssid caller must ensure that the SSID passed thru this API match 3314 * the WifiConfiguration.SSID rules, and thus be surrounded by quotes. 3315 * @return true if network was deleted, false otherwise. 3316 */ 3317 public boolean wasEphemeralNetworkDeleted(String ssid) { 3318 return mDeletedEphemeralSSIDs.contains(ssid); 3319 } 3320 3321 /** 3322 * Check if the User has enabled connecting to carrier networks from Settings. 3323 * @return true if enabled in Settings, false otherwise. 3324 */ 3325 public boolean getIsCarrierNetworkEnabledByUser() { 3326 return android.provider.Settings.Global.getInt(mContext.getContentResolver(), 3327 Settings.Global.WIFI_CONNECT_CARRIER_NETWORKS, 0) == 1; 3328 } 3329} 3330