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