WifiStateMachine.java revision f9f7c4ceed78d380a78c2d79a2af3d0cf473e065
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.WifiManager.WIFI_AP_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 24import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 25import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 26import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 27import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 28/** 29 * TODO: 30 * Deprecate WIFI_STATE_UNKNOWN 31 */ 32import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 33 34import android.app.ActivityManager; 35import android.app.AlarmManager; 36import android.app.AlertDialog; 37import android.app.PendingIntent; 38import android.app.backup.IBackupManager; 39import android.bluetooth.BluetoothAdapter; 40import android.content.BroadcastReceiver; 41import android.content.Context; 42import android.content.DialogInterface; 43import android.content.Intent; 44import android.content.IntentFilter; 45import android.content.pm.ApplicationInfo; 46import android.content.pm.PackageManager; 47import android.content.pm.PackageManager.NameNotFoundException; 48import android.database.ContentObserver; 49import android.net.ConnectivityManager; 50import android.net.DhcpResults; 51import android.net.BaseDhcpStateMachine; 52import android.net.DhcpStateMachine; 53import android.net.dhcp.DhcpClient; 54import android.net.InterfaceConfiguration; 55import android.net.LinkAddress; 56import android.net.LinkProperties; 57import android.net.NetworkAgent; 58import android.net.NetworkCapabilities; 59import android.net.NetworkFactory; 60import android.net.NetworkInfo; 61import android.net.NetworkInfo.DetailedState; 62import android.net.NetworkRequest; 63import android.net.NetworkUtils; 64import android.net.RouteInfo; 65import android.net.StaticIpConfiguration; 66import android.net.TrafficStats; 67import android.net.wifi.BatchedScanResult; 68import android.net.wifi.BatchedScanSettings; 69import android.net.wifi.RssiPacketCountInfo; 70import android.net.wifi.ScanResult; 71import android.net.wifi.ScanSettings; 72import android.net.wifi.SupplicantState; 73import android.net.wifi.WifiChannel; 74import android.net.wifi.WifiConfiguration; 75import android.net.wifi.WifiConnectionStatistics; 76import android.net.wifi.WifiEnterpriseConfig; 77import android.net.wifi.WifiInfo; 78import android.net.wifi.WifiLinkLayerStats; 79import android.net.wifi.WifiManager; 80import android.net.wifi.WifiSsid; 81import android.net.wifi.WpsInfo; 82import android.net.wifi.WpsResult; 83import android.net.wifi.WpsResult.Status; 84import android.net.wifi.p2p.IWifiP2pManager; 85import android.net.wifi.passpoint.IWifiPasspointManager; 86import android.os.BatteryStats; 87import android.os.Bundle; 88import android.os.IBinder; 89import android.os.INetworkManagementService; 90import android.os.Looper; 91import android.os.Message; 92import android.os.Messenger; 93import android.os.PowerManager; 94import android.os.Process; 95import android.os.RemoteException; 96import android.os.ServiceManager; 97import android.os.SystemClock; 98import android.os.SystemProperties; 99import android.os.UserHandle; 100import android.os.WorkSource; 101import android.provider.Settings; 102import android.telephony.TelephonyManager; 103import android.text.TextUtils; 104import android.util.Log; 105import android.util.LruCache; 106import android.view.WindowManager; 107 108import com.android.internal.R; 109import com.android.internal.app.IBatteryStats; 110import com.android.internal.util.AsyncChannel; 111import com.android.internal.util.Protocol; 112import com.android.internal.util.State; 113import com.android.internal.util.StateMachine; 114import com.android.server.net.NetlinkTracker; 115import com.android.server.wifi.hotspot2.NetworkDetail; 116import com.android.server.wifi.hotspot2.SupplicantBridge; 117import com.android.server.wifi.p2p.WifiP2pServiceImpl; 118 119import java.io.BufferedReader; 120import java.io.FileDescriptor; 121import java.io.FileNotFoundException; 122import java.io.FileReader; 123import java.io.IOException; 124import java.io.PrintWriter; 125import java.net.Inet4Address; 126import java.net.InetAddress; 127import java.net.SocketException; 128import java.util.ArrayList; 129import java.util.Calendar; 130import java.util.HashSet; 131import java.util.LinkedList; 132import java.util.List; 133import java.util.Locale; 134import java.util.Queue; 135import java.util.Random; 136import java.util.concurrent.atomic.AtomicBoolean; 137import java.util.concurrent.atomic.AtomicInteger; 138import java.util.regex.Matcher; 139import java.util.regex.Pattern; 140 141/** 142 * Track the state of Wifi connectivity. All event handling is done here, 143 * and all changes in connectivity state are initiated here. 144 * 145 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 146 * In the current implementation, we support concurrent wifi p2p and wifi operation. 147 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 148 * handles p2p operation. 149 * 150 * @hide 151 */ 152public class WifiStateMachine extends StateMachine { 153 154 private static final String NETWORKTYPE = "WIFI"; 155 private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT"; 156 private static boolean DBG = false; 157 private static boolean VDBG = false; 158 private static boolean VVDBG = false; 159 private static boolean mLogMessages = false; 160 private static final String TAG = "WifiStateMachine"; 161 162 private static final int ONE_HOUR_MILLI = 1000 * 60 * 60; 163 164 private static final String GOOGLE_OUI = "DA-A1-19"; 165 166 /* temporary debug flag - best network selection development */ 167 private static boolean PDBG = false; 168 169 /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting 170 * the corresponding BSSID. 171 */ 172 private boolean didBlackListBSSID = false; 173 174 /** 175 * Log with error attribute 176 * 177 * @param s is string log 178 */ 179 protected void loge(String s) { 180 Log.e(getName(), s); 181 } 182 protected void logd(String s) { 183 Log.d(getName(), s); 184 } 185 protected void log(String s) {; 186 Log.e(getName(), s); 187 } 188 189 private WifiMonitor mWifiMonitor; 190 private WifiNative mWifiNative; 191 private WifiConfigStore mWifiConfigStore; 192 private WifiAutoJoinController mWifiAutoJoinController; 193 private INetworkManagementService mNwService; 194 private ConnectivityManager mCm; 195 private WifiLogger mWifiLogger; 196 197 private final boolean mP2pSupported; 198 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 199 private boolean mTemporarilyDisconnectWifi = false; 200 private final String mPrimaryDeviceType; 201 202 /* Scan results handling */ 203 private List<ScanDetail> mScanResults = new ArrayList<>(); 204 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 205 private static final int SCAN_RESULT_CACHE_SIZE = 160; 206 private final LruCache<NetworkDetail, ScanDetail> mScanResultCache; 207 // For debug, number of known scan results that were found as part of last scan result event, 208 // as well the number of scans results returned by the supplicant with that message 209 private int mNumScanResultsKnown; 210 private int mNumScanResultsReturned; 211 212 /* Batch scan results */ 213 private final List<BatchedScanResult> mBatchedScanResults = 214 new ArrayList<BatchedScanResult>(); 215 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 216 private int mExpectedBatchedScans = 0; 217 private long mBatchedScanMinPollTime = 0; 218 219 private boolean mScreenOn = false; 220 221 /* Chipset supports background scan */ 222 private final boolean mBackgroundScanSupported; 223 224 private String mInterfaceName; 225 /* Tethering interface could be separate from wlan interface */ 226 private String mTetherInterfaceName; 227 228 private int mLastSignalLevel = -1; 229 private String mLastBssid; 230 private int mLastNetworkId; // The network Id we successfully joined 231 private boolean linkDebouncing = false; 232 233 // Testing various network disconnect cases by sending lots of spurious 234 // disconnect to supplicant 235 private boolean testNetworkDisconnect = false; 236 237 private boolean mEnableRssiPolling = false; 238 private boolean mEnableBackgroundScan = false; 239 private int mRssiPollToken = 0; 240 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 241 * In CONNECT_MODE, the STA can scan and connect to an access point 242 * In SCAN_ONLY_MODE, the STA can only scan for access points 243 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 244 */ 245 private int mOperationalMode = CONNECT_MODE; 246 private boolean mIsScanOngoing = false; 247 private boolean mIsFullScanOngoing = false; 248 private boolean mSendScanResultsBroadcast = false; 249 250 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 251 private WorkSource mScanWorkSource = null; 252 private static final int UNKNOWN_SCAN_SOURCE = -1; 253 private static final int SCAN_ALARM_SOURCE = -2; 254 private static final int ADD_OR_UPDATE_SOURCE = -3; 255 private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4; 256 private static final int ENABLE_WIFI = -5; 257 public static final int DFS_RESTRICTED_SCAN_REQUEST = -6; 258 259 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 260 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 261 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 262 private static final String SCAN_REQUEST_TIME = "scan_request_time"; 263 264 private static final String BATCHED_SETTING = "batched_settings"; 265 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 266 267 /* Tracks if state machine has received any screen state change broadcast yet. 268 * We can miss one of these at boot. 269 */ 270 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 271 272 private boolean mBluetoothConnectionActive = false; 273 274 private PowerManager.WakeLock mSuspendWakeLock; 275 276 /** 277 * Interval in milliseconds between polling for RSSI 278 * and linkspeed information 279 */ 280 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 281 282 /** 283 * Interval in milliseconds between receiving a disconnect event 284 * while connected to a good AP, and handling the disconnect proper 285 */ 286 private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000; 287 288 /** 289 * Delay between supplicant restarts upon failure to establish connection 290 */ 291 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 292 293 /** 294 * Number of times we attempt to restart supplicant 295 */ 296 private static final int SUPPLICANT_RESTART_TRIES = 5; 297 298 private int mSupplicantRestartCount = 0; 299 /* Tracks sequence number on stop failure message */ 300 private int mSupplicantStopFailureToken = 0; 301 302 /** 303 * Tether state change notification time out 304 */ 305 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 306 307 /* Tracks sequence number on a tether notification time out */ 308 private int mTetherToken = 0; 309 310 /** 311 * Driver start time out. 312 */ 313 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 314 315 /* Tracks sequence number on a driver time out */ 316 private int mDriverStartToken = 0; 317 318 /** 319 * The link properties of the wifi interface. 320 * Do not modify this directly; use updateLinkProperties instead. 321 */ 322 private LinkProperties mLinkProperties; 323 324 /* Tracks sequence number on a periodic scan message */ 325 private int mPeriodicScanToken = 0; 326 327 // Wakelock held during wifi start/stop and driver load/unload 328 private PowerManager.WakeLock mWakeLock; 329 330 private Context mContext; 331 332 private final Object mDhcpResultsLock = new Object(); 333 private DhcpResults mDhcpResults; 334 private WifiInfo mWifiInfo; 335 private NetworkInfo mNetworkInfo; 336 private NetworkCapabilities mNetworkCapabilities; 337 private SupplicantStateTracker mSupplicantStateTracker; 338 private BaseDhcpStateMachine mDhcpStateMachine; 339 private boolean mDhcpActive = false; 340 341 private int mWifiLinkLayerStatsSupported = 4; // Temporary disable 342 343 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 344 345 // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress 346 private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 347 348 // Roaming failure count 349 private int mRoamFailCount = 0; 350 351 // This is the BSSID we are trying to associate to, it can be set to "any" 352 // if we havent selected a BSSID for joining. 353 // if we havent selected a BSSID for joining. 354 // The BSSID we are associated to is found in mWifiInfo 355 private String mTargetRoamBSSID = "any"; 356 357 private long mLastDriverRoamAttempt = 0; 358 359 private WifiConfiguration targetWificonfiguration = null; 360 361 // Used as debug to indicate which configuration last was saved 362 private WifiConfiguration lastSavedConfigurationAttempt = null; 363 364 // Used as debug to indicate which configuration last was removed 365 private WifiConfiguration lastForgetConfigurationAttempt = null; 366 367 //Random used by softAP channel Selection 368 private static Random mRandom = new Random(Calendar.getInstance().getTimeInMillis()); 369 boolean isRoaming() { 370 return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING 371 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING; 372 } 373 374 public void autoRoamSetBSSID(int netId, String bssid) { 375 autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid); 376 } 377 378 public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) { 379 boolean ret = true; 380 if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any"; 381 if (bssid == null) bssid = "any"; 382 if (config == null) return false; // Nothing to do 383 384 if (mTargetRoamBSSID != null && bssid == mTargetRoamBSSID && bssid == config.BSSID) { 385 return false; // We didnt change anything 386 } 387 if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) { 388 // Changing to ANY 389 if (!mWifiConfigStore.roamOnAny) { 390 ret = false; // Nothing to do 391 } 392 } 393 if (VDBG) { 394 loge("autoRoamSetBSSID " + bssid 395 + " key=" + config.configKey()); 396 } 397 config.autoJoinBSSID = bssid; 398 mTargetRoamBSSID = bssid; 399 mWifiConfigStore.saveWifiConfigBSSID(config); 400 return ret; 401 } 402 403 /** 404 * Save the UID correctly depending on if this is a new or existing network. 405 * @return true if operation is authorized, false otherwise 406 */ 407 boolean recordUidIfAuthorized(WifiConfiguration config, int uid) { 408 if (!mWifiConfigStore.isNetworkConfigured(config)) { 409 config.creatorUid = uid; 410 config.creatorName = mContext.getPackageManager().getNameForUid(uid); 411 } else if (!mWifiConfigStore.canModifyNetwork(uid, config)) { 412 return false; 413 } 414 415 config.lastUpdateUid = uid; 416 config.lastUpdateName = mContext.getPackageManager().getNameForUid(uid); 417 418 return true; 419 420 } 421 422 /** 423 * Checks to see if user has specified if the apps configuration is connectable. 424 * If the user hasn't specified we query the user and return true. 425 * 426 * @param message The message to be deffered 427 * @param netId Network id of the configuration to check against 428 * @param allowOverride If true we won't defer to the user if the uid of the message holds the 429 * CONFIG_OVERRIDE_PERMISSION 430 * @return True if we are waiting for user feedback or netId is invalid. False otherwise. 431 */ 432 boolean deferForUserInput(Message message, int netId, boolean allowOverride){ 433 final WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(netId); 434 435 // We can only evaluate saved configurations. 436 if (config == null) { 437 loge("deferForUserInput: configuration for netId="+netId+" not stored"); 438 return true; 439 } 440 441 // User initiated actions and system networks don't need to be queried 442 if ((allowOverride && mWifiConfigStore.checkConfigOverridePermission(message.sendingUid)) 443 || (mWifiConfigStore.checkConfigOverridePermission(config.lastUpdateUid))) { 444 config.userApproved = WifiConfiguration.USER_APPROVED; 445 446 if (config.linkedConfigurations != null) { 447 for (String key : config.linkedConfigurations.keySet()) { 448 WifiConfiguration linked = 449 mWifiConfigStore.getWifiConfiguration(key); 450 linked.userApproved = config.userApproved; 451 } 452 } 453 454 return false; 455 } 456 457 switch (config.userApproved) { 458 case WifiConfiguration.USER_APPROVED: 459 case WifiConfiguration.USER_BANNED: 460 return false; 461 case WifiConfiguration.USER_PENDING: 462 default: // USER_UNSPECIFIED 463 /* the intention was to ask user here; but a dialog box is * 464 * too invasive; so we are going to allow connection for now */ 465 config.userApproved = WifiConfiguration.USER_APPROVED; 466 return false; 467 } 468 } 469 470 /** 471 * Subset of link properties coming from netlink. 472 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 473 * and domains obtained from router advertisements (RFC 6106). 474 */ 475 private NetlinkTracker mNetlinkTracker; 476 477 private AlarmManager mAlarmManager; 478 private PendingIntent mScanIntent; 479 private PendingIntent mDriverStopIntent; 480 private PendingIntent mBatchedScanIntervalIntent; 481 482 /* Tracks current frequency mode */ 483 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 484 485 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 486 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 487 488 // Channel for sending replies. 489 private AsyncChannel mReplyChannel = new AsyncChannel(); 490 491 private WifiP2pServiceImpl mWifiP2pServiceImpl; 492 493 // Used to initiate a connection with WifiP2pService 494 private AsyncChannel mWifiP2pChannel; 495 private AsyncChannel mWifiApConfigChannel; 496 497 private int mConnectionRequests = 0; 498 private WifiNetworkFactory mNetworkFactory; 499 private UntrustedWifiNetworkFactory mUntrustedNetworkFactory; 500 private WifiNetworkAgent mNetworkAgent; 501 502 // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi 503 // We should really persist that into the networkHistory.txt file, and read it back when 504 // WifiStateMachine starts up 505 private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics(); 506 507 // Used to filter out requests we couldn't possibly satisfy. 508 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 509 510 /* The base for wifi message types */ 511 static final int BASE = Protocol.BASE_WIFI; 512 /* Start the supplicant */ 513 static final int CMD_START_SUPPLICANT = BASE + 11; 514 /* Stop the supplicant */ 515 static final int CMD_STOP_SUPPLICANT = BASE + 12; 516 /* Start the driver */ 517 static final int CMD_START_DRIVER = BASE + 13; 518 /* Stop the driver */ 519 static final int CMD_STOP_DRIVER = BASE + 14; 520 /* Indicates Static IP succeeded */ 521 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 522 /* Indicates Static IP failed */ 523 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 524 /* Indicates supplicant stop failed */ 525 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 526 /* Delayed stop to avoid shutting down driver too quick*/ 527 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 528 /* A delayed message sent to start driver when it fail to come up */ 529 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 530 531 /* Start the soft access point */ 532 static final int CMD_START_AP = BASE + 21; 533 /* Indicates soft ap start succeeded */ 534 static final int CMD_START_AP_SUCCESS = BASE + 22; 535 /* Indicates soft ap start failed */ 536 static final int CMD_START_AP_FAILURE = BASE + 23; 537 /* Stop the soft access point */ 538 static final int CMD_STOP_AP = BASE + 24; 539 /* Set the soft access point configuration */ 540 static final int CMD_SET_AP_CONFIG = BASE + 25; 541 /* Soft access point configuration set completed */ 542 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 543 /* Request the soft access point configuration */ 544 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 545 /* Response to access point configuration request */ 546 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 547 /* Invoked when getting a tether state change notification */ 548 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 549 /* A delayed message sent to indicate tether state change failed to arrive */ 550 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 551 552 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 553 554 /* Supplicant commands */ 555 /* Is supplicant alive ? */ 556 static final int CMD_PING_SUPPLICANT = BASE + 51; 557 /* Add/update a network configuration */ 558 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 559 /* Delete a network */ 560 static final int CMD_REMOVE_NETWORK = BASE + 53; 561 /* Enable a network. The device will attempt a connection to the given network. */ 562 static final int CMD_ENABLE_NETWORK = BASE + 54; 563 /* Enable all networks */ 564 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 565 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 566 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 567 /* Clear the blacklist network list */ 568 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 569 /* Save configuration */ 570 static final int CMD_SAVE_CONFIG = BASE + 58; 571 /* Get configured networks */ 572 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 573 /* Get available frequencies */ 574 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 575 /* Get adaptors */ 576 static final int CMD_GET_SUPPORTED_FEATURES = BASE + 61; 577 /* Get configured networks with real preSharedKey */ 578 static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62; 579 /* Get Link Layer Stats thru HAL */ 580 static final int CMD_GET_LINK_LAYER_STATS = BASE + 63; 581 /* Supplicant commands after driver start*/ 582 /* Initiate a scan */ 583 static final int CMD_START_SCAN = BASE + 71; 584 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 585 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 586 /* Disconnect from a network */ 587 static final int CMD_DISCONNECT = BASE + 73; 588 /* Reconnect to a network */ 589 static final int CMD_RECONNECT = BASE + 74; 590 /* Reassociate to a network */ 591 static final int CMD_REASSOCIATE = BASE + 75; 592 /* Get Connection Statistis */ 593 static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76; 594 595 /* Controls suspend mode optimizations 596 * 597 * When high perf mode is enabled, suspend mode optimizations are disabled 598 * 599 * When high perf mode is disabled, suspend mode optimizations are enabled 600 * 601 * Suspend mode optimizations include: 602 * - packet filtering 603 * - turn off roaming 604 * - DTIM wake up settings 605 */ 606 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 607 /* Set the country code */ 608 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 609 /* Enables RSSI poll */ 610 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 611 /* RSSI poll */ 612 static final int CMD_RSSI_POLL = BASE + 83; 613 /* Set up packet filtering */ 614 static final int CMD_START_PACKET_FILTERING = BASE + 84; 615 /* Clear packet filter */ 616 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 617 /* Enable suspend mode optimizations in the driver */ 618 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 619 /* Delayed NETWORK_DISCONNECT */ 620 static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87; 621 /* When there are no saved networks, we do a periodic scan to notify user of 622 * an open network */ 623 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 624 /* Test network Disconnection NETWORK_DISCONNECT */ 625 static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89; 626 private int testNetworkDisconnectCounter = 0; 627 628 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 629 static final int MULTICAST_V6 = 1; 630 static final int MULTICAST_V4 = 0; 631 632 /* Set the frequency band */ 633 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 634 /* Enable TDLS on a specific MAC address */ 635 static final int CMD_ENABLE_TDLS = BASE + 92; 636 /* DHCP/IP configuration watchdog */ 637 static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93; 638 /* Remove a packages associated configrations */ 639 static final int CMD_REMOVE_APP_CONFIGURATIONS = BASE + 97; 640 /* Remove a packages associated configrations */ 641 static final int CMD_REMOVE_USER_CONFIGURATIONS = BASE + 149; 642 643 /** 644 * Make this timer 40 seconds, which is about the normal DHCP timeout. 645 * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress 646 * for more than 30 seconds. 647 */ 648 static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 40000; 649 650 int obtainingIpWatchdogCount = 0; 651 652 /* Commands from/to the SupplicantStateTracker */ 653 /* Reset the supplicant state tracker */ 654 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 655 656 657 /** 658 * Watchdog for protecting against b/16823537 659 * Leave time for 4-ways handshake to succeed 660 */ 661 static final int ROAM_GUARD_TIMER_MSEC = 15000; 662 663 int roamWatchdogCount = 0; 664 /* Roam state watchdog */ 665 static final int CMD_ROAM_WATCHDOG_TIMER = BASE + 94; 666 /* Screen change intent handling */ 667 static final int CMD_SCREEN_STATE_CHANGED = BASE + 95; 668 669 int disconnectingWatchdogCount = 0; 670 static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000; 671 672 /* Disconnecting state watchdog */ 673 static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96; 674 675 /* Disable an ephemeral network */ 676 static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98; 677 678 /* P2p commands */ 679 /* We are ok with no response here since we wont do much with it anyway */ 680 public static final int CMD_ENABLE_P2P = BASE + 131; 681 /* In order to shut down supplicant cleanly, we wait till p2p has 682 * been disabled */ 683 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 684 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 685 686 public static final int CMD_BOOT_COMPLETED = BASE + 134; 687 688 /* change the batch scan settings. 689 * arg1 = responsible UID 690 * arg2 = csph (channel scans per hour) 691 * obj = bundle with the new settings and the optional worksource 692 */ 693 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 694 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 695 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 696 697 /* We now have a valid IP configuration. */ 698 static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138; 699 /* We no longer have a valid IP configuration. */ 700 static final int CMD_IP_CONFIGURATION_LOST = BASE + 139; 701 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 702 static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140; 703 704 /* Supplicant is trying to associate to a given BSSID */ 705 static final int CMD_TARGET_BSSID = BASE + 141; 706 707 /* Reload all networks and reconnect */ 708 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 709 710 static final int CMD_AUTO_CONNECT = BASE + 143; 711 712 static final int network_status_unwanted_disconnect = 0; 713 static final int network_status_unwanted_disable_autojoin = 1; 714 715 static final int CMD_UNWANTED_NETWORK = BASE + 144; 716 717 static final int CMD_AUTO_ROAM = BASE + 145; 718 719 static final int CMD_AUTO_SAVE_NETWORK = BASE + 146; 720 721 static final int CMD_ASSOCIATED_BSSID = BASE + 147; 722 723 static final int CMD_NETWORK_STATUS = BASE + 148; 724 725 /* Wifi state machine modes of operation */ 726 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 727 public static final int CONNECT_MODE = 1; 728 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 729 public static final int SCAN_ONLY_MODE = 2; 730 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 731 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 732 733 private static final int SUCCESS = 1; 734 private static final int FAILURE = -1; 735 736 /* Tracks if suspend optimizations need to be disabled by DHCP, 737 * screen or due to high perf mode. 738 * When any of them needs to disable it, we keep the suspend optimizations 739 * disabled 740 */ 741 private int mSuspendOptNeedsDisabled = 0; 742 743 private static final int SUSPEND_DUE_TO_DHCP = 1; 744 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 745 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 746 747 /* Tracks if user has enabled suspend optimizations through settings */ 748 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 749 750 /** 751 * Default framework scan interval in milliseconds. This is used in the scenario in which 752 * wifi chipset does not support background scanning to set up a 753 * periodic wake up scan so that the device can connect to a new access 754 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 755 * override this. 756 */ 757 private final int mDefaultFrameworkScanIntervalMs; 758 759 private int mDisconnectedScanPeriodMs = 10000; 760 761 /** 762 * Supplicant scan interval in milliseconds. 763 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 764 * from the default config if the setting is not set 765 */ 766 private long mSupplicantScanIntervalMs; 767 768 /** 769 * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit 770 */ 771 private long lastFullBandConnectedTimeMilli; 772 773 /** 774 * time interval to the next full band scan we will perform for 775 * autojoin while connected with screen lit 776 */ 777 private long fullBandConnectedTimeIntervalMilli; 778 779 /** 780 * max time interval to the next full band scan we will perform for 781 * autojoin while connected with screen lit 782 * Max time is 5 minutes 783 */ 784 private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5; 785 786 /** 787 * Minimum time interval between enabling all networks. 788 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 789 * due to enabling every time. We add a threshold to avoid this. 790 */ 791 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 792 private long mLastEnableAllNetworksTime; 793 794 int mRunningBeaconCount = 0; 795 796 /** 797 * Starting and shutting down driver too quick causes problems leading to driver 798 * being in a bad state. Delay driver stop. 799 */ 800 private final int mDriverStopDelayMs; 801 private int mDelayedStopCounter; 802 private boolean mInDelayedStop = false; 803 804 // there is a delay between StateMachine change country code and Supplicant change country code 805 // here save the current WifiStateMachine set country code 806 private volatile String mSetCountryCode = null; 807 808 // Supplicant doesn't like setting the same country code multiple times (it may drop 809 // currently connected network), so we save the current device set country code here to avoid 810 // redundency 811 private String mDriverSetCountryCode = null; 812 813 /* Default parent state */ 814 private State mDefaultState = new DefaultState(); 815 /* Temporary initial state */ 816 private State mInitialState = new InitialState(); 817 /* Driver loaded, waiting for supplicant to start */ 818 private State mSupplicantStartingState = new SupplicantStartingState(); 819 /* Driver loaded and supplicant ready */ 820 private State mSupplicantStartedState = new SupplicantStartedState(); 821 /* Waiting for supplicant to stop and monitor to exit */ 822 private State mSupplicantStoppingState = new SupplicantStoppingState(); 823 /* Driver start issued, waiting for completed event */ 824 private State mDriverStartingState = new DriverStartingState(); 825 /* Driver started */ 826 private State mDriverStartedState = new DriverStartedState(); 827 /* Wait until p2p is disabled 828 * This is a special state which is entered right after we exit out of DriverStartedState 829 * before transitioning to another state. 830 */ 831 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 832 /* Driver stopping */ 833 private State mDriverStoppingState = new DriverStoppingState(); 834 /* Driver stopped */ 835 private State mDriverStoppedState = new DriverStoppedState(); 836 /* Scan for networks, no connection will be established */ 837 private State mScanModeState = new ScanModeState(); 838 /* Connecting to an access point */ 839 private State mConnectModeState = new ConnectModeState(); 840 /* Connected at 802.11 (L2) level */ 841 private State mL2ConnectedState = new L2ConnectedState(); 842 /* fetching IP after connection to access point (assoc+auth complete) */ 843 private State mObtainingIpState = new ObtainingIpState(); 844 /* Waiting for link quality verification to be complete */ 845 private State mVerifyingLinkState = new VerifyingLinkState(); 846 /* Connected with IP addr */ 847 private State mConnectedState = new ConnectedState(); 848 /* Roaming */ 849 private State mRoamingState = new RoamingState(); 850 /* disconnect issued, waiting for network disconnect confirmation */ 851 private State mDisconnectingState = new DisconnectingState(); 852 /* Network is not connected, supplicant assoc+auth is not complete */ 853 private State mDisconnectedState = new DisconnectedState(); 854 /* Waiting for WPS to be completed*/ 855 private State mWpsRunningState = new WpsRunningState(); 856 857 /* Soft ap is starting up */ 858 private State mSoftApStartingState = new SoftApStartingState(); 859 /* Soft ap is running */ 860 private State mSoftApStartedState = new SoftApStartedState(); 861 /* Soft ap is running and we are waiting for tether notification */ 862 private State mTetheringState = new TetheringState(); 863 /* Soft ap is running and we are tethered through connectivity service */ 864 private State mTetheredState = new TetheredState(); 865 /* Waiting for untether confirmation before stopping soft Ap */ 866 private State mUntetheringState = new UntetheringState(); 867 868 private class TetherStateChange { 869 ArrayList<String> available; 870 ArrayList<String> active; 871 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 872 available = av; 873 active = ac; 874 } 875 } 876 877 public static class SimAuthRequestData { 878 int networkId; 879 int protocol; 880 String ssid; 881 String[] challenges; 882 } 883 884 public static class SimAuthResponseData { 885 int id; 886 String Kc1; 887 String SRES1; 888 String Kc2; 889 String SRES2; 890 String Kc3; 891 String SRES3; 892 } 893 894 /** 895 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 896 * {@link WifiManager#WIFI_STATE_DISABLING}, 897 * {@link WifiManager#WIFI_STATE_ENABLED}, 898 * {@link WifiManager#WIFI_STATE_ENABLING}, 899 * {@link WifiManager#WIFI_STATE_UNKNOWN} 900 * 901 */ 902 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 903 904 /** 905 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 906 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 907 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 908 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 909 * {@link WifiManager#WIFI_AP_STATE_FAILED} 910 * 911 */ 912 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 913 914 private static final int SCAN_REQUEST = 0; 915 private static final String ACTION_START_SCAN = 916 "com.android.server.WifiManager.action.START_SCAN"; 917 918 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 919 private static final int DRIVER_STOP_REQUEST = 0; 920 private static final String ACTION_DELAYED_DRIVER_STOP = 921 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 922 923 private static final String ACTION_REFRESH_BATCHED_SCAN = 924 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 925 /** 926 * Keep track of whether WIFI is running. 927 */ 928 private boolean mIsRunning = false; 929 930 /** 931 * Keep track of whether we last told the battery stats we had started. 932 */ 933 private boolean mReportedRunning = false; 934 935 /** 936 * Most recently set source of starting WIFI. 937 */ 938 private final WorkSource mRunningWifiUids = new WorkSource(); 939 940 /** 941 * The last reported UIDs that were responsible for starting WIFI. 942 */ 943 private final WorkSource mLastRunningWifiUids = new WorkSource(); 944 945 private final IBatteryStats mBatteryStats; 946 947 private BatchedScanSettings mBatchedScanSettings = null; 948 949 /** 950 * Track the worksource/cost of the current settings and track what's been noted 951 * to the battery stats, so we can mark the end of the previous when changing. 952 */ 953 private WorkSource mBatchedScanWorkSource = null; 954 private int mBatchedScanCsph = 0; 955 private WorkSource mNotedBatchedScanWorkSource = null; 956 private int mNotedBatchedScanCsph = 0; 957 958 private String mTcpBufferSizes = null; 959 960 // Used for debug and stats gathering 961 private static int sScanAlarmIntentCount = 0; 962 963 final static int frameworkMinScanIntervalSaneValue = 10000; 964 965 public WifiStateMachine(Context context, String wlanInterface, 966 WifiTrafficPoller trafficPoller){ 967 super("WifiStateMachine"); 968 mContext = context; 969 mSetCountryCode = Settings.Global.getString( 970 mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE); 971 mInterfaceName = wlanInterface; 972 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 973 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 974 BatteryStats.SERVICE_NAME)); 975 976 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 977 mNwService = INetworkManagementService.Stub.asInterface(b); 978 979 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 980 PackageManager.FEATURE_WIFI_DIRECT); 981 982 mWifiNative = new WifiNative(mInterfaceName); 983 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 984 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 985 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); 986 mWifiLogger = new WifiLogger(mContext, this); 987 mWifiMonitor = new WifiMonitor(this, mWifiNative); 988 mWifiInfo = new WifiInfo(); 989 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 990 getHandler()); 991 mLinkProperties = new LinkProperties(); 992 993 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 994 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1); 995 996 IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE); 997 998 mNetworkInfo.setIsAvailable(false); 999 mLastBssid = null; 1000 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 1001 mLastSignalLevel = -1; 1002 1003 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 1004 public void update() { 1005 sendMessage(CMD_UPDATE_LINKPROPERTIES); 1006 } 1007 }); 1008 try { 1009 mNwService.registerObserver(mNetlinkTracker); 1010 } catch (RemoteException e) { 1011 loge("Couldn't register netlink tracker: " + e.toString()); 1012 } 1013 1014 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 1015 mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST); 1016 mBatchedScanIntervalIntent = getPrivateBroadcast(ACTION_REFRESH_BATCHED_SCAN, 0); 1017 1018 // Make sure the interval is not configured less than 10 seconds 1019 int period = mContext.getResources().getInteger( 1020 R.integer.config_wifi_framework_scan_interval); 1021 if (period < frameworkMinScanIntervalSaneValue) { 1022 period = frameworkMinScanIntervalSaneValue; 1023 } 1024 mDefaultFrameworkScanIntervalMs = period; 1025 mDriverStopDelayMs = mContext.getResources().getInteger( 1026 R.integer.config_wifi_driver_stop_delay); 1027 1028 mBackgroundScanSupported = mContext.getResources().getBoolean( 1029 R.bool.config_wifi_background_scan_support); 1030 1031 mPrimaryDeviceType = mContext.getResources().getString( 1032 R.string.config_wifi_p2p_device_type); 1033 1034 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 1035 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 1036 1037 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 1038 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 1039 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 1040 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 1041 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 1042 // TODO - needs to be a bit more dynamic 1043 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 1044 1045 mContext.registerReceiver( 1046 new BroadcastReceiver() { 1047 @Override 1048 public void onReceive(Context context, Intent intent) { 1049 ArrayList<String> available = intent.getStringArrayListExtra( 1050 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 1051 ArrayList<String> active = intent.getStringArrayListExtra( 1052 ConnectivityManager.EXTRA_ACTIVE_TETHER); 1053 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 1054 } 1055 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 1056 1057 mContext.registerReceiver( 1058 new BroadcastReceiver() { 1059 @Override 1060 public void onReceive(Context context, Intent intent) { 1061 sScanAlarmIntentCount++; // Used for debug only 1062 startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null); 1063 if (VDBG) 1064 loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get()); 1065 } 1066 }, 1067 new IntentFilter(ACTION_START_SCAN)); 1068 1069 IntentFilter filter = new IntentFilter(); 1070 filter.addAction(Intent.ACTION_SCREEN_ON); 1071 filter.addAction(Intent.ACTION_SCREEN_OFF); 1072 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 1073 mContext.registerReceiver( 1074 new BroadcastReceiver() { 1075 @Override 1076 public void onReceive(Context context, Intent intent) { 1077 String action = intent.getAction(); 1078 1079 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1080 sendMessage(CMD_SCREEN_STATE_CHANGED, 1); 1081 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1082 sendMessage(CMD_SCREEN_STATE_CHANGED, 0); 1083 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 1084 startNextBatchedScanAsync(); 1085 } 1086 } 1087 }, filter); 1088 1089 mContext.registerReceiver( 1090 new BroadcastReceiver() { 1091 @Override 1092 public void onReceive(Context context, Intent intent) { 1093 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 1094 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 1095 } 1096 }, 1097 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 1098 1099 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 1100 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 1101 new ContentObserver(getHandler()) { 1102 @Override 1103 public void onChange(boolean selfChange) { 1104 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 1105 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 1106 } 1107 }); 1108 1109 mContext.registerReceiver( 1110 new BroadcastReceiver() { 1111 @Override 1112 public void onReceive(Context context, Intent intent) { 1113 sendMessage(CMD_BOOT_COMPLETED); 1114 } 1115 }, 1116 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 1117 1118 mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE); 1119 1120 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 1121 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 1122 1123 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 1124 mSuspendWakeLock.setReferenceCounted(false); 1125 1126 mTcpBufferSizes = mContext.getResources().getString( 1127 com.android.internal.R.string.config_wifi_tcp_buffers); 1128 1129 addState(mDefaultState); 1130 addState(mInitialState, mDefaultState); 1131 addState(mSupplicantStartingState, mDefaultState); 1132 addState(mSupplicantStartedState, mDefaultState); 1133 addState(mDriverStartingState, mSupplicantStartedState); 1134 addState(mDriverStartedState, mSupplicantStartedState); 1135 addState(mScanModeState, mDriverStartedState); 1136 addState(mConnectModeState, mDriverStartedState); 1137 addState(mL2ConnectedState, mConnectModeState); 1138 addState(mObtainingIpState, mL2ConnectedState); 1139 addState(mVerifyingLinkState, mL2ConnectedState); 1140 addState(mConnectedState, mL2ConnectedState); 1141 addState(mRoamingState, mL2ConnectedState); 1142 addState(mDisconnectingState, mConnectModeState); 1143 addState(mDisconnectedState, mConnectModeState); 1144 addState(mWpsRunningState, mConnectModeState); 1145 addState(mWaitForP2pDisableState, mSupplicantStartedState); 1146 addState(mDriverStoppingState, mSupplicantStartedState); 1147 addState(mDriverStoppedState, mSupplicantStartedState); 1148 addState(mSupplicantStoppingState, mDefaultState); 1149 addState(mSoftApStartingState, mDefaultState); 1150 addState(mSoftApStartedState, mDefaultState); 1151 addState(mTetheringState, mSoftApStartedState); 1152 addState(mTetheredState, mSoftApStartedState); 1153 addState(mUntetheringState, mSoftApStartedState); 1154 1155 setInitialState(mInitialState); 1156 1157 setLogRecSize(ActivityManager.isLowRamDeviceStatic() ? 100 : 3000); 1158 setLogOnlyTransitions(false); 1159 if (VDBG) setDbg(true); 1160 1161 //start the state machine 1162 start(); 1163 1164 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 1165 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1166 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 1167 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1168 } 1169 1170 1171 PendingIntent getPrivateBroadcast(String action, int requestCode) { 1172 Intent intent = new Intent(action, null); 1173 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1174 intent.setPackage(this.getClass().getPackage().getName()); 1175 return PendingIntent.getBroadcast(mContext, requestCode, intent, 0); 1176 } 1177 1178 private int mVerboseLoggingLevel = 0; 1179 1180 int getVerboseLoggingLevel() { 1181 return mVerboseLoggingLevel; 1182 } 1183 1184 void enableVerboseLogging(int verbose) { 1185 mVerboseLoggingLevel = verbose; 1186 if (verbose > 0) { 1187 DBG = true; 1188 VDBG = true; 1189 PDBG = true; 1190 mLogMessages = true; 1191 mWifiNative.setSupplicantLogLevel("DEBUG"); 1192 } else { 1193 DBG = false; 1194 VDBG = false; 1195 PDBG = false; 1196 mLogMessages = false; 1197 mWifiNative.setSupplicantLogLevel("INFO"); 1198 } 1199 mWifiAutoJoinController.enableVerboseLogging(verbose); 1200 mWifiMonitor.enableVerboseLogging(verbose); 1201 mWifiNative.enableVerboseLogging(verbose); 1202 mWifiConfigStore.enableVerboseLogging(verbose); 1203 mSupplicantStateTracker.enableVerboseLogging(verbose); 1204 } 1205 1206 private int mAggressiveHandover = 0; 1207 1208 int getAggressiveHandover() { 1209 return mAggressiveHandover; 1210 } 1211 1212 void enableAggressiveHandover(int enabled) { 1213 mAggressiveHandover = enabled; 1214 } 1215 1216 public void setAllowScansWithTraffic(int enabled) { 1217 mWifiConfigStore.alwaysEnableScansWhileAssociated.set(enabled); 1218 } 1219 1220 public int getAllowScansWithTraffic() { 1221 return mWifiConfigStore.alwaysEnableScansWhileAssociated.get(); 1222 } 1223 1224 public void setAllowScansWhileAssociated(boolean enabled) { 1225 mWifiConfigStore.enableAutoJoinScanWhenAssociated.set(enabled); 1226 } 1227 1228 public boolean getAllowScansWhileAssociated() { 1229 return mWifiConfigStore.enableAutoJoinScanWhenAssociated.get(); 1230 } 1231 1232 /* 1233 * 1234 * Framework scan control 1235 */ 1236 1237 private boolean mAlarmEnabled = false; 1238 /* This is set from the overlay config file or from a secure setting. 1239 * A value of 0 disables scanning in the framework. 1240 */ 1241 private long mFrameworkScanIntervalMs = 10000; 1242 1243 private AtomicInteger mDelayedScanCounter = new AtomicInteger(); 1244 1245 private void setScanAlarm(boolean enabled) { 1246 if (PDBG) { 1247 loge("setScanAlarm " + enabled 1248 + " period " + mDefaultFrameworkScanIntervalMs 1249 + " mBackgroundScanSupported " + mBackgroundScanSupported); 1250 } 1251 if (mBackgroundScanSupported == false) { 1252 // Scan alarm is only used for background scans if they are not 1253 // offloaded to the wifi chipset, hence enable the scan alarm 1254 // gicing us RTC_WAKEUP of backgroundScan is NOT supported 1255 enabled = true; 1256 } 1257 1258 if (enabled == mAlarmEnabled) return; 1259 if (enabled) { 1260 /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */ 1261 /* going to wake up the host processor to look for access points */ 1262 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 1263 System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs, 1264 mScanIntent); 1265 mAlarmEnabled = true; 1266 } else { 1267 mAlarmManager.cancel(mScanIntent); 1268 mAlarmEnabled = false; 1269 } 1270 } 1271 1272 private void cancelDelayedScan() { 1273 mDelayedScanCounter.incrementAndGet(); 1274 loge("cancelDelayedScan -> " + mDelayedScanCounter); 1275 } 1276 1277 private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli, 1278 ScanSettings settings, WorkSource workSource) { 1279 if (counter != mDelayedScanCounter.get()) { 1280 return false; 1281 } 1282 if (restart) 1283 startDelayedScan(milli, settings, workSource); 1284 return true; 1285 } 1286 1287 private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) { 1288 if (milli <= 0) return; 1289 /** 1290 * The cases where the scan alarm should be run are : 1291 * - DisconnectedState && screenOn => used delayed timer 1292 * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO 1293 * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm 1294 * - ConnectedState && screenOn => used delayed timer 1295 */ 1296 1297 mDelayedScanCounter.incrementAndGet(); 1298 if (mScreenOn && 1299 (getCurrentState() == mDisconnectedState 1300 || getCurrentState() == mConnectedState)) { 1301 Bundle bundle = new Bundle(); 1302 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1303 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1304 bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); 1305 sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE, 1306 mDelayedScanCounter.get(), bundle, milli); 1307 if (DBG) loge("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli); 1308 } else if (mBackgroundScanSupported == false 1309 && !mScreenOn && getCurrentState() == mDisconnectedState) { 1310 setScanAlarm(true); 1311 if (DBG) loge("startDelayedScan start scan alarm -> " 1312 + mDelayedScanCounter + " milli " + milli); 1313 } else { 1314 if (DBG) loge("startDelayedScan unhandled -> " 1315 + mDelayedScanCounter + " milli " + milli); 1316 } 1317 } 1318 1319 private boolean setRandomMacOui() { 1320 String oui = mContext.getResources().getString( 1321 R.string.config_wifi_random_mac_oui, GOOGLE_OUI); 1322 String[] ouiParts = oui.split("-"); 1323 byte[] ouiBytes = new byte[3]; 1324 ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF); 1325 ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF); 1326 ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF); 1327 1328 logd("Setting OUI to " + oui); 1329 return mWifiNative.setScanningMacOui(ouiBytes); 1330 } 1331 1332 /********************************************************* 1333 * Methods exposed for public use 1334 ********************************************************/ 1335 1336 public Messenger getMessenger() { 1337 return new Messenger(getHandler()); 1338 } 1339 1340 public WifiMonitor getWifiMonitor() { 1341 return mWifiMonitor; 1342 } 1343 1344 /** 1345 * TODO: doc 1346 */ 1347 public boolean syncPingSupplicant(AsyncChannel channel) { 1348 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1349 boolean result = (resultMsg.arg1 != FAILURE); 1350 resultMsg.recycle(); 1351 return result; 1352 } 1353 1354 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1355 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1356 List<WifiChannel> list = null; 1357 if (resultMsg.obj != null) { 1358 list = new ArrayList<WifiChannel>(); 1359 String freqs = (String) resultMsg.obj; 1360 String[] lines = freqs.split("\n"); 1361 for (String line : lines) 1362 if (line.contains("MHz")) { 1363 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1364 WifiChannel c = new WifiChannel(); 1365 String[] prop = line.split(" "); 1366 if (prop.length < 5) continue; 1367 try { 1368 c.channelNum = Integer.parseInt(prop[1]); 1369 c.freqMHz = Integer.parseInt(prop[3]); 1370 } catch (NumberFormatException e) { } 1371 c.isDFS = line.contains("(DFS)"); 1372 list.add(c); 1373 } else if (line.contains("Mode[B] Channels:")) { 1374 // B channels are the same as G channels, skipped 1375 break; 1376 } 1377 } 1378 resultMsg.recycle(); 1379 return (list != null && list.size() > 0) ? list : null; 1380 } 1381 1382 /** 1383 * When settings allowing making use of untrusted networks change, trigger a scan 1384 * so as to kick of autojoin. 1385 */ 1386 public void startScanForUntrustedSettingChange() { 1387 startScan(SET_ALLOW_UNTRUSTED_SOURCE, 0, null, null); 1388 } 1389 1390 /** 1391 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1392 * given to callingUid. 1393 * 1394 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1395 * workSource is specified. 1396 * @param workSource If not null, blame is given to workSource. 1397 * @param settings Scan settings, see {@link ScanSettings}. 1398 */ 1399 public void startScan(int callingUid, int scanCounter, 1400 ScanSettings settings, WorkSource workSource) { 1401 Bundle bundle = new Bundle(); 1402 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1403 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1404 bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); 1405 sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle); 1406 } 1407 1408 /** 1409 * start or stop batched scanning using the given settings 1410 */ 1411 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1412 WorkSource workSource) { 1413 Bundle bundle = new Bundle(); 1414 bundle.putParcelable(BATCHED_SETTING, settings); 1415 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1416 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1417 } 1418 1419 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1420 synchronized (mBatchedScanResults) { 1421 List<BatchedScanResult> batchedScanList = 1422 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1423 for(BatchedScanResult result: mBatchedScanResults) { 1424 batchedScanList.add(new BatchedScanResult(result)); 1425 } 1426 return batchedScanList; 1427 } 1428 } 1429 1430 public void requestBatchedScanPoll() { 1431 sendMessage(CMD_POLL_BATCHED_SCAN); 1432 } 1433 1434 private void startBatchedScan() { 1435 if (mBatchedScanSettings == null) return; 1436 1437 if (mDhcpActive) { 1438 if (DBG) log("not starting Batched Scans due to DHCP"); 1439 return; 1440 } 1441 1442 // first grab any existing data 1443 retrieveBatchedScanData(); 1444 1445 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1446 1447 1448 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1449 1450 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1451 try { 1452 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1453 setNextBatchedAlarm(mExpectedBatchedScans); 1454 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1455 } catch (NumberFormatException e) { 1456 stopBatchedScan(); 1457 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1458 } 1459 } 1460 1461 // called from BroadcastListener 1462 private void startNextBatchedScanAsync() { 1463 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1464 } 1465 1466 private void startNextBatchedScan() { 1467 // first grab any existing data 1468 retrieveBatchedScanData(); 1469 1470 setNextBatchedAlarm(mExpectedBatchedScans); 1471 } 1472 1473 private void handleBatchedScanPollRequest() { 1474 if (DBG) { 1475 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1476 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1477 mBatchedScanSettings); 1478 } 1479 // if there is no appropriate PollTime that's because we either aren't 1480 // batching or we've already set a time for a poll request 1481 if (mBatchedScanMinPollTime == 0) return; 1482 if (mBatchedScanSettings == null) return; 1483 1484 long now = System.currentTimeMillis(); 1485 1486 if (now > mBatchedScanMinPollTime) { 1487 // do the poll and reset our timers 1488 startNextBatchedScan(); 1489 } else { 1490 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1491 mBatchedScanIntervalIntent); 1492 mBatchedScanMinPollTime = 0; 1493 } 1494 } 1495 1496 // return true if new/different 1497 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1498 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1499 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1500 1501 if (DBG) { 1502 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1503 ", worksource=" + responsibleWorkSource); 1504 } 1505 if (settings != null) { 1506 if (settings.equals(mBatchedScanSettings)) return false; 1507 } else { 1508 if (mBatchedScanSettings == null) return false; 1509 } 1510 mBatchedScanSettings = settings; 1511 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1512 mBatchedScanWorkSource = responsibleWorkSource; 1513 mBatchedScanCsph = csph; 1514 return true; 1515 } 1516 1517 private void stopBatchedScan() { 1518 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1519 retrieveBatchedScanData(); 1520 mWifiNative.setBatchedScanSettings(null); 1521 noteBatchedScanStop(); 1522 } 1523 1524 private void setNextBatchedAlarm(int scansExpected) { 1525 1526 if (mBatchedScanSettings == null || scansExpected < 1) return; 1527 1528 mBatchedScanMinPollTime = System.currentTimeMillis() + 1529 mBatchedScanSettings.scanIntervalSec * 1000; 1530 1531 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1532 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1533 } 1534 1535 int secToFull = mBatchedScanSettings.scanIntervalSec; 1536 secToFull *= scansExpected; 1537 1538 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1539 if (debugPeriod > 0) secToFull = debugPeriod; 1540 1541 // set the alarm to do the next poll. We set it a little short as we'd rather 1542 // wake up wearly than miss a scan due to buffer overflow 1543 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1544 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1545 mBatchedScanIntervalIntent); 1546 } 1547 1548 /** 1549 * Start reading new scan data 1550 * Data comes in as: 1551 * "scancount=5\n" 1552 * "nextcount=5\n" 1553 * "apcount=3\n" 1554 * "trunc\n" (optional) 1555 * "bssid=...\n" 1556 * "ssid=...\n" 1557 * "freq=...\n" (in Mhz) 1558 * "level=...\n" 1559 * "dist=...\n" (in cm) 1560 * "distsd=...\n" (standard deviation, in cm) 1561 * "====" 1562 * "bssid=...\n" 1563 * etc 1564 * "====" 1565 * "bssid=...\n" 1566 * etc 1567 * "%%%%" 1568 * "apcount=2\n" 1569 * "bssid=...\n" 1570 * etc 1571 * "%%%% 1572 * etc 1573 * "----" 1574 */ 1575 private final static boolean DEBUG_PARSE = false; 1576 private void retrieveBatchedScanData() { 1577 String rawData = mWifiNative.getBatchedScanResults(); 1578 if (DEBUG_PARSE) log("rawData = " + rawData); 1579 mBatchedScanMinPollTime = 0; 1580 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1581 loge("Unexpected BatchedScanResults :" + rawData); 1582 return; 1583 } 1584 1585 int scanCount = 0; 1586 final String END_OF_BATCHES = "----"; 1587 final String SCANCOUNT = "scancount="; 1588 final String TRUNCATED = "trunc"; 1589 final String AGE = "age="; 1590 final String DIST = "dist="; 1591 final String DISTSD = "distSd="; 1592 1593 String splitData[] = rawData.split("\n"); 1594 int n = 0; 1595 if (splitData[n].startsWith(SCANCOUNT)) { 1596 try { 1597 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1598 } catch (NumberFormatException e) { 1599 loge("scancount parseInt Exception from " + splitData[n]); 1600 } 1601 } else log("scancount not found"); 1602 if (scanCount == 0) { 1603 loge("scanCount==0 - aborting"); 1604 return; 1605 } 1606 1607 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1608 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1609 1610 synchronized (mBatchedScanResults) { 1611 mBatchedScanResults.clear(); 1612 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1613 1614 String bssid = null; 1615 WifiSsid wifiSsid = null; 1616 int level = 0; 1617 int freq = 0; 1618 int dist, distSd; 1619 long tsf = 0; 1620 dist = distSd = ScanResult.UNSPECIFIED; 1621 final long now = SystemClock.elapsedRealtime(); 1622 final int bssidStrLen = BSSID_STR.length(); 1623 1624 while (true) { 1625 while (n < splitData.length) { 1626 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1627 if (splitData[n].equals(END_OF_BATCHES)) { 1628 if (n+1 != splitData.length) { 1629 loge("didn't consume " + (splitData.length-n)); 1630 } 1631 if (mBatchedScanResults.size() > 0) { 1632 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1633 } 1634 logd("retrieveBatchedScanResults X"); 1635 return; 1636 } 1637 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1638 if (bssid != null) { 1639 batchedScanResult.scanResults.add(new ScanResult( 1640 wifiSsid, bssid, null, 1641 level, freq, tsf, dist, distSd)); 1642 wifiSsid = null; 1643 bssid = null; 1644 level = 0; 1645 freq = 0; 1646 tsf = 0; 1647 dist = distSd = ScanResult.UNSPECIFIED; 1648 } 1649 if (splitData[n].equals(END_STR)) { 1650 if (batchedScanResult.scanResults.size() != 0) { 1651 mBatchedScanResults.add(batchedScanResult); 1652 batchedScanResult = new BatchedScanResult(); 1653 } else { 1654 logd("Found empty batch"); 1655 } 1656 } 1657 } else if (splitData[n].equals(TRUNCATED)) { 1658 batchedScanResult.truncated = true; 1659 } else if (splitData[n].startsWith(BSSID_STR)) { 1660 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1661 splitData[n].length() - bssidStrLen); 1662 } else if (splitData[n].startsWith(FREQ_STR)) { 1663 try { 1664 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1665 } catch (NumberFormatException e) { 1666 loge("Invalid freqency: " + splitData[n]); 1667 freq = 0; 1668 } 1669 } else if (splitData[n].startsWith(AGE)) { 1670 try { 1671 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1672 tsf *= 1000; // convert mS -> uS 1673 } catch (NumberFormatException e) { 1674 loge("Invalid timestamp: " + splitData[n]); 1675 tsf = 0; 1676 } 1677 } else if (splitData[n].startsWith(SSID_STR)) { 1678 wifiSsid = WifiSsid.createFromAsciiEncoded( 1679 splitData[n].substring(SSID_STR.length())); 1680 } else if (splitData[n].startsWith(LEVEL_STR)) { 1681 try { 1682 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1683 if (level > 0) level -= 256; 1684 } catch (NumberFormatException e) { 1685 loge("Invalid level: " + splitData[n]); 1686 level = 0; 1687 } 1688 } else if (splitData[n].startsWith(DIST)) { 1689 try { 1690 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1691 } catch (NumberFormatException e) { 1692 loge("Invalid distance: " + splitData[n]); 1693 dist = ScanResult.UNSPECIFIED; 1694 } 1695 } else if (splitData[n].startsWith(DISTSD)) { 1696 try { 1697 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1698 } catch (NumberFormatException e) { 1699 loge("Invalid distanceSd: " + splitData[n]); 1700 distSd = ScanResult.UNSPECIFIED; 1701 } 1702 } else { 1703 loge("Unable to parse batched scan result line: " + splitData[n]); 1704 } 1705 n++; 1706 } 1707 rawData = mWifiNative.getBatchedScanResults(); 1708 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1709 if (rawData == null) { 1710 loge("Unexpected null BatchedScanResults"); 1711 return; 1712 } 1713 splitData = rawData.split("\n"); 1714 if (splitData.length == 0 || splitData[0].equals("ok")) { 1715 loge("batch scan results just ended!"); 1716 if (mBatchedScanResults.size() > 0) { 1717 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1718 } 1719 return; 1720 } 1721 n = 0; 1722 } 1723 } 1724 } 1725 1726 private long mDisconnectedTimeStamp = 0; 1727 1728 public long getDisconnectedTimeMilli() { 1729 if (getCurrentState() == mDisconnectedState 1730 && mDisconnectedTimeStamp != 0) { 1731 long now_ms = System.currentTimeMillis(); 1732 return now_ms - mDisconnectedTimeStamp; 1733 } 1734 return 0; 1735 } 1736 1737 // Keeping track of scan requests 1738 private long lastStartScanTimeStamp = 0; 1739 private long lastScanDuration = 0; 1740 // Last connect attempt is used to prevent scan requests: 1741 // - for a period of 10 seconds after attempting to connect 1742 private long lastConnectAttempt = 0; 1743 private String lastScanFreqs = null; 1744 1745 // For debugging, keep track of last message status handling 1746 // TODO, find an equivalent mechanism as part of parent class 1747 private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2; 1748 private static int MESSAGE_HANDLING_STATUS_OK = 1; 1749 private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0; 1750 private static int MESSAGE_HANDLING_STATUS_REFUSED = -1; 1751 private static int MESSAGE_HANDLING_STATUS_FAIL = -2; 1752 private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3; 1753 private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4; 1754 private static int MESSAGE_HANDLING_STATUS_DISCARD = -5; 1755 private static int MESSAGE_HANDLING_STATUS_LOOPED = -6; 1756 private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7; 1757 1758 private int messageHandlingStatus = 0; 1759 1760 //TODO: this is used only to track connection attempts, however the link state and packet per 1761 //TODO: second logic should be folded into that 1762 private boolean checkOrDeferScanAllowed(Message msg) { 1763 long now = System.currentTimeMillis(); 1764 if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { 1765 Message dmsg = Message.obtain(msg); 1766 sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttempt)); 1767 return false; 1768 } 1769 return true; 1770 } 1771 1772 private int mOnTime = 0; 1773 private int mTxTime = 0; 1774 private int mRxTime = 0; 1775 private int mOnTimeStartScan = 0; 1776 private int mTxTimeStartScan = 0; 1777 private int mRxTimeStartScan = 0; 1778 private int mOnTimeScan = 0; 1779 private int mTxTimeScan = 0; 1780 private int mRxTimeScan = 0; 1781 private int mOnTimeThisScan = 0; 1782 private int mTxTimeThisScan = 0; 1783 private int mRxTimeThisScan = 0; 1784 1785 private int mOnTimeScreenStateChange = 0; 1786 private int mOnTimeAtLastReport = 0; 1787 private long lastOntimeReportTimeStamp = 0; 1788 private long lastScreenStateChangeTimeStamp = 0; 1789 private int mOnTimeLastReport = 0; 1790 private int mTxTimeLastReport = 0; 1791 private int mRxTimeLastReport = 0; 1792 1793 private long lastLinkLayerStatsUpdate = 0; 1794 1795 String reportOnTime() { 1796 long now = System.currentTimeMillis(); 1797 StringBuilder sb = new StringBuilder(); 1798 // Report stats since last report 1799 int on = mOnTime - mOnTimeLastReport; 1800 mOnTimeLastReport = mOnTime; 1801 int tx = mTxTime - mTxTimeLastReport; 1802 mTxTimeLastReport = mTxTime; 1803 int rx = mRxTime - mRxTimeLastReport; 1804 mRxTimeLastReport = mRxTime; 1805 int period = (int)(now - lastOntimeReportTimeStamp); 1806 lastOntimeReportTimeStamp = now; 1807 sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period)); 1808 // Report stats since Screen State Changed 1809 on = mOnTime - mOnTimeScreenStateChange; 1810 period = (int)(now - lastScreenStateChangeTimeStamp); 1811 sb.append(String.format(" from screen [on:%d period:%d]", on, period)); 1812 return sb.toString(); 1813 } 1814 1815 WifiLinkLayerStats getWifiLinkLayerStats(boolean dbg) { 1816 WifiLinkLayerStats stats = null; 1817 if (mWifiLinkLayerStatsSupported > 0) { 1818 String name = "wlan0"; 1819 stats = mWifiNative.getWifiLinkLayerStats(name); 1820 if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) { 1821 mWifiLinkLayerStatsSupported -= 1; 1822 } else if (stats != null) { 1823 lastLinkLayerStatsUpdate = System.currentTimeMillis(); 1824 mOnTime = stats.on_time; 1825 mTxTime = stats.tx_time; 1826 mRxTime = stats.rx_time; 1827 mRunningBeaconCount = stats.beacon_rx; 1828 if (dbg) { 1829 loge(stats.toString()); 1830 } 1831 } 1832 } 1833 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 1834 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 1835 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 1836 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 1837 } else { 1838 mWifiInfo.updatePacketRates(stats); 1839 } 1840 return stats; 1841 } 1842 1843 void startRadioScanStats() { 1844 WifiLinkLayerStats stats = getWifiLinkLayerStats(false); 1845 if (stats != null) { 1846 mOnTimeStartScan = stats.on_time; 1847 mTxTimeStartScan = stats.tx_time; 1848 mRxTimeStartScan = stats.rx_time; 1849 mOnTime = stats.on_time; 1850 mTxTime = stats.tx_time; 1851 mRxTime = stats.rx_time; 1852 } 1853 } 1854 1855 void closeRadioScanStats() { 1856 WifiLinkLayerStats stats = getWifiLinkLayerStats(false); 1857 if (stats != null) { 1858 mOnTimeThisScan = stats.on_time - mOnTimeStartScan; 1859 mTxTimeThisScan = stats.tx_time - mTxTimeStartScan; 1860 mRxTimeThisScan = stats.rx_time - mRxTimeStartScan; 1861 mOnTimeScan += mOnTimeThisScan; 1862 mTxTimeScan += mTxTimeThisScan; 1863 mRxTimeScan += mRxTimeThisScan; 1864 } 1865 } 1866 1867 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1868 private void noteScanStart(int callingUid, WorkSource workSource) { 1869 long now = System.currentTimeMillis(); 1870 lastStartScanTimeStamp = now; 1871 lastScanDuration = 0; 1872 if (DBG) { 1873 String ts = String.format("[%,d ms]", now); 1874 if (workSource != null) { 1875 loge(ts + " noteScanStart" + workSource.toString() 1876 + " uid " + Integer.toString(callingUid)); 1877 } else { 1878 loge(ts + " noteScanstart no scan source" 1879 + " uid " + Integer.toString(callingUid)); 1880 } 1881 } 1882 startRadioScanStats(); 1883 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE 1884 && callingUid != SCAN_ALARM_SOURCE) 1885 || workSource != null)) { 1886 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1887 try { 1888 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1889 } catch (RemoteException e) { 1890 log(e.toString()); 1891 } 1892 } 1893 } 1894 1895 private void noteScanEnd() { 1896 long now = System.currentTimeMillis(); 1897 if (lastStartScanTimeStamp != 0) { 1898 lastScanDuration = now - lastStartScanTimeStamp; 1899 } 1900 lastStartScanTimeStamp = 0; 1901 if (DBG) { 1902 String ts = String.format("[%,d ms]", now); 1903 if (mScanWorkSource != null) 1904 loge(ts + " noteScanEnd " + mScanWorkSource.toString() 1905 + " onTime=" + mOnTimeThisScan); 1906 else 1907 loge(ts + " noteScanEnd no scan source" 1908 + " onTime=" + mOnTimeThisScan); 1909 } 1910 if (mScanWorkSource != null) { 1911 try { 1912 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1913 } catch (RemoteException e) { 1914 log(e.toString()); 1915 } finally { 1916 mScanWorkSource = null; 1917 } 1918 } 1919 } 1920 1921 private void noteBatchedScanStart() { 1922 if (PDBG) loge("noteBatchedScanstart()"); 1923 // note the end of a previous scan set 1924 if (mNotedBatchedScanWorkSource != null && 1925 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1926 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1927 try { 1928 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1929 } catch (RemoteException e) { 1930 log(e.toString()); 1931 } finally { 1932 mNotedBatchedScanWorkSource = null; 1933 mNotedBatchedScanCsph = 0; 1934 } 1935 } 1936 // note the start of the new 1937 try { 1938 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1939 mBatchedScanCsph); 1940 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1941 mNotedBatchedScanCsph = mBatchedScanCsph; 1942 } catch (RemoteException e) { 1943 log(e.toString()); 1944 } 1945 } 1946 1947 private void noteBatchedScanStop() { 1948 if (PDBG) loge("noteBatchedScanstop()"); 1949 1950 if (mNotedBatchedScanWorkSource != null) { 1951 try { 1952 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1953 } catch (RemoteException e) { 1954 log(e.toString()); 1955 } finally { 1956 mNotedBatchedScanWorkSource = null; 1957 mNotedBatchedScanCsph = 0; 1958 } 1959 } 1960 } 1961 1962 private void handleScanRequest(int type, Message message) { 1963 ScanSettings settings = null; 1964 WorkSource workSource = null; 1965 1966 // unbundle parameters 1967 Bundle bundle = (Bundle) message.obj; 1968 1969 if (bundle != null) { 1970 settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1971 workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1972 } 1973 1974 // parse scan settings 1975 String freqs = null; 1976 if (settings != null && settings.channelSet != null) { 1977 StringBuilder sb = new StringBuilder(); 1978 boolean first = true; 1979 for (WifiChannel channel : settings.channelSet) { 1980 if (!first) sb.append(','); else first = false; 1981 sb.append(channel.freqMHz); 1982 } 1983 freqs = sb.toString(); 1984 } 1985 1986 // call wifi native to start the scan 1987 if (startScanNative(type, freqs)) { 1988 // only count battery consumption if scan request is accepted 1989 noteScanStart(message.arg1, workSource); 1990 // a full scan covers everything, clearing scan request buffer 1991 if (freqs == null) 1992 mBufferedScanMsg.clear(); 1993 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; 1994 if (workSource != null) { 1995 // External worksource was passed along the scan request, 1996 // hence always send a broadcast 1997 mSendScanResultsBroadcast = true; 1998 } 1999 return; 2000 } 2001 2002 // if reach here, scan request is rejected 2003 2004 if (!mIsScanOngoing) { 2005 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 2006 2007 // discard this request and pop up the next one 2008 if (mBufferedScanMsg.size() > 0) { 2009 sendMessage(mBufferedScanMsg.remove()); 2010 } 2011 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 2012 } else if (!mIsFullScanOngoing) { 2013 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 2014 // buffer the scan request to make sure specified channels will be scanned eventually 2015 if (freqs == null) 2016 mBufferedScanMsg.clear(); 2017 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 2018 Message msg = obtainMessage(CMD_START_SCAN, 2019 message.arg1, message.arg2, bundle); 2020 mBufferedScanMsg.add(msg); 2021 } else { 2022 // if too many requests in buffer, combine them into a single full scan 2023 bundle = new Bundle(); 2024 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 2025 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 2026 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle); 2027 mBufferedScanMsg.clear(); 2028 mBufferedScanMsg.add(msg); 2029 } 2030 messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED; 2031 } else { 2032 // mIsScanOngoing and mIsFullScanOngoing 2033 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 2034 } 2035 } 2036 2037 2038 /** return true iff scan request is accepted */ 2039 private boolean startScanNative(int type, String freqs) { 2040 if (mWifiNative.scan(type, freqs)) { 2041 mIsScanOngoing = true; 2042 mIsFullScanOngoing = (freqs == null); 2043 lastScanFreqs = freqs; 2044 return true; 2045 } 2046 return false; 2047 } 2048 2049 /** 2050 * TODO: doc 2051 */ 2052 public void setSupplicantRunning(boolean enable) { 2053 if (enable) { 2054 sendMessage(CMD_START_SUPPLICANT); 2055 } else { 2056 sendMessage(CMD_STOP_SUPPLICANT); 2057 } 2058 } 2059 2060 /** 2061 * TODO: doc 2062 */ 2063 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 2064 if (enable) { 2065 sendMessage(CMD_START_AP, wifiConfig); 2066 } else { 2067 sendMessage(CMD_STOP_AP); 2068 } 2069 } 2070 2071 public void setWifiApConfiguration(WifiConfiguration config) { 2072 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 2073 } 2074 2075 public WifiConfiguration syncGetWifiApConfiguration() { 2076 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 2077 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 2078 resultMsg.recycle(); 2079 return ret; 2080 } 2081 2082 /** 2083 * TODO: doc 2084 */ 2085 public int syncGetWifiState() { 2086 return mWifiState.get(); 2087 } 2088 2089 /** 2090 * TODO: doc 2091 */ 2092 public String syncGetWifiStateByName() { 2093 switch (mWifiState.get()) { 2094 case WIFI_STATE_DISABLING: 2095 return "disabling"; 2096 case WIFI_STATE_DISABLED: 2097 return "disabled"; 2098 case WIFI_STATE_ENABLING: 2099 return "enabling"; 2100 case WIFI_STATE_ENABLED: 2101 return "enabled"; 2102 case WIFI_STATE_UNKNOWN: 2103 return "unknown state"; 2104 default: 2105 return "[invalid state]"; 2106 } 2107 } 2108 2109 /** 2110 * TODO: doc 2111 */ 2112 public int syncGetWifiApState() { 2113 return mWifiApState.get(); 2114 } 2115 2116 /** 2117 * TODO: doc 2118 */ 2119 public String syncGetWifiApStateByName() { 2120 switch (mWifiApState.get()) { 2121 case WIFI_AP_STATE_DISABLING: 2122 return "disabling"; 2123 case WIFI_AP_STATE_DISABLED: 2124 return "disabled"; 2125 case WIFI_AP_STATE_ENABLING: 2126 return "enabling"; 2127 case WIFI_AP_STATE_ENABLED: 2128 return "enabled"; 2129 case WIFI_AP_STATE_FAILED: 2130 return "failed"; 2131 default: 2132 return "[invalid state]"; 2133 } 2134 } 2135 2136 /** 2137 * Get status information for the current connection, if any. 2138 * @return a {@link WifiInfo} object containing information about the current connection 2139 * 2140 */ 2141 public WifiInfo syncRequestConnectionInfo() { 2142 return mWifiInfo; 2143 } 2144 2145 public DhcpResults syncGetDhcpResults() { 2146 synchronized (mDhcpResultsLock) { 2147 return new DhcpResults(mDhcpResults); 2148 } 2149 } 2150 2151 /** 2152 * TODO: doc 2153 */ 2154 public void setDriverStart(boolean enable) { 2155 if (enable) { 2156 sendMessage(CMD_START_DRIVER); 2157 } else { 2158 sendMessage(CMD_STOP_DRIVER); 2159 } 2160 } 2161 2162 /** 2163 * TODO: doc 2164 */ 2165 public void setOperationalMode(int mode) { 2166 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 2167 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 2168 } 2169 2170 /** 2171 * TODO: doc 2172 */ 2173 public List<ScanResult> syncGetScanResultsList() { 2174 synchronized (mScanResultCache) { 2175 List<ScanResult> scanList = new ArrayList<ScanResult>(); 2176 for(ScanDetail result: mScanResults) { 2177 scanList.add(new ScanResult(result.getScanResult())); 2178 } 2179 return scanList; 2180 } 2181 } 2182 2183 public void disableEphemeralNetwork(String SSID) { 2184 if (SSID != null) { 2185 sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID); 2186 } 2187 } 2188 2189 /** 2190 * Get unsynchronized pointer to scan result list 2191 * Can be called only from AutoJoinController which runs in the WifiStateMachine context 2192 */ 2193 public List<ScanDetail> getScanResultsListNoCopyUnsync() { 2194 return mScanResults; 2195 } 2196 2197 /** 2198 * Disconnect from Access Point 2199 */ 2200 public void disconnectCommand() { 2201 sendMessage(CMD_DISCONNECT); 2202 } 2203 2204 public void disconnectCommand(int uid, int reason) { 2205 sendMessage(CMD_DISCONNECT, uid, reason); 2206 } 2207 2208 /** 2209 * Initiate a reconnection to AP 2210 */ 2211 public void reconnectCommand() { 2212 sendMessage(CMD_RECONNECT); 2213 } 2214 2215 /** 2216 * Initiate a re-association to AP 2217 */ 2218 public void reassociateCommand() { 2219 sendMessage(CMD_REASSOCIATE); 2220 } 2221 2222 /** 2223 * Reload networks and then reconnect; helps load correct data for TLS networks 2224 */ 2225 2226 public void reloadTlsNetworksAndReconnect() { 2227 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 2228 } 2229 2230 /** 2231 * Add a network synchronously 2232 * 2233 * @return network id of the new network 2234 */ 2235 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 2236 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 2237 int result = resultMsg.arg1; 2238 resultMsg.recycle(); 2239 return result; 2240 } 2241 2242 /** 2243 * Get configured networks synchronously 2244 * @param channel 2245 * @return 2246 */ 2247 2248 public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) { 2249 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid); 2250 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 2251 resultMsg.recycle(); 2252 return result; 2253 } 2254 2255 public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) { 2256 Message resultMsg = channel.sendMessageSynchronously( 2257 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS); 2258 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 2259 resultMsg.recycle(); 2260 return result; 2261 } 2262 2263 2264 /** 2265 * Get connection statistics synchronously 2266 * @param channel 2267 * @return 2268 */ 2269 2270 public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) { 2271 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS); 2272 WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj; 2273 resultMsg.recycle(); 2274 return result; 2275 } 2276 2277 /** 2278 * Get adaptors synchronously 2279 */ 2280 2281 public int syncGetSupportedFeatures(AsyncChannel channel) { 2282 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES); 2283 int supportedFeatureSet = resultMsg.arg1; 2284 resultMsg.recycle(); 2285 return supportedFeatureSet; 2286 } 2287 2288 /** 2289 * Get link layers stats for adapter synchronously 2290 */ 2291 public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) { 2292 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS); 2293 WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj; 2294 resultMsg.recycle(); 2295 return result; 2296 } 2297 2298 /** 2299 * Delete a network 2300 * 2301 * @param networkId id of the network to be removed 2302 */ 2303 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 2304 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 2305 boolean result = (resultMsg.arg1 != FAILURE); 2306 resultMsg.recycle(); 2307 return result; 2308 } 2309 2310 /** 2311 * Enable a network 2312 * 2313 * @param netId network id of the network 2314 * @param disableOthers true, if all other networks have to be disabled 2315 * @return {@code true} if the operation succeeds, {@code false} otherwise 2316 */ 2317 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 2318 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 2319 disableOthers ? 1 : 0); 2320 boolean result = (resultMsg.arg1 != FAILURE); 2321 resultMsg.recycle(); 2322 return result; 2323 } 2324 2325 /** 2326 * Disable a network 2327 * 2328 * @param netId network id of the network 2329 * @return {@code true} if the operation succeeds, {@code false} otherwise 2330 */ 2331 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 2332 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 2333 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 2334 resultMsg.recycle(); 2335 return result; 2336 } 2337 2338 /** 2339 * Retrieves a WPS-NFC configuration token for the specified network 2340 * @return a hex string representation of the WPS-NFC configuration token 2341 */ 2342 public String syncGetWpsNfcConfigurationToken(int netId) { 2343 return mWifiNative.getNfcWpsConfigurationToken(netId); 2344 } 2345 2346 void enableBackgroundScan(boolean enable) { 2347 if (enable) { 2348 mWifiConfigStore.enableAllNetworks(); 2349 } 2350 mWifiNative.enableBackgroundScan(enable); 2351 } 2352 2353 /** 2354 * Blacklist a BSSID. This will avoid the AP if there are 2355 * alternate APs to connect 2356 * 2357 * @param bssid BSSID of the network 2358 */ 2359 public void addToBlacklist(String bssid) { 2360 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 2361 } 2362 2363 /** 2364 * Clear the blacklist list 2365 * 2366 */ 2367 public void clearBlacklist() { 2368 sendMessage(CMD_CLEAR_BLACKLIST); 2369 } 2370 2371 public void enableRssiPolling(boolean enabled) { 2372 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 2373 } 2374 2375 public void enableAllNetworks() { 2376 sendMessage(CMD_ENABLE_ALL_NETWORKS); 2377 } 2378 2379 /** 2380 * Start filtering Multicast v4 packets 2381 */ 2382 public void startFilteringMulticastV4Packets() { 2383 mFilteringMulticastV4Packets.set(true); 2384 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 2385 } 2386 2387 /** 2388 * Stop filtering Multicast v4 packets 2389 */ 2390 public void stopFilteringMulticastV4Packets() { 2391 mFilteringMulticastV4Packets.set(false); 2392 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 2393 } 2394 2395 /** 2396 * Start filtering Multicast v4 packets 2397 */ 2398 public void startFilteringMulticastV6Packets() { 2399 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 2400 } 2401 2402 /** 2403 * Stop filtering Multicast v4 packets 2404 */ 2405 public void stopFilteringMulticastV6Packets() { 2406 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 2407 } 2408 2409 /** 2410 * Set high performance mode of operation. 2411 * Enabling would set active power mode and disable suspend optimizations; 2412 * disabling would set auto power mode and enable suspend optimizations 2413 * @param enable true if enable, false otherwise 2414 */ 2415 public void setHighPerfModeEnabled(boolean enable) { 2416 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 2417 } 2418 2419 /** 2420 * Set the country code 2421 * @param countryCode following ISO 3166 format 2422 * @param persist {@code true} if the setting should be remembered. 2423 */ 2424 public synchronized void setCountryCode(String countryCode, boolean persist) { 2425 // If it's a good country code, apply after the current 2426 // wifi connection is terminated; ignore resetting of code 2427 // for now (it is unclear what the chipset should do when 2428 // country code is reset) 2429 2430 if (TextUtils.isEmpty(countryCode)) { 2431 log("Ignoring resetting of country code"); 2432 } else { 2433 // if mCountryCodeSequence == 0, it is the first time to set country code, always set 2434 // else only when the new country code is different from the current one to set 2435 int countryCodeSequence = mCountryCodeSequence.get(); 2436 if(countryCodeSequence == 0 || countryCode.equals(mSetCountryCode) == false) { 2437 2438 countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 2439 mSetCountryCode = countryCode; 2440 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, 2441 countryCode); 2442 } 2443 2444 if (persist) { 2445 Settings.Global.putString(mContext.getContentResolver(), 2446 Settings.Global.WIFI_COUNTRY_CODE, 2447 countryCode); 2448 } 2449 } 2450 } 2451 2452 /** 2453 * Get the country code 2454 * @param countryCode following ISO 3166 format 2455 */ 2456 public String getCountryCode() { 2457 return mSetCountryCode; 2458 } 2459 2460 2461 /** 2462 * Set the operational frequency band 2463 * @param band 2464 * @param persist {@code true} if the setting should be remembered. 2465 */ 2466 public void setFrequencyBand(int band, boolean persist) { 2467 if (persist) { 2468 Settings.Global.putInt(mContext.getContentResolver(), 2469 Settings.Global.WIFI_FREQUENCY_BAND, 2470 band); 2471 } 2472 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 2473 } 2474 2475 /** 2476 * Enable TDLS for a specific MAC address 2477 */ 2478 public void enableTdls(String remoteMacAddress, boolean enable) { 2479 int enabler = enable ? 1 : 0; 2480 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 2481 } 2482 2483 /** 2484 * Returns the operational frequency band 2485 */ 2486 public int getFrequencyBand() { 2487 return mFrequencyBand.get(); 2488 } 2489 2490 /** 2491 * Returns the wifi configuration file 2492 */ 2493 public String getConfigFile() { 2494 return mWifiConfigStore.getConfigFile(); 2495 } 2496 2497 /** 2498 * Send a message indicating bluetooth adapter connection state changed 2499 */ 2500 public void sendBluetoothAdapterStateChange(int state) { 2501 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 2502 } 2503 2504 /** 2505 * Send a message indicating a package has been uninstalled. 2506 */ 2507 public void removeAppConfigs(String packageName, int uid) { 2508 // Build partial AppInfo manually - package may not exist in database any more 2509 ApplicationInfo ai = new ApplicationInfo(); 2510 ai.packageName = packageName; 2511 ai.uid = uid; 2512 sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai); 2513 } 2514 2515 /** 2516 * Send a message indicating a user has been removed. 2517 */ 2518 public void removeUserConfigs(int userId) { 2519 sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId); 2520 } 2521 2522 /** 2523 * Save configuration on supplicant 2524 * 2525 * @return {@code true} if the operation succeeds, {@code false} otherwise 2526 * 2527 * TODO: deprecate this 2528 */ 2529 public boolean syncSaveConfig(AsyncChannel channel) { 2530 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 2531 boolean result = (resultMsg.arg1 != FAILURE); 2532 resultMsg.recycle(); 2533 return result; 2534 } 2535 2536 public void updateBatteryWorkSource(WorkSource newSource) { 2537 synchronized (mRunningWifiUids) { 2538 try { 2539 if (newSource != null) { 2540 mRunningWifiUids.set(newSource); 2541 } 2542 if (mIsRunning) { 2543 if (mReportedRunning) { 2544 // If the work source has changed since last time, need 2545 // to remove old work from battery stats. 2546 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 2547 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 2548 mRunningWifiUids); 2549 mLastRunningWifiUids.set(mRunningWifiUids); 2550 } 2551 } else { 2552 // Now being started, report it. 2553 mBatteryStats.noteWifiRunning(mRunningWifiUids); 2554 mLastRunningWifiUids.set(mRunningWifiUids); 2555 mReportedRunning = true; 2556 } 2557 } else { 2558 if (mReportedRunning) { 2559 // Last reported we were running, time to stop. 2560 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 2561 mLastRunningWifiUids.clear(); 2562 mReportedRunning = false; 2563 } 2564 } 2565 mWakeLock.setWorkSource(newSource); 2566 } catch (RemoteException ignore) { 2567 } 2568 } 2569 } 2570 2571 @Override 2572 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2573 super.dump(fd, pw, args); 2574 mSupplicantStateTracker.dump(fd, pw, args); 2575 pw.println("mLinkProperties " + mLinkProperties); 2576 pw.println("mWifiInfo " + mWifiInfo); 2577 pw.println("mDhcpResults " + mDhcpResults); 2578 pw.println("mNetworkInfo " + mNetworkInfo); 2579 pw.println("mLastSignalLevel " + mLastSignalLevel); 2580 pw.println("mLastBssid " + mLastBssid); 2581 pw.println("mLastNetworkId " + mLastNetworkId); 2582 pw.println("mOperationalMode " + mOperationalMode); 2583 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 2584 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2585 pw.println("Supplicant status " + mWifiNative.status(true)); 2586 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 2587 pw.println("mSetCountryCode " + mSetCountryCode); 2588 pw.println("mDriverSetCountryCode " + mDriverSetCountryCode); 2589 mNetworkFactory.dump(fd, pw, args); 2590 mUntrustedNetworkFactory.dump(fd, pw, args); 2591 pw.println(); 2592 mWifiConfigStore.dump(fd, pw, args); 2593 } 2594 2595 /********************************************************* 2596 * Internal private functions 2597 ********************************************************/ 2598 2599 private void logStateAndMessage(Message message, String state) { 2600 messageHandlingStatus = 0; 2601 if (mLogMessages) { 2602 //long now = SystemClock.elapsedRealtimeNanos(); 2603 //String ts = String.format("[%,d us]", now/1000); 2604 2605 loge( " " + state + " " + getLogRecString(message)); 2606 } 2607 } 2608 2609 /** 2610 * helper, prints the milli time since boot wi and w/o suspended time 2611 */ 2612 String printTime() { 2613 StringBuilder sb = new StringBuilder(); 2614 sb.append(" rt=").append(SystemClock.uptimeMillis()); 2615 sb.append("/").append(SystemClock.elapsedRealtime()); 2616 return sb.toString(); 2617 } 2618 2619 /** 2620 * Return the additional string to be logged by LogRec, default 2621 * 2622 * @param msg that was processed 2623 * @return information to be logged as a String 2624 */ 2625 protected String getLogRecString(Message msg) { 2626 WifiConfiguration config; 2627 Long now; 2628 String report; 2629 String key; 2630 StringBuilder sb = new StringBuilder(); 2631 if (mScreenOn) { 2632 sb.append("!"); 2633 } 2634 if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) { 2635 sb.append("(").append(messageHandlingStatus).append(")"); 2636 } 2637 sb.append(smToString(msg)); 2638 if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) { 2639 sb.append(" uid=" + msg.sendingUid); 2640 } 2641 switch (msg.what) { 2642 case CMD_START_SCAN: 2643 now = System.currentTimeMillis(); 2644 sb.append(" "); 2645 sb.append(Integer.toString(msg.arg1)); 2646 sb.append(" "); 2647 sb.append(Integer.toString(msg.arg2)); 2648 sb.append(" ic="); 2649 sb.append(Integer.toString(sScanAlarmIntentCount)); 2650 if (msg.obj != null) { 2651 Bundle bundle = (Bundle)msg.obj; 2652 Long request = bundle.getLong(SCAN_REQUEST_TIME, 0); 2653 if (request != 0) { 2654 sb.append(" proc(ms):").append(now - request); 2655 } 2656 } 2657 if (mIsScanOngoing) sb.append(" onGoing"); 2658 if (mIsFullScanOngoing) sb.append(" full"); 2659 if (lastStartScanTimeStamp != 0) { 2660 sb.append(" started:").append(lastStartScanTimeStamp); 2661 sb.append(",").append(now - lastStartScanTimeStamp); 2662 } 2663 if (lastScanDuration != 0) { 2664 sb.append(" dur:").append(lastScanDuration); 2665 } 2666 sb.append(" cnt=").append(mDelayedScanCounter); 2667 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2668 sb.append(" f=").append(mWifiInfo.getFrequency()); 2669 sb.append(" sc=").append(mWifiInfo.score); 2670 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2671 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2672 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2673 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2674 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2675 if (lastScanFreqs != null) { 2676 sb.append(" list=").append(lastScanFreqs); 2677 } else { 2678 sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli); 2679 } 2680 report = reportOnTime(); 2681 if (report != null) { 2682 sb.append(" ").append(report); 2683 } 2684 break; 2685 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2686 sb.append(" "); 2687 sb.append(Integer.toString(msg.arg1)); 2688 sb.append(" "); 2689 sb.append(Integer.toString(msg.arg2)); 2690 sb.append(printTime()); 2691 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2692 if (stateChangeResult != null) { 2693 sb.append(stateChangeResult.toString()); 2694 } 2695 break; 2696 case WifiManager.SAVE_NETWORK: 2697 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 2698 sb.append(" "); 2699 sb.append(Integer.toString(msg.arg1)); 2700 sb.append(" "); 2701 sb.append(Integer.toString(msg.arg2)); 2702 if (lastSavedConfigurationAttempt != null) { 2703 sb.append(" ").append(lastSavedConfigurationAttempt.configKey()); 2704 sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId); 2705 if (lastSavedConfigurationAttempt.hiddenSSID) { 2706 sb.append(" hidden"); 2707 } 2708 if (lastSavedConfigurationAttempt.preSharedKey != null 2709 && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) { 2710 sb.append(" hasPSK"); 2711 } 2712 if (lastSavedConfigurationAttempt.ephemeral) { 2713 sb.append(" ephemeral"); 2714 } 2715 if (lastSavedConfigurationAttempt.selfAdded) { 2716 sb.append(" selfAdded"); 2717 } 2718 sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid); 2719 sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid); 2720 } 2721 break; 2722 case WifiManager.FORGET_NETWORK: 2723 sb.append(" "); 2724 sb.append(Integer.toString(msg.arg1)); 2725 sb.append(" "); 2726 sb.append(Integer.toString(msg.arg2)); 2727 if (lastForgetConfigurationAttempt != null) { 2728 sb.append(" ").append(lastForgetConfigurationAttempt.configKey()); 2729 sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId); 2730 if (lastForgetConfigurationAttempt.hiddenSSID) { 2731 sb.append(" hidden"); 2732 } 2733 if (lastForgetConfigurationAttempt.preSharedKey != null) { 2734 sb.append(" hasPSK"); 2735 } 2736 if (lastForgetConfigurationAttempt.ephemeral) { 2737 sb.append(" ephemeral"); 2738 } 2739 if (lastForgetConfigurationAttempt.selfAdded) { 2740 sb.append(" selfAdded"); 2741 } 2742 sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid); 2743 sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid); 2744 sb.append(" ajst=").append(lastForgetConfigurationAttempt.autoJoinStatus); 2745 } 2746 break; 2747 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2748 sb.append(" "); 2749 sb.append(Integer.toString(msg.arg1)); 2750 sb.append(" "); 2751 sb.append(Integer.toString(msg.arg2)); 2752 String bssid = (String)msg.obj; 2753 if (bssid != null && bssid.length()>0) { 2754 sb.append(" "); 2755 sb.append(bssid); 2756 } 2757 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); 2758 sb.append(printTime()); 2759 break; 2760 case WifiMonitor.SCAN_RESULTS_EVENT: 2761 sb.append(" "); 2762 sb.append(Integer.toString(msg.arg1)); 2763 sb.append(" "); 2764 sb.append(Integer.toString(msg.arg2)); 2765 if (mScanResults != null) { 2766 sb.append(" found="); 2767 sb.append(mScanResults.size()); 2768 } 2769 sb.append(" known=").append(mNumScanResultsKnown); 2770 sb.append(" got=").append(mNumScanResultsReturned); 2771 if (lastScanDuration != 0) { 2772 sb.append(" dur:").append(lastScanDuration); 2773 } 2774 if (mOnTime != 0) { 2775 sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan); 2776 sb.append(",").append(mOnTime); 2777 } 2778 if (mTxTime != 0) { 2779 sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan); 2780 sb.append(",").append(mTxTime); 2781 } 2782 if (mRxTime != 0) { 2783 sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan); 2784 sb.append(",").append(mRxTime); 2785 } 2786 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 2787 sb.append(String.format(" con=%d", mConnectionRequests)); 2788 key = mWifiConfigStore.getLastSelectedConfiguration(); 2789 if (key != null) { 2790 sb.append(" last=").append(key); 2791 } 2792 break; 2793 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2794 sb.append(" "); 2795 sb.append(Integer.toString(msg.arg1)); 2796 sb.append(" "); 2797 sb.append(Integer.toString(msg.arg2)); 2798 sb.append(" ").append(mLastBssid); 2799 sb.append(" nid=").append(mLastNetworkId); 2800 config = getCurrentWifiConfiguration(); 2801 if (config != null) { 2802 sb.append(" ").append(config.configKey()); 2803 } 2804 sb.append(printTime()); 2805 key = mWifiConfigStore.getLastSelectedConfiguration(); 2806 if (key != null) { 2807 sb.append(" last=").append(key); 2808 } 2809 break; 2810 case CMD_TARGET_BSSID: 2811 case CMD_ASSOCIATED_BSSID: 2812 sb.append(" "); 2813 sb.append(Integer.toString(msg.arg1)); 2814 sb.append(" "); 2815 sb.append(Integer.toString(msg.arg2)); 2816 if (msg.obj != null) { 2817 sb.append(" BSSID=").append((String)msg.obj); 2818 } 2819 if (mTargetRoamBSSID != null) { 2820 sb.append(" Target=").append(mTargetRoamBSSID); 2821 } 2822 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2823 sb.append(printTime()); 2824 break; 2825 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2826 if (msg.obj != null) { 2827 sb.append(" ").append((String)msg.obj); 2828 } 2829 sb.append(" nid=").append(msg.arg1); 2830 sb.append(" reason=").append(msg.arg2); 2831 if (mLastBssid != null) { 2832 sb.append(" lastbssid=").append(mLastBssid); 2833 } 2834 if (mWifiInfo.getFrequency() != -1) { 2835 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2836 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2837 } 2838 if (linkDebouncing) { 2839 sb.append(" debounce"); 2840 } 2841 sb.append(printTime()); 2842 break; 2843 case WifiMonitor.SSID_TEMP_DISABLED: 2844 case WifiMonitor.SSID_REENABLED: 2845 sb.append(" nid=").append(msg.arg1); 2846 if (msg.obj != null) { 2847 sb.append(" ").append((String)msg.obj); 2848 } 2849 config = getCurrentWifiConfiguration(); 2850 if (config != null) { 2851 sb.append(" cur=").append(config.configKey()); 2852 sb.append(" ajst=").append(config.autoJoinStatus); 2853 if (config.selfAdded) { 2854 sb.append(" selfAdded"); 2855 } 2856 if (config.status != 0) { 2857 sb.append(" st=").append(config.status); 2858 sb.append(" rs=").append(config.disableReason); 2859 } 2860 if (config.lastConnected != 0) { 2861 now = System.currentTimeMillis(); 2862 sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)"); 2863 } 2864 if (mLastBssid != null) { 2865 sb.append(" lastbssid=").append(mLastBssid); 2866 } 2867 if (mWifiInfo.getFrequency() != -1) { 2868 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2869 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2870 sb.append(" bssid=").append(mWifiInfo.getBSSID()); 2871 } 2872 } 2873 sb.append(printTime()); 2874 break; 2875 case CMD_RSSI_POLL: 2876 case CMD_UNWANTED_NETWORK: 2877 case WifiManager.RSSI_PKTCNT_FETCH: 2878 sb.append(" "); 2879 sb.append(Integer.toString(msg.arg1)); 2880 sb.append(" "); 2881 sb.append(Integer.toString(msg.arg2)); 2882 if (mWifiInfo.getSSID() != null) 2883 if (mWifiInfo.getSSID() != null) 2884 sb.append(" ").append(mWifiInfo.getSSID()); 2885 if (mWifiInfo.getBSSID() != null) 2886 sb.append(" ").append(mWifiInfo.getBSSID()); 2887 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2888 sb.append(" f=").append(mWifiInfo.getFrequency()); 2889 sb.append(" sc=").append(mWifiInfo.score); 2890 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2891 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2892 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2893 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2894 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2895 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 2896 report = reportOnTime(); 2897 if (report != null) { 2898 sb.append(" ").append(report); 2899 } 2900 if (wifiScoringReport != null) { 2901 sb.append(wifiScoringReport); 2902 } 2903 break; 2904 case CMD_AUTO_CONNECT: 2905 case WifiManager.CONNECT_NETWORK: 2906 sb.append(" "); 2907 sb.append(Integer.toString(msg.arg1)); 2908 sb.append(" "); 2909 sb.append(Integer.toString(msg.arg2)); 2910 config = (WifiConfiguration) msg.obj; 2911 if (config != null) { 2912 sb.append(" ").append(config.configKey()); 2913 if (config.visibility != null) { 2914 sb.append(" ").append(config.visibility.toString()); 2915 } 2916 } 2917 if (mTargetRoamBSSID != null) { 2918 sb.append(" ").append(mTargetRoamBSSID); 2919 } 2920 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2921 sb.append(printTime()); 2922 config = getCurrentWifiConfiguration(); 2923 if (config != null) { 2924 sb.append(config.configKey()); 2925 if (config.visibility != null) { 2926 sb.append(" ").append(config.visibility.toString()); 2927 } 2928 } 2929 break; 2930 case CMD_AUTO_ROAM: 2931 sb.append(" "); 2932 sb.append(Integer.toString(msg.arg1)); 2933 sb.append(" "); 2934 sb.append(Integer.toString(msg.arg2)); 2935 ScanResult result = (ScanResult)msg.obj; 2936 if (result != null) { 2937 now = System.currentTimeMillis(); 2938 sb.append(" bssid=").append(result.BSSID); 2939 sb.append(" rssi=").append(result.level); 2940 sb.append(" freq=").append(result.frequency); 2941 if (result.seen > 0 && result.seen < now) { 2942 sb.append(" seen=").append(now - result.seen); 2943 } else { 2944 // Somehow the timestamp for this scan result is inconsistent 2945 sb.append(" !seen=").append(result.seen); 2946 } 2947 } 2948 if (mTargetRoamBSSID != null) { 2949 sb.append(" ").append(mTargetRoamBSSID); 2950 } 2951 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2952 sb.append(" fail count=").append(Integer.toString(mRoamFailCount)); 2953 sb.append(printTime()); 2954 break; 2955 case CMD_ADD_OR_UPDATE_NETWORK: 2956 sb.append(" "); 2957 sb.append(Integer.toString(msg.arg1)); 2958 sb.append(" "); 2959 sb.append(Integer.toString(msg.arg2)); 2960 if (msg.obj != null) { 2961 config = (WifiConfiguration)msg.obj; 2962 sb.append(" ").append(config.configKey()); 2963 sb.append(" prio=").append(config.priority); 2964 sb.append(" status=").append(config.status); 2965 if (config.BSSID != null) { 2966 sb.append(" ").append(config.BSSID); 2967 } 2968 WifiConfiguration curConfig = getCurrentWifiConfiguration(); 2969 if (curConfig != null) { 2970 if (curConfig.configKey().equals(config.configKey())) { 2971 sb.append(" is current"); 2972 } else { 2973 sb.append(" current=").append(curConfig.configKey()); 2974 sb.append(" prio=").append(curConfig.priority); 2975 sb.append(" status=").append(curConfig.status); 2976 } 2977 } 2978 } 2979 break; 2980 case WifiManager.DISABLE_NETWORK: 2981 case CMD_ENABLE_NETWORK: 2982 sb.append(" "); 2983 sb.append(Integer.toString(msg.arg1)); 2984 sb.append(" "); 2985 sb.append(Integer.toString(msg.arg2)); 2986 key = mWifiConfigStore.getLastSelectedConfiguration(); 2987 if (key != null) { 2988 sb.append(" last=").append(key); 2989 } 2990 config = mWifiConfigStore.getWifiConfiguration(msg.arg1); 2991 if (config != null && (key == null || !config.configKey().equals(key))) { 2992 sb.append(" target=").append(key); 2993 } 2994 break; 2995 case CMD_GET_CONFIGURED_NETWORKS: 2996 sb.append(" "); 2997 sb.append(Integer.toString(msg.arg1)); 2998 sb.append(" "); 2999 sb.append(Integer.toString(msg.arg2)); 3000 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize()); 3001 break; 3002 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3003 sb.append(" "); 3004 sb.append(Integer.toString(msg.arg1)); 3005 sb.append(" "); 3006 sb.append(Integer.toString(msg.arg2)); 3007 sb.append(" txpkts=").append(mWifiInfo.txSuccess); 3008 sb.append(",").append(mWifiInfo.txBad); 3009 sb.append(",").append(mWifiInfo.txRetries); 3010 break; 3011 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3012 sb.append(" "); 3013 sb.append(Integer.toString(msg.arg1)); 3014 sb.append(" "); 3015 sb.append(Integer.toString(msg.arg2)); 3016 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3017 sb.append(" OK "); 3018 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3019 sb.append(" FAIL "); 3020 } 3021 if (mLinkProperties != null) { 3022 if (mLinkProperties.hasIPv4Address()) { 3023 sb.append(" v4"); 3024 } 3025 if (mLinkProperties.hasGlobalIPv6Address()) { 3026 sb.append(" v6"); 3027 } 3028 if (mLinkProperties.hasIPv4DefaultRoute()) { 3029 sb.append(" v4r"); 3030 } 3031 if (mLinkProperties.hasIPv6DefaultRoute()) { 3032 sb.append(" v6r"); 3033 } 3034 if (mLinkProperties.hasIPv4DnsServer()) { 3035 sb.append(" v4dns"); 3036 } 3037 if (mLinkProperties.hasIPv6DnsServer()) { 3038 sb.append(" v6dns"); 3039 } 3040 } 3041 break; 3042 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 3043 sb.append(" "); 3044 sb.append(Integer.toString(msg.arg1)); 3045 sb.append(" "); 3046 sb.append(Integer.toString(msg.arg2)); 3047 if (msg.obj != null) { 3048 NetworkInfo info = (NetworkInfo)msg.obj; 3049 NetworkInfo.State state = info.getState(); 3050 NetworkInfo.DetailedState detailedState = info.getDetailedState(); 3051 if (state != null) { 3052 sb.append(" st=").append(state); 3053 } 3054 if (detailedState != null) { 3055 sb.append("/").append(detailedState); 3056 } 3057 } 3058 break; 3059 case CMD_IP_CONFIGURATION_LOST: 3060 int count = -1; 3061 WifiConfiguration c = getCurrentWifiConfiguration(); 3062 if (c != null) count = c.numIpConfigFailures; 3063 sb.append(" "); 3064 sb.append(Integer.toString(msg.arg1)); 3065 sb.append(" "); 3066 sb.append(Integer.toString(msg.arg2)); 3067 sb.append(" failures: "); 3068 sb.append(Integer.toString(count)); 3069 sb.append("/"); 3070 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries())); 3071 if (mWifiInfo.getBSSID() != null) { 3072 sb.append(" ").append(mWifiInfo.getBSSID()); 3073 } 3074 if (c != null) { 3075 if (c.scanResultCache != null) { 3076 for (ScanResult r : c.scanResultCache.values()) { 3077 if (r.BSSID.equals(mWifiInfo.getBSSID())) { 3078 sb.append(" ipfail=").append(r.numIpConfigFailures); 3079 sb.append(",st=").append(r.autoJoinStatus); 3080 } 3081 } 3082 } 3083 sb.append(" -> ajst=").append(c.autoJoinStatus); 3084 sb.append(" ").append(c.disableReason); 3085 sb.append(" txpkts=").append(mWifiInfo.txSuccess); 3086 sb.append(",").append(mWifiInfo.txBad); 3087 sb.append(",").append(mWifiInfo.txRetries); 3088 } 3089 sb.append(printTime()); 3090 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 3091 break; 3092 case CMD_UPDATE_LINKPROPERTIES: 3093 sb.append(" "); 3094 sb.append(Integer.toString(msg.arg1)); 3095 sb.append(" "); 3096 sb.append(Integer.toString(msg.arg2)); 3097 if (mLinkProperties != null) { 3098 if (mLinkProperties.hasIPv4Address()) { 3099 sb.append(" v4"); 3100 } 3101 if (mLinkProperties.hasGlobalIPv6Address()) { 3102 sb.append(" v6"); 3103 } 3104 if (mLinkProperties.hasIPv4DefaultRoute()) { 3105 sb.append(" v4r"); 3106 } 3107 if (mLinkProperties.hasIPv6DefaultRoute()) { 3108 sb.append(" v6r"); 3109 } 3110 if (mLinkProperties.hasIPv4DnsServer()) { 3111 sb.append(" v4dns"); 3112 } 3113 if (mLinkProperties.hasIPv6DnsServer()) { 3114 sb.append(" v6dns"); 3115 } 3116 } 3117 break; 3118 case CMD_SET_COUNTRY_CODE: 3119 sb.append(" "); 3120 sb.append(Integer.toString(msg.arg1)); 3121 sb.append(" "); 3122 sb.append(Integer.toString(msg.arg2)); 3123 if (msg.obj != null) { 3124 sb.append(" ").append((String)msg.obj); 3125 } 3126 break; 3127 case CMD_ROAM_WATCHDOG_TIMER: 3128 sb.append(" "); 3129 sb.append(Integer.toString(msg.arg1)); 3130 sb.append(" "); 3131 sb.append(Integer.toString(msg.arg2)); 3132 sb.append(" cur=").append(roamWatchdogCount); 3133 break; 3134 case CMD_DISCONNECTING_WATCHDOG_TIMER: 3135 sb.append(" "); 3136 sb.append(Integer.toString(msg.arg1)); 3137 sb.append(" "); 3138 sb.append(Integer.toString(msg.arg2)); 3139 sb.append(" cur=").append(disconnectingWatchdogCount); 3140 break; 3141 default: 3142 sb.append(" "); 3143 sb.append(Integer.toString(msg.arg1)); 3144 sb.append(" "); 3145 sb.append(Integer.toString(msg.arg2)); 3146 break; 3147 } 3148 3149 return sb.toString(); 3150 } 3151 3152 private void handleScreenStateChanged(boolean screenOn, boolean startBackgroundScanIfNeeded) { 3153 mScreenOn = screenOn; 3154 if (PDBG) { 3155 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 3156 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 3157 + " state " + getCurrentState().getName() 3158 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 3159 } 3160 enableRssiPolling(screenOn); 3161 if (screenOn) enableAllNetworks(); 3162 if (mUserWantsSuspendOpt.get()) { 3163 if (screenOn) { 3164 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 3165 } else { 3166 // Allow 2s for suspend optimizations to be set 3167 mSuspendWakeLock.acquire(2000); 3168 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 3169 } 3170 } 3171 mScreenBroadcastReceived.set(true); 3172 3173 getWifiLinkLayerStats(false); 3174 mOnTimeScreenStateChange = mOnTime; 3175 lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate; 3176 mEnableBackgroundScan = false; 3177 cancelDelayedScan(); 3178 3179 if (screenOn) { 3180 setScanAlarm(false); 3181 clearBlacklist(); 3182 3183 fullBandConnectedTimeIntervalMilli = mWifiConfigStore.associatedPartialScanPeriodMilli.get(); 3184 // In either Disconnectedstate or ConnectedState, 3185 // start the scan alarm so as to enable autojoin 3186 if (getCurrentState() == mConnectedState 3187 && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get()) { 3188 // Scan after 500ms 3189 startDelayedScan(500, null, null); 3190 } else if (getCurrentState() == mDisconnectedState) { 3191 // Scan after 200ms 3192 startDelayedScan(200, null, null); 3193 } 3194 } else if (startBackgroundScanIfNeeded) { 3195 // Screen Off and Disconnected and chipset doesn't support scan offload 3196 // => start scan alarm 3197 // Screen Off and Disconnected and chipset does support scan offload 3198 // => will use scan offload (i.e. background scan) 3199 if (!mBackgroundScanSupported) { 3200 setScanAlarm(true); 3201 } else { 3202 mEnableBackgroundScan = true; 3203 } 3204 } 3205 if (DBG) logd("backgroundScan enabled=" + mEnableBackgroundScan 3206 + " startBackgroundScanIfNeeded:" + startBackgroundScanIfNeeded); 3207 if (startBackgroundScanIfNeeded) { 3208 // to scan for them in background, we need all networks enabled 3209 enableBackgroundScan(mEnableBackgroundScan); 3210 } 3211 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 3212 } 3213 3214 private void checkAndSetConnectivityInstance() { 3215 if (mCm == null) { 3216 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 3217 } 3218 } 3219 3220 private boolean startTethering(ArrayList<String> available) { 3221 3222 boolean wifiAvailable = false; 3223 3224 checkAndSetConnectivityInstance(); 3225 3226 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 3227 3228 for (String intf : available) { 3229 for (String regex : wifiRegexs) { 3230 if (intf.matches(regex)) { 3231 3232 InterfaceConfiguration ifcg = null; 3233 try { 3234 ifcg = mNwService.getInterfaceConfig(intf); 3235 if (ifcg != null) { 3236 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 3237 ifcg.setLinkAddress(new LinkAddress( 3238 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 3239 ifcg.setInterfaceUp(); 3240 3241 mNwService.setInterfaceConfig(intf, ifcg); 3242 } 3243 } catch (Exception e) { 3244 loge("Error configuring interface " + intf + ", :" + e); 3245 return false; 3246 } 3247 3248 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 3249 loge("Error tethering on " + intf); 3250 return false; 3251 } 3252 mTetherInterfaceName = intf; 3253 return true; 3254 } 3255 } 3256 } 3257 // We found no interfaces to tether 3258 return false; 3259 } 3260 3261 private void stopTethering() { 3262 3263 checkAndSetConnectivityInstance(); 3264 3265 /* Clear the interface config to allow dhcp correctly configure new 3266 ip settings */ 3267 InterfaceConfiguration ifcg = null; 3268 try { 3269 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 3270 if (ifcg != null) { 3271 ifcg.setLinkAddress( 3272 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 3273 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 3274 } 3275 } catch (Exception e) { 3276 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 3277 } 3278 3279 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 3280 loge("Untether initiate failed!"); 3281 } 3282 } 3283 3284 private boolean isWifiTethered(ArrayList<String> active) { 3285 3286 checkAndSetConnectivityInstance(); 3287 3288 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 3289 for (String intf : active) { 3290 for (String regex : wifiRegexs) { 3291 if (intf.matches(regex)) { 3292 return true; 3293 } 3294 } 3295 } 3296 // We found no interfaces that are tethered 3297 return false; 3298 } 3299 3300 /** 3301 * Set the country code from the system setting value, if any. 3302 */ 3303 private void setCountryCode() { 3304 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 3305 Settings.Global.WIFI_COUNTRY_CODE); 3306 if (countryCode != null && !countryCode.isEmpty()) { 3307 setCountryCode(countryCode, false); 3308 } else { 3309 //use driver default 3310 } 3311 } 3312 3313 /** 3314 * Set the frequency band from the system setting value, if any. 3315 */ 3316 private void setFrequencyBand() { 3317 int band = Settings.Global.getInt(mContext.getContentResolver(), 3318 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 3319 setFrequencyBand(band, false); 3320 } 3321 3322 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 3323 if (DBG) { 3324 log("setSuspendOptimizationsNative: " + reason + " " + enabled 3325 + " -want " + mUserWantsSuspendOpt.get() 3326 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3327 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 3328 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 3329 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 3330 } 3331 //mWifiNative.setSuspendOptimizations(enabled); 3332 3333 if (enabled) { 3334 mSuspendOptNeedsDisabled &= ~reason; 3335 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 3336 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 3337 if (DBG) { 3338 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 3339 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3340 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 3341 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 3342 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 3343 } 3344 mWifiNative.setSuspendOptimizations(true); 3345 } 3346 } else { 3347 mSuspendOptNeedsDisabled |= reason; 3348 mWifiNative.setSuspendOptimizations(false); 3349 } 3350 } 3351 3352 private void setSuspendOptimizations(int reason, boolean enabled) { 3353 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 3354 if (enabled) { 3355 mSuspendOptNeedsDisabled &= ~reason; 3356 } else { 3357 mSuspendOptNeedsDisabled |= reason; 3358 } 3359 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 3360 } 3361 3362 private void setWifiState(int wifiState) { 3363 final int previousWifiState = mWifiState.get(); 3364 3365 try { 3366 if (wifiState == WIFI_STATE_ENABLED) { 3367 mBatteryStats.noteWifiOn(); 3368 } else if (wifiState == WIFI_STATE_DISABLED) { 3369 mBatteryStats.noteWifiOff(); 3370 } 3371 } catch (RemoteException e) { 3372 loge("Failed to note battery stats in wifi"); 3373 } 3374 3375 mWifiState.set(wifiState); 3376 3377 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 3378 3379 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 3380 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3381 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 3382 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 3383 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3384 } 3385 3386 private void setWifiApState(int wifiApState) { 3387 final int previousWifiApState = mWifiApState.get(); 3388 3389 try { 3390 if (wifiApState == WIFI_AP_STATE_ENABLED) { 3391 mBatteryStats.noteWifiOn(); 3392 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 3393 mBatteryStats.noteWifiOff(); 3394 } 3395 } catch (RemoteException e) { 3396 loge("Failed to note battery stats in wifi"); 3397 } 3398 3399 // Update state 3400 mWifiApState.set(wifiApState); 3401 3402 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 3403 3404 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 3405 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3406 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 3407 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 3408 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3409 } 3410 3411 /* 3412 void ageOutScanResults(int age) { 3413 synchronized(mScanResultCache) { 3414 // Trim mScanResults, which prevent WifiStateMachine to return 3415 // obsolete scan results to queriers 3416 long now = System.CurrentTimeMillis(); 3417 for (int i = 0; i < mScanResults.size(); i++) { 3418 ScanResult result = mScanResults.get(i); 3419 if ((result.seen > now || (now - result.seen) > age)) { 3420 mScanResults.remove(i); 3421 } 3422 } 3423 } 3424 }*/ 3425 3426 private static final String IE_STR = "ie="; 3427 private static final String ID_STR = "id="; 3428 private static final String BSSID_STR = "bssid="; 3429 private static final String FREQ_STR = "freq="; 3430 private static final String LEVEL_STR = "level="; 3431 private static final String TSF_STR = "tsf="; 3432 private static final String FLAGS_STR = "flags="; 3433 private static final String SSID_STR = "ssid="; 3434 private static final String DELIMITER_STR = "===="; 3435 private static final String END_STR = "####"; 3436 3437 int emptyScanResultCount = 0; 3438 3439 // Used for matching BSSID strings, at least one characteer must be a non-zero number 3440 private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]"); 3441 3442 /** 3443 * Format: 3444 * 3445 * id=1 3446 * bssid=68:7f:76:d7:1a:6e 3447 * freq=2412 3448 * level=-44 3449 * tsf=1344626243700342 3450 * flags=[WPA2-PSK-CCMP][WPS][ESS] 3451 * ssid=zfdy 3452 * ==== 3453 * id=2 3454 * bssid=68:5f:74:d7:1a:6f 3455 * freq=5180 3456 * level=-73 3457 * tsf=1344626243700373 3458 * flags=[WPA2-PSK-CCMP][WPS][ESS] 3459 * ssid=zuby 3460 * ==== 3461 */ 3462 private void setScanResults() { 3463 mNumScanResultsKnown = 0; 3464 mNumScanResultsReturned = 0; 3465 String bssid = ""; 3466 int level = 0; 3467 int freq = 0; 3468 long tsf = 0; 3469 String flags = ""; 3470 WifiSsid wifiSsid = null; 3471 String scanResults; 3472 String tmpResults; 3473 StringBuffer scanResultsBuf = new StringBuffer(); 3474 int sid = 0; 3475 3476 while (true) { 3477 tmpResults = mWifiNative.scanResults(sid); 3478 if (TextUtils.isEmpty(tmpResults)) break; 3479 scanResultsBuf.append(tmpResults); 3480 scanResultsBuf.append("\n"); 3481 String[] lines = tmpResults.split("\n"); 3482 sid = -1; 3483 for (int i=lines.length - 1; i >= 0; i--) { 3484 if (lines[i].startsWith(END_STR)) { 3485 break; 3486 } else if (lines[i].startsWith(ID_STR)) { 3487 try { 3488 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 3489 } catch (NumberFormatException e) { 3490 // Nothing to do 3491 } 3492 break; 3493 } 3494 } 3495 if (sid == -1) break; 3496 } 3497 3498 // Age out scan results, we return all scan results found in the last 12 seconds, 3499 // and NOT all scan results since last scan. 3500 // ageOutScanResults(12000); 3501 3502 scanResults = scanResultsBuf.toString(); 3503 if (TextUtils.isEmpty(scanResults)) { 3504 emptyScanResultCount++; 3505 if (emptyScanResultCount > 10) { 3506 // If we got too many empty scan results, the current scan cache is stale, 3507 // hence clear it. 3508 mScanResults = new ArrayList<>(); 3509 } 3510 return; 3511 } 3512 3513 emptyScanResultCount = 0; 3514 3515 // note that all these splits and substrings keep references to the original 3516 // huge string buffer while the amount we really want is generally pretty small 3517 // so make copies instead (one example b/11087956 wasted 400k of heap here). 3518 synchronized(mScanResultCache) { 3519 mScanResults = new ArrayList<>(); 3520 String[] lines = scanResults.split("\n"); 3521 final int bssidStrLen = BSSID_STR.length(); 3522 final int flagLen = FLAGS_STR.length(); 3523 String infoElements = null; 3524 List<String> anqpLines = null; 3525 3526 for (String line : lines) { 3527 if (line.startsWith(BSSID_STR)) { 3528 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 3529 } else if (line.startsWith(FREQ_STR)) { 3530 try { 3531 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 3532 } catch (NumberFormatException e) { 3533 freq = 0; 3534 } 3535 } else if (line.startsWith(LEVEL_STR)) { 3536 try { 3537 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 3538 /* some implementations avoid negative values by adding 256 3539 * so we need to adjust for that here. 3540 */ 3541 if (level > 0) level -= 256; 3542 } catch(NumberFormatException e) { 3543 level = 0; 3544 } 3545 } else if (line.startsWith(TSF_STR)) { 3546 try { 3547 tsf = Long.parseLong(line.substring(TSF_STR.length())); 3548 } catch (NumberFormatException e) { 3549 tsf = 0; 3550 } 3551 } else if (line.startsWith(FLAGS_STR)) { 3552 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 3553 } else if (line.startsWith(SSID_STR)) { 3554 wifiSsid = WifiSsid.createFromAsciiEncoded( 3555 line.substring(SSID_STR.length())); 3556 } else if (line.startsWith(IE_STR)) { 3557 infoElements = line; 3558 } else if (SupplicantBridge.isAnqpAttribute(line)) { 3559 if (anqpLines == null) { 3560 anqpLines = new ArrayList<>(); 3561 } 3562 anqpLines.add(line); 3563 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 3564 if (bssid != null) { 3565 try { 3566 NetworkDetail networkDetail = 3567 new NetworkDetail(bssid, infoElements, anqpLines, freq); 3568 3569 String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 3570 if (!xssid.equals(networkDetail.getSSID())) { 3571 Log.d("HS2J", "Inconsistency: SSID: '" + xssid + 3572 "' vs '" + networkDetail.getSSID() + "': " + infoElements); 3573 } 3574 3575 if (networkDetail.hasInterworking()) { 3576 Log.d("HS2J", "HSNwk: '" + networkDetail); 3577 } 3578 3579 ScanDetail scanDetail = mScanResultCache.get(networkDetail); 3580 if (scanDetail != null) { 3581 scanDetail.updateResults(networkDetail, level, wifiSsid, xssid, 3582 flags, freq, tsf); 3583 } else { 3584 scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, 3585 flags, level, freq, tsf); 3586 mScanResultCache.put(networkDetail, scanDetail); 3587 } 3588 3589 mNumScanResultsReturned++; // Keep track of how many scan results we got 3590 // as part of this scan's processing 3591 mScanResults.add(scanDetail); 3592 } 3593 catch (IllegalArgumentException iae) { 3594 Log.d("HS2J", "Failed to parse information elements: " + iae); 3595 } 3596 } 3597 bssid = null; 3598 level = 0; 3599 freq = 0; 3600 tsf = 0; 3601 flags = ""; 3602 wifiSsid = null; 3603 infoElements = null; 3604 anqpLines = null; 3605 } 3606 } 3607 } 3608 3609 boolean attemptAutoJoin = true; 3610 SupplicantState state = mWifiInfo.getSupplicantState(); 3611 String selection = mWifiConfigStore.getLastSelectedConfiguration(); 3612 if (getCurrentState() == mRoamingState 3613 || getCurrentState() == mObtainingIpState 3614 || getCurrentState() == mScanModeState 3615 || getCurrentState() == mDisconnectingState 3616 || (getCurrentState() == mConnectedState 3617 && !mWifiConfigStore.enableAutoJoinWhenAssociated.get()) 3618 || linkDebouncing 3619 || state == SupplicantState.ASSOCIATING 3620 || state == SupplicantState.AUTHENTICATING 3621 || state == SupplicantState.FOUR_WAY_HANDSHAKE 3622 || state == SupplicantState.GROUP_HANDSHAKE 3623 || (/* keep autojoin enabled if user has manually selected a wifi network, 3624 so as to make sure we reliably remain connected to this network */ 3625 mConnectionRequests == 0 && selection == null)) { 3626 // Dont attempt auto-joining again while we are already attempting to join 3627 // and/or obtaining Ip address 3628 attemptAutoJoin = false; 3629 } 3630 if (DBG) { 3631 if (selection == null) { 3632 selection = "<none>"; 3633 } 3634 loge("wifi setScanResults state" + getCurrentState() 3635 + " sup_state=" + state 3636 + " debouncing=" + linkDebouncing 3637 + " mConnectionRequests=" + mConnectionRequests 3638 + " selection=" + selection); 3639 } 3640 if (attemptAutoJoin) { 3641 messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED; 3642 } 3643 // Loose last selected configuration if we have been disconnected for 5 minutes 3644 if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) { 3645 mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 3646 } 3647 3648 if (mWifiConfigStore.enableAutoJoinWhenAssociated.get()) { 3649 synchronized(mScanResultCache) { 3650 // AutoJoincontroller will directly acces the scan result list and update it with 3651 // ScanResult status 3652 mNumScanResultsKnown = mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin); 3653 } 3654 } 3655 if (linkDebouncing) { 3656 // If debouncing, we dont re-select a SSID or BSSID hence 3657 // there is no need to call the network selection code 3658 // in WifiAutoJoinController, instead, 3659 // just try to reconnect to the same SSID by triggering a roam 3660 sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null); 3661 } 3662 } 3663 3664 /* 3665 * Fetch RSSI, linkspeed, and frequency on current connection 3666 */ 3667 private void fetchRssiLinkSpeedAndFrequencyNative() { 3668 int newRssi = -1; 3669 int newLinkSpeed = -1; 3670 int newFrequency = -1; 3671 3672 String signalPoll = mWifiNative.signalPoll(); 3673 3674 if (signalPoll != null) { 3675 String[] lines = signalPoll.split("\n"); 3676 for (String line : lines) { 3677 String[] prop = line.split("="); 3678 if (prop.length < 2) continue; 3679 try { 3680 if (prop[0].equals("RSSI")) { 3681 newRssi = Integer.parseInt(prop[1]); 3682 } else if (prop[0].equals("LINKSPEED")) { 3683 newLinkSpeed = Integer.parseInt(prop[1]); 3684 } else if (prop[0].equals("FREQUENCY")) { 3685 newFrequency = Integer.parseInt(prop[1]); 3686 } 3687 } catch (NumberFormatException e) { 3688 //Ignore, defaults on rssi and linkspeed are assigned 3689 } 3690 } 3691 } 3692 3693 if (PDBG) { 3694 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 3695 + Integer.toString(newRssi) + " linkspeed=" 3696 + Integer.toString(newLinkSpeed)); 3697 } 3698 3699 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 3700 // screen out invalid values 3701 /* some implementations avoid negative values by adding 256 3702 * so we need to adjust for that here. 3703 */ 3704 if (newRssi > 0) newRssi -= 256; 3705 mWifiInfo.setRssi(newRssi); 3706 /* 3707 * Rather then sending the raw RSSI out every time it 3708 * changes, we precalculate the signal level that would 3709 * be displayed in the status bar, and only send the 3710 * broadcast if that much more coarse-grained number 3711 * changes. This cuts down greatly on the number of 3712 * broadcasts, at the cost of not informing others 3713 * interested in RSSI of all the changes in signal 3714 * level. 3715 */ 3716 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 3717 if (newSignalLevel != mLastSignalLevel) { 3718 sendRssiChangeBroadcast(newRssi); 3719 } 3720 mLastSignalLevel = newSignalLevel; 3721 } else { 3722 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 3723 } 3724 3725 if (newLinkSpeed != -1) { 3726 mWifiInfo.setLinkSpeed(newLinkSpeed); 3727 } 3728 if (newFrequency > 0) { 3729 if (ScanResult.is5GHz(newFrequency)) { 3730 mWifiConnectionStatistics.num5GhzConnected++; 3731 } 3732 if (ScanResult.is24GHz(newFrequency)) { 3733 mWifiConnectionStatistics.num24GhzConnected++; 3734 } 3735 mWifiInfo.setFrequency(newFrequency); 3736 } 3737 mWifiConfigStore.updateConfiguration(mWifiInfo); 3738 } 3739 3740 /** 3741 * Determine if we need to switch network: 3742 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 3743 * - match the uregncy of the switch versus the packet usage at the interface 3744 */ 3745 boolean shouldSwitchNetwork(int networkDelta) { 3746 int delta; 3747 if (networkDelta <= 0) { 3748 return false; 3749 } 3750 delta = networkDelta; 3751 if (mWifiInfo != null) { 3752 if (!mWifiConfigStore.enableAutoJoinWhenAssociated.get() 3753 && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3754 // If AutoJoin while associated is not enabled, 3755 // we should never switch network when already associated 3756 delta = -1000; 3757 } else { 3758 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present 3759 // TODO: at the interface. We should also discriminate between ucast and mcast, 3760 // TODO: since the rxSuccessRate include all the bonjour and Ipv6 3761 // TODO: broadcasts 3762 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 3763 delta -= 999; 3764 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 3765 delta -= 6; 3766 } 3767 loge("WifiStateMachine shouldSwitchNetwork " 3768 + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 3769 + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 3770 + " delta " + networkDelta + " -> " + delta); 3771 } 3772 } else { 3773 loge("WifiStateMachine shouldSwitchNetwork " 3774 + " delta " + networkDelta + " -> " + delta); 3775 } 3776 if (delta > 0) { 3777 return true; 3778 } 3779 return false; 3780 } 3781 3782 // Polling has completed, hence we wont have a score anymore 3783 private void cleanWifiScore() { 3784 mWifiInfo.txBadRate = 0; 3785 mWifiInfo.txSuccessRate = 0; 3786 mWifiInfo.txRetriesRate = 0; 3787 mWifiInfo.rxSuccessRate = 0; 3788 } 3789 3790 int mBadLinkspeedcount = 0; 3791 3792 // For debug, provide information about the last scoring operation 3793 String wifiScoringReport = null; 3794 private void calculateWifiScore(WifiLinkLayerStats stats) { 3795 StringBuilder sb = new StringBuilder(); 3796 3797 int score = 56; // Starting score, temporarily hardcoded in between 50 and 60 3798 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 3799 && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24) 3800 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() 3801 < mWifiConfigStore.badLinkSpeed5); 3802 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 3803 && mWifiInfo.getLinkSpeed() >= mWifiConfigStore.goodLinkSpeed24) 3804 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() 3805 >= mWifiConfigStore.goodLinkSpeed5); 3806 3807 if (isBadLinkspeed) { 3808 if (mBadLinkspeedcount < 6) 3809 mBadLinkspeedcount++; 3810 } else { 3811 if (mBadLinkspeedcount > 0) 3812 mBadLinkspeedcount--; 3813 } 3814 3815 if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")"); 3816 if (isGoodLinkspeed) sb.append(" gl"); 3817 3818 /** 3819 * We want to make sure that we use the 24GHz RSSI thresholds if 3820 * there are 2.4GHz scan results 3821 * otherwise we end up lowering the score based on 5GHz values 3822 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 3823 * We also might unblacklist the configuation based on 2.4GHz 3824 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 3825 */ 3826 boolean use24Thresholds = false; 3827 boolean homeNetworkBoost = false; 3828 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 3829 if (currentConfiguration != null 3830 && currentConfiguration.scanResultCache != null) { 3831 currentConfiguration.setVisibility(12000); 3832 if (currentConfiguration.visibility != null) { 3833 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 3834 && currentConfiguration.visibility.rssi24 3835 >= (currentConfiguration.visibility.rssi5-2)) { 3836 use24Thresholds = true; 3837 } 3838 } 3839 if (currentConfiguration.scanResultCache.size() <= 6 3840 && currentConfiguration.allowedKeyManagement.cardinality() == 1 3841 && currentConfiguration.allowedKeyManagement. 3842 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 3843 // A PSK network with less than 6 known BSSIDs 3844 // This is most likely a home network and thus we want to stick to wifi more 3845 homeNetworkBoost = true; 3846 } 3847 } 3848 if (homeNetworkBoost) sb.append(" hn"); 3849 if (use24Thresholds) sb.append(" u24"); 3850 3851 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 3852 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 3853 sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover)); 3854 3855 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 3856 3857 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get()) 3858 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get()); 3859 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get()) 3860 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get()); 3861 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get()) 3862 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get()); 3863 3864 if (isBadRSSI) sb.append(" br"); 3865 if (isLowRSSI) sb.append(" lr"); 3866 if (isHighRSSI) sb.append(" hr"); 3867 3868 int penalizedDueToUserTriggeredDisconnect = 0; // For debug information 3869 if (currentConfiguration!= null && 3870 (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) { 3871 if (isBadRSSI) { 3872 currentConfiguration.numTicksAtBadRSSI++; 3873 if (currentConfiguration.numTicksAtBadRSSI > 1000) { 3874 // We remained associated for a compound amount of time while passing 3875 // traffic, hence loose the corresponding user triggered disabled stats 3876 if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) { 3877 currentConfiguration.numUserTriggeredWifiDisableBadRSSI--; 3878 } 3879 if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) { 3880 currentConfiguration.numUserTriggeredWifiDisableLowRSSI--; 3881 } 3882 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 3883 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 3884 } 3885 currentConfiguration.numTicksAtBadRSSI = 0; 3886 } 3887 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 3888 (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0 3889 || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0 3890 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) { 3891 score = score -5; 3892 penalizedDueToUserTriggeredDisconnect = 1; 3893 sb.append(" p1"); 3894 } 3895 } else if (isLowRSSI) { 3896 currentConfiguration.numTicksAtLowRSSI++; 3897 if (currentConfiguration.numTicksAtLowRSSI > 1000) { 3898 // We remained associated for a compound amount of time while passing 3899 // traffic, hence loose the corresponding user triggered disabled stats 3900 if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) { 3901 currentConfiguration.numUserTriggeredWifiDisableLowRSSI--; 3902 } 3903 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 3904 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 3905 } 3906 currentConfiguration.numTicksAtLowRSSI = 0; 3907 } 3908 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 3909 (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0 3910 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) { 3911 score = score -5; 3912 penalizedDueToUserTriggeredDisconnect = 2; 3913 sb.append(" p2"); 3914 } 3915 } else if (!isHighRSSI) { 3916 currentConfiguration.numTicksAtNotHighRSSI++; 3917 if (currentConfiguration.numTicksAtNotHighRSSI > 1000) { 3918 // We remained associated for a compound amount of time while passing 3919 // traffic, hence loose the corresponding user triggered disabled stats 3920 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 3921 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 3922 } 3923 currentConfiguration.numTicksAtNotHighRSSI = 0; 3924 } 3925 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 3926 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 3927 score = score -5; 3928 penalizedDueToUserTriggeredDisconnect = 3; 3929 sb.append(" p3"); 3930 } 3931 } 3932 sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI, 3933 currentConfiguration.numTicksAtLowRSSI, 3934 currentConfiguration.numTicksAtNotHighRSSI)); 3935 } 3936 3937 if (PDBG) { 3938 String rssiStatus = ""; 3939 if (isBadRSSI) rssiStatus += " badRSSI "; 3940 else if (isHighRSSI) rssiStatus += " highRSSI "; 3941 else if (isLowRSSI) rssiStatus += " lowRSSI "; 3942 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 3943 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 3944 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 3945 + " score=" + Integer.toString(mWifiInfo.score) 3946 + rssiStatus 3947 + " -> txbadrate=" + String.format( "%.2f", mWifiInfo.txBadRate ) 3948 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 3949 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 3950 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 3951 + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect); 3952 } 3953 3954 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 3955 && (isBadRSSI || isLowRSSI)) { 3956 // Link is stuck 3957 if (mWifiInfo.linkStuckCount < 5) 3958 mWifiInfo.linkStuckCount += 1; 3959 sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount)); 3960 if (PDBG) loge(" bad link -> stuck count =" 3961 + Integer.toString(mWifiInfo.linkStuckCount)); 3962 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 3963 if (mWifiInfo.linkStuckCount > 0) 3964 mWifiInfo.linkStuckCount -= 1; 3965 sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount)); 3966 if (PDBG) loge(" good link -> stuck count =" 3967 + Integer.toString(mWifiInfo.linkStuckCount)); 3968 } 3969 3970 sb.append(String.format(" [%d", score)); 3971 3972 if (mWifiInfo.linkStuckCount > 1) { 3973 // Once link gets stuck for more than 3 seconds, start reducing the score 3974 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 3975 } 3976 sb.append(String.format(",%d", score)); 3977 3978 if (isBadLinkspeed) { 3979 score -= 4 ; 3980 if (PDBG) { 3981 loge(" isBadLinkspeed ---> count=" + mBadLinkspeedcount 3982 + " score=" + Integer.toString(score)); 3983 } 3984 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 3985 score += 4; // So as bad rssi alone dont kill us 3986 } 3987 sb.append(String.format(",%d", score)); 3988 3989 if (isBadRSSI) { 3990 if (mWifiInfo.badRssiCount < 7) 3991 mWifiInfo.badRssiCount += 1; 3992 } else if (isLowRSSI) { 3993 mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1 3994 if (mWifiInfo.badRssiCount > 0) { 3995 // Decrement bad Rssi count 3996 mWifiInfo.badRssiCount -= 1; 3997 } 3998 } else { 3999 mWifiInfo.badRssiCount = 0; 4000 mWifiInfo.lowRssiCount = 0; 4001 } 4002 4003 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount ; 4004 sb.append(String.format(",%d", score)); 4005 4006 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 4007 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 4008 + " --> score " + Integer.toString(score)); 4009 4010 4011 if (isHighRSSI) { 4012 score += 5; 4013 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 4014 } 4015 sb.append(String.format(",%d]", score)); 4016 4017 sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount)); 4018 4019 //sanitize boundaries 4020 if (score > NetworkAgent.WIFI_BASE_SCORE) 4021 score = NetworkAgent.WIFI_BASE_SCORE; 4022 if (score < 0) 4023 score = 0; 4024 4025 //report score 4026 if (score != mWifiInfo.score) { 4027 if (DBG) { 4028 loge("calculateWifiScore() report new score " + Integer.toString(score)); 4029 } 4030 mWifiInfo.score = score; 4031 if (mNetworkAgent != null) { 4032 mNetworkAgent.sendNetworkScore(score); 4033 } 4034 } 4035 wifiScoringReport = sb.toString(); 4036 } 4037 4038 public double getTxPacketRate() { 4039 if (mWifiInfo != null) { 4040 return mWifiInfo.txSuccessRate; 4041 } 4042 return -1; 4043 } 4044 4045 public double getRxPacketRate() { 4046 if (mWifiInfo != null) { 4047 return mWifiInfo.rxSuccessRate; 4048 } 4049 return -1; 4050 } 4051 4052 /** 4053 * Fetch TX packet counters on current connection 4054 */ 4055 private void fetchPktcntNative(RssiPacketCountInfo info) { 4056 String pktcntPoll = mWifiNative.pktcntPoll(); 4057 4058 if (pktcntPoll != null) { 4059 String[] lines = pktcntPoll.split("\n"); 4060 for (String line : lines) { 4061 String[] prop = line.split("="); 4062 if (prop.length < 2) continue; 4063 try { 4064 if (prop[0].equals("TXGOOD")) { 4065 info.txgood = Integer.parseInt(prop[1]); 4066 } else if (prop[0].equals("TXBAD")) { 4067 info.txbad = Integer.parseInt(prop[1]); 4068 } 4069 } catch (NumberFormatException e) { 4070 // Ignore 4071 } 4072 } 4073 } 4074 } 4075 4076 private boolean clearIPv4Address(String iface) { 4077 try { 4078 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 4079 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 4080 mNwService.setInterfaceConfig(iface, ifcg); 4081 return true; 4082 } catch (RemoteException e) { 4083 return false; 4084 } 4085 } 4086 4087 private boolean isProvisioned(LinkProperties lp) { 4088 return lp.isProvisioned() || 4089 (mWifiConfigStore.isUsingStaticIp(mLastNetworkId) && lp.hasIPv4Address()); 4090 } 4091 4092 /** 4093 * Updates mLinkProperties by merging information from various sources. 4094 * 4095 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 4096 * netlink, static configuration, ...). When one of these sources of information has updated 4097 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 4098 * information that came from other sources. Instead, when one of those sources has new 4099 * information, we update the object that tracks the information from that source and then 4100 * call this method to apply the change to mLinkProperties. 4101 * 4102 * The information in mLinkProperties is currently obtained as follows: 4103 * - Interface name: set in the constructor. 4104 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 4105 * - IPv4 routes, DNS servers, and domains: DHCP. 4106 * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker. 4107 * - HTTP proxy: the wifi config store. 4108 */ 4109 private void updateLinkProperties(int reason) { 4110 LinkProperties newLp = new LinkProperties(); 4111 4112 // Interface name and proxy are locally configured. 4113 newLp.setInterfaceName(mInterfaceName); 4114 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 4115 4116 // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink. 4117 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 4118 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 4119 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 4120 newLp.addRoute(route); 4121 } 4122 for (InetAddress dns : netlinkLinkProperties.getDnsServers()) { 4123 newLp.addDnsServer(dns); 4124 } 4125 4126 // IPv4 routes, DNS servers and domains come from mDhcpResults. 4127 synchronized (mDhcpResultsLock) { 4128 // Even when we're using static configuration, we don't need to look at the config 4129 // store, because static IP configuration also populates mDhcpResults. 4130 if ((mDhcpResults != null)) { 4131 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) { 4132 newLp.addRoute(route); 4133 } 4134 for (InetAddress dns : mDhcpResults.dnsServers) { 4135 newLp.addDnsServer(dns); 4136 } 4137 newLp.setDomains(mDhcpResults.domains); 4138 } 4139 } 4140 4141 final boolean linkChanged = !newLp.equals(mLinkProperties); 4142 final boolean wasProvisioned = isProvisioned(mLinkProperties); 4143 final boolean isProvisioned = isProvisioned(newLp); 4144 final boolean lostIPv4Provisioning = 4145 mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address(); 4146 final DetailedState detailedState = getNetworkDetailedState(); 4147 4148 if (linkChanged) { 4149 if (DBG) { 4150 log("Link configuration changed for netId: " + mLastNetworkId 4151 + " old: " + mLinkProperties + " new: " + newLp); 4152 } 4153 mLinkProperties = newLp; 4154 if (TextUtils.isEmpty(mTcpBufferSizes) == false) { 4155 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes); 4156 } 4157 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 4158 } 4159 4160 if (DBG) { 4161 StringBuilder sb = new StringBuilder(); 4162 sb.append("updateLinkProperties nid: " + mLastNetworkId); 4163 sb.append(" state: " + detailedState); 4164 sb.append(" reason: " + smToString(reason)); 4165 4166 if (mLinkProperties != null) { 4167 if (mLinkProperties.hasIPv4Address()) { 4168 sb.append(" v4"); 4169 } 4170 if (mLinkProperties.hasGlobalIPv6Address()) { 4171 sb.append(" v6"); 4172 } 4173 if (mLinkProperties.hasIPv4DefaultRoute()) { 4174 sb.append(" v4r"); 4175 } 4176 if (mLinkProperties.hasIPv6DefaultRoute()) { 4177 sb.append(" v6r"); 4178 } 4179 if (mLinkProperties.hasIPv4DnsServer()) { 4180 sb.append(" v4dns"); 4181 } 4182 if (mLinkProperties.hasIPv6DnsServer()) { 4183 sb.append(" v6dns"); 4184 } 4185 if (isProvisioned) { 4186 sb.append(" isprov"); 4187 } 4188 } 4189 loge(sb.toString()); 4190 } 4191 4192 // If we just configured or lost IP configuration, do the needful. 4193 // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost() 4194 // here because those should only be called if we're attempting to connect or already 4195 // connected, whereas updateLinkProperties can be called at any time. 4196 switch (reason) { 4197 case DhcpStateMachine.DHCP_SUCCESS: 4198 case CMD_STATIC_IP_SUCCESS: 4199 // IPv4 provisioning succeded. Advance to connected state. 4200 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4201 if (!isProvisioned) { 4202 // Can never happen unless DHCP reports success but isProvisioned thinks the 4203 // resulting configuration is invalid (e.g., no IPv4 address, or the state in 4204 // mLinkProperties is out of sync with reality, or there's a bug in this code). 4205 // TODO: disconnect here instead. If our configuration is not usable, there's no 4206 // point in staying connected, and if mLinkProperties is out of sync with 4207 // reality, that will cause problems in the future. 4208 loge("IPv4 config succeeded, but not provisioned"); 4209 } 4210 break; 4211 4212 case DhcpStateMachine.DHCP_FAILURE: 4213 // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it, 4214 // give up and disconnect. 4215 // If we're already provisioned (e.g., IPv6-only network), stay connected. 4216 if (!isProvisioned || lostIPv4Provisioning) { 4217 sendMessage(CMD_IP_CONFIGURATION_LOST); 4218 } else { 4219 // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). 4220 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4221 4222 // To be sure we don't get stuck with a non-working network if all we had is 4223 // IPv4, remove the IPv4 address from the interface (since we're using DHCP, 4224 // and DHCP failed). If we had an IPv4 address before, the deletion of the 4225 // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was 4226 // necessary for provisioning, its deletion will cause us to disconnect. 4227 // 4228 // This shouldn't be needed, because on an IPv4-only network a DHCP failure will 4229 // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will 4230 // not return true if we're using DHCP and don't have an IPv4 default route. So 4231 // for now it's only here for extra redundancy. However, it will increase 4232 // robustness if we move to getting IPv4 routes from netlink as well. 4233 loge("DHCP failure: provisioned, clearing IPv4 address."); 4234 if (!clearIPv4Address(mInterfaceName)) { 4235 sendMessage(CMD_IP_CONFIGURATION_LOST); 4236 } 4237 } 4238 break; 4239 4240 case CMD_STATIC_IP_FAILURE: 4241 // Static configuration was invalid, or an error occurred in applying it. Give up. 4242 sendMessage(CMD_IP_CONFIGURATION_LOST); 4243 break; 4244 4245 case CMD_UPDATE_LINKPROPERTIES: 4246 // IP addresses, DNS servers, etc. changed. Act accordingly. 4247 if (wasProvisioned && !isProvisioned) { 4248 // We no longer have a usable network configuration. Disconnect. 4249 sendMessage(CMD_IP_CONFIGURATION_LOST); 4250 } else if (!wasProvisioned && isProvisioned) { 4251 // We have a usable IPv6-only config. Advance to connected state. 4252 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4253 } 4254 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) { 4255 // If anything has changed and we're already connected, send out a notification. 4256 sendLinkConfigurationChangedBroadcast(); 4257 } 4258 break; 4259 } 4260 } 4261 4262 /** 4263 * Clears all our link properties. 4264 */ 4265 private void clearLinkProperties() { 4266 // Clear the link properties obtained from DHCP and netlink. 4267 synchronized (mDhcpResultsLock) { 4268 if (mDhcpResults != null) { 4269 mDhcpResults.clear(); 4270 } 4271 } 4272 mNetlinkTracker.clearLinkProperties(); 4273 4274 // Now clear the merged link properties. 4275 mLinkProperties.clear(); 4276 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 4277 } 4278 4279 /** 4280 * try to update default route MAC address. 4281 */ 4282 private String updateDefaultRouteMacAddress(int timeout) { 4283 String address = null; 4284 for (RouteInfo route : mLinkProperties.getRoutes()) { 4285 if (route.isDefaultRoute() && route.hasGateway()) { 4286 InetAddress gateway = route.getGateway(); 4287 if (gateway instanceof Inet4Address) { 4288 if (PDBG) { 4289 loge("updateDefaultRouteMacAddress found Ipv4 default :" 4290 + gateway.getHostAddress()); 4291 } 4292 address = macAddressFromRoute(gateway.getHostAddress()); 4293 /* The gateway's MAC address is known */ 4294 if ((address == null) && (timeout > 0)) { 4295 boolean reachable = false; 4296 try { 4297 reachable = gateway.isReachable(timeout); 4298 } catch (Exception e) { 4299 loge("updateDefaultRouteMacAddress exception reaching :" 4300 + gateway.getHostAddress()); 4301 4302 } finally { 4303 if (reachable == true) { 4304 4305 address = macAddressFromRoute(gateway.getHostAddress()); 4306 if (PDBG) { 4307 loge("updateDefaultRouteMacAddress reachable (tried again) :" 4308 + gateway.getHostAddress() + " found " + address); 4309 } 4310 } 4311 } 4312 } 4313 if (address != null) { 4314 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 4315 } 4316 } 4317 } 4318 } 4319 return address; 4320 } 4321 4322 private void sendScanResultsAvailableBroadcast() { 4323 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 4324 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4325 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4326 } 4327 4328 private void sendRssiChangeBroadcast(final int newRssi) { 4329 try { 4330 mBatteryStats.noteWifiRssiChanged(newRssi); 4331 } catch (RemoteException e) { 4332 // Won't happen. 4333 } 4334 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 4335 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4336 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 4337 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4338 } 4339 4340 private void sendNetworkStateChangeBroadcast(String bssid) { 4341 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 4342 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4343 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 4344 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 4345 if (bssid != null) 4346 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 4347 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 4348 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 4349 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 4350 } 4351 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4352 } 4353 4354 private void sendLinkConfigurationChangedBroadcast() { 4355 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 4356 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4357 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 4358 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4359 } 4360 4361 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 4362 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 4363 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4364 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 4365 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4366 } 4367 4368 /** 4369 * Record the detailed state of a network. 4370 * @param state the new {@code DetailedState} 4371 */ 4372 private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) { 4373 boolean hidden = false; 4374 4375 if (linkDebouncing || isRoaming()) { 4376 // There is generally a confusion in the system about colluding 4377 // WiFi Layer 2 state (as reported by supplicant) and the Network state 4378 // which leads to multiple confusion. 4379 // 4380 // If link is de-bouncing or roaming, we already have an IP address 4381 // as well we were connected and are doing L2 cycles of 4382 // reconnecting or renewing IP address to check that we still have it 4383 // This L2 link flapping should ne be reflected into the Network state 4384 // which is the state of the WiFi Network visible to Layer 3 and applications 4385 // Note that once debouncing and roaming are completed, we will 4386 // set the Network state to where it should be, or leave it as unchanged 4387 // 4388 hidden = true; 4389 } 4390 if (DBG) { 4391 log("setDetailed state, old =" 4392 + mNetworkInfo.getDetailedState() + " and new state=" + state 4393 + " hidden=" + hidden); 4394 } 4395 if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null) { 4396 // Always indicate that SSID has changed 4397 if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) { 4398 if (DBG) { 4399 log("setDetailed state send new extra info" + mWifiInfo.getSSID()); 4400 } 4401 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID()); 4402 sendNetworkStateChangeBroadcast(null); 4403 } 4404 } 4405 if (hidden == true) { 4406 return false; 4407 } 4408 4409 if (state != mNetworkInfo.getDetailedState()) { 4410 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 4411 if (mNetworkAgent != null) { 4412 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4413 } 4414 sendNetworkStateChangeBroadcast(null); 4415 return true; 4416 } 4417 return false; 4418 } 4419 4420 private DetailedState getNetworkDetailedState() { 4421 return mNetworkInfo.getDetailedState(); 4422 } 4423 4424 private SupplicantState handleSupplicantStateChange(Message message) { 4425 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4426 SupplicantState state = stateChangeResult.state; 4427 // Supplicant state change 4428 // [31-13] Reserved for future use 4429 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 4430 // 50023 supplicant_state_changed (custom|1|5) 4431 mWifiInfo.setSupplicantState(state); 4432 // Network id is only valid when we start connecting 4433 if (SupplicantState.isConnecting(state)) { 4434 mWifiInfo.setNetworkId(stateChangeResult.networkId); 4435 } else { 4436 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 4437 } 4438 4439 mWifiInfo.setBSSID(stateChangeResult.BSSID); 4440 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 4441 4442 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 4443 4444 return state; 4445 } 4446 4447 /** 4448 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 4449 * using the interface, stopping DHCP & disabling interface 4450 */ 4451 private void handleNetworkDisconnect() { 4452 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 4453 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 4454 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 4455 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 4456 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 4457 4458 4459 clearCurrentConfigBSSID("handleNetworkDisconnect"); 4460 4461 stopDhcp(); 4462 4463 try { 4464 mNwService.clearInterfaceAddresses(mInterfaceName); 4465 mNwService.disableIpv6(mInterfaceName); 4466 } catch (Exception e) { 4467 loge("Failed to clear addresses or disable ipv6" + e); 4468 } 4469 4470 /* Reset data structures */ 4471 mBadLinkspeedcount = 0; 4472 mWifiInfo.reset(); 4473 linkDebouncing = false; 4474 /* Reset roaming parameters */ 4475 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 4476 4477 /** 4478 * fullBandConnectedTimeIntervalMilli: 4479 * - start scans at mWifiConfigStore.associatedPartialScanPeriodMilli seconds interval 4480 * - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli 4481 * Initialize to sane value = 20 seconds 4482 */ 4483 fullBandConnectedTimeIntervalMilli = 20 * 1000; 4484 4485 setNetworkDetailedState(DetailedState.DISCONNECTED); 4486 if (mNetworkAgent != null) { 4487 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4488 mNetworkAgent = null; 4489 } 4490 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 4491 4492 /* Clear network properties */ 4493 clearLinkProperties(); 4494 4495 /* Cend event to CM & network change broadcast */ 4496 sendNetworkStateChangeBroadcast(mLastBssid); 4497 4498 /* Cancel auto roam requests */ 4499 autoRoamSetBSSID(mLastNetworkId, "any"); 4500 4501 mLastBssid= null; 4502 registerDisconnected(); 4503 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 4504 } 4505 4506 private void handleSupplicantConnectionLoss() { 4507 /* Socket connection can be lost when we do a graceful shutdown 4508 * or when the driver is hung. Ensure supplicant is stopped here. 4509 */ 4510 mWifiMonitor.killSupplicant(mP2pSupported); 4511 mWifiNative.closeSupplicantConnection(); 4512 sendSupplicantConnectionChangedBroadcast(false); 4513 setWifiState(WIFI_STATE_DISABLED); 4514 } 4515 4516 void handlePreDhcpSetup() { 4517 mDhcpActive = true; 4518 if (!mBluetoothConnectionActive) { 4519 /* 4520 * There are problems setting the Wi-Fi driver's power 4521 * mode to active when bluetooth coexistence mode is 4522 * enabled or sense. 4523 * <p> 4524 * We set Wi-Fi to active mode when 4525 * obtaining an IP address because we've found 4526 * compatibility issues with some routers with low power 4527 * mode. 4528 * <p> 4529 * In order for this active power mode to properly be set, 4530 * we disable coexistence mode until we're done with 4531 * obtaining an IP address. One exception is if we 4532 * are currently connected to a headset, since disabling 4533 * coexistence would interrupt that connection. 4534 */ 4535 // Disable the coexistence mode 4536 mWifiNative.setBluetoothCoexistenceMode( 4537 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 4538 } 4539 4540 // Disable power save and suspend optimizations during DHCP 4541 // Note: The order here is important for now. Brcm driver changes 4542 // power settings when we control suspend mode optimizations. 4543 // TODO: Remove this comment when the driver is fixed. 4544 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 4545 mWifiNative.setPowerSave(false); 4546 4547 // stopBatchedScan(); 4548 WifiNative.pauseScan(); 4549 4550 // Update link layer stats 4551 getWifiLinkLayerStats(false); 4552 4553 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 4554 Message msg = new Message(); 4555 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 4556 msg.arg1 = WifiP2pServiceImpl.ENABLED; 4557 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 4558 msg.obj = mDhcpStateMachine; 4559 mWifiP2pChannel.sendMessage(msg); 4560 } 4561 4562 4563 private boolean useLegacyDhcpClient() { 4564 return Settings.Global.getInt( 4565 mContext.getContentResolver(), 4566 Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1; 4567 } 4568 4569 private void maybeInitDhcpStateMachine() { 4570 if (mDhcpStateMachine == null) { 4571 if (useLegacyDhcpClient()) { 4572 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 4573 mContext, WifiStateMachine.this, mInterfaceName); 4574 } else { 4575 mDhcpStateMachine = DhcpClient.makeDhcpStateMachine( 4576 mContext, WifiStateMachine.this, mInterfaceName); 4577 } 4578 } 4579 } 4580 4581 void startDhcp() { 4582 maybeInitDhcpStateMachine(); 4583 mDhcpStateMachine.registerForPreDhcpNotification(); 4584 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 4585 } 4586 4587 void renewDhcp() { 4588 maybeInitDhcpStateMachine(); 4589 mDhcpStateMachine.registerForPreDhcpNotification(); 4590 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 4591 } 4592 4593 void stopDhcp() { 4594 if (mDhcpStateMachine != null) { 4595 /* In case we were in middle of DHCP operation restore back powermode */ 4596 handlePostDhcpSetup(); 4597 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 4598 } 4599 } 4600 4601 void handlePostDhcpSetup() { 4602 /* Restore power save and suspend optimizations */ 4603 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 4604 mWifiNative.setPowerSave(true); 4605 4606 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 4607 4608 // Set the coexistence mode back to its default value 4609 mWifiNative.setBluetoothCoexistenceMode( 4610 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 4611 4612 mDhcpActive = false; 4613 4614 // startBatchedScan(); 4615 WifiNative.restartScan(); 4616 } 4617 4618 private void handleIPv4Success(DhcpResults dhcpResults, int reason) { 4619 4620 if (PDBG) { 4621 loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() + ">"); 4622 loge("link address " + dhcpResults.ipAddress); 4623 } 4624 4625 synchronized (mDhcpResultsLock) { 4626 mDhcpResults = dhcpResults; 4627 } 4628 4629 Inet4Address addr = (Inet4Address) dhcpResults.ipAddress.getAddress(); 4630 if (isRoaming()) { 4631 if (addr instanceof Inet4Address) { 4632 int previousAddress = mWifiInfo.getIpAddress(); 4633 int newAddress = NetworkUtils.inetAddressToInt(addr); 4634 if (previousAddress != newAddress) { 4635 loge("handleIPv4Success, roaming and address changed" + 4636 mWifiInfo + " got: " + addr); 4637 } else { 4638 4639 } 4640 } else { 4641 loge("handleIPv4Success, roaming and didnt get an IPv4 address" + 4642 addr.toString()); 4643 } 4644 } 4645 mWifiInfo.setInetAddress(addr); 4646 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 4647 updateLinkProperties(reason); 4648 } 4649 4650 private void handleSuccessfulIpConfiguration() { 4651 mLastSignalLevel = -1; // Force update of signal strength 4652 WifiConfiguration c = getCurrentWifiConfiguration(); 4653 if (c != null) { 4654 // Reset IP failure tracking 4655 c.numConnectionFailures = 0; 4656 4657 // Tell the framework whether the newly connected network is trusted or untrusted. 4658 updateCapabilities(c); 4659 } 4660 if (c != null) { 4661 ScanResult result = getCurrentScanResult(); 4662 if (result == null) { 4663 loge("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" + 4664 c.configKey()); 4665 } else { 4666 // Clear the per BSSID failure count 4667 result.numIpConfigFailures = 0; 4668 // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry 4669 // any BSSID, even though it may already have a non zero ip failure count, 4670 // this will typically happen if the user walks away and come back to his arrea 4671 // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted 4672 // in supplicant for a couple of hours or a day 4673 mWifiNative.clearBlacklist(); 4674 } 4675 } 4676 } 4677 4678 private void handleIPv4Failure(int reason) { 4679 synchronized(mDhcpResultsLock) { 4680 if (mDhcpResults != null) { 4681 mDhcpResults.clear(); 4682 } 4683 } 4684 if (PDBG) { 4685 loge("wifistatemachine handleIPv4Failure"); 4686 } 4687 updateLinkProperties(reason); 4688 } 4689 4690 private void handleIpConfigurationLost() { 4691 mWifiInfo.setInetAddress(null); 4692 mWifiInfo.setMeteredHint(false); 4693 4694 mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false, 4695 "DHCP FAILURE", mWifiInfo.getBSSID()); 4696 4697 /* DHCP times out after about 30 seconds, we do a 4698 * disconnect thru supplicant, we will let autojoin retry connecting to the network 4699 */ 4700 mWifiNative.disconnect(); 4701 } 4702 4703 private int convertFrequencyToChannelNumber(int frequency) { 4704 if (frequency >= 2412 && frequency <= 2484) { 4705 return (frequency -2412) / 5 + 1; 4706 } else if (frequency >= 5170 && frequency <=5825) { 4707 //DFS is included 4708 return (frequency -5170) / 5 + 34; 4709 } else { 4710 return 0; 4711 } 4712 } 4713 4714 private int chooseApChannel(int apBand) { 4715 int apChannel; 4716 int[] channel; 4717 4718 if (apBand == 0) { 4719 //for 2.4GHz, we only set the AP at channel 1,6,11 4720 apChannel = 5 * mRandom.nextInt(3) + 1; 4721 } else { 4722 //5G without DFS 4723 channel = mWifiNative.getChannelsForBand(2); 4724 if (channel != null && channel.length > 0) { 4725 apChannel = channel[mRandom.nextInt(channel.length)]; 4726 apChannel = convertFrequencyToChannelNumber(apChannel); 4727 } else { 4728 Log.e(TAG, "SoftAp do not get available channel list"); 4729 apChannel = 0; 4730 } 4731 } 4732 4733 if(DBG) { 4734 Log.d(TAG, "SoftAp set on channel " + apChannel); 4735 } 4736 4737 return apChannel; 4738 } 4739 4740 4741 /* Current design is to not set the config on a running hostapd but instead 4742 * stop and start tethering when user changes config on a running access point 4743 * 4744 * TODO: Add control channel setup through hostapd that allows changing config 4745 * on a running daemon 4746 */ 4747 private void startSoftApWithConfig(final WifiConfiguration configuration) { 4748 // set channel 4749 final WifiConfiguration config = new WifiConfiguration(configuration); 4750 4751 if (DBG) { 4752 Log.d(TAG, "SoftAp config channel is: " + config.apChannel); 4753 } 4754 //fix me -- set country code through HAL Here 4755 if (config.apChannel == 0) { 4756 config.apChannel = chooseApChannel(config.apBand); 4757 if (config.apChannel == 0) { 4758 //fail to get available channel 4759 sendMessage(CMD_START_AP_FAILURE); 4760 return; 4761 } 4762 } 4763 //turn off interface 4764 if (!mWifiNative.toggleInterface(0)) { 4765 sendMessage(CMD_START_AP_FAILURE); 4766 return; 4767 } 4768 // Start hostapd on a separate thread 4769 new Thread(new Runnable() { 4770 public void run() { 4771 try { 4772 mNwService.startAccessPoint(config, mInterfaceName); 4773 } catch (Exception e) { 4774 loge("Exception in softap start " + e); 4775 try { 4776 mNwService.stopAccessPoint(mInterfaceName); 4777 mNwService.startAccessPoint(config, mInterfaceName); 4778 } catch (Exception e1) { 4779 loge("Exception in softap re-start " + e1); 4780 sendMessage(CMD_START_AP_FAILURE); 4781 return; 4782 } 4783 } 4784 if (DBG) log("Soft AP start successful"); 4785 sendMessage(CMD_START_AP_SUCCESS); 4786 } 4787 }).start(); 4788 } 4789 4790 /* 4791 * Read a MAC address in /proc/arp/table, used by WifistateMachine 4792 * so as to record MAC address of default gateway. 4793 **/ 4794 private String macAddressFromRoute(String ipAddress) { 4795 String macAddress = null; 4796 BufferedReader reader = null; 4797 try { 4798 reader = new BufferedReader(new FileReader("/proc/net/arp")); 4799 4800 // Skip over the line bearing colum titles 4801 String line = reader.readLine(); 4802 4803 while ((line = reader.readLine()) != null) { 4804 String[] tokens = line.split("[ ]+"); 4805 if (tokens.length < 6) { 4806 continue; 4807 } 4808 4809 // ARP column format is 4810 // Address HWType HWAddress Flags Mask IFace 4811 String ip = tokens[0]; 4812 String mac = tokens[3]; 4813 4814 if (ipAddress.equals(ip)) { 4815 macAddress = mac; 4816 break; 4817 } 4818 } 4819 4820 if (macAddress == null) { 4821 loge("Did not find remoteAddress {" + ipAddress + "} in " + 4822 "/proc/net/arp"); 4823 } 4824 4825 } catch (FileNotFoundException e) { 4826 loge("Could not open /proc/net/arp to lookup mac address"); 4827 } catch (IOException e) { 4828 loge("Could not read /proc/net/arp to lookup mac address"); 4829 } finally { 4830 try { 4831 if (reader != null) { 4832 reader.close(); 4833 } 4834 } catch (IOException e) { 4835 // Do nothing 4836 } 4837 } 4838 return macAddress; 4839 4840 } 4841 4842 private class WifiNetworkFactory extends NetworkFactory { 4843 public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { 4844 super(l, c, TAG, f); 4845 } 4846 4847 @Override 4848 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 4849 ++mConnectionRequests; 4850 } 4851 4852 @Override 4853 protected void releaseNetworkFor(NetworkRequest networkRequest) { 4854 --mConnectionRequests; 4855 } 4856 4857 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4858 pw.println("mConnectionRequests " + mConnectionRequests); 4859 } 4860 4861 } 4862 4863 private class UntrustedWifiNetworkFactory extends NetworkFactory { 4864 private int mUntrustedReqCount; 4865 4866 public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) { 4867 super(l, c, tag, f); 4868 } 4869 4870 @Override 4871 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 4872 if (!networkRequest.networkCapabilities.hasCapability( 4873 NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { 4874 if (++mUntrustedReqCount == 1) { 4875 mWifiAutoJoinController.setAllowUntrustedConnections(true); 4876 } 4877 } 4878 } 4879 4880 @Override 4881 protected void releaseNetworkFor(NetworkRequest networkRequest) { 4882 if (!networkRequest.networkCapabilities.hasCapability( 4883 NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { 4884 if (--mUntrustedReqCount == 0) { 4885 mWifiAutoJoinController.setAllowUntrustedConnections(false); 4886 } 4887 } 4888 } 4889 4890 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4891 pw.println("mUntrustedReqCount " + mUntrustedReqCount); 4892 } 4893 } 4894 4895 void maybeRegisterNetworkFactory() { 4896 if (mNetworkFactory == null) { 4897 checkAndSetConnectivityInstance(); 4898 if (mCm != null) { 4899 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, 4900 NETWORKTYPE, mNetworkCapabilitiesFilter); 4901 mNetworkFactory.setScoreFilter(60); 4902 mNetworkFactory.register(); 4903 4904 // We can't filter untrusted network in the capabilities filter because a trusted 4905 // network would still satisfy a request that accepts untrusted ones. 4906 mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(), 4907 mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter); 4908 mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE); 4909 mUntrustedNetworkFactory.register(); 4910 } 4911 } 4912 } 4913 4914 /******************************************************** 4915 * HSM states 4916 *******************************************************/ 4917 4918 class DefaultState extends State { 4919 @Override 4920 public boolean processMessage(Message message) { 4921 logStateAndMessage(message, getClass().getSimpleName()); 4922 4923 switch (message.what) { 4924 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 4925 AsyncChannel ac = (AsyncChannel) message.obj; 4926 if (ac == mWifiP2pChannel) { 4927 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 4928 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 4929 } else { 4930 loge("WifiP2pService connection failure, error=" + message.arg1); 4931 } 4932 } else { 4933 loge("got HALF_CONNECTED for unknown channel"); 4934 } 4935 break; 4936 } 4937 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 4938 AsyncChannel ac = (AsyncChannel) message.obj; 4939 if (ac == mWifiP2pChannel) { 4940 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 4941 //TODO: Re-establish connection to state machine after a delay 4942 // mWifiP2pChannel.connect(mContext, getHandler(), 4943 // mWifiP2pManager.getMessenger()); 4944 } 4945 break; 4946 } 4947 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 4948 mBluetoothConnectionActive = (message.arg1 != 4949 BluetoothAdapter.STATE_DISCONNECTED); 4950 break; 4951 /* Synchronous call returns */ 4952 case CMD_PING_SUPPLICANT: 4953 case CMD_ENABLE_NETWORK: 4954 case CMD_ADD_OR_UPDATE_NETWORK: 4955 case CMD_REMOVE_NETWORK: 4956 case CMD_SAVE_CONFIG: 4957 replyToMessage(message, message.what, FAILURE); 4958 break; 4959 case CMD_GET_CAPABILITY_FREQ: 4960 replyToMessage(message, message.what, null); 4961 break; 4962 case CMD_GET_CONFIGURED_NETWORKS: 4963 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 4964 break; 4965 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 4966 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 4967 break; 4968 case CMD_ENABLE_RSSI_POLL: 4969 mEnableRssiPolling = (message.arg1 == 1); 4970 break; 4971 case CMD_SET_HIGH_PERF_MODE: 4972 if (message.arg1 == 1) { 4973 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 4974 } else { 4975 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 4976 } 4977 break; 4978 case CMD_BOOT_COMPLETED: 4979 maybeRegisterNetworkFactory(); 4980 break; 4981 case CMD_SET_BATCHED_SCAN: 4982 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 4983 break; 4984 case CMD_POLL_BATCHED_SCAN: 4985 handleBatchedScanPollRequest(); 4986 break; 4987 case CMD_START_NEXT_BATCHED_SCAN: 4988 startNextBatchedScan(); 4989 break; 4990 case CMD_SCREEN_STATE_CHANGED: 4991 handleScreenStateChanged(message.arg1 != 0, 4992 /* startBackgroundScanIfNeeded = */ false); 4993 break; 4994 /* Discard */ 4995 case CMD_START_SCAN: 4996 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 4997 break; 4998 case CMD_START_SUPPLICANT: 4999 case CMD_STOP_SUPPLICANT: 5000 case CMD_STOP_SUPPLICANT_FAILED: 5001 case CMD_START_DRIVER: 5002 case CMD_STOP_DRIVER: 5003 case CMD_DELAYED_STOP_DRIVER: 5004 case CMD_DRIVER_START_TIMED_OUT: 5005 case CMD_START_AP: 5006 case CMD_START_AP_SUCCESS: 5007 case CMD_START_AP_FAILURE: 5008 case CMD_STOP_AP: 5009 case CMD_TETHER_STATE_CHANGE: 5010 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5011 case CMD_DISCONNECT: 5012 case CMD_RECONNECT: 5013 case CMD_REASSOCIATE: 5014 case CMD_RELOAD_TLS_AND_RECONNECT: 5015 case WifiMonitor.SUP_CONNECTION_EVENT: 5016 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5017 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5018 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5019 case WifiMonitor.SCAN_RESULTS_EVENT: 5020 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5021 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5022 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5023 case WifiMonitor.WPS_OVERLAP_EVENT: 5024 case CMD_BLACKLIST_NETWORK: 5025 case CMD_CLEAR_BLACKLIST: 5026 case CMD_SET_OPERATIONAL_MODE: 5027 case CMD_SET_COUNTRY_CODE: 5028 case CMD_SET_FREQUENCY_BAND: 5029 case CMD_RSSI_POLL: 5030 case CMD_ENABLE_ALL_NETWORKS: 5031 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 5032 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 5033 /* Handled by WifiApConfigStore */ 5034 case CMD_SET_AP_CONFIG: 5035 case CMD_SET_AP_CONFIG_COMPLETED: 5036 case CMD_REQUEST_AP_CONFIG: 5037 case CMD_RESPONSE_AP_CONFIG: 5038 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5039 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 5040 case CMD_NO_NETWORKS_PERIODIC_SCAN: 5041 case CMD_DISABLE_P2P_RSP: 5042 case WifiMonitor.SUP_REQUEST_IDENTITY: 5043 case CMD_TEST_NETWORK_DISCONNECT: 5044 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 5045 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 5046 case CMD_TARGET_BSSID: 5047 case CMD_AUTO_CONNECT: 5048 case CMD_AUTO_ROAM: 5049 case CMD_AUTO_SAVE_NETWORK: 5050 case CMD_ASSOCIATED_BSSID: 5051 case CMD_UNWANTED_NETWORK: 5052 case CMD_DISCONNECTING_WATCHDOG_TIMER: 5053 case CMD_ROAM_WATCHDOG_TIMER: 5054 case CMD_DISABLE_EPHEMERAL_NETWORK: 5055 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5056 break; 5057 case DhcpStateMachine.CMD_ON_QUIT: 5058 mDhcpStateMachine = null; 5059 break; 5060 case CMD_SET_SUSPEND_OPT_ENABLED: 5061 if (message.arg1 == 1) { 5062 mSuspendWakeLock.release(); 5063 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 5064 } else { 5065 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 5066 } 5067 break; 5068 case WifiMonitor.DRIVER_HUNG_EVENT: 5069 setSupplicantRunning(false); 5070 setSupplicantRunning(true); 5071 break; 5072 case WifiManager.CONNECT_NETWORK: 5073 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5074 WifiManager.BUSY); 5075 break; 5076 case WifiManager.FORGET_NETWORK: 5077 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 5078 WifiManager.BUSY); 5079 break; 5080 case WifiManager.SAVE_NETWORK: 5081 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 5082 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5083 WifiManager.BUSY); 5084 break; 5085 case WifiManager.START_WPS: 5086 replyToMessage(message, WifiManager.WPS_FAILED, 5087 WifiManager.BUSY); 5088 break; 5089 case WifiManager.CANCEL_WPS: 5090 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 5091 WifiManager.BUSY); 5092 break; 5093 case WifiManager.DISABLE_NETWORK: 5094 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 5095 WifiManager.BUSY); 5096 break; 5097 case WifiManager.RSSI_PKTCNT_FETCH: 5098 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 5099 WifiManager.BUSY); 5100 break; 5101 case CMD_GET_SUPPORTED_FEATURES: 5102 if (WifiNative.startHal()) { 5103 int featureSet = WifiNative.getSupportedFeatureSet(); 5104 replyToMessage(message, message.what, featureSet); 5105 } else { 5106 replyToMessage(message, message.what, 0); 5107 } 5108 break; 5109 case CMD_GET_LINK_LAYER_STATS: 5110 // Not supported hence reply with error message 5111 replyToMessage(message, message.what, null); 5112 break; 5113 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 5114 NetworkInfo info = (NetworkInfo) message.obj; 5115 mP2pConnected.set(info.isConnected()); 5116 break; 5117 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5118 mTemporarilyDisconnectWifi = (message.arg1 == 1); 5119 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 5120 break; 5121 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 5122 case CMD_UPDATE_LINKPROPERTIES: 5123 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 5124 break; 5125 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5126 case CMD_IP_CONFIGURATION_LOST: 5127 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5128 break; 5129 case CMD_GET_CONNECTION_STATISTICS: 5130 replyToMessage(message, message.what, mWifiConnectionStatistics); 5131 break; 5132 case CMD_REMOVE_APP_CONFIGURATIONS: 5133 deferMessage(message); 5134 break; 5135 case CMD_REMOVE_USER_CONFIGURATIONS: 5136 deferMessage(message); 5137 break; 5138 default: 5139 loge("Error! unhandled message" + message); 5140 break; 5141 } 5142 return HANDLED; 5143 } 5144 } 5145 5146 class InitialState extends State { 5147 @Override 5148 public void enter() { 5149 mWifiNative.unloadDriver(); 5150 5151 if (mWifiP2pChannel == null) { 5152 mWifiP2pChannel = new AsyncChannel(); 5153 mWifiP2pChannel.connect(mContext, getHandler(), 5154 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 5155 } 5156 5157 if (mWifiApConfigChannel == null) { 5158 mWifiApConfigChannel = new AsyncChannel(); 5159 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 5160 mContext, getHandler()); 5161 wifiApConfigStore.loadApConfiguration(); 5162 mWifiApConfigChannel.connectSync(mContext, getHandler(), 5163 wifiApConfigStore.getMessenger()); 5164 } 5165 } 5166 @Override 5167 public boolean processMessage(Message message) { 5168 logStateAndMessage(message, getClass().getSimpleName()); 5169 switch (message.what) { 5170 case CMD_START_SUPPLICANT: 5171 if (mWifiNative.loadDriver()) { 5172 try { 5173 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 5174 } catch (Exception e) { 5175 loge("Failed to reload STA firmware " + e); 5176 // Continue 5177 } 5178 5179 try { 5180 // A runtime crash can leave the interface up and 5181 // IP addresses configured, and this affects 5182 // connectivity when supplicant starts up. 5183 // Ensure interface is down and we have no IP 5184 // addresses before a supplicant start. 5185 mNwService.setInterfaceDown(mInterfaceName); 5186 mNwService.clearInterfaceAddresses(mInterfaceName); 5187 5188 // Set privacy extensions 5189 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 5190 5191 // IPv6 is enabled only as long as access point is connected since: 5192 // - IPv6 addresses and routes stick around after disconnection 5193 // - kernel is unaware when connected and fails to start IPv6 negotiation 5194 // - kernel can start autoconfiguration when 802.1x is not complete 5195 mNwService.disableIpv6(mInterfaceName); 5196 } catch (RemoteException re) { 5197 loge("Unable to change interface settings: " + re); 5198 } catch (IllegalStateException ie) { 5199 loge("Unable to change interface settings: " + ie); 5200 } 5201 5202 /* Stop a running supplicant after a runtime restart 5203 * Avoids issues with drivers that do not handle interface down 5204 * on a running supplicant properly. 5205 */ 5206 mWifiMonitor.killSupplicant(mP2pSupported); 5207 if(mWifiNative.startSupplicant(mP2pSupported)) { 5208 setWifiState(WIFI_STATE_ENABLING); 5209 if (DBG) log("Supplicant start successful"); 5210 mWifiMonitor.startMonitoring(); 5211 transitionTo(mSupplicantStartingState); 5212 } else { 5213 loge("Failed to start supplicant!"); 5214 } 5215 } else { 5216 loge("Failed to load driver"); 5217 } 5218 break; 5219 case CMD_START_AP: 5220 if (mWifiNative.loadDriver()) { 5221 setWifiApState(WIFI_AP_STATE_ENABLING); 5222 transitionTo(mSoftApStartingState); 5223 } else { 5224 loge("Failed to load driver for softap"); 5225 } 5226 break; 5227 default: 5228 return NOT_HANDLED; 5229 } 5230 return HANDLED; 5231 } 5232 } 5233 5234 class SupplicantStartingState extends State { 5235 private void initializeWpsDetails() { 5236 String detail; 5237 detail = SystemProperties.get("ro.product.name", ""); 5238 if (!mWifiNative.setDeviceName(detail)) { 5239 loge("Failed to set device name " + detail); 5240 } 5241 detail = SystemProperties.get("ro.product.manufacturer", ""); 5242 if (!mWifiNative.setManufacturer(detail)) { 5243 loge("Failed to set manufacturer " + detail); 5244 } 5245 detail = SystemProperties.get("ro.product.model", ""); 5246 if (!mWifiNative.setModelName(detail)) { 5247 loge("Failed to set model name " + detail); 5248 } 5249 detail = SystemProperties.get("ro.product.model", ""); 5250 if (!mWifiNative.setModelNumber(detail)) { 5251 loge("Failed to set model number " + detail); 5252 } 5253 detail = SystemProperties.get("ro.serialno", ""); 5254 if (!mWifiNative.setSerialNumber(detail)) { 5255 loge("Failed to set serial number " + detail); 5256 } 5257 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 5258 loge("Failed to set WPS config methods"); 5259 } 5260 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 5261 loge("Failed to set primary device type " + mPrimaryDeviceType); 5262 } 5263 } 5264 5265 @Override 5266 public boolean processMessage(Message message) { 5267 logStateAndMessage(message, getClass().getSimpleName()); 5268 5269 switch(message.what) { 5270 case WifiMonitor.SUP_CONNECTION_EVENT: 5271 if (DBG) log("Supplicant connection established"); 5272 setWifiState(WIFI_STATE_ENABLED); 5273 mSupplicantRestartCount = 0; 5274 /* Reset the supplicant state to indicate the supplicant 5275 * state is not known at this time */ 5276 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5277 /* Initialize data structures */ 5278 mLastBssid = null; 5279 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 5280 mLastSignalLevel = -1; 5281 5282 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 5283 mWifiNative.enableSaveConfig(); 5284 mWifiConfigStore.loadAndEnableAllNetworks(); 5285 if (mWifiConfigStore.enableVerboseLogging.get() > 0) { 5286 enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get()); 5287 } 5288 if (mWifiConfigStore.associatedPartialScanPeriodMilli.get() < 0) { 5289 mWifiConfigStore.associatedPartialScanPeriodMilli.set(0); 5290 } 5291 initializeWpsDetails(); 5292 5293 sendSupplicantConnectionChangedBroadcast(true); 5294 transitionTo(mDriverStartedState); 5295 break; 5296 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5297 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 5298 loge("Failed to setup control channel, restart supplicant"); 5299 mWifiMonitor.killSupplicant(mP2pSupported); 5300 transitionTo(mInitialState); 5301 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 5302 } else { 5303 loge("Failed " + mSupplicantRestartCount + 5304 " times to start supplicant, unload driver"); 5305 mSupplicantRestartCount = 0; 5306 setWifiState(WIFI_STATE_UNKNOWN); 5307 transitionTo(mInitialState); 5308 } 5309 break; 5310 case CMD_START_SUPPLICANT: 5311 case CMD_STOP_SUPPLICANT: 5312 case CMD_START_AP: 5313 case CMD_STOP_AP: 5314 case CMD_START_DRIVER: 5315 case CMD_STOP_DRIVER: 5316 case CMD_SET_OPERATIONAL_MODE: 5317 case CMD_SET_COUNTRY_CODE: 5318 case CMD_SET_FREQUENCY_BAND: 5319 case CMD_START_PACKET_FILTERING: 5320 case CMD_STOP_PACKET_FILTERING: 5321 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5322 deferMessage(message); 5323 break; 5324 default: 5325 return NOT_HANDLED; 5326 } 5327 return HANDLED; 5328 } 5329 } 5330 5331 class SupplicantStartedState extends State { 5332 @Override 5333 public void enter() { 5334 /* Wifi is available as long as we have a connection to supplicant */ 5335 mNetworkInfo.setIsAvailable(true); 5336 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 5337 5338 int defaultInterval = mContext.getResources().getInteger( 5339 R.integer.config_wifi_supplicant_scan_interval); 5340 5341 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 5342 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 5343 defaultInterval); 5344 5345 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 5346 mWifiNative.setExternalSim(true); 5347 5348 /* turn on use of DFS channels */ 5349 WifiNative.setDfsFlag(true); 5350 5351 /* set country code */ 5352 setCountryCode(); 5353 5354 setRandomMacOui(); 5355 mWifiNative.enableAutoConnect(false); 5356 } 5357 5358 @Override 5359 public boolean processMessage(Message message) { 5360 logStateAndMessage(message, getClass().getSimpleName()); 5361 5362 switch(message.what) { 5363 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 5364 if (mP2pSupported) { 5365 transitionTo(mWaitForP2pDisableState); 5366 } else { 5367 transitionTo(mSupplicantStoppingState); 5368 } 5369 break; 5370 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 5371 loge("Connection lost, restart supplicant"); 5372 handleSupplicantConnectionLoss(); 5373 handleNetworkDisconnect(); 5374 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5375 if (mP2pSupported) { 5376 transitionTo(mWaitForP2pDisableState); 5377 } else { 5378 transitionTo(mInitialState); 5379 } 5380 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 5381 break; 5382 case WifiMonitor.SCAN_RESULTS_EVENT: 5383 maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered 5384 closeRadioScanStats(); 5385 noteScanEnd(); 5386 setScanResults(); 5387 if (mIsFullScanOngoing || mSendScanResultsBroadcast) { 5388 /* Just updated results from full scan, let apps know about this */ 5389 sendScanResultsAvailableBroadcast(); 5390 } 5391 mSendScanResultsBroadcast = false; 5392 mIsScanOngoing = false; 5393 mIsFullScanOngoing = false; 5394 if (mBufferedScanMsg.size() > 0) 5395 sendMessage(mBufferedScanMsg.remove()); 5396 break; 5397 case CMD_PING_SUPPLICANT: 5398 boolean ok = mWifiNative.ping(); 5399 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 5400 break; 5401 case CMD_GET_CAPABILITY_FREQ: 5402 String freqs = mWifiNative.getFreqCapability(); 5403 replyToMessage(message, message.what, freqs); 5404 break; 5405 case CMD_START_AP: 5406 /* Cannot start soft AP while in client mode */ 5407 loge("Failed to start soft AP with a running supplicant"); 5408 setWifiApState(WIFI_AP_STATE_FAILED); 5409 break; 5410 case CMD_SET_OPERATIONAL_MODE: 5411 mOperationalMode = message.arg1; 5412 mWifiConfigStore. 5413 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 5414 break; 5415 case CMD_TARGET_BSSID: 5416 // Trying to associate to this BSSID 5417 if (message.obj != null) { 5418 mTargetRoamBSSID = (String) message.obj; 5419 } 5420 break; 5421 case CMD_GET_LINK_LAYER_STATS: 5422 WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG); 5423 if (stats == null) { 5424 // When firmware doesnt support link layer stats, return an empty object 5425 stats = new WifiLinkLayerStats(); 5426 } 5427 replyToMessage(message, message.what, stats); 5428 break; 5429 case CMD_SET_COUNTRY_CODE: 5430 String country = (String) message.obj; 5431 5432 final boolean persist = (message.arg2 == 1); 5433 final int sequence = message.arg1; 5434 5435 if (sequence != mCountryCodeSequence.get()) { 5436 if (DBG) log("set country code ignored due to sequnce num"); 5437 break; 5438 } 5439 if (DBG) log("set country code " + country); 5440 country = country.toUpperCase(Locale.ROOT); 5441 5442 if (mDriverSetCountryCode == null || !mDriverSetCountryCode.equals(country)) { 5443 if (mWifiNative.setCountryCode(country)) { 5444 mDriverSetCountryCode = country; 5445 } else { 5446 loge("Failed to set country code " + country); 5447 } 5448 } 5449 5450 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 5451 break; 5452 default: 5453 return NOT_HANDLED; 5454 } 5455 return HANDLED; 5456 } 5457 5458 @Override 5459 public void exit() { 5460 mNetworkInfo.setIsAvailable(false); 5461 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 5462 } 5463 } 5464 5465 class SupplicantStoppingState extends State { 5466 @Override 5467 public void enter() { 5468 /* Send any reset commands to supplicant before shutting it down */ 5469 handleNetworkDisconnect(); 5470 if (mDhcpStateMachine != null) { 5471 mDhcpStateMachine.doQuit(); 5472 } 5473 5474 String suppState = System.getProperty("init.svc.wpa_supplicant"); 5475 if (suppState == null) suppState = "unknown"; 5476 String p2pSuppState = System.getProperty("init.svc.p2p_supplicant"); 5477 if (p2pSuppState == null) p2pSuppState = "unknown"; 5478 5479 loge("SupplicantStoppingState: stopSupplicant " 5480 + " init.svc.wpa_supplicant=" + suppState 5481 + " init.svc.p2p_supplicant=" + p2pSuppState); 5482 mWifiMonitor.stopSupplicant(); 5483 5484 /* Send ourselves a delayed message to indicate failure after a wait time */ 5485 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 5486 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 5487 setWifiState(WIFI_STATE_DISABLING); 5488 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5489 } 5490 @Override 5491 public boolean processMessage(Message message) { 5492 logStateAndMessage(message, getClass().getSimpleName()); 5493 5494 switch(message.what) { 5495 case WifiMonitor.SUP_CONNECTION_EVENT: 5496 loge("Supplicant connection received while stopping"); 5497 break; 5498 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5499 if (DBG) log("Supplicant connection lost"); 5500 handleSupplicantConnectionLoss(); 5501 transitionTo(mInitialState); 5502 break; 5503 case CMD_STOP_SUPPLICANT_FAILED: 5504 if (message.arg1 == mSupplicantStopFailureToken) { 5505 loge("Timed out on a supplicant stop, kill and proceed"); 5506 handleSupplicantConnectionLoss(); 5507 transitionTo(mInitialState); 5508 } 5509 break; 5510 case CMD_START_SUPPLICANT: 5511 case CMD_STOP_SUPPLICANT: 5512 case CMD_START_AP: 5513 case CMD_STOP_AP: 5514 case CMD_START_DRIVER: 5515 case CMD_STOP_DRIVER: 5516 case CMD_SET_OPERATIONAL_MODE: 5517 case CMD_SET_COUNTRY_CODE: 5518 case CMD_SET_FREQUENCY_BAND: 5519 case CMD_START_PACKET_FILTERING: 5520 case CMD_STOP_PACKET_FILTERING: 5521 deferMessage(message); 5522 break; 5523 default: 5524 return NOT_HANDLED; 5525 } 5526 return HANDLED; 5527 } 5528 } 5529 5530 class DriverStartingState extends State { 5531 private int mTries; 5532 @Override 5533 public void enter() { 5534 mTries = 1; 5535 /* Send ourselves a delayed message to start driver a second time */ 5536 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 5537 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 5538 } 5539 @Override 5540 public boolean processMessage(Message message) { 5541 logStateAndMessage(message, getClass().getSimpleName()); 5542 5543 switch(message.what) { 5544 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5545 SupplicantState state = handleSupplicantStateChange(message); 5546 /* If suplicant is exiting out of INTERFACE_DISABLED state into 5547 * a state that indicates driver has started, it is ready to 5548 * receive driver commands 5549 */ 5550 if (SupplicantState.isDriverActive(state)) { 5551 transitionTo(mDriverStartedState); 5552 } 5553 break; 5554 case CMD_DRIVER_START_TIMED_OUT: 5555 if (message.arg1 == mDriverStartToken) { 5556 if (mTries >= 2) { 5557 loge("Failed to start driver after " + mTries); 5558 transitionTo(mDriverStoppedState); 5559 } else { 5560 loge("Driver start failed, retrying"); 5561 mWakeLock.acquire(); 5562 mWifiNative.startDriver(); 5563 mWakeLock.release(); 5564 5565 ++mTries; 5566 /* Send ourselves a delayed message to start driver again */ 5567 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 5568 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 5569 } 5570 } 5571 break; 5572 /* Queue driver commands & connection events */ 5573 case CMD_START_DRIVER: 5574 case CMD_STOP_DRIVER: 5575 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5576 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5577 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5578 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5579 case WifiMonitor.WPS_OVERLAP_EVENT: 5580 case CMD_SET_COUNTRY_CODE: 5581 case CMD_SET_FREQUENCY_BAND: 5582 case CMD_START_PACKET_FILTERING: 5583 case CMD_STOP_PACKET_FILTERING: 5584 case CMD_START_SCAN: 5585 case CMD_DISCONNECT: 5586 case CMD_REASSOCIATE: 5587 case CMD_RECONNECT: 5588 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5589 deferMessage(message); 5590 break; 5591 case WifiMonitor.SCAN_RESULTS_EVENT: 5592 // Loose scan results obtained in Driver Starting state, they can only confuse 5593 // the state machine 5594 break; 5595 default: 5596 return NOT_HANDLED; 5597 } 5598 return HANDLED; 5599 } 5600 } 5601 5602 class DriverStartedState extends State { 5603 @Override 5604 public void enter() { 5605 5606 if (PDBG) { 5607 loge("DriverStartedState enter"); 5608 } 5609 mIsRunning = true; 5610 mInDelayedStop = false; 5611 mDelayedStopCounter++; 5612 updateBatteryWorkSource(null); 5613 /** 5614 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 5615 * When this mode is on, some of the low-level scan parameters used by the 5616 * driver are changed to reduce interference with bluetooth 5617 */ 5618 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 5619 /* set frequency band of operation */ 5620 setFrequencyBand(); 5621 /* initialize network state */ 5622 setNetworkDetailedState(DetailedState.DISCONNECTED); 5623 5624 /* Remove any filtering on Multicast v6 at start */ 5625 mWifiNative.stopFilteringMulticastV6Packets(); 5626 5627 /* Reset Multicast v4 filtering state */ 5628 if (mFilteringMulticastV4Packets.get()) { 5629 mWifiNative.startFilteringMulticastV4Packets(); 5630 } else { 5631 mWifiNative.stopFilteringMulticastV4Packets(); 5632 } 5633 5634 mDhcpActive = false; 5635 5636 startBatchedScan(); 5637 5638 if (mOperationalMode != CONNECT_MODE) { 5639 mWifiNative.disconnect(); 5640 mWifiConfigStore.disableAllNetworks(); 5641 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 5642 setWifiState(WIFI_STATE_DISABLED); 5643 } 5644 transitionTo(mScanModeState); 5645 } else { 5646 5647 // Status pulls in the current supplicant state and network connection state 5648 // events over the monitor connection. This helps framework sync up with 5649 // current supplicant state 5650 // TODO: actually check th supplicant status string and make sure the supplicant 5651 // is in disconnecte4d state. 5652 mWifiNative.status(); 5653 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin 5654 transitionTo(mDisconnectedState); 5655 } 5656 5657 // We may have missed screen update at boot 5658 if (mScreenBroadcastReceived.get() == false) { 5659 PowerManager powerManager = (PowerManager)mContext.getSystemService( 5660 Context.POWER_SERVICE); 5661 handleScreenStateChanged(powerManager.isScreenOn(), 5662 /* startBackgroundScanIfNeeded = */ false); 5663 } else { 5664 // Set the right suspend mode settings 5665 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 5666 && mUserWantsSuspendOpt.get()); 5667 } 5668 mWifiNative.setPowerSave(true); 5669 5670 if (mP2pSupported) { 5671 if (mOperationalMode == CONNECT_MODE) { 5672 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 5673 } else { 5674 // P2P statemachine starts in disabled state, and is not enabled until 5675 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 5676 // keep it disabled. 5677 } 5678 } 5679 5680 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 5681 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 5682 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 5683 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 5684 5685 if (PDBG) { 5686 loge("Driverstarted State enter done"); 5687 } 5688 } 5689 5690 @Override 5691 public boolean processMessage(Message message) { 5692 logStateAndMessage(message, getClass().getSimpleName()); 5693 5694 switch(message.what) { 5695 case CMD_START_SCAN: 5696 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5697 break; 5698 case CMD_SET_BATCHED_SCAN: 5699 if (recordBatchedScanSettings(message.arg1, message.arg2, 5700 (Bundle) message.obj)) { 5701 if (mBatchedScanSettings != null) { 5702 startBatchedScan(); 5703 } else { 5704 stopBatchedScan(); 5705 } 5706 } 5707 break; 5708 case CMD_SET_FREQUENCY_BAND: 5709 int band = message.arg1; 5710 if (DBG) log("set frequency band " + band); 5711 if (mWifiNative.setBand(band)) { 5712 5713 if (PDBG) loge("did set frequency band " + band); 5714 5715 mFrequencyBand.set(band); 5716 // Flush old data - like scan results 5717 mWifiNative.bssFlush(); 5718 // Fetch the latest scan results when frequency band is set 5719 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 5720 5721 if (PDBG) loge("done set frequency band " + band); 5722 5723 } else { 5724 loge("Failed to set frequency band " + band); 5725 } 5726 break; 5727 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 5728 mBluetoothConnectionActive = (message.arg1 != 5729 BluetoothAdapter.STATE_DISCONNECTED); 5730 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 5731 break; 5732 case CMD_STOP_DRIVER: 5733 int mode = message.arg1; 5734 5735 /* Already doing a delayed stop */ 5736 if (mInDelayedStop) { 5737 if (DBG) log("Already in delayed stop"); 5738 break; 5739 } 5740 /* disconnect right now, but leave the driver running for a bit */ 5741 mWifiConfigStore.disableAllNetworks(); 5742 5743 mInDelayedStop = true; 5744 mDelayedStopCounter++; 5745 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 5746 5747 /* send regular delayed shut down */ 5748 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 5749 driverStopIntent.setPackage(this.getClass().getPackage().getName()); 5750 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 5751 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 5752 DRIVER_STOP_REQUEST, driverStopIntent, 5753 PendingIntent.FLAG_UPDATE_CURRENT); 5754 5755 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 5756 + mDriverStopDelayMs, mDriverStopIntent); 5757 break; 5758 case CMD_START_DRIVER: 5759 if (mInDelayedStop) { 5760 mInDelayedStop = false; 5761 mDelayedStopCounter++; 5762 mAlarmManager.cancel(mDriverStopIntent); 5763 if (DBG) log("Delayed stop ignored due to start"); 5764 if (mOperationalMode == CONNECT_MODE) { 5765 mWifiConfigStore.enableAllNetworks(); 5766 } 5767 } 5768 break; 5769 case CMD_DELAYED_STOP_DRIVER: 5770 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 5771 if (message.arg1 != mDelayedStopCounter) break; 5772 if (getCurrentState() != mDisconnectedState) { 5773 mWifiNative.disconnect(); 5774 handleNetworkDisconnect(); 5775 } 5776 mWakeLock.acquire(); 5777 mWifiNative.stopDriver(); 5778 mWakeLock.release(); 5779 if (mP2pSupported) { 5780 transitionTo(mWaitForP2pDisableState); 5781 } else { 5782 transitionTo(mDriverStoppingState); 5783 } 5784 break; 5785 case CMD_START_PACKET_FILTERING: 5786 if (message.arg1 == MULTICAST_V6) { 5787 mWifiNative.startFilteringMulticastV6Packets(); 5788 } else if (message.arg1 == MULTICAST_V4) { 5789 mWifiNative.startFilteringMulticastV4Packets(); 5790 } else { 5791 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 5792 } 5793 break; 5794 case CMD_STOP_PACKET_FILTERING: 5795 if (message.arg1 == MULTICAST_V6) { 5796 mWifiNative.stopFilteringMulticastV6Packets(); 5797 } else if (message.arg1 == MULTICAST_V4) { 5798 mWifiNative.stopFilteringMulticastV4Packets(); 5799 } else { 5800 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 5801 } 5802 break; 5803 case CMD_SET_SUSPEND_OPT_ENABLED: 5804 if (message.arg1 == 1) { 5805 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 5806 mSuspendWakeLock.release(); 5807 } else { 5808 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 5809 } 5810 break; 5811 case CMD_SET_HIGH_PERF_MODE: 5812 if (message.arg1 == 1) { 5813 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 5814 } else { 5815 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 5816 } 5817 break; 5818 case CMD_ENABLE_TDLS: 5819 if (message.obj != null) { 5820 String remoteAddress = (String) message.obj; 5821 boolean enable = (message.arg1 == 1); 5822 mWifiNative.startTdls(remoteAddress, enable); 5823 } 5824 break; 5825 default: 5826 return NOT_HANDLED; 5827 } 5828 return HANDLED; 5829 } 5830 @Override 5831 public void exit() { 5832 mIsRunning = false; 5833 updateBatteryWorkSource(null); 5834 mScanResults = new ArrayList<>(); 5835 5836 stopBatchedScan(); 5837 5838 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 5839 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 5840 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 5841 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 5842 noteScanEnd(); // wrap up any pending request. 5843 mBufferedScanMsg.clear(); 5844 } 5845 } 5846 5847 class WaitForP2pDisableState extends State { 5848 private State mTransitionToState; 5849 @Override 5850 public void enter() { 5851 switch (getCurrentMessage().what) { 5852 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5853 mTransitionToState = mInitialState; 5854 break; 5855 case CMD_DELAYED_STOP_DRIVER: 5856 mTransitionToState = mDriverStoppingState; 5857 break; 5858 case CMD_STOP_SUPPLICANT: 5859 mTransitionToState = mSupplicantStoppingState; 5860 break; 5861 default: 5862 mTransitionToState = mDriverStoppingState; 5863 break; 5864 } 5865 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 5866 } 5867 @Override 5868 public boolean processMessage(Message message) { 5869 logStateAndMessage(message, getClass().getSimpleName()); 5870 5871 switch(message.what) { 5872 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 5873 transitionTo(mTransitionToState); 5874 break; 5875 /* Defer wifi start/shut and driver commands */ 5876 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5877 case CMD_START_SUPPLICANT: 5878 case CMD_STOP_SUPPLICANT: 5879 case CMD_START_AP: 5880 case CMD_STOP_AP: 5881 case CMD_START_DRIVER: 5882 case CMD_STOP_DRIVER: 5883 case CMD_SET_OPERATIONAL_MODE: 5884 case CMD_SET_COUNTRY_CODE: 5885 case CMD_SET_FREQUENCY_BAND: 5886 case CMD_START_PACKET_FILTERING: 5887 case CMD_STOP_PACKET_FILTERING: 5888 case CMD_START_SCAN: 5889 case CMD_DISCONNECT: 5890 case CMD_REASSOCIATE: 5891 case CMD_RECONNECT: 5892 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5893 deferMessage(message); 5894 break; 5895 default: 5896 return NOT_HANDLED; 5897 } 5898 return HANDLED; 5899 } 5900 } 5901 5902 class DriverStoppingState extends State { 5903 @Override 5904 public boolean processMessage(Message message) { 5905 logStateAndMessage(message, getClass().getSimpleName()); 5906 5907 switch(message.what) { 5908 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5909 SupplicantState state = handleSupplicantStateChange(message); 5910 if (state == SupplicantState.INTERFACE_DISABLED) { 5911 transitionTo(mDriverStoppedState); 5912 } 5913 break; 5914 /* Queue driver commands */ 5915 case CMD_START_DRIVER: 5916 case CMD_STOP_DRIVER: 5917 case CMD_SET_COUNTRY_CODE: 5918 case CMD_SET_FREQUENCY_BAND: 5919 case CMD_START_PACKET_FILTERING: 5920 case CMD_STOP_PACKET_FILTERING: 5921 case CMD_START_SCAN: 5922 case CMD_DISCONNECT: 5923 case CMD_REASSOCIATE: 5924 case CMD_RECONNECT: 5925 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5926 deferMessage(message); 5927 break; 5928 default: 5929 return NOT_HANDLED; 5930 } 5931 return HANDLED; 5932 } 5933 } 5934 5935 class DriverStoppedState extends State { 5936 @Override 5937 public boolean processMessage(Message message) { 5938 logStateAndMessage(message, getClass().getSimpleName()); 5939 switch (message.what) { 5940 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5941 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 5942 SupplicantState state = stateChangeResult.state; 5943 // A WEXT bug means that we can be back to driver started state 5944 // unexpectedly 5945 if (SupplicantState.isDriverActive(state)) { 5946 transitionTo(mDriverStartedState); 5947 } 5948 break; 5949 case CMD_START_DRIVER: 5950 mWakeLock.acquire(); 5951 mWifiNative.startDriver(); 5952 mWakeLock.release(); 5953 transitionTo(mDriverStartingState); 5954 break; 5955 default: 5956 return NOT_HANDLED; 5957 } 5958 return HANDLED; 5959 } 5960 } 5961 5962 class ScanModeState extends State { 5963 private int mLastOperationMode; 5964 @Override 5965 public void enter() { 5966 mLastOperationMode = mOperationalMode; 5967 } 5968 @Override 5969 public boolean processMessage(Message message) { 5970 logStateAndMessage(message, getClass().getSimpleName()); 5971 5972 switch(message.what) { 5973 case CMD_SET_OPERATIONAL_MODE: 5974 if (message.arg1 == CONNECT_MODE) { 5975 5976 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 5977 setWifiState(WIFI_STATE_ENABLED); 5978 // Load and re-enable networks when going back to enabled state 5979 // This is essential for networks to show up after restore 5980 mWifiConfigStore.loadAndEnableAllNetworks(); 5981 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 5982 } else { 5983 mWifiConfigStore.enableAllNetworks(); 5984 } 5985 5986 // Try autojoining with recent network already present in the cache 5987 // If none are found then trigger a scan which will trigger autojoin 5988 // upon reception of scan results event 5989 if (!mWifiAutoJoinController.attemptAutoJoin()) { 5990 startScan(ENABLE_WIFI, 0, null, null); 5991 } 5992 5993 // Loose last selection choice since user toggled WiFi 5994 mWifiConfigStore. 5995 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 5996 5997 mOperationalMode = CONNECT_MODE; 5998 transitionTo(mDisconnectedState); 5999 } else { 6000 // Nothing to do 6001 return HANDLED; 6002 } 6003 break; 6004 // Handle scan. All the connection related commands are 6005 // handled only in ConnectModeState 6006 case CMD_START_SCAN: 6007 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 6008 break; 6009 default: 6010 return NOT_HANDLED; 6011 } 6012 return HANDLED; 6013 } 6014 } 6015 6016 6017 String smToString(Message message) { 6018 return smToString(message.what); 6019 } 6020 6021 String smToString(int what) { 6022 String s = "unknown"; 6023 switch (what) { 6024 case WifiMonitor.DRIVER_HUNG_EVENT: 6025 s = "DRIVER_HUNG_EVENT"; 6026 break; 6027 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 6028 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED"; 6029 break; 6030 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 6031 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED"; 6032 break; 6033 case CMD_SET_FREQUENCY_BAND: 6034 s = "CMD_SET_FREQUENCY_BAND"; 6035 break; 6036 case CMD_DELAYED_NETWORK_DISCONNECT: 6037 s = "CMD_DELAYED_NETWORK_DISCONNECT"; 6038 break; 6039 case CMD_TEST_NETWORK_DISCONNECT: 6040 s = "CMD_TEST_NETWORK_DISCONNECT"; 6041 break; 6042 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 6043 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER"; 6044 break; 6045 case CMD_DISABLE_EPHEMERAL_NETWORK: 6046 s = "CMD_DISABLE_EPHEMERAL_NETWORK"; 6047 break; 6048 case CMD_START_DRIVER: 6049 s = "CMD_START_DRIVER"; 6050 break; 6051 case CMD_STOP_DRIVER: 6052 s = "CMD_STOP_DRIVER"; 6053 break; 6054 case CMD_STOP_SUPPLICANT: 6055 s = "CMD_STOP_SUPPLICANT"; 6056 break; 6057 case CMD_STOP_SUPPLICANT_FAILED: 6058 s = "CMD_STOP_SUPPLICANT_FAILED"; 6059 break; 6060 case CMD_START_SUPPLICANT: 6061 s = "CMD_START_SUPPLICANT"; 6062 break; 6063 case CMD_REQUEST_AP_CONFIG: 6064 s = "CMD_REQUEST_AP_CONFIG"; 6065 break; 6066 case CMD_RESPONSE_AP_CONFIG: 6067 s = "CMD_RESPONSE_AP_CONFIG"; 6068 break; 6069 case CMD_TETHER_STATE_CHANGE: 6070 s = "CMD_TETHER_STATE_CHANGE"; 6071 break; 6072 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6073 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT"; 6074 break; 6075 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 6076 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE"; 6077 break; 6078 case CMD_ADD_OR_UPDATE_NETWORK: 6079 s = "CMD_ADD_OR_UPDATE_NETWORK"; 6080 break; 6081 case CMD_REMOVE_NETWORK: 6082 s = "CMD_REMOVE_NETWORK"; 6083 break; 6084 case CMD_ENABLE_NETWORK: 6085 s = "CMD_ENABLE_NETWORK"; 6086 break; 6087 case CMD_ENABLE_ALL_NETWORKS: 6088 s = "CMD_ENABLE_ALL_NETWORKS"; 6089 break; 6090 case CMD_AUTO_CONNECT: 6091 s = "CMD_AUTO_CONNECT"; 6092 break; 6093 case CMD_AUTO_ROAM: 6094 s = "CMD_AUTO_ROAM"; 6095 break; 6096 case CMD_AUTO_SAVE_NETWORK: 6097 s = "CMD_AUTO_SAVE_NETWORK"; 6098 break; 6099 case CMD_BOOT_COMPLETED: 6100 s = "CMD_BOOT_COMPLETED"; 6101 break; 6102 case DhcpStateMachine.CMD_START_DHCP: 6103 s = "CMD_START_DHCP"; 6104 break; 6105 case DhcpStateMachine.CMD_STOP_DHCP: 6106 s = "CMD_STOP_DHCP"; 6107 break; 6108 case DhcpStateMachine.CMD_RENEW_DHCP: 6109 s = "CMD_RENEW_DHCP"; 6110 break; 6111 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 6112 s = "CMD_PRE_DHCP_ACTION"; 6113 break; 6114 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 6115 s = "CMD_POST_DHCP_ACTION"; 6116 break; 6117 case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE: 6118 s = "CMD_PRE_DHCP_ACTION_COMPLETE"; 6119 break; 6120 case DhcpStateMachine.CMD_ON_QUIT: 6121 s = "CMD_ON_QUIT"; 6122 break; 6123 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 6124 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST"; 6125 break; 6126 case WifiManager.DISABLE_NETWORK: 6127 s = "WifiManager.DISABLE_NETWORK"; 6128 break; 6129 case CMD_BLACKLIST_NETWORK: 6130 s = "CMD_BLACKLIST_NETWORK"; 6131 break; 6132 case CMD_CLEAR_BLACKLIST: 6133 s = "CMD_CLEAR_BLACKLIST"; 6134 break; 6135 case CMD_SAVE_CONFIG: 6136 s = "CMD_SAVE_CONFIG"; 6137 break; 6138 case CMD_GET_CONFIGURED_NETWORKS: 6139 s = "CMD_GET_CONFIGURED_NETWORKS"; 6140 break; 6141 case CMD_GET_SUPPORTED_FEATURES: 6142 s = "CMD_GET_ADAPTORS"; 6143 break; 6144 case CMD_UNWANTED_NETWORK: 6145 s = "CMD_UNWANTED_NETWORK"; 6146 break; 6147 case CMD_NETWORK_STATUS: 6148 s = "CMD_NETWORK_STATUS"; 6149 break; 6150 case CMD_GET_LINK_LAYER_STATS: 6151 s = "CMD_GET_LINK_LAYER_STATS"; 6152 break; 6153 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 6154 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS"; 6155 break; 6156 case CMD_DISCONNECT: 6157 s = "CMD_DISCONNECT"; 6158 break; 6159 case CMD_RECONNECT: 6160 s = "CMD_RECONNECT"; 6161 break; 6162 case CMD_REASSOCIATE: 6163 s = "CMD_REASSOCIATE"; 6164 break; 6165 case CMD_GET_CONNECTION_STATISTICS: 6166 s = "CMD_GET_CONNECTION_STATISTICS"; 6167 break; 6168 case CMD_SET_HIGH_PERF_MODE: 6169 s = "CMD_SET_HIGH_PERF_MODE"; 6170 break; 6171 case CMD_SET_COUNTRY_CODE: 6172 s = "CMD_SET_COUNTRY_CODE"; 6173 break; 6174 case CMD_ENABLE_RSSI_POLL: 6175 s = "CMD_ENABLE_RSSI_POLL"; 6176 break; 6177 case CMD_RSSI_POLL: 6178 s = "CMD_RSSI_POLL"; 6179 break; 6180 case CMD_START_PACKET_FILTERING: 6181 s = "CMD_START_PACKET_FILTERING"; 6182 break; 6183 case CMD_STOP_PACKET_FILTERING: 6184 s = "CMD_STOP_PACKET_FILTERING"; 6185 break; 6186 case CMD_SET_SUSPEND_OPT_ENABLED: 6187 s = "CMD_SET_SUSPEND_OPT_ENABLED"; 6188 break; 6189 case CMD_NO_NETWORKS_PERIODIC_SCAN: 6190 s = "CMD_NO_NETWORKS_PERIODIC_SCAN"; 6191 break; 6192 case CMD_SET_BATCHED_SCAN: 6193 s = "CMD_SET_BATCHED_SCAN"; 6194 break; 6195 case CMD_START_NEXT_BATCHED_SCAN: 6196 s = "CMD_START_NEXT_BATCHED_SCAN"; 6197 break; 6198 case CMD_POLL_BATCHED_SCAN: 6199 s = "CMD_POLL_BATCHED_SCAN"; 6200 break; 6201 case CMD_UPDATE_LINKPROPERTIES: 6202 s = "CMD_UPDATE_LINKPROPERTIES"; 6203 break; 6204 case CMD_RELOAD_TLS_AND_RECONNECT: 6205 s = "CMD_RELOAD_TLS_AND_RECONNECT"; 6206 break; 6207 case WifiManager.CONNECT_NETWORK: 6208 s = "CONNECT_NETWORK"; 6209 break; 6210 case WifiManager.SAVE_NETWORK: 6211 s = "SAVE_NETWORK"; 6212 break; 6213 case WifiManager.FORGET_NETWORK: 6214 s = "FORGET_NETWORK"; 6215 break; 6216 case WifiMonitor.SUP_CONNECTION_EVENT: 6217 s = "SUP_CONNECTION_EVENT"; 6218 break; 6219 case WifiMonitor.SUP_DISCONNECTION_EVENT: 6220 s = "SUP_DISCONNECTION_EVENT"; 6221 break; 6222 case WifiMonitor.SCAN_RESULTS_EVENT: 6223 s = "SCAN_RESULTS_EVENT"; 6224 break; 6225 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6226 s = "SUPPLICANT_STATE_CHANGE_EVENT"; 6227 break; 6228 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6229 s = "AUTHENTICATION_FAILURE_EVENT"; 6230 break; 6231 case WifiMonitor.SSID_TEMP_DISABLED: 6232 s = "SSID_TEMP_DISABLED"; 6233 break; 6234 case WifiMonitor.SSID_REENABLED: 6235 s = "SSID_REENABLED"; 6236 break; 6237 case WifiMonitor.WPS_SUCCESS_EVENT: 6238 s = "WPS_SUCCESS_EVENT"; 6239 break; 6240 case WifiMonitor.WPS_FAIL_EVENT: 6241 s = "WPS_FAIL_EVENT"; 6242 break; 6243 case WifiMonitor.SUP_REQUEST_IDENTITY: 6244 s = "SUP_REQUEST_IDENTITY"; 6245 break; 6246 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6247 s = "NETWORK_CONNECTION_EVENT"; 6248 break; 6249 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6250 s = "NETWORK_DISCONNECTION_EVENT"; 6251 break; 6252 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6253 s = "ASSOCIATION_REJECTION_EVENT"; 6254 break; 6255 case CMD_SET_OPERATIONAL_MODE: 6256 s = "CMD_SET_OPERATIONAL_MODE"; 6257 break; 6258 case CMD_START_SCAN: 6259 s = "CMD_START_SCAN"; 6260 break; 6261 case CMD_DISABLE_P2P_RSP: 6262 s = "CMD_DISABLE_P2P_RSP"; 6263 break; 6264 case CMD_DISABLE_P2P_REQ: 6265 s = "CMD_DISABLE_P2P_REQ"; 6266 break; 6267 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 6268 s = "GOOD_LINK_DETECTED"; 6269 break; 6270 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6271 s = "POOR_LINK_DETECTED"; 6272 break; 6273 case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT: 6274 s = "GROUP_CREATING_TIMED_OUT"; 6275 break; 6276 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 6277 s = "P2P_CONNECTION_CHANGED"; 6278 break; 6279 case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE: 6280 s = "P2P.DISCONNECT_WIFI_RESPONSE"; 6281 break; 6282 case WifiP2pServiceImpl.SET_MIRACAST_MODE: 6283 s = "P2P.SET_MIRACAST_MODE"; 6284 break; 6285 case WifiP2pServiceImpl.BLOCK_DISCOVERY: 6286 s = "P2P.BLOCK_DISCOVERY"; 6287 break; 6288 case WifiP2pServiceImpl.SET_COUNTRY_CODE: 6289 s = "P2P.SET_COUNTRY_CODE"; 6290 break; 6291 case WifiManager.CANCEL_WPS: 6292 s = "CANCEL_WPS"; 6293 break; 6294 case WifiManager.CANCEL_WPS_FAILED: 6295 s = "CANCEL_WPS_FAILED"; 6296 break; 6297 case WifiManager.CANCEL_WPS_SUCCEDED: 6298 s = "CANCEL_WPS_SUCCEDED"; 6299 break; 6300 case WifiManager.START_WPS: 6301 s = "START_WPS"; 6302 break; 6303 case WifiManager.START_WPS_SUCCEEDED: 6304 s = "START_WPS_SUCCEEDED"; 6305 break; 6306 case WifiManager.WPS_FAILED: 6307 s = "WPS_FAILED"; 6308 break; 6309 case WifiManager.WPS_COMPLETED: 6310 s = "WPS_COMPLETED"; 6311 break; 6312 case WifiManager.RSSI_PKTCNT_FETCH: 6313 s = "RSSI_PKTCNT_FETCH"; 6314 break; 6315 case CMD_IP_CONFIGURATION_LOST: 6316 s = "CMD_IP_CONFIGURATION_LOST"; 6317 break; 6318 case CMD_IP_CONFIGURATION_SUCCESSFUL: 6319 s = "CMD_IP_CONFIGURATION_SUCCESSFUL"; 6320 break; 6321 case CMD_STATIC_IP_SUCCESS: 6322 s = "CMD_STATIC_IP_SUCCESSFUL"; 6323 break; 6324 case CMD_STATIC_IP_FAILURE: 6325 s = "CMD_STATIC_IP_FAILURE"; 6326 break; 6327 case DhcpStateMachine.DHCP_SUCCESS: 6328 s = "DHCP_SUCCESS"; 6329 break; 6330 case DhcpStateMachine.DHCP_FAILURE: 6331 s = "DHCP_FAILURE"; 6332 break; 6333 case CMD_TARGET_BSSID: 6334 s = "CMD_TARGET_BSSID"; 6335 break; 6336 case CMD_ASSOCIATED_BSSID: 6337 s = "CMD_ASSOCIATED_BSSID"; 6338 break; 6339 case CMD_REMOVE_APP_CONFIGURATIONS: 6340 s = "CMD_REMOVE_APP_CONFIGURATIONS"; 6341 break; 6342 case CMD_REMOVE_USER_CONFIGURATIONS: 6343 s = "CMD_REMOVE_USER_CONFIGURATIONS"; 6344 break; 6345 case CMD_ROAM_WATCHDOG_TIMER: 6346 s = "CMD_ROAM_WATCHDOG_TIMER"; 6347 break; 6348 case CMD_SCREEN_STATE_CHANGED: 6349 s = "CMD_SCREEN_STATE_CHANGED"; 6350 break; 6351 case CMD_DISCONNECTING_WATCHDOG_TIMER: 6352 s = "CMD_DISCONNECTING_WATCHDOG_TIMER"; 6353 break; 6354 default: 6355 s = "what:" + Integer.toString(what); 6356 break; 6357 } 6358 return s; 6359 } 6360 6361 void registerConnected() { 6362 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 6363 long now_ms = System.currentTimeMillis(); 6364 // We are switching away from this configuration, 6365 // hence record the time we were connected last 6366 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6367 if (config != null) { 6368 config.lastConnected = System.currentTimeMillis(); 6369 config.autoJoinBailedDueToLowRssi = false; 6370 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 6371 config.numConnectionFailures = 0; 6372 config.numIpConfigFailures = 0; 6373 config.numAuthFailures = 0; 6374 config.numAssociation++; 6375 } 6376 mBadLinkspeedcount = 0; 6377 } 6378 } 6379 6380 void registerDisconnected() { 6381 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 6382 long now_ms = System.currentTimeMillis(); 6383 // We are switching away from this configuration, 6384 // hence record the time we were connected last 6385 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6386 if (config != null) { 6387 config.lastDisconnected = System.currentTimeMillis(); 6388 if (config.ephemeral) { 6389 // Remove ephemeral WifiConfigurations from file 6390 mWifiConfigStore.forgetNetwork(mLastNetworkId); 6391 } 6392 } 6393 } 6394 } 6395 6396 void noteWifiDisabledWhileAssociated() { 6397 // We got disabled by user while we were associated, make note of it 6398 int rssi = mWifiInfo.getRssi(); 6399 WifiConfiguration config = getCurrentWifiConfiguration(); 6400 if (getCurrentState() == mConnectedState 6401 && rssi != WifiInfo.INVALID_RSSI 6402 && config != null) { 6403 boolean is24GHz = mWifiInfo.is24GHz(); 6404 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get()) 6405 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get()); 6406 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get()) 6407 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get()); 6408 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get()) 6409 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get()); 6410 if (isBadRSSI) { 6411 // Take note that we got disabled while RSSI was Bad 6412 config.numUserTriggeredWifiDisableLowRSSI++; 6413 } else if (isLowRSSI) { 6414 // Take note that we got disabled while RSSI was Low 6415 config.numUserTriggeredWifiDisableBadRSSI++; 6416 } else if (!isHighRSSI) { 6417 // Take note that we got disabled while RSSI was Not high 6418 config.numUserTriggeredWifiDisableNotHighRSSI++; 6419 } 6420 } 6421 } 6422 6423 WifiConfiguration getCurrentWifiConfiguration() { 6424 if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 6425 return null; 6426 } 6427 return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6428 } 6429 6430 ScanResult getCurrentScanResult() { 6431 WifiConfiguration config = getCurrentWifiConfiguration(); 6432 if (config == null) { 6433 return null; 6434 } 6435 String BSSID = mWifiInfo.getBSSID(); 6436 if (BSSID == null) { 6437 BSSID = mTargetRoamBSSID; 6438 } 6439 if (config.scanResultCache == null) { 6440 return null; 6441 } 6442 return config.scanResultCache.get(BSSID); 6443 } 6444 6445 String getCurrentBSSID() { 6446 if (linkDebouncing) { 6447 return null; 6448 } 6449 return mLastBssid; 6450 } 6451 6452 class ConnectModeState extends State { 6453 @Override 6454 public boolean processMessage(Message message) { 6455 WifiConfiguration config; 6456 int netId; 6457 boolean ok; 6458 boolean didDisconnect; 6459 String bssid; 6460 String ssid; 6461 NetworkUpdateResult result; 6462 logStateAndMessage(message, getClass().getSimpleName()); 6463 6464 switch (message.what) { 6465 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6466 didBlackListBSSID = false; 6467 bssid = (String) message.obj; 6468 if (bssid == null || TextUtils.isEmpty(bssid)) { 6469 // If BSSID is null, use the target roam BSSID 6470 bssid = mTargetRoamBSSID; 6471 } 6472 if (bssid != null) { 6473 // If we have a BSSID, tell configStore to black list it 6474 synchronized(mScanResultCache) { 6475 didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList 6476 (mLastNetworkId, bssid, false); 6477 } 6478 } 6479 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 6480 break; 6481 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6482 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 6483 break; 6484 case WifiMonitor.SSID_TEMP_DISABLED: 6485 case WifiMonitor.SSID_REENABLED: 6486 String substr = (String) message.obj; 6487 String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ? 6488 "temp-disabled" : "re-enabled"; 6489 loge("ConnectModeState SSID state=" + en + " nid=" 6490 + Integer.toString(message.arg1) + " [" + substr + "]"); 6491 synchronized(mScanResultCache) { 6492 mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what == 6493 WifiMonitor.SSID_REENABLED, substr, mWifiInfo.getBSSID()); 6494 } 6495 break; 6496 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6497 SupplicantState state = handleSupplicantStateChange(message); 6498 // A driver/firmware hang can now put the interface in a down state. 6499 // We detect the interface going down and recover from it 6500 if (!SupplicantState.isDriverActive(state)) { 6501 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 6502 handleNetworkDisconnect(); 6503 } 6504 log("Detected an interface down, restart driver"); 6505 transitionTo(mDriverStoppedState); 6506 sendMessage(CMD_START_DRIVER); 6507 break; 6508 } 6509 6510 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 6511 // when authentication times out after a successful connection, 6512 // we can figure this from the supplicant state. If supplicant 6513 // state is DISCONNECTED, but the mNetworkInfo says we are not 6514 // disconnected, we need to handle a disconnection 6515 if (!linkDebouncing && state == SupplicantState.DISCONNECTED && 6516 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 6517 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 6518 handleNetworkDisconnect(); 6519 transitionTo(mDisconnectedState); 6520 } 6521 break; 6522 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 6523 if (message.arg1 == 1) { 6524 mWifiNative.disconnect(); 6525 mTemporarilyDisconnectWifi = true; 6526 } else { 6527 mWifiNative.reconnect(); 6528 mTemporarilyDisconnectWifi = false; 6529 } 6530 break; 6531 case CMD_ADD_OR_UPDATE_NETWORK: 6532 config = (WifiConfiguration) message.obj; 6533 6534 if (!recordUidIfAuthorized(config, message.sendingUid)) { 6535 loge("Not authorized to update network " 6536 + " config=" + config.SSID 6537 + " cnid=" + config.networkId 6538 + " uid=" + message.sendingUid); 6539 replyToMessage(message, message.what, FAILURE); 6540 break; 6541 } 6542 6543 int res = mWifiConfigStore.addOrUpdateNetwork(config, message.sendingUid); 6544 if (res < 0) { 6545 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6546 } else { 6547 WifiConfiguration curConfig = getCurrentWifiConfiguration(); 6548 if (curConfig != null && config != null) { 6549 if (curConfig.priority < config.priority 6550 && config.status == WifiConfiguration.Status.ENABLED) { 6551 // Interpret this as a connect attempt 6552 // Set the last selected configuration so as to allow the system to 6553 // stick the last user choice without persisting the choice 6554 mWifiConfigStore.setLastSelectedConfiguration(res); 6555 6556 // Remember time of last connection attempt 6557 lastConnectAttempt = System.currentTimeMillis(); 6558 6559 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6560 6561 // As a courtesy to the caller, trigger a scan now 6562 startScan(ADD_OR_UPDATE_SOURCE, 0, null, null); 6563 } 6564 } 6565 } 6566 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res); 6567 break; 6568 case CMD_REMOVE_NETWORK: 6569 netId = message.arg1; 6570 if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId)) { 6571 loge("Not authorized to remove network " 6572 + " cnid=" + netId 6573 + " uid=" + message.sendingUid); 6574 replyToMessage(message, message.what, FAILURE); 6575 break; 6576 } 6577 6578 ok = mWifiConfigStore.removeNetwork(message.arg1); 6579 if (!ok) { 6580 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6581 } 6582 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 6583 break; 6584 case CMD_ENABLE_NETWORK: 6585 boolean others = message.arg2 == 1; 6586 // Tell autojoin the user did try to select to that network 6587 // However, do NOT persist the choice by bumping the priority of the network 6588 if (others) { 6589 mWifiAutoJoinController. 6590 updateConfigurationHistory(message.arg1, true, false); 6591 // Set the last selected configuration so as to allow the system to 6592 // stick the last user choice without persisting the choice 6593 mWifiConfigStore.setLastSelectedConfiguration(message.arg1); 6594 6595 // Remember time of last connection attempt 6596 lastConnectAttempt = System.currentTimeMillis(); 6597 6598 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6599 } 6600 // Cancel auto roam requests 6601 autoRoamSetBSSID(message.arg1, "any"); 6602 6603 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 6604 if (!ok) { 6605 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6606 } 6607 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 6608 break; 6609 case CMD_ENABLE_ALL_NETWORKS: 6610 long time = android.os.SystemClock.elapsedRealtime(); 6611 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 6612 mWifiConfigStore.enableAllNetworks(); 6613 mLastEnableAllNetworksTime = time; 6614 } 6615 break; 6616 case WifiManager.DISABLE_NETWORK: 6617 if (mWifiConfigStore.disableNetwork(message.arg1, 6618 WifiConfiguration.DISABLED_BY_WIFI_MANAGER) == true) { 6619 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 6620 } else { 6621 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6622 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 6623 WifiManager.ERROR); 6624 } 6625 break; 6626 case CMD_DISABLE_EPHEMERAL_NETWORK: 6627 config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj); 6628 if (config != null) { 6629 if (config.networkId == mLastNetworkId) { 6630 // Disconnect and let autojoin reselect a new network 6631 sendMessage(CMD_DISCONNECT); 6632 } 6633 } 6634 break; 6635 case CMD_BLACKLIST_NETWORK: 6636 mWifiNative.addToBlacklist((String) message.obj); 6637 break; 6638 case CMD_CLEAR_BLACKLIST: 6639 mWifiNative.clearBlacklist(); 6640 break; 6641 case CMD_SAVE_CONFIG: 6642 ok = mWifiConfigStore.saveConfig(); 6643 6644 if (DBG) loge("wifistatemachine did save config " + ok); 6645 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 6646 6647 // Inform the backup manager about a data change 6648 IBackupManager ibm = IBackupManager.Stub.asInterface( 6649 ServiceManager.getService(Context.BACKUP_SERVICE)); 6650 if (ibm != null) { 6651 try { 6652 ibm.dataChanged("com.android.providers.settings"); 6653 } catch (Exception e) { 6654 // Try again later 6655 } 6656 } 6657 break; 6658 case CMD_GET_CONFIGURED_NETWORKS: 6659 replyToMessage(message, message.what, 6660 mWifiConfigStore.getConfiguredNetworks()); 6661 break; 6662 case WifiMonitor.SUP_REQUEST_IDENTITY: 6663 int networkId = message.arg2; 6664 boolean identitySent = false; 6665 int eapMethod = WifiEnterpriseConfig.Eap.NONE; 6666 6667 if (targetWificonfiguration != null 6668 && targetWificonfiguration.enterpriseConfig != null) { 6669 eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod(); 6670 } 6671 6672 // For SIM & AKA EAP method Only, get identity from ICC 6673 if (targetWificonfiguration != null 6674 && targetWificonfiguration.networkId == networkId 6675 && targetWificonfiguration.allowedKeyManagement 6676 .get(WifiConfiguration.KeyMgmt.IEEE8021X) 6677 && (eapMethod == WifiEnterpriseConfig.Eap.SIM 6678 || eapMethod == WifiEnterpriseConfig.Eap.AKA)) { 6679 TelephonyManager tm = (TelephonyManager) 6680 mContext.getSystemService(Context.TELEPHONY_SERVICE); 6681 if (tm != null) { 6682 String imsi = tm.getSubscriberId(); 6683 String mccMnc = ""; 6684 6685 if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) 6686 mccMnc = tm.getSimOperator(); 6687 6688 String identity = buildIdentity(eapMethod, imsi, mccMnc); 6689 6690 if (!identity.isEmpty()) { 6691 mWifiNative.simIdentityResponse(networkId, identity); 6692 identitySent = true; 6693 } 6694 } 6695 } 6696 if (!identitySent) { 6697 // Supplicant lacks credentials to connect to that network, hence black list 6698 ssid = (String) message.obj; 6699 if (targetWificonfiguration != null && ssid != null 6700 && targetWificonfiguration.SSID != null 6701 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) { 6702 mWifiConfigStore.handleSSIDStateChange( 6703 targetWificonfiguration.networkId, false, 6704 "AUTH_FAILED no identity", null); 6705 } 6706 // Disconnect now, as we don't have any way to fullfill 6707 // the supplicant request. 6708 mWifiConfigStore.setLastSelectedConfiguration( 6709 WifiConfiguration.INVALID_NETWORK_ID); 6710 mWifiNative.disconnect(); 6711 } 6712 break; 6713 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 6714 logd("Received SUP_REQUEST_SIM_AUTH"); 6715 SimAuthRequestData requestData = (SimAuthRequestData) message.obj; 6716 if (requestData != null) { 6717 if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) { 6718 handleGsmAuthRequest(requestData); 6719 } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA) { 6720 handle3GAuthRequest(requestData); 6721 } 6722 } else { 6723 loge("Invalid sim auth request"); 6724 } 6725 break; 6726 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 6727 replyToMessage(message, message.what, 6728 mWifiConfigStore.getPrivilegedConfiguredNetworks()); 6729 break; 6730 /* Do a redundant disconnect without transition */ 6731 case CMD_DISCONNECT: 6732 mWifiConfigStore.setLastSelectedConfiguration 6733 (WifiConfiguration.INVALID_NETWORK_ID); 6734 mWifiNative.disconnect(); 6735 break; 6736 case CMD_RECONNECT: 6737 mWifiAutoJoinController.attemptAutoJoin(); 6738 break; 6739 case CMD_REASSOCIATE: 6740 lastConnectAttempt = System.currentTimeMillis(); 6741 mWifiNative.reassociate(); 6742 break; 6743 case CMD_RELOAD_TLS_AND_RECONNECT: 6744 if (mWifiConfigStore.needsUnlockedKeyStore()) { 6745 logd("Reconnecting to give a chance to un-connected TLS networks"); 6746 mWifiNative.disconnect(); 6747 lastConnectAttempt = System.currentTimeMillis(); 6748 mWifiNative.reconnect(); 6749 } 6750 break; 6751 case CMD_AUTO_ROAM: 6752 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 6753 return HANDLED; 6754 case CMD_AUTO_CONNECT: 6755 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 6756 * associated status to the STATUS command but somehow-someplace still thinks 6757 * it is associated and thus will ignore select/reconnect command with 6758 * following message: 6759 * "Already associated with the selected network - do nothing" 6760 * 6761 * Hence, sends a disconnect to supplicant first. 6762 */ 6763 didDisconnect = false; 6764 if (getCurrentState() != mDisconnectedState) { 6765 /** Supplicant will ignore the reconnect if we are currently associated, 6766 * hence trigger a disconnect 6767 */ 6768 didDisconnect = true; 6769 mWifiNative.disconnect(); 6770 } 6771 6772 /* connect command coming from auto-join */ 6773 config = (WifiConfiguration) message.obj; 6774 netId = message.arg1; 6775 int roam = message.arg2; 6776 loge("CMD_AUTO_CONNECT sup state " 6777 + mSupplicantStateTracker.getSupplicantStateName() 6778 + " my state " + getCurrentState().getName() 6779 + " nid=" + Integer.toString(netId) 6780 + " roam=" + Integer.toString(roam)); 6781 if (config == null) { 6782 loge("AUTO_CONNECT and no config, bail out..."); 6783 break; 6784 } 6785 6786 /* Make sure we cancel any previous roam request */ 6787 autoRoamSetBSSID(netId, config.BSSID); 6788 6789 /* Save the network config */ 6790 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 6791 + " nid=" + Integer.toString(netId)); 6792 result = mWifiConfigStore.saveNetwork(config, -1); 6793 netId = result.getNetworkId(); 6794 loge("CMD_AUTO_CONNECT did save config -> " 6795 + " nid=" + Integer.toString(netId)); 6796 6797 if (deferForUserInput(message, netId, false)) { 6798 break; 6799 } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved == 6800 WifiConfiguration.USER_BANNED) { 6801 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6802 WifiManager.NOT_AUTHORIZED); 6803 break; 6804 } 6805 6806 // Make sure the network is enabled, since supplicant will not reenable it 6807 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 6808 6809 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false) && 6810 mWifiNative.reconnect()) { 6811 lastConnectAttempt = System.currentTimeMillis(); 6812 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 6813 config = mWifiConfigStore.getWifiConfiguration(netId); 6814 if (config != null 6815 && !mWifiConfigStore.isLastSelectedConfiguration(config)) { 6816 // If we autojoined a different config than the user selected one, 6817 // it means we could not see the last user selection, 6818 // or that the last user selection was faulty and ended up blacklisted 6819 // for some reason (in which case the user is notified with an error 6820 // message in the Wifi picker), and thus we managed to auto-join away 6821 // from the selected config. -> in that case we need to forget 6822 // the selection because we don't want to abruptly switch back to it. 6823 // 6824 // Note that the user selection is also forgotten after a period of time 6825 // during which the device has been disconnected. 6826 // The default value is 30 minutes : see the code path at bottom of 6827 // setScanResults() function. 6828 mWifiConfigStore. 6829 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 6830 } 6831 mAutoRoaming = roam; 6832 if (isRoaming() || linkDebouncing) { 6833 transitionTo(mRoamingState); 6834 } else if (didDisconnect) { 6835 transitionTo(mDisconnectingState); 6836 } else { 6837 /* Already in disconnected state, nothing to change */ 6838 } 6839 } else { 6840 loge("Failed to connect config: " + config + " netId: " + netId); 6841 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6842 WifiManager.ERROR); 6843 break; 6844 } 6845 break; 6846 case CMD_REMOVE_APP_CONFIGURATIONS: 6847 mWifiConfigStore.removeNetworksForApp((ApplicationInfo) message.obj); 6848 break; 6849 case CMD_REMOVE_USER_CONFIGURATIONS: 6850 mWifiConfigStore.removeNetworksForUser(message.arg1); 6851 break; 6852 case WifiManager.CONNECT_NETWORK: 6853 /** 6854 * The connect message can contain a network id passed as arg1 on message or 6855 * or a config passed as obj on message. 6856 * For a new network, a config is passed to create and connect. 6857 * For an existing network, a network id is passed 6858 */ 6859 netId = message.arg1; 6860 config = (WifiConfiguration) message.obj; 6861 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6862 boolean updatedExisting = false; 6863 6864 /* Save the network config */ 6865 if (config != null) { 6866 if (!recordUidIfAuthorized(config, message.sendingUid)) { 6867 loge("Not authorized to update network " 6868 + " config=" + config.SSID 6869 + " cnid=" + config.networkId 6870 + " uid=" + message.sendingUid); 6871 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6872 WifiManager.NOT_AUTHORIZED); 6873 break; 6874 } 6875 6876 String configKey = config.configKey(true /* allowCached */); 6877 WifiConfiguration savedConfig = 6878 mWifiConfigStore.getWifiConfiguration(configKey); 6879 if (savedConfig != null) { 6880 // There is an existing config with this netId, but it wasn't exposed 6881 // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore# 6882 // getConfiguredNetworks). Remove those bits and update the config. 6883 config = savedConfig; 6884 loge("CONNECT_NETWORK updating existing config with id=" + 6885 config.networkId + " configKey=" + configKey); 6886 config.ephemeral = false; 6887 config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED; 6888 updatedExisting = true; 6889 } 6890 6891 result = mWifiConfigStore.saveNetwork(config, message.sendingUid); 6892 netId = result.getNetworkId(); 6893 } 6894 config = mWifiConfigStore.getWifiConfiguration(netId); 6895 6896 if (config == null) { 6897 loge("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " " 6898 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 6899 + getCurrentState().getName()); 6900 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6901 WifiManager.ERROR); 6902 break; 6903 } else { 6904 String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : ""; 6905 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 6906 + " config=" + config.SSID 6907 + " cnid=" + config.networkId 6908 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 6909 + " my state " + getCurrentState().getName() 6910 + " uid = " + message.sendingUid 6911 + wasSkipped); 6912 } 6913 6914 autoRoamSetBSSID(netId, "any"); 6915 6916 if (message.sendingUid == Process.WIFI_UID 6917 || message.sendingUid == Process.SYSTEM_UID) { 6918 // As a sanity measure, clear the BSSID in the supplicant network block. 6919 // If system or Wifi Settings want to connect, they will not 6920 // specify the BSSID. 6921 // If an app however had added a BSSID to this configuration, and the BSSID 6922 // was wrong, Then we would forever fail to connect until that BSSID 6923 // is cleaned up. 6924 clearConfigBSSID(config, "CONNECT_NETWORK"); 6925 } 6926 6927 if (deferForUserInput(message, netId, true)) { 6928 break; 6929 } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved == 6930 WifiConfiguration.USER_BANNED) { 6931 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6932 WifiManager.NOT_AUTHORIZED); 6933 break; 6934 } 6935 6936 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6937 6938 /* Tell autojoin the user did try to connect to that network if from settings */ 6939 boolean persist = 6940 mWifiConfigStore.checkConfigOverridePermission(message.sendingUid); 6941 mWifiAutoJoinController.updateConfigurationHistory(netId, true, persist); 6942 6943 mWifiConfigStore.setLastSelectedConfiguration(netId); 6944 6945 didDisconnect = false; 6946 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID 6947 && mLastNetworkId != netId) { 6948 /** Supplicant will ignore the reconnect if we are currently associated, 6949 * hence trigger a disconnect 6950 */ 6951 didDisconnect = true; 6952 mWifiNative.disconnect(); 6953 } 6954 6955 // Make sure the network is enabled, since supplicant will not reenable it 6956 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 6957 6958 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true) && 6959 mWifiNative.reconnect()) { 6960 lastConnectAttempt = System.currentTimeMillis(); 6961 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 6962 6963 /* The state tracker handles enabling networks upon completion/failure */ 6964 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 6965 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 6966 if (didDisconnect) { 6967 /* Expect a disconnection from the old connection */ 6968 transitionTo(mDisconnectingState); 6969 } else if (updatedExisting && getCurrentState() == mConnectedState && 6970 getCurrentWifiConfiguration().networkId == netId) { 6971 // Update the current set of network capabilities, but stay in the 6972 // current state. 6973 updateCapabilities(config); 6974 } else { 6975 /** 6976 * Directly go to disconnected state where we 6977 * process the connection events from supplicant 6978 **/ 6979 transitionTo(mDisconnectedState); 6980 } 6981 } else { 6982 loge("Failed to connect config: " + config + " netId: " + netId); 6983 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6984 WifiManager.ERROR); 6985 break; 6986 } 6987 break; 6988 case WifiManager.SAVE_NETWORK: 6989 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6990 // Fall thru 6991 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 6992 lastSavedConfigurationAttempt = null; // Used for debug 6993 config = (WifiConfiguration) message.obj; 6994 if (config == null) { 6995 loge("ERROR: SAVE_NETWORK with null configuration" 6996 + mSupplicantStateTracker.getSupplicantStateName() 6997 + " my state " + getCurrentState().getName()); 6998 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6999 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7000 WifiManager.ERROR); 7001 break; 7002 } 7003 lastSavedConfigurationAttempt = new WifiConfiguration(config); 7004 int nid = config.networkId; 7005 loge("SAVE_NETWORK id=" + Integer.toString(nid) 7006 + " config=" + config.SSID 7007 + " nid=" + config.networkId 7008 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 7009 + " my state " + getCurrentState().getName()); 7010 7011 // Only record the uid if this is user initiated 7012 boolean checkUid = (message.what == WifiManager.SAVE_NETWORK); 7013 if (checkUid && !recordUidIfAuthorized(config, message.sendingUid)) { 7014 loge("Not authorized to update network " 7015 + " config=" + config.SSID 7016 + " cnid=" + config.networkId 7017 + " uid=" + message.sendingUid); 7018 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7019 WifiManager.NOT_AUTHORIZED); 7020 break; 7021 } 7022 7023 result = mWifiConfigStore.saveNetwork(config, -1); 7024 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 7025 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 7026 if (result.hasIpChanged()) { 7027 // The currently connection configuration was changed 7028 // We switched from DHCP to static or from static to DHCP, or the 7029 // static IP address has changed. 7030 log("Reconfiguring IP on connection"); 7031 // TODO: clear addresses and disable IPv6 7032 // to simplify obtainingIpState. 7033 transitionTo(mObtainingIpState); 7034 } 7035 if (result.hasProxyChanged()) { 7036 log("Reconfiguring proxy on connection"); 7037 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 7038 } 7039 } 7040 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 7041 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config); 7042 7043 if (VDBG) { 7044 loge("Success save network nid=" 7045 + Integer.toString(result.getNetworkId())); 7046 } 7047 7048 synchronized(mScanResultCache) { 7049 /** 7050 * If the command comes from WifiManager, then 7051 * tell autojoin the user did try to modify and save that network, 7052 * and interpret the SAVE_NETWORK as a request to connect 7053 */ 7054 boolean user = message.what == WifiManager.SAVE_NETWORK; 7055 7056 // Did this connect come from settings 7057 boolean persistConnect = 7058 mWifiConfigStore.checkConfigOverridePermission(message.sendingUid); 7059 7060 mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() 7061 , user, persistConnect); 7062 mWifiAutoJoinController.attemptAutoJoin(); 7063 } 7064 } else { 7065 loge("Failed to save network"); 7066 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 7067 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7068 WifiManager.ERROR); 7069 } 7070 break; 7071 case WifiManager.FORGET_NETWORK: 7072 // Debug only, remember last configuration that was forgotten 7073 WifiConfiguration toRemove 7074 = mWifiConfigStore.getWifiConfiguration(message.arg1); 7075 if (toRemove == null) { 7076 lastForgetConfigurationAttempt = null; 7077 } else { 7078 lastForgetConfigurationAttempt = new WifiConfiguration(toRemove); 7079 } 7080 // check that the caller owns this network 7081 netId = message.arg1; 7082 7083 if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId)) { 7084 loge("Not authorized to forget network " 7085 + " cnid=" + netId 7086 + " uid=" + message.sendingUid); 7087 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 7088 WifiManager.NOT_AUTHORIZED); 7089 break; 7090 } 7091 7092 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 7093 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 7094 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT, 7095 (WifiConfiguration) message.obj); 7096 } else { 7097 loge("Failed to forget network"); 7098 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 7099 WifiManager.ERROR); 7100 } 7101 break; 7102 case WifiManager.START_WPS: 7103 WpsInfo wpsInfo = (WpsInfo) message.obj; 7104 WpsResult wpsResult; 7105 switch (wpsInfo.setup) { 7106 case WpsInfo.PBC: 7107 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 7108 break; 7109 case WpsInfo.KEYPAD: 7110 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 7111 break; 7112 case WpsInfo.DISPLAY: 7113 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 7114 break; 7115 default: 7116 wpsResult = new WpsResult(Status.FAILURE); 7117 loge("Invalid setup for WPS"); 7118 break; 7119 } 7120 mWifiConfigStore.setLastSelectedConfiguration 7121 (WifiConfiguration.INVALID_NETWORK_ID); 7122 if (wpsResult.status == Status.SUCCESS) { 7123 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 7124 transitionTo(mWpsRunningState); 7125 } else { 7126 loge("Failed to start WPS with config " + wpsInfo.toString()); 7127 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 7128 } 7129 break; 7130 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7131 if (DBG) log("Network connection established"); 7132 mLastNetworkId = message.arg1; 7133 mLastBssid = (String) message.obj; 7134 7135 mWifiInfo.setBSSID(mLastBssid); 7136 mWifiInfo.setNetworkId(mLastNetworkId); 7137 7138 sendNetworkStateChangeBroadcast(mLastBssid); 7139 transitionTo(mObtainingIpState); 7140 break; 7141 case WifiMonitor.ANQP_DONE_EVENT: 7142 Log.d("HS2J", String.format("WFSM: ANQP for %016x %s", 7143 (Long)message.obj, message.arg1 != 0 ? "success" : "fail")); 7144 mWifiConfigStore.notifyANQPDone((Long) message.obj, message.arg1 != 0); 7145 break; 7146 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 7147 // Calling handleNetworkDisconnect here is redundant because we might already 7148 // have called it when leaving L2ConnectedState to go to disconnecting state 7149 // or thru other path 7150 // We should normally check the mWifiInfo or mLastNetworkId so as to check 7151 // if they are valid, and only in this case call handleNEtworkDisconnect, 7152 // TODO: this should be fixed for a L MR release 7153 // The side effect of calling handleNetworkDisconnect twice is that a bunch of 7154 // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode 7155 // at the chip etc... 7156 if (DBG) log("ConnectModeState: Network connection lost "); 7157 handleNetworkDisconnect(); 7158 transitionTo(mDisconnectedState); 7159 break; 7160 default: 7161 return NOT_HANDLED; 7162 } 7163 return HANDLED; 7164 } 7165 } 7166 7167 private void updateCapabilities(WifiConfiguration config) { 7168 if (config.ephemeral) { 7169 mNetworkCapabilities.removeCapability( 7170 NetworkCapabilities.NET_CAPABILITY_TRUSTED); 7171 } else { 7172 mNetworkCapabilities.addCapability( 7173 NetworkCapabilities.NET_CAPABILITY_TRUSTED); 7174 } 7175 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 7176 } 7177 7178 private class WifiNetworkAgent extends NetworkAgent { 7179 public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, 7180 NetworkCapabilities nc, LinkProperties lp, int score) { 7181 super(l, c, TAG, ni, nc, lp, score); 7182 } 7183 protected void unwanted() { 7184 // Ignore if we're not the current networkAgent. 7185 if (this != mNetworkAgent) return; 7186 if (DBG) log("WifiNetworkAgent -> Wifi unwanted score " 7187 + Integer.toString(mWifiInfo.score)); 7188 unwantedNetwork(network_status_unwanted_disconnect); 7189 } 7190 7191 protected void networkStatus(int status) { 7192 if (status == NetworkAgent.INVALID_NETWORK) { 7193 if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score=" 7194 + Integer.toString(mWifiInfo.score)); 7195 unwantedNetwork(network_status_unwanted_disable_autojoin); 7196 } else if (status == NetworkAgent.VALID_NETWORK) { 7197 if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= " 7198 + Integer.toString(mWifiInfo.score)); 7199 doNetworkStatus(status); 7200 } 7201 } 7202 } 7203 7204 void unwantedNetwork(int reason) { 7205 sendMessage(CMD_UNWANTED_NETWORK, reason); 7206 } 7207 7208 void doNetworkStatus(int status) { 7209 sendMessage(CMD_NETWORK_STATUS, status); 7210 } 7211 7212 // rfc4186 & rfc4187: 7213 // create Permanent Identity base on IMSI, 7214 // identity = usernam@realm 7215 // with username = prefix | IMSI 7216 // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003) 7217 private String buildIdentity(int eapMethod, String imsi, String mccMnc) { 7218 String mcc; 7219 String mnc; 7220 String prefix; 7221 7222 if (imsi == null || imsi.isEmpty()) 7223 return ""; 7224 7225 if (eapMethod == WifiEnterpriseConfig.Eap.SIM) 7226 prefix = "1"; 7227 else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) 7228 prefix = "0"; 7229 else // not a valide EapMethod 7230 return ""; 7231 7232 /* extract mcc & mnc from mccMnc */ 7233 if (mccMnc != null && !mccMnc.isEmpty()) { 7234 mcc = mccMnc.substring(0, 3); 7235 mnc = mccMnc.substring(3); 7236 if (mnc.length() == 2) 7237 mnc = "0" + mnc; 7238 } else { 7239 // extract mcc & mnc from IMSI, assume mnc size is 3 7240 mcc = imsi.substring(0, 3); 7241 mnc = imsi.substring(3, 6); 7242 } 7243 7244 return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org"; 7245 } 7246 7247 boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) { 7248 if (config == null) 7249 return false; 7250 7251 // We are still seeing a fairly high power consumption triggered by autojoin scans 7252 // Hence do partial scans only for PSK configuration that are roamable since the 7253 // primary purpose of the partial scans is roaming. 7254 // Full badn scans with exponential backoff for the purpose or extended roaming and 7255 // network switching are performed unconditionally. 7256 if (config.scanResultCache == null 7257 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 7258 || config.scanResultCache.size() > 6) { 7259 //return true but to not trigger the scan 7260 return true; 7261 } 7262 HashSet<Integer> channels 7263 = mWifiConfigStore.makeChannelList(config, 7264 ONE_HOUR_MILLI, restrictChannelList); 7265 if (channels != null && channels.size() != 0) { 7266 StringBuilder freqs = new StringBuilder(); 7267 boolean first = true; 7268 for (Integer channel : channels) { 7269 if (!first) 7270 freqs.append(","); 7271 freqs.append(channel.toString()); 7272 first = false; 7273 } 7274 //if (DBG) { 7275 loge("WifiStateMachine starting scan for " + config.configKey() + " with " + freqs); 7276 //} 7277 // Call wifi native to start the scan 7278 if (startScanNative( 7279 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, 7280 freqs.toString())) { 7281 // Only count battery consumption if scan request is accepted 7282 noteScanStart(SCAN_ALARM_SOURCE, null); 7283 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; 7284 } else { 7285 // used for debug only, mark scan as failed 7286 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; 7287 } 7288 return true; 7289 } else { 7290 if (DBG) loge("WifiStateMachine no channels for " + config.configKey()); 7291 return false; 7292 } 7293 } 7294 7295 void clearCurrentConfigBSSID(String dbg) { 7296 // Clear the bssid in the current config's network block 7297 WifiConfiguration config = getCurrentWifiConfiguration(); 7298 if (config == null) 7299 return; 7300 clearConfigBSSID(config, dbg); 7301 } 7302 void clearConfigBSSID(WifiConfiguration config, String dbg) { 7303 if (config == null) 7304 return; 7305 if (DBG) { 7306 loge(dbg + " " + mTargetRoamBSSID + " config " + config.configKey() 7307 + " config.bssid " + config.BSSID); 7308 } 7309 config.autoJoinBSSID = "any"; 7310 config.BSSID = "any"; 7311 if (DBG) { 7312 loge(dbg + " " + config.SSID 7313 + " nid=" + Integer.toString(config.networkId)); 7314 } 7315 mWifiConfigStore.saveWifiConfigBSSID(config); 7316 } 7317 7318 class L2ConnectedState extends State { 7319 @Override 7320 public void enter() { 7321 mRssiPollToken++; 7322 if (mEnableRssiPolling) { 7323 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 7324 } 7325 if (mNetworkAgent != null) { 7326 loge("Have NetworkAgent when entering L2Connected"); 7327 setNetworkDetailedState(DetailedState.DISCONNECTED); 7328 } 7329 setNetworkDetailedState(DetailedState.CONNECTING); 7330 7331 if (TextUtils.isEmpty(mTcpBufferSizes) == false) { 7332 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes); 7333 } 7334 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 7335 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 7336 mLinkProperties, 60); 7337 7338 // We must clear the config BSSID, as the wifi chipset may decide to roam 7339 // from this point on and having the BSSID specified in the network block would 7340 // cause the roam to faile and the device to disconnect 7341 clearCurrentConfigBSSID("L2ConnectedState"); 7342 } 7343 7344 @Override 7345 public void exit() { 7346 // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState 7347 // Bug: 15347363 7348 // For paranoia's sake, call handleNetworkDisconnect 7349 // only if BSSID is null or last networkId 7350 // is not invalid. 7351 if (DBG) { 7352 StringBuilder sb = new StringBuilder(); 7353 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId)); 7354 if (mLastBssid !=null) { 7355 sb.append(" ").append(mLastBssid); 7356 } 7357 } 7358 if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 7359 handleNetworkDisconnect(); 7360 } 7361 } 7362 7363 @Override 7364 public boolean processMessage(Message message) { 7365 logStateAndMessage(message, getClass().getSimpleName()); 7366 7367 switch (message.what) { 7368 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 7369 handlePreDhcpSetup(); 7370 break; 7371 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 7372 handlePostDhcpSetup(); 7373 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 7374 if (DBG) log("WifiStateMachine DHCP successful"); 7375 handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS); 7376 // We advance to mVerifyingLinkState because handleIPv4Success will call 7377 // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL. 7378 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 7379 if (DBG) { 7380 int count = -1; 7381 WifiConfiguration config = getCurrentWifiConfiguration(); 7382 if (config != null) { 7383 count = config.numConnectionFailures; 7384 } 7385 log("WifiStateMachine DHCP failure count=" + count); 7386 } 7387 handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); 7388 // As above, we transition to mDisconnectingState via updateLinkProperties. 7389 } 7390 break; 7391 case CMD_IP_CONFIGURATION_SUCCESSFUL: 7392 handleSuccessfulIpConfiguration(); 7393 sendConnectedState(); 7394 transitionTo(mConnectedState); 7395 break; 7396 case CMD_IP_CONFIGURATION_LOST: 7397 // Get Link layer stats so as we get fresh tx packet counters 7398 getWifiLinkLayerStats(true); 7399 handleIpConfigurationLost(); 7400 transitionTo(mDisconnectingState); 7401 break; 7402 case CMD_DISCONNECT: 7403 mWifiNative.disconnect(); 7404 transitionTo(mDisconnectingState); 7405 break; 7406 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 7407 if (message.arg1 == 1) { 7408 mWifiNative.disconnect(); 7409 mTemporarilyDisconnectWifi = true; 7410 transitionTo(mDisconnectingState); 7411 } 7412 break; 7413 case CMD_SET_OPERATIONAL_MODE: 7414 if (message.arg1 != CONNECT_MODE) { 7415 sendMessage(CMD_DISCONNECT); 7416 deferMessage(message); 7417 if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 7418 noteWifiDisabledWhileAssociated(); 7419 } 7420 } 7421 mWifiConfigStore. 7422 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 7423 break; 7424 case CMD_SET_COUNTRY_CODE: 7425 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7426 deferMessage(message); 7427 break; 7428 case CMD_START_SCAN: 7429 //if (DBG) { 7430 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 7431 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 7432 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 7433 + " targetRoamBSSID=" + mTargetRoamBSSID 7434 + " RSSI=" + mWifiInfo.getRssi()); 7435 //} 7436 if (message.arg1 == SCAN_ALARM_SOURCE) { 7437 // Check if the CMD_START_SCAN message is obsolete (and thus if it should 7438 // not be processed) and restart the scan if needed 7439 boolean shouldScan = 7440 mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get(); 7441 if (!checkAndRestartDelayedScan(message.arg2, 7442 shouldScan, 7443 mWifiConfigStore.associatedPartialScanPeriodMilli.get(), null, null)) { 7444 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; 7445 loge("WifiStateMachine L2Connected CMD_START_SCAN source " 7446 + message.arg1 7447 + " " + message.arg2 + ", " + mDelayedScanCounter 7448 + " -> obsolete"); 7449 return HANDLED; 7450 } 7451 if (mP2pConnected.get()) { 7452 loge("WifiStateMachine L2Connected CMD_START_SCAN source " 7453 + message.arg1 7454 + " " + message.arg2 + ", " + mDelayedScanCounter 7455 + " ignore because P2P is connected"); 7456 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7457 return HANDLED; 7458 } 7459 boolean tryFullBandScan = false; 7460 boolean restrictChannelList = false; 7461 long now_ms = System.currentTimeMillis(); 7462 if (DBG) { 7463 loge("WifiStateMachine CMD_START_SCAN with age=" 7464 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 7465 + " interval=" + fullBandConnectedTimeIntervalMilli 7466 + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli); 7467 } 7468 if (mWifiInfo != null) { 7469 if (mWifiConfigStore.enableFullBandScanWhenAssociated.get() && 7470 (now_ms - lastFullBandConnectedTimeMilli) 7471 > fullBandConnectedTimeIntervalMilli) { 7472 if (DBG) { 7473 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 7474 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 7475 + " interval=" + fullBandConnectedTimeIntervalMilli 7476 + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli); 7477 } 7478 tryFullBandScan = true; 7479 } 7480 7481 if (mWifiInfo.txSuccessRate > 7482 mWifiConfigStore.maxTxPacketForFullScans 7483 || mWifiInfo.rxSuccessRate > 7484 mWifiConfigStore.maxRxPacketForFullScans) { 7485 // Too much traffic at the interface, hence no full band scan 7486 if (DBG) { 7487 loge("WifiStateMachine CMD_START_SCAN " + 7488 "prevent full band scan due to pkt rate"); 7489 } 7490 tryFullBandScan = false; 7491 } 7492 7493 if (mWifiInfo.txSuccessRate > 7494 mWifiConfigStore.maxTxPacketForPartialScans 7495 || mWifiInfo.rxSuccessRate > 7496 mWifiConfigStore.maxRxPacketForPartialScans) { 7497 // Don't scan if lots of packets are being sent 7498 restrictChannelList = true; 7499 if (mWifiConfigStore.alwaysEnableScansWhileAssociated.get() == 0) { 7500 if (DBG) { 7501 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 7502 + " ...and ignore scans" 7503 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 7504 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 7505 } 7506 messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; 7507 return HANDLED; 7508 } 7509 } 7510 } 7511 7512 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 7513 if (DBG) { 7514 loge("WifiStateMachine CMD_START_SCAN full=" + 7515 tryFullBandScan); 7516 } 7517 if (currentConfiguration != null) { 7518 if (fullBandConnectedTimeIntervalMilli 7519 < mWifiConfigStore.associatedPartialScanPeriodMilli.get()) { 7520 // Sanity 7521 fullBandConnectedTimeIntervalMilli 7522 = mWifiConfigStore.associatedPartialScanPeriodMilli.get(); 7523 } 7524 if (tryFullBandScan) { 7525 lastFullBandConnectedTimeMilli = now_ms; 7526 if (fullBandConnectedTimeIntervalMilli 7527 < mWifiConfigStore.associatedFullScanMaxIntervalMilli) { 7528 // Increase the interval 7529 fullBandConnectedTimeIntervalMilli 7530 = fullBandConnectedTimeIntervalMilli 7531 * mWifiConfigStore.associatedFullScanBackoff.get() / 8; 7532 7533 if (DBG) { 7534 loge("WifiStateMachine CMD_START_SCAN bump interval =" 7535 + fullBandConnectedTimeIntervalMilli); 7536 } 7537 } 7538 handleScanRequest( 7539 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 7540 } else { 7541 if (!startScanForConfiguration( 7542 currentConfiguration, restrictChannelList)) { 7543 if (DBG) { 7544 loge("WifiStateMachine starting scan, " + 7545 " did not find channels -> full"); 7546 } 7547 lastFullBandConnectedTimeMilli = now_ms; 7548 if (fullBandConnectedTimeIntervalMilli 7549 < mWifiConfigStore.associatedFullScanMaxIntervalMilli) { 7550 // Increase the interval 7551 fullBandConnectedTimeIntervalMilli 7552 = fullBandConnectedTimeIntervalMilli 7553 * mWifiConfigStore.associatedFullScanBackoff.get() / 8; 7554 7555 if (DBG) { 7556 loge("WifiStateMachine CMD_START_SCAN bump interval =" 7557 + fullBandConnectedTimeIntervalMilli); 7558 } 7559 } 7560 handleScanRequest( 7561 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 7562 } 7563 } 7564 7565 } else { 7566 loge("CMD_START_SCAN : connected mode and no configuration"); 7567 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; 7568 } 7569 } else { 7570 // Not scan alarm source 7571 return NOT_HANDLED; 7572 } 7573 break; 7574 /* Ignore connection to same network */ 7575 case WifiManager.CONNECT_NETWORK: 7576 int netId = message.arg1; 7577 if (mWifiInfo.getNetworkId() == netId) { 7578 break; 7579 } 7580 return NOT_HANDLED; 7581 /* Ignore */ 7582 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7583 break; 7584 case CMD_RSSI_POLL: 7585 if (message.arg1 == mRssiPollToken) { 7586 if (mWifiConfigStore.enableChipWakeUpWhenAssociated.get()) { 7587 if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported); 7588 WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG); 7589 if (stats != null) { 7590 // Sanity check the results provided by driver 7591 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI 7592 && (stats.rssi_mgmt == 0 7593 || stats.beacon_rx == 0)) { 7594 stats = null; 7595 } 7596 } 7597 // Get Info and continue polling 7598 fetchRssiLinkSpeedAndFrequencyNative(); 7599 calculateWifiScore(stats); 7600 } 7601 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 7602 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 7603 7604 if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi()); 7605 } else { 7606 // Polling has completed 7607 } 7608 break; 7609 case CMD_ENABLE_RSSI_POLL: 7610 if (mWifiConfigStore.enableRssiPollWhenAssociated.get()) { 7611 mEnableRssiPolling = (message.arg1 == 1); 7612 } else { 7613 mEnableRssiPolling = false; 7614 } 7615 mRssiPollToken++; 7616 if (mEnableRssiPolling) { 7617 // First poll 7618 fetchRssiLinkSpeedAndFrequencyNative(); 7619 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 7620 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 7621 } else { 7622 cleanWifiScore(); 7623 } 7624 break; 7625 case WifiManager.RSSI_PKTCNT_FETCH: 7626 RssiPacketCountInfo info = new RssiPacketCountInfo(); 7627 fetchRssiLinkSpeedAndFrequencyNative(); 7628 info.rssi = mWifiInfo.getRssi(); 7629 fetchPktcntNative(info); 7630 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 7631 break; 7632 case CMD_DELAYED_NETWORK_DISCONNECT: 7633 if (!linkDebouncing && mWifiConfigStore.enableLinkDebouncing) { 7634 7635 // Ignore if we are not debouncing 7636 loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore " 7637 + message.arg1); 7638 return HANDLED; 7639 } else { 7640 loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect " 7641 + message.arg1); 7642 7643 linkDebouncing = false; 7644 // If we are still debouncing while this message comes, 7645 // it means we were not able to reconnect within the alloted time 7646 // = LINK_FLAPPING_DEBOUNCE_MSEC 7647 // and thus, trigger a real disconnect 7648 handleNetworkDisconnect(); 7649 transitionTo(mDisconnectedState); 7650 } 7651 break; 7652 case CMD_ASSOCIATED_BSSID: 7653 if ((String) message.obj == null) { 7654 loge("Associated command w/o BSSID"); 7655 break; 7656 } 7657 mLastBssid = (String) message.obj; 7658 if (mLastBssid != null 7659 && (mWifiInfo.getBSSID() == null 7660 || !mLastBssid.equals(mWifiInfo.getBSSID()))) { 7661 mWifiInfo.setBSSID((String) message.obj); 7662 sendNetworkStateChangeBroadcast(mLastBssid); 7663 } 7664 break; 7665 default: 7666 return NOT_HANDLED; 7667 } 7668 7669 return HANDLED; 7670 } 7671 } 7672 7673 class ObtainingIpState extends State { 7674 @Override 7675 public void enter() { 7676 if (DBG) { 7677 String key = ""; 7678 if (getCurrentWifiConfiguration() != null) { 7679 key = getCurrentWifiConfiguration().configKey(); 7680 } 7681 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 7682 + " " + key + " " 7683 + " roam=" + mAutoRoaming 7684 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId) 7685 + " watchdog= " + obtainingIpWatchdogCount); 7686 } 7687 7688 // Reset link Debouncing, indicating we have successfully re-connected to the AP 7689 // We might still be roaming 7690 linkDebouncing = false; 7691 7692 // Send event to CM & network change broadcast 7693 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 7694 7695 // We must clear the config BSSID, as the wifi chipset may decide to roam 7696 // from this point on and having the BSSID specified in the network block would 7697 // cause the roam to faile and the device to disconnect 7698 clearCurrentConfigBSSID("ObtainingIpAddress"); 7699 7700 try { 7701 mNwService.enableIpv6(mInterfaceName); 7702 } catch (RemoteException re) { 7703 loge("Failed to enable IPv6: " + re); 7704 } catch (IllegalStateException e) { 7705 loge("Failed to enable IPv6: " + e); 7706 } 7707 7708 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 7709 if (isRoaming()) { 7710 renewDhcp(); 7711 } else { 7712 // Remove any IP address on the interface in case we're switching from static 7713 // IP configuration to DHCP. This is safe because if we get here when not 7714 // roaming, we don't have a usable address. 7715 clearIPv4Address(mInterfaceName); 7716 startDhcp(); 7717 } 7718 obtainingIpWatchdogCount++; 7719 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); 7720 // Get Link layer stats so as we get fresh tx packet counters 7721 getWifiLinkLayerStats(true); 7722 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, 7723 obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); 7724 } else { 7725 // stop any running dhcp before assigning static IP 7726 stopDhcp(); 7727 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration( 7728 mLastNetworkId); 7729 if (config.ipAddress == null) { 7730 loge("Static IP lacks address"); 7731 sendMessage(CMD_STATIC_IP_FAILURE); 7732 } else { 7733 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 7734 ifcg.setLinkAddress(config.ipAddress); 7735 ifcg.setInterfaceUp(); 7736 try { 7737 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 7738 if (DBG) log("Static IP configuration succeeded"); 7739 DhcpResults dhcpResults = new DhcpResults(config); 7740 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 7741 } catch (RemoteException re) { 7742 loge("Static IP configuration failed: " + re); 7743 sendMessage(CMD_STATIC_IP_FAILURE); 7744 } catch (IllegalStateException e) { 7745 loge("Static IP configuration failed: " + e); 7746 sendMessage(CMD_STATIC_IP_FAILURE); 7747 } 7748 } 7749 } 7750 } 7751 @Override 7752 public boolean processMessage(Message message) { 7753 logStateAndMessage(message, getClass().getSimpleName()); 7754 7755 switch(message.what) { 7756 case CMD_STATIC_IP_SUCCESS: 7757 handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 7758 break; 7759 case CMD_STATIC_IP_FAILURE: 7760 handleIPv4Failure(CMD_STATIC_IP_FAILURE); 7761 break; 7762 case CMD_AUTO_CONNECT: 7763 case CMD_AUTO_ROAM: 7764 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7765 break; 7766 case WifiManager.SAVE_NETWORK: 7767 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 7768 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7769 deferMessage(message); 7770 break; 7771 /* Defer any power mode changes since we must keep active power mode at DHCP */ 7772 case CMD_SET_HIGH_PERF_MODE: 7773 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7774 deferMessage(message); 7775 break; 7776 /* Defer scan request since we should not switch to other channels at DHCP */ 7777 case CMD_START_SCAN: 7778 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7779 deferMessage(message); 7780 break; 7781 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 7782 if (message.arg1 == obtainingIpWatchdogCount) { 7783 loge("ObtainingIpAddress: Watchdog Triggered, count=" 7784 + obtainingIpWatchdogCount); 7785 handleIpConfigurationLost(); 7786 transitionTo(mDisconnectingState); 7787 break; 7788 } 7789 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7790 break; 7791 default: 7792 return NOT_HANDLED; 7793 } 7794 return HANDLED; 7795 } 7796 } 7797 7798 class VerifyingLinkState extends State { 7799 @Override 7800 public void enter() { 7801 log(getName() + " enter"); 7802 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 7803 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 7804 sendNetworkStateChangeBroadcast(mLastBssid); 7805 // End roaming 7806 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 7807 } 7808 @Override 7809 public boolean processMessage(Message message) { 7810 logStateAndMessage(message, getClass().getSimpleName()); 7811 7812 switch (message.what) { 7813 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 7814 // Stay here 7815 log(getName() + " POOR_LINK_DETECTED: no transition"); 7816 break; 7817 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 7818 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 7819 7820 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 7821 sendConnectedState(); 7822 transitionTo(mConnectedState); 7823 break; 7824 default: 7825 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 7826 return NOT_HANDLED; 7827 } 7828 return HANDLED; 7829 } 7830 } 7831 7832 private void sendConnectedState() { 7833 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 7834 // existing behaviour. The captive portal check really happens after we 7835 // transition into DetailedState.CONNECTED. 7836 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 7837 mWifiConfigStore.updateStatus(mLastNetworkId, 7838 DetailedState.CAPTIVE_PORTAL_CHECK); 7839 sendNetworkStateChangeBroadcast(mLastBssid); 7840 7841 if (mWifiConfigStore.getLastSelectedConfiguration() != null) { 7842 if (mNetworkAgent != null) mNetworkAgent.explicitlySelected(); 7843 } 7844 7845 setNetworkDetailedState(DetailedState.CONNECTED); 7846 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 7847 sendNetworkStateChangeBroadcast(mLastBssid); 7848 } 7849 7850 class RoamingState extends State { 7851 boolean mAssociated; 7852 @Override 7853 public void enter() { 7854 if (DBG) { 7855 log("RoamingState Enter" 7856 + " mScreenOn=" + mScreenOn ); 7857 } 7858 setScanAlarm(false); 7859 7860 // Make sure we disconnect if roaming fails 7861 roamWatchdogCount++; 7862 loge("Start Roam Watchdog " + roamWatchdogCount); 7863 sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER, 7864 roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC); 7865 mAssociated = false; 7866 } 7867 @Override 7868 public boolean processMessage(Message message) { 7869 logStateAndMessage(message, getClass().getSimpleName()); 7870 WifiConfiguration config; 7871 switch (message.what) { 7872 case CMD_IP_CONFIGURATION_LOST: 7873 config = getCurrentWifiConfiguration(); 7874 if (config != null) { 7875 mWifiConfigStore.noteRoamingFailure(config, 7876 WifiConfiguration.ROAMING_FAILURE_IP_CONFIG); 7877 } 7878 return NOT_HANDLED; 7879 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 7880 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 7881 return HANDLED; 7882 case CMD_UNWANTED_NETWORK: 7883 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 7884 return HANDLED; 7885 case CMD_SET_OPERATIONAL_MODE: 7886 if (message.arg1 != CONNECT_MODE) { 7887 deferMessage(message); 7888 } 7889 break; 7890 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 7891 /** 7892 * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT 7893 * before NETWORK_DISCONNECTION_EVENT 7894 * And there is an associated BSSID corresponding to our target BSSID, then 7895 * we have missed the network disconnection, transition to mDisconnectedState 7896 * and handle the rest of the events there. 7897 */ 7898 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 7899 if (stateChangeResult.state == SupplicantState.DISCONNECTED 7900 || stateChangeResult.state == SupplicantState.INACTIVE 7901 || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) { 7902 if (DBG) { 7903 log("STATE_CHANGE_EVENT in roaming state " 7904 + stateChangeResult.toString() ); 7905 } 7906 if (stateChangeResult.BSSID != null 7907 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) { 7908 handleNetworkDisconnect(); 7909 transitionTo(mDisconnectedState); 7910 } 7911 } 7912 if (stateChangeResult.state == SupplicantState.ASSOCIATED) { 7913 // We completed the layer2 roaming part 7914 mAssociated = true; 7915 if (stateChangeResult.BSSID != null) { 7916 mTargetRoamBSSID = (String) stateChangeResult.BSSID; 7917 } 7918 } 7919 break; 7920 case CMD_ROAM_WATCHDOG_TIMER: 7921 if (roamWatchdogCount == message.arg1) { 7922 if (DBG) log("roaming watchdog! -> disconnect"); 7923 mRoamFailCount++; 7924 handleNetworkDisconnect(); 7925 mWifiNative.disconnect(); 7926 transitionTo(mDisconnectedState); 7927 } 7928 break; 7929 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7930 if (mAssociated) { 7931 if (DBG) log("roaming and Network connection established"); 7932 mLastNetworkId = message.arg1; 7933 mLastBssid = (String) message.obj; 7934 mWifiInfo.setBSSID(mLastBssid); 7935 mWifiInfo.setNetworkId(mLastNetworkId); 7936 mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true); 7937 sendNetworkStateChangeBroadcast(mLastBssid); 7938 transitionTo(mObtainingIpState); 7939 } else { 7940 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7941 } 7942 break; 7943 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 7944 // Throw away but only if it corresponds to the network we're roaming to 7945 String bssid = (String)message.obj; 7946 if (true) { 7947 String target = ""; 7948 if (mTargetRoamBSSID != null) target = mTargetRoamBSSID; 7949 log("NETWORK_DISCONNECTION_EVENT in roaming state" 7950 + " BSSID=" + bssid 7951 + " target=" + target); 7952 } 7953 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 7954 handleNetworkDisconnect(); 7955 transitionTo(mDisconnectedState); 7956 } 7957 break; 7958 case WifiMonitor.SSID_TEMP_DISABLED: 7959 // Auth error while roaming 7960 loge("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId) 7961 + " id=" + Integer.toString(message.arg1) 7962 + " isRoaming=" + isRoaming() 7963 + " roam=" + Integer.toString(mAutoRoaming)); 7964 if (message.arg1 == mLastNetworkId) { 7965 config = getCurrentWifiConfiguration(); 7966 if (config != null) { 7967 mWifiConfigStore.noteRoamingFailure(config, 7968 WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE); 7969 } 7970 handleNetworkDisconnect(); 7971 transitionTo(mDisconnectingState); 7972 } 7973 return NOT_HANDLED; 7974 case CMD_START_SCAN: 7975 deferMessage(message); 7976 break; 7977 default: 7978 return NOT_HANDLED; 7979 } 7980 return HANDLED; 7981 } 7982 7983 @Override 7984 public void exit() { 7985 loge("WifiStateMachine: Leaving Roaming state"); 7986 } 7987 } 7988 7989 class ConnectedState extends State { 7990 @Override 7991 public void enter() { 7992 String address; 7993 updateDefaultRouteMacAddress(1000); 7994 if (DBG) { 7995 log("ConnectedState Enter " 7996 + " mScreenOn=" + mScreenOn 7997 + " scanperiod=" 7998 + Integer.toString(mWifiConfigStore.associatedPartialScanPeriodMilli.get()) ); 7999 } 8000 if (mScreenOn 8001 && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get()) { 8002 // restart scan alarm 8003 startDelayedScan(mWifiConfigStore.associatedPartialScanPeriodMilli.get(), null, null); 8004 } 8005 registerConnected(); 8006 lastConnectAttempt = 0; 8007 targetWificonfiguration = null; 8008 // Paranoia 8009 linkDebouncing = false; 8010 8011 // Not roaming anymore 8012 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8013 8014 if (testNetworkDisconnect) { 8015 testNetworkDisconnectCounter++; 8016 loge("ConnectedState Enter start disconnect test " + 8017 testNetworkDisconnectCounter); 8018 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT, 8019 testNetworkDisconnectCounter, 0), 15000); 8020 } 8021 8022 // Reenable all networks, allow for hidden networks to be scanned 8023 mWifiConfigStore.enableAllNetworks(); 8024 8025 mLastDriverRoamAttempt = 0; 8026 } 8027 @Override 8028 public boolean processMessage(Message message) { 8029 WifiConfiguration config = null; 8030 logStateAndMessage(message, getClass().getSimpleName()); 8031 8032 switch (message.what) { 8033 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 8034 if (DBG) log("Watchdog reports poor link"); 8035 transitionTo(mVerifyingLinkState); 8036 break; 8037 case CMD_UNWANTED_NETWORK: 8038 if (message.arg1 == network_status_unwanted_disconnect) { 8039 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 8040 mWifiNative.disconnect(); 8041 transitionTo(mDisconnectingState); 8042 } else if (message.arg1 == network_status_unwanted_disable_autojoin) { 8043 config = getCurrentWifiConfiguration(); 8044 if (config != null) { 8045 // Disable autojoin 8046 config.numNoInternetAccessReports += 1; 8047 } 8048 } 8049 return HANDLED; 8050 case CMD_NETWORK_STATUS: 8051 if (message.arg1 == NetworkAgent.VALID_NETWORK) { 8052 config = getCurrentWifiConfiguration(); 8053 if (config != null) { 8054 // re-enable autojoin 8055 config.numNoInternetAccessReports = 0; 8056 config.validatedInternetAccess = true; 8057 } 8058 } 8059 return HANDLED; 8060 case CMD_TEST_NETWORK_DISCONNECT: 8061 // Force a disconnect 8062 if (message.arg1 == testNetworkDisconnectCounter) { 8063 mWifiNative.disconnect(); 8064 } 8065 break; 8066 case CMD_ASSOCIATED_BSSID: 8067 // ASSOCIATING to a new BSSID while already connected, indicates 8068 // that driver is roaming 8069 mLastDriverRoamAttempt = System.currentTimeMillis(); 8070 String toBSSID = (String)message.obj; 8071 if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) { 8072 mWifiConfigStore.driverRoamedFrom(mWifiInfo); 8073 } 8074 return NOT_HANDLED; 8075 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8076 long lastRoam = 0; 8077 if (mLastDriverRoamAttempt != 0) { 8078 // Calculate time since last driver roam attempt 8079 lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt; 8080 mLastDriverRoamAttempt = 0; 8081 } 8082 config = getCurrentWifiConfiguration(); 8083 if (mScreenOn 8084 && !linkDebouncing 8085 && config != null 8086 && config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED 8087 && !mWifiConfigStore.isLastSelectedConfiguration(config) 8088 && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */ 8089 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */) 8090 && ((ScanResult.is24GHz(mWifiInfo.getFrequency()) 8091 && mWifiInfo.getRssi() > 8092 WifiConfiguration.BAD_RSSI_24) 8093 || (ScanResult.is5GHz(mWifiInfo.getFrequency()) 8094 && mWifiInfo.getRssi() > 8095 WifiConfiguration.BAD_RSSI_5))) { 8096 // Start de-bouncing the L2 disconnection: 8097 // this L2 disconnection might be spurious. 8098 // Hence we allow 7 seconds for the state machine to try 8099 // to reconnect, go thru the 8100 // roaming cycle and enter Obtaining IP address 8101 // before signalling the disconnect to ConnectivityService and L3 8102 startScanForConfiguration(getCurrentWifiConfiguration(), false); 8103 linkDebouncing = true; 8104 8105 sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT, 8106 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC); 8107 if (DBG) { 8108 log("NETWORK_DISCONNECTION_EVENT in connected state" 8109 + " BSSID=" + mWifiInfo.getBSSID() 8110 + " RSSI=" + mWifiInfo.getRssi() 8111 + " freq=" + mWifiInfo.getFrequency() 8112 + " reason=" + message.arg2 8113 + " -> debounce"); 8114 } 8115 return HANDLED; 8116 } else { 8117 if (DBG) { 8118 int ajst = -1; 8119 if (config != null) ajst = config.autoJoinStatus; 8120 log("NETWORK_DISCONNECTION_EVENT in connected state" 8121 + " BSSID=" + mWifiInfo.getBSSID() 8122 + " RSSI=" + mWifiInfo.getRssi() 8123 + " freq=" + mWifiInfo.getFrequency() 8124 + " was debouncing=" + linkDebouncing 8125 + " reason=" + message.arg2 8126 + " ajst=" + ajst); 8127 } 8128 } 8129 break; 8130 case CMD_AUTO_ROAM: 8131 // Clear the driver roam indication since we are attempting a framerwork roam 8132 mLastDriverRoamAttempt = 0; 8133 8134 /* Connect command coming from auto-join */ 8135 ScanResult candidate = (ScanResult)message.obj; 8136 String bssid = "any"; 8137 if (candidate != null && candidate.is5GHz()) { 8138 // Only lock BSSID for 5GHz networks 8139 bssid = candidate.BSSID; 8140 } 8141 int netId = mLastNetworkId; 8142 config = getCurrentWifiConfiguration(); 8143 8144 8145 if (config == null) { 8146 loge("AUTO_ROAM and no config, bail out..."); 8147 break; 8148 } 8149 8150 loge("CMD_AUTO_ROAM sup state " 8151 + mSupplicantStateTracker.getSupplicantStateName() 8152 + " my state " + getCurrentState().getName() 8153 + " nid=" + Integer.toString(netId) 8154 + " config " + config.configKey() 8155 + " roam=" + Integer.toString(message.arg2) 8156 + " to " + bssid 8157 + " targetRoamBSSID " + mTargetRoamBSSID); 8158 8159 /* Save the BSSID so as to lock it @ firmware */ 8160 if (!autoRoamSetBSSID(config, bssid) && !linkDebouncing) { 8161 loge("AUTO_ROAM nothing to do"); 8162 // Same BSSID, nothing to do 8163 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8164 break; 8165 }; 8166 8167 // Make sure the network is enabled, since supplicant will not reenable it 8168 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 8169 8170 if (deferForUserInput(message, netId, false)) { 8171 break; 8172 } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved == 8173 WifiConfiguration.USER_BANNED) { 8174 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 8175 WifiManager.NOT_AUTHORIZED); 8176 break; 8177 } 8178 8179 boolean ret = false; 8180 if (mLastNetworkId != netId) { 8181 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false) && 8182 mWifiNative.reconnect()) { 8183 ret = true; 8184 } 8185 } else { 8186 ret = mWifiNative.reassociate(); 8187 } 8188 if (ret) { 8189 lastConnectAttempt = System.currentTimeMillis(); 8190 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 8191 8192 // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 8193 mAutoRoaming = message.arg2; 8194 transitionTo(mRoamingState); 8195 8196 } else { 8197 loge("Failed to connect config: " + config + " netId: " + netId); 8198 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 8199 WifiManager.ERROR); 8200 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 8201 break; 8202 } 8203 break; 8204 default: 8205 return NOT_HANDLED; 8206 } 8207 return HANDLED; 8208 } 8209 8210 @Override 8211 public void exit() { 8212 loge("WifiStateMachine: Leaving Connected state"); 8213 setScanAlarm(false); 8214 mLastDriverRoamAttempt = 0; 8215 } 8216 } 8217 8218 class DisconnectingState extends State { 8219 8220 @Override 8221 public void enter() { 8222 8223 if (PDBG) { 8224 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 8225 + " mEnableBackgroundScan= " + mEnableBackgroundScan 8226 + " screenOn=" + mScreenOn); 8227 } 8228 8229 // Make sure we disconnect: we enter this state prior connecting to a new 8230 // network, waiting for either a DISCONECT event or a SUPPLICANT_STATE_CHANGE 8231 // event which in this case will be indicating that supplicant started to associate. 8232 // In some cases supplicant doesn't ignore the connect requests (it might not 8233 // find the target SSID in its cache), 8234 // Therefore we end up stuck that state, hence the need for the watchdog. 8235 disconnectingWatchdogCount++; 8236 loge("Start Disconnecting Watchdog " + disconnectingWatchdogCount); 8237 sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER, 8238 disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC); 8239 } 8240 8241 @Override 8242 public boolean processMessage(Message message) { 8243 logStateAndMessage(message, getClass().getSimpleName()); 8244 switch (message.what) { 8245 case CMD_SET_OPERATIONAL_MODE: 8246 if (message.arg1 != CONNECT_MODE) { 8247 deferMessage(message); 8248 } 8249 break; 8250 case CMD_START_SCAN: 8251 deferMessage(message); 8252 return HANDLED; 8253 case CMD_DISCONNECTING_WATCHDOG_TIMER: 8254 if (disconnectingWatchdogCount == message.arg1) { 8255 if (DBG) log("disconnecting watchdog! -> disconnect"); 8256 handleNetworkDisconnect(); 8257 transitionTo(mDisconnectedState); 8258 } 8259 break; 8260 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8261 /** 8262 * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 8263 * we have missed the network disconnection, transition to mDisconnectedState 8264 * and handle the rest of the events there 8265 */ 8266 deferMessage(message); 8267 handleNetworkDisconnect(); 8268 transitionTo(mDisconnectedState); 8269 break; 8270 default: 8271 return NOT_HANDLED; 8272 } 8273 return HANDLED; 8274 } 8275 } 8276 8277 class DisconnectedState extends State { 8278 @Override 8279 public void enter() { 8280 // We dont scan frequently if this is a temporary disconnect 8281 // due to p2p 8282 if (mTemporarilyDisconnectWifi) { 8283 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 8284 return; 8285 } 8286 8287 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 8288 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 8289 mDefaultFrameworkScanIntervalMs); 8290 8291 if (PDBG) { 8292 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 8293 + " mEnableBackgroundScan= " + mEnableBackgroundScan 8294 + " screenOn=" + mScreenOn 8295 + " mFrameworkScanIntervalMs=" + mFrameworkScanIntervalMs); 8296 } 8297 8298 /** clear the roaming state, if we were roaming, we failed */ 8299 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8300 8301 if (mScreenOn) { 8302 /** 8303 * screen lit and => delayed timer 8304 */ 8305 startDelayedScan(mDisconnectedScanPeriodMs, null, null); 8306 } else { 8307 /** 8308 * screen dark and PNO supported => scan alarm disabled 8309 */ 8310 if (mEnableBackgroundScan) { 8311 /* If a regular scan result is pending, do not initiate background 8312 * scan until the scan results are returned. This is needed because 8313 * initiating a background scan will cancel the regular scan and 8314 * scan results will not be returned until background scanning is 8315 * cleared 8316 */ 8317 if (!mIsScanOngoing) { 8318 enableBackgroundScan(true); 8319 } 8320 } else { 8321 setScanAlarm(true); 8322 } 8323 } 8324 8325 /** 8326 * If we have no networks saved, the supplicant stops doing the periodic scan. 8327 * The scans are useful to notify the user of the presence of an open network. 8328 * Note that these are not wake up scans. 8329 */ 8330 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8331 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8332 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8333 } 8334 8335 mDisconnectedTimeStamp = System.currentTimeMillis(); 8336 8337 } 8338 @Override 8339 public boolean processMessage(Message message) { 8340 boolean ret = HANDLED; 8341 8342 logStateAndMessage(message, getClass().getSimpleName()); 8343 8344 switch (message.what) { 8345 case CMD_NO_NETWORKS_PERIODIC_SCAN: 8346 if (mP2pConnected.get()) break; 8347 if (message.arg1 == mPeriodicScanToken && 8348 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8349 startScan(UNKNOWN_SCAN_SOURCE, -1, null, null); 8350 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8351 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8352 } 8353 break; 8354 case WifiManager.FORGET_NETWORK: 8355 case CMD_REMOVE_NETWORK: 8356 case CMD_REMOVE_APP_CONFIGURATIONS: 8357 case CMD_REMOVE_USER_CONFIGURATIONS: 8358 // Set up a delayed message here. After the forget/remove is handled 8359 // the handled delayed message will determine if there is a need to 8360 // scan and continue 8361 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8362 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8363 ret = NOT_HANDLED; 8364 break; 8365 case CMD_SET_OPERATIONAL_MODE: 8366 if (message.arg1 != CONNECT_MODE) { 8367 mOperationalMode = message.arg1; 8368 8369 mWifiConfigStore.disableAllNetworks(); 8370 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 8371 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 8372 setWifiState(WIFI_STATE_DISABLED); 8373 } 8374 transitionTo(mScanModeState); 8375 } 8376 mWifiConfigStore. 8377 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 8378 break; 8379 /* Ignore network disconnect */ 8380 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8381 break; 8382 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8383 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 8384 if (DBG) { 8385 loge("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state + 8386 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state) 8387 + " debouncing=" + linkDebouncing); 8388 } 8389 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 8390 /* ConnectModeState does the rest of the handling */ 8391 ret = NOT_HANDLED; 8392 break; 8393 case CMD_START_SCAN: 8394 if (!checkOrDeferScanAllowed(message)) { 8395 // The scan request was rescheduled 8396 messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; 8397 return HANDLED; 8398 } 8399 /* Disable background scan temporarily during a regular scan */ 8400 if (mEnableBackgroundScan) { 8401 enableBackgroundScan(false); 8402 } 8403 if (message.arg1 == SCAN_ALARM_SOURCE) { 8404 // Check if the CMD_START_SCAN message is obsolete (and thus if it should 8405 // not be processed) and restart the scan 8406 int period = mDisconnectedScanPeriodMs; 8407 if (mP2pConnected.get()) { 8408 period = (int)Settings.Global.getLong(mContext.getContentResolver(), 8409 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 8410 mDisconnectedScanPeriodMs); 8411 } 8412 if (!checkAndRestartDelayedScan(message.arg2, 8413 true, period, null, null)) { 8414 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; 8415 loge("WifiStateMachine Disconnected CMD_START_SCAN source " 8416 + message.arg1 8417 + " " + message.arg2 + ", " + mDelayedScanCounter 8418 + " -> obsolete"); 8419 return HANDLED; 8420 } 8421 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 8422 ret = HANDLED; 8423 } else { 8424 ret = NOT_HANDLED; 8425 } 8426 break; 8427 case WifiMonitor.SCAN_RESULTS_EVENT: 8428 /* Re-enable background scan when a pending scan result is received */ 8429 if (mEnableBackgroundScan && mIsScanOngoing) { 8430 enableBackgroundScan(true); 8431 } 8432 /* Handled in parent state */ 8433 ret = NOT_HANDLED; 8434 break; 8435 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 8436 NetworkInfo info = (NetworkInfo) message.obj; 8437 mP2pConnected.set(info.isConnected()); 8438 if (mP2pConnected.get()) { 8439 int defaultInterval = mContext.getResources().getInteger( 8440 R.integer.config_wifi_scan_interval_p2p_connected); 8441 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 8442 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 8443 defaultInterval); 8444 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 8445 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8446 if (DBG) log("Turn on scanning after p2p disconnected"); 8447 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8448 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8449 } else { 8450 // If P2P is not connected and there are saved networks, then restart 8451 // scanning at the normal period. This is necessary because scanning might 8452 // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS 8453 // was set to zero. 8454 startDelayedScan(mDisconnectedScanPeriodMs, null, null); 8455 } 8456 break; 8457 case CMD_RECONNECT: 8458 case CMD_REASSOCIATE: 8459 if (mTemporarilyDisconnectWifi) { 8460 // Drop a third party reconnect/reassociate if STA is 8461 // temporarily disconnected for p2p 8462 break; 8463 } else { 8464 // ConnectModeState handles it 8465 ret = NOT_HANDLED; 8466 } 8467 break; 8468 case CMD_SCREEN_STATE_CHANGED: 8469 handleScreenStateChanged(message.arg1 != 0, 8470 /* startBackgroundScanIfNeeded = */ true); 8471 break; 8472 default: 8473 ret = NOT_HANDLED; 8474 } 8475 return ret; 8476 } 8477 8478 @Override 8479 public void exit() { 8480 /* No need for a background scan upon exit from a disconnected state */ 8481 if (mEnableBackgroundScan) { 8482 enableBackgroundScan(false); 8483 } 8484 setScanAlarm(false); 8485 } 8486 } 8487 8488 class WpsRunningState extends State { 8489 // Tracks the source to provide a reply 8490 private Message mSourceMessage; 8491 @Override 8492 public void enter() { 8493 mSourceMessage = Message.obtain(getCurrentMessage()); 8494 } 8495 @Override 8496 public boolean processMessage(Message message) { 8497 logStateAndMessage(message, getClass().getSimpleName()); 8498 8499 switch (message.what) { 8500 case WifiMonitor.WPS_SUCCESS_EVENT: 8501 // Ignore intermediate success, wait for full connection 8502 break; 8503 case WifiMonitor.NETWORK_CONNECTION_EVENT: 8504 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 8505 mSourceMessage.recycle(); 8506 mSourceMessage = null; 8507 deferMessage(message); 8508 transitionTo(mDisconnectedState); 8509 break; 8510 case WifiMonitor.WPS_OVERLAP_EVENT: 8511 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 8512 WifiManager.WPS_OVERLAP_ERROR); 8513 mSourceMessage.recycle(); 8514 mSourceMessage = null; 8515 transitionTo(mDisconnectedState); 8516 break; 8517 case WifiMonitor.WPS_FAIL_EVENT: 8518 // Arg1 has the reason for the failure 8519 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 8520 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 8521 mSourceMessage.recycle(); 8522 mSourceMessage = null; 8523 transitionTo(mDisconnectedState); 8524 } else { 8525 if (DBG) log("Ignore unspecified fail event during WPS connection"); 8526 } 8527 break; 8528 case WifiMonitor.WPS_TIMEOUT_EVENT: 8529 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 8530 WifiManager.WPS_TIMED_OUT); 8531 mSourceMessage.recycle(); 8532 mSourceMessage = null; 8533 transitionTo(mDisconnectedState); 8534 break; 8535 case WifiManager.START_WPS: 8536 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 8537 break; 8538 case WifiManager.CANCEL_WPS: 8539 if (mWifiNative.cancelWps()) { 8540 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 8541 } else { 8542 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 8543 } 8544 transitionTo(mDisconnectedState); 8545 break; 8546 /** 8547 * Defer all commands that can cause connections to a different network 8548 * or put the state machine out of connect mode 8549 */ 8550 case CMD_STOP_DRIVER: 8551 case CMD_SET_OPERATIONAL_MODE: 8552 case WifiManager.CONNECT_NETWORK: 8553 case CMD_ENABLE_NETWORK: 8554 case CMD_RECONNECT: 8555 case CMD_REASSOCIATE: 8556 case CMD_ENABLE_ALL_NETWORKS: 8557 deferMessage(message); 8558 break; 8559 case CMD_AUTO_CONNECT: 8560 case CMD_AUTO_ROAM: 8561 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8562 return HANDLED; 8563 case CMD_START_SCAN: 8564 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8565 return HANDLED; 8566 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8567 if (DBG) log("Network connection lost"); 8568 handleNetworkDisconnect(); 8569 break; 8570 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 8571 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 8572 break; 8573 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 8574 // Disregard auth failure events during WPS connection. The 8575 // EAP sequence is retried several times, and there might be 8576 // failures (especially for wps pin). We will get a WPS_XXX 8577 // event at the end of the sequence anyway. 8578 if (DBG) log("Ignore auth failure during WPS connection"); 8579 break; 8580 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8581 // Throw away supplicant state changes when WPS is running. 8582 // We will start getting supplicant state changes once we get 8583 // a WPS success or failure 8584 break; 8585 default: 8586 return NOT_HANDLED; 8587 } 8588 return HANDLED; 8589 } 8590 8591 @Override 8592 public void exit() { 8593 mWifiConfigStore.enableAllNetworks(); 8594 mWifiConfigStore.loadConfiguredNetworks(); 8595 } 8596 } 8597 8598 class SoftApStartingState extends State { 8599 @Override 8600 public void enter() { 8601 final Message message = getCurrentMessage(); 8602 if (message.what == CMD_START_AP) { 8603 final WifiConfiguration config = (WifiConfiguration) message.obj; 8604 8605 if (config == null) { 8606 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 8607 } else { 8608 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 8609 startSoftApWithConfig(config); 8610 } 8611 } else { 8612 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 8613 } 8614 } 8615 @Override 8616 public boolean processMessage(Message message) { 8617 logStateAndMessage(message, getClass().getSimpleName()); 8618 8619 switch(message.what) { 8620 case CMD_START_SUPPLICANT: 8621 case CMD_STOP_SUPPLICANT: 8622 case CMD_START_AP: 8623 case CMD_STOP_AP: 8624 case CMD_START_DRIVER: 8625 case CMD_STOP_DRIVER: 8626 case CMD_SET_OPERATIONAL_MODE: 8627 case CMD_SET_COUNTRY_CODE: 8628 case CMD_SET_FREQUENCY_BAND: 8629 case CMD_START_PACKET_FILTERING: 8630 case CMD_STOP_PACKET_FILTERING: 8631 case CMD_TETHER_STATE_CHANGE: 8632 deferMessage(message); 8633 break; 8634 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 8635 WifiConfiguration config = (WifiConfiguration) message.obj; 8636 if (config != null) { 8637 startSoftApWithConfig(config); 8638 } else { 8639 loge("Softap config is null!"); 8640 sendMessage(CMD_START_AP_FAILURE); 8641 } 8642 break; 8643 case CMD_START_AP_SUCCESS: 8644 setWifiApState(WIFI_AP_STATE_ENABLED); 8645 transitionTo(mSoftApStartedState); 8646 break; 8647 case CMD_START_AP_FAILURE: 8648 setWifiApState(WIFI_AP_STATE_FAILED); 8649 transitionTo(mInitialState); 8650 break; 8651 default: 8652 return NOT_HANDLED; 8653 } 8654 return HANDLED; 8655 } 8656 } 8657 8658 class SoftApStartedState extends State { 8659 @Override 8660 public boolean processMessage(Message message) { 8661 logStateAndMessage(message, getClass().getSimpleName()); 8662 8663 switch(message.what) { 8664 case CMD_STOP_AP: 8665 if (DBG) log("Stopping Soft AP"); 8666 /* We have not tethered at this point, so we just shutdown soft Ap */ 8667 try { 8668 mNwService.stopAccessPoint(mInterfaceName); 8669 } catch(Exception e) { 8670 loge("Exception in stopAccessPoint()"); 8671 } 8672 setWifiApState(WIFI_AP_STATE_DISABLED); 8673 transitionTo(mInitialState); 8674 break; 8675 case CMD_START_AP: 8676 // Ignore a start on a running access point 8677 break; 8678 // Fail client mode operation when soft AP is enabled 8679 case CMD_START_SUPPLICANT: 8680 loge("Cannot start supplicant with a running soft AP"); 8681 setWifiState(WIFI_STATE_UNKNOWN); 8682 break; 8683 case CMD_TETHER_STATE_CHANGE: 8684 TetherStateChange stateChange = (TetherStateChange) message.obj; 8685 if (startTethering(stateChange.available)) { 8686 transitionTo(mTetheringState); 8687 } 8688 break; 8689 default: 8690 return NOT_HANDLED; 8691 } 8692 return HANDLED; 8693 } 8694 } 8695 8696 class TetheringState extends State { 8697 @Override 8698 public void enter() { 8699 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 8700 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 8701 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 8702 } 8703 @Override 8704 public boolean processMessage(Message message) { 8705 logStateAndMessage(message, getClass().getSimpleName()); 8706 8707 switch(message.what) { 8708 case CMD_TETHER_STATE_CHANGE: 8709 TetherStateChange stateChange = (TetherStateChange) message.obj; 8710 if (isWifiTethered(stateChange.active)) { 8711 transitionTo(mTetheredState); 8712 } 8713 return HANDLED; 8714 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 8715 if (message.arg1 == mTetherToken) { 8716 loge("Failed to get tether update, shutdown soft access point"); 8717 transitionTo(mSoftApStartedState); 8718 // Needs to be first thing handled 8719 sendMessageAtFrontOfQueue(CMD_STOP_AP); 8720 } 8721 break; 8722 case CMD_START_SUPPLICANT: 8723 case CMD_STOP_SUPPLICANT: 8724 case CMD_START_AP: 8725 case CMD_STOP_AP: 8726 case CMD_START_DRIVER: 8727 case CMD_STOP_DRIVER: 8728 case CMD_SET_OPERATIONAL_MODE: 8729 case CMD_SET_COUNTRY_CODE: 8730 case CMD_SET_FREQUENCY_BAND: 8731 case CMD_START_PACKET_FILTERING: 8732 case CMD_STOP_PACKET_FILTERING: 8733 deferMessage(message); 8734 break; 8735 default: 8736 return NOT_HANDLED; 8737 } 8738 return HANDLED; 8739 } 8740 } 8741 8742 class TetheredState extends State { 8743 @Override 8744 public boolean processMessage(Message message) { 8745 logStateAndMessage(message, getClass().getSimpleName()); 8746 8747 switch(message.what) { 8748 case CMD_TETHER_STATE_CHANGE: 8749 TetherStateChange stateChange = (TetherStateChange) message.obj; 8750 if (!isWifiTethered(stateChange.active)) { 8751 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 8752 setHostApRunning(null, false); 8753 setHostApRunning(null, true); 8754 } 8755 return HANDLED; 8756 case CMD_STOP_AP: 8757 if (DBG) log("Untethering before stopping AP"); 8758 setWifiApState(WIFI_AP_STATE_DISABLING); 8759 stopTethering(); 8760 transitionTo(mUntetheringState); 8761 // More work to do after untethering 8762 deferMessage(message); 8763 break; 8764 default: 8765 return NOT_HANDLED; 8766 } 8767 return HANDLED; 8768 } 8769 } 8770 8771 class UntetheringState extends State { 8772 @Override 8773 public void enter() { 8774 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 8775 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 8776 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 8777 8778 } 8779 @Override 8780 public boolean processMessage(Message message) { 8781 logStateAndMessage(message, getClass().getSimpleName()); 8782 8783 switch(message.what) { 8784 case CMD_TETHER_STATE_CHANGE: 8785 TetherStateChange stateChange = (TetherStateChange) message.obj; 8786 8787 /* Wait till wifi is untethered */ 8788 if (isWifiTethered(stateChange.active)) break; 8789 8790 transitionTo(mSoftApStartedState); 8791 break; 8792 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 8793 if (message.arg1 == mTetherToken) { 8794 loge("Failed to get tether update, force stop access point"); 8795 transitionTo(mSoftApStartedState); 8796 } 8797 break; 8798 case CMD_START_SUPPLICANT: 8799 case CMD_STOP_SUPPLICANT: 8800 case CMD_START_AP: 8801 case CMD_STOP_AP: 8802 case CMD_START_DRIVER: 8803 case CMD_STOP_DRIVER: 8804 case CMD_SET_OPERATIONAL_MODE: 8805 case CMD_SET_COUNTRY_CODE: 8806 case CMD_SET_FREQUENCY_BAND: 8807 case CMD_START_PACKET_FILTERING: 8808 case CMD_STOP_PACKET_FILTERING: 8809 deferMessage(message); 8810 break; 8811 default: 8812 return NOT_HANDLED; 8813 } 8814 return HANDLED; 8815 } 8816 } 8817 8818 /** 8819 * State machine initiated requests can have replyTo set to null indicating 8820 * there are no recepients, we ignore those reply actions. 8821 */ 8822 private void replyToMessage(Message msg, int what) { 8823 if (msg.replyTo == null) return; 8824 Message dstMsg = obtainMessageWithWhatAndArg2(msg, what); 8825 mReplyChannel.replyToMessage(msg, dstMsg); 8826 } 8827 8828 private void replyToMessage(Message msg, int what, int arg1) { 8829 if (msg.replyTo == null) return; 8830 Message dstMsg = obtainMessageWithWhatAndArg2(msg, what); 8831 dstMsg.arg1 = arg1; 8832 mReplyChannel.replyToMessage(msg, dstMsg); 8833 } 8834 8835 private void replyToMessage(Message msg, int what, Object obj) { 8836 if (msg.replyTo == null) return; 8837 Message dstMsg = obtainMessageWithWhatAndArg2(msg, what); 8838 dstMsg.obj = obj; 8839 mReplyChannel.replyToMessage(msg, dstMsg); 8840 } 8841 8842 /** 8843 * arg2 on the source message has a unique id that needs to be retained in replies 8844 * to match the request 8845 * <p>see WifiManager for details 8846 */ 8847 private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) { 8848 Message msg = Message.obtain(); 8849 msg.what = what; 8850 msg.arg2 = srcMsg.arg2; 8851 return msg; 8852 } 8853 8854 /** 8855 * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT 8856 * @param msg Must have a WifiConfiguration obj to succeed 8857 */ 8858 private void broadcastWifiCredentialChanged(int wifiCredentialEventType, 8859 WifiConfiguration config) { 8860 if (config != null && config.preSharedKey != null) { 8861 Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION); 8862 intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID); 8863 intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE, 8864 wifiCredentialEventType); 8865 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT, 8866 android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE); 8867 } 8868 } 8869 8870 private static int parseHex(char ch) { 8871 if ('0' <= ch && ch <= '9') { 8872 return ch - '0'; 8873 } else if ('a' <= ch && ch <= 'f') { 8874 return ch - 'a' + 10; 8875 } else if ('A' <= ch && ch <= 'F') { 8876 return ch - 'A' + 10; 8877 } else { 8878 throw new NumberFormatException("" + ch + " is not a valid hex digit"); 8879 } 8880 } 8881 8882 private byte[] parseHex(String hex) { 8883 /* This only works for good input; don't throw bad data at it */ 8884 if (hex == null) { 8885 return new byte[0]; 8886 } 8887 8888 if (hex.length() % 2 != 0) { 8889 throw new NumberFormatException(hex + " is not a valid hex string"); 8890 } 8891 8892 byte[] result = new byte[(hex.length())/2 + 1]; 8893 result[0] = (byte) ((hex.length())/2); 8894 for (int i = 0, j = 1; i < hex.length(); i += 2, j++) { 8895 int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1)); 8896 byte b = (byte) (val & 0xFF); 8897 result[j] = b; 8898 } 8899 8900 return result; 8901 } 8902 8903 private static String makeHex(byte[] bytes) { 8904 StringBuilder sb = new StringBuilder(); 8905 for (byte b : bytes) { 8906 sb.append(String.format("%02x", b)); 8907 } 8908 return sb.toString(); 8909 } 8910 8911 private static String makeHex(byte[] bytes, int from, int len) { 8912 StringBuilder sb = new StringBuilder(); 8913 for (int i = 0; i < len; i++) { 8914 sb.append(String.format("%02x", bytes[from+i])); 8915 } 8916 return sb.toString(); 8917 } 8918 8919 8920 private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) { 8921 8922 int len = array1.length + array2.length + array3.length; 8923 8924 if (array1.length != 0) { 8925 len++; /* add another byte for size */ 8926 } 8927 8928 if (array2.length != 0) { 8929 len++; /* add another byte for size */ 8930 } 8931 8932 if (array3.length != 0) { 8933 len++; /* add another byte for size */ 8934 } 8935 8936 byte[] result = new byte[len]; 8937 8938 int index = 0; 8939 if (array1.length != 0) { 8940 result[index] = (byte) (array1.length & 0xFF); 8941 index++; 8942 for (byte b : array1) { 8943 result[index] = b; 8944 index++; 8945 } 8946 } 8947 8948 if (array2.length != 0) { 8949 result[index] = (byte) (array2.length & 0xFF); 8950 index++; 8951 for (byte b : array2) { 8952 result[index] = b; 8953 index++; 8954 } 8955 } 8956 8957 if (array3.length != 0) { 8958 result[index] = (byte) (array3.length & 0xFF); 8959 index++; 8960 for (byte b : array3) { 8961 result[index] = b; 8962 index++; 8963 } 8964 } 8965 return result; 8966 } 8967 8968 void handleGsmAuthRequest(SimAuthRequestData requestData) { 8969 if (targetWificonfiguration == null 8970 || targetWificonfiguration.networkId == requestData.networkId) { 8971 logd("id matches targetWifiConfiguration"); 8972 } else { 8973 logd("id does not match targetWifiConfiguration"); 8974 return; 8975 } 8976 8977 TelephonyManager tm = (TelephonyManager) 8978 mContext.getSystemService(Context.TELEPHONY_SERVICE); 8979 8980 if (tm != null) { 8981 StringBuilder sb = new StringBuilder(); 8982 for (String challenge : requestData.challenges) { 8983 8984 logd("RAND = " + challenge); 8985 8986 byte[] rand = null; 8987 try { 8988 rand = parseHex(challenge); 8989 } catch (NumberFormatException e) { 8990 loge("malformed challenge"); 8991 continue; 8992 } 8993 8994 String base64Challenge = android.util.Base64.encodeToString( 8995 rand, android.util.Base64.NO_WRAP); 8996 /* 8997 * appType = 1 => SIM, 2 => USIM according to 8998 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx 8999 */ 9000 int appType = 2; 9001 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9002 logv("Raw Response - " + tmResponse); 9003 9004 if (tmResponse != null && tmResponse.length() > 4) { 9005 byte[] result = android.util.Base64.decode(tmResponse, 9006 android.util.Base64.DEFAULT); 9007 logv("Hex Response -" + makeHex(result)); 9008 int sres_len = result[0]; 9009 String sres = makeHex(result, 1, sres_len); 9010 int kc_offset = 1+sres_len; 9011 int kc_len = result[kc_offset]; 9012 String kc = makeHex(result, 1+kc_offset, kc_len); 9013 sb.append(":" + kc + ":" + sres); 9014 logv("kc:" + kc + " sres:" + sres); 9015 } else { 9016 loge("bad response - " + tmResponse); 9017 } 9018 } 9019 9020 String response = sb.toString(); 9021 logv("Supplicant Response -" + response); 9022 mWifiNative.simAuthResponse(requestData.networkId, response); 9023 } else { 9024 loge("could not get telephony manager"); 9025 } 9026 } 9027 9028 void handle3GAuthRequest(SimAuthRequestData requestData) { 9029 9030 } 9031} 9032