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