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