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