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