WifiStateMachine.java revision 51991e784c605a7432a90c9e9a91b080fb106197
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_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25/** 26 * TODO: 27 * Deprecate WIFI_STATE_UNKNOWN 28 */ 29import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 30import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 31import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 32import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 33import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 34 35import android.app.AlarmManager; 36import android.app.PendingIntent; 37import android.app.backup.IBackupManager; 38import android.bluetooth.BluetoothAdapter; 39import android.content.BroadcastReceiver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.database.ContentObserver; 45import android.net.*; 46import android.net.NetworkInfo.DetailedState; 47import android.net.wifi.BatchedScanResult; 48import android.net.wifi.BatchedScanSettings; 49import android.net.wifi.RssiPacketCountInfo; 50import android.net.wifi.ScanResult; 51import android.net.wifi.ScanSettings; 52import android.net.wifi.WifiChannel; 53import android.net.wifi.SupplicantState; 54import android.net.wifi.WifiConfiguration; 55import android.net.wifi.WifiInfo; 56import android.net.wifi.WifiLinkLayerStats; 57import android.net.wifi.WifiManager; 58import android.net.wifi.WifiSsid; 59import android.net.wifi.WpsInfo; 60import android.net.wifi.WpsResult; 61import android.net.wifi.WpsResult.Status; 62import android.net.wifi.p2p.IWifiP2pManager; 63import android.net.wifi.passpoint.IWifiPasspointManager; 64import android.os.*; 65import android.os.Process; 66import android.provider.Settings; 67import android.util.LruCache; 68import android.text.TextUtils; 69import android.util.Log; 70 71import com.android.internal.R; 72import com.android.internal.app.IBatteryStats; 73import com.android.internal.util.AsyncChannel; 74import com.android.internal.util.Protocol; 75import com.android.internal.util.State; 76import com.android.internal.util.StateMachine; 77import com.android.server.net.BaseNetworkObserver; 78import com.android.server.net.NetlinkTracker; 79 80import com.android.server.wifi.p2p.WifiP2pServiceImpl; 81import com.android.server.wifi.passpoint.WifiPasspointServiceImpl; 82import com.android.server.wifi.passpoint.WifiPasspointStateMachine; 83 84import java.io.FileDescriptor; 85import java.io.PrintWriter; 86import java.net.InetAddress; 87import java.util.*; 88import java.util.concurrent.atomic.AtomicInteger; 89import java.util.concurrent.atomic.AtomicBoolean; 90import java.util.regex.Pattern; 91import java.io.FileReader; 92import java.io.BufferedReader; 93import java.io.FileNotFoundException; 94import java.io.IOException; 95import java.net.InetAddress; 96import java.net.Inet4Address; 97import java.net.Inet6Address; 98 99/** 100 * Track the state of Wifi connectivity. All event handling is done here, 101 * and all changes in connectivity state are initiated here. 102 * 103 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 104 * In the current implementation, we support concurrent wifi p2p and wifi operation. 105 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 106 * handles p2p operation. 107 * 108 * @hide 109 */ 110public class WifiStateMachine extends StateMachine { 111 112 private static final String NETWORKTYPE = "WIFI"; 113 private static boolean DBG = false; 114 private static boolean VDBG = false; 115 private static boolean mLogMessages = false; 116 117 /* temporary debug flag - best network selection development */ 118 private static boolean PDBG = false; 119 /** 120 * Log with error attribute 121 * 122 * @param s is string log 123 */ 124 protected void loge(String s) { 125 long now = SystemClock.elapsedRealtimeNanos(); 126 String ts = String.format("[%,d us] ", now / 1000); 127 Log.e(getName(), ts + s); 128 } 129 protected void log(String s) { 130 long now = SystemClock.elapsedRealtimeNanos(); 131 String ts = String.format("[%,d us] ", now / 1000); 132 Log.e(getName(), ts + s); 133 } 134 135 private WifiMonitor mWifiMonitor; 136 private WifiNative mWifiNative; 137 private WifiConfigStore mWifiConfigStore; 138 private WifiAutoJoinController mWifiAutoJoinController; 139 private INetworkManagementService mNwService; 140 private ConnectivityManager mCm; 141 142 private final boolean mP2pSupported; 143 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 144 private boolean mTemporarilyDisconnectWifi = false; 145 private final String mPrimaryDeviceType; 146 147 /* Scan results handling */ 148 private List<ScanResult> mScanResults = new ArrayList<ScanResult>(); 149 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 150 private static final int SCAN_RESULT_CACHE_SIZE = 80; 151 private final LruCache<String, ScanResult> mScanResultCache; 152 153 /* Batch scan results */ 154 private final List<BatchedScanResult> mBatchedScanResults = 155 new ArrayList<BatchedScanResult>(); 156 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 157 private int mExpectedBatchedScans = 0; 158 private long mBatchedScanMinPollTime = 0; 159 160 private boolean mScreenOn = false; 161 162 /* Chipset supports background scan */ 163 private final boolean mBackgroundScanSupported; 164 165 private String mInterfaceName; 166 /* Tethering interface could be separate from wlan interface */ 167 private String mTetherInterfaceName; 168 169 private int mLastSignalLevel = -1; 170 private String mLastBssid; 171 private int mLastNetworkId; 172 private boolean mEnableRssiPolling = false; 173 private boolean mEnableBackgroundScan = false; 174 private int mRssiPollToken = 0; 175 private int mReconnectCount = 0; 176 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 177 * In CONNECT_MODE, the STA can scan and connect to an access point 178 * In SCAN_ONLY_MODE, the STA can only scan for access points 179 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 180 */ 181 private int mOperationalMode = CONNECT_MODE; 182 private boolean mIsScanOngoing = false; 183 private boolean mIsFullScanOngoing = false; 184 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 185 private WorkSource mScanWorkSource = null; 186 private static final int UNKNOWN_SCAN_SOURCE = -1; 187 private static final int SCAN_ALARM_SOURCE = -2; 188 189 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 190 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 191 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 192 private static final String BATCHED_SETTING = "batched_settings"; 193 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 194 195 /* Tracks if state machine has received any screen state change broadcast yet. 196 * We can miss one of these at boot. 197 */ 198 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 199 200 private boolean mBluetoothConnectionActive = false; 201 202 private PowerManager.WakeLock mSuspendWakeLock; 203 204 /** 205 * Interval in milliseconds between polling for RSSI 206 * and linkspeed information 207 */ 208 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 209 210 /** 211 * Delay between supplicant restarts upon failure to establish connection 212 */ 213 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 214 215 /** 216 * Number of times we attempt to restart supplicant 217 */ 218 private static final int SUPPLICANT_RESTART_TRIES = 5; 219 220 private int mSupplicantRestartCount = 0; 221 /* Tracks sequence number on stop failure message */ 222 private int mSupplicantStopFailureToken = 0; 223 224 /** 225 * Tether state change notification time out 226 */ 227 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 228 229 /* Tracks sequence number on a tether notification time out */ 230 private int mTetherToken = 0; 231 232 /** 233 * Driver start time out. 234 */ 235 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 236 237 /* Tracks sequence number on a driver time out */ 238 private int mDriverStartToken = 0; 239 240 /** 241 * The link properties of the wifi interface. 242 * Do not modify this directly; use updateLinkProperties instead. 243 */ 244 private LinkProperties mLinkProperties; 245 246 /* Tracks sequence number on a periodic scan message */ 247 private int mPeriodicScanToken = 0; 248 249 // Wakelock held during wifi start/stop and driver load/unload 250 private PowerManager.WakeLock mWakeLock; 251 252 private Context mContext; 253 254 private final Object mDhcpResultsLock = new Object(); 255 private DhcpResults mDhcpResults; 256 private WifiInfo mWifiInfo; 257 private NetworkInfo mNetworkInfo; 258 private NetworkCapabilities mNetworkCapabilities; 259 private SupplicantStateTracker mSupplicantStateTracker; 260 private DhcpStateMachine mDhcpStateMachine; 261 private boolean mDhcpActive = false; 262 263 private int mWifiLinkLayerStatsSupported = 4; 264 265 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 266 267 //whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress 268 private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 269 270 private String mTargetRoamBSSID = "any"; 271 272 boolean isRoaming() { 273 return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING 274 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING; 275 } 276 277 public void autoRoamSetBSSID(int netId, String bssid) { 278 autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid); 279 } 280 281 public void autoRoamSetBSSID(WifiConfiguration config, String bssid) { 282 mTargetRoamBSSID = "any"; 283 if (config == null) 284 return; 285 if (config.bssidOwnerUid == 0 || config.bssidOwnerUid == Process.WIFI_UID) { 286 if (VDBG) { 287 loge("autoRoamSetBSSID uid=" + Long.toString(config.bssidOwnerUid) 288 + " bssid=" + bssid 289 + " key=" + config.configKey()); 290 } 291 config.bssidOwnerUid = Process.WIFI_UID; 292 config.BSSID = bssid; 293 mTargetRoamBSSID = bssid; 294 } 295 } 296 297 static private final int ONE_HOUR_MILLI = 1000 * 60 * 60; 298 299 /** 300 * Subset of link properties coming from netlink. 301 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 302 * and domains obtained from router advertisements (RFC 6106). 303 */ 304 private NetlinkTracker mNetlinkTracker; 305 306 private AlarmManager mAlarmManager; 307 private PendingIntent mScanIntent; 308 private PendingIntent mDriverStopIntent; 309 private PendingIntent mBatchedScanIntervalIntent; 310 311 /* Tracks current frequency mode */ 312 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 313 314 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 315 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 316 317 // Channel for sending replies. 318 private AsyncChannel mReplyChannel = new AsyncChannel(); 319 320 private WifiP2pServiceImpl mWifiP2pServiceImpl; 321 private WifiPasspointServiceImpl mPasspointServiceImpl; 322 323 // Used to initiate a connection with WifiP2pService 324 private AsyncChannel mWifiP2pChannel; 325 private AsyncChannel mWifiApConfigChannel; 326 327 private WifiNetworkFactory mNetworkFactory; 328 private WifiNetworkAgent mNetworkAgent; 329 330 // Used to filter out requests we couldn't possibly satisfy. 331 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 332 333 /* The base for wifi message types */ 334 static final int BASE = Protocol.BASE_WIFI; 335 /* Start the supplicant */ 336 static final int CMD_START_SUPPLICANT = BASE + 11; 337 /* Stop the supplicant */ 338 static final int CMD_STOP_SUPPLICANT = BASE + 12; 339 /* Start the driver */ 340 static final int CMD_START_DRIVER = BASE + 13; 341 /* Stop the driver */ 342 static final int CMD_STOP_DRIVER = BASE + 14; 343 /* Indicates Static IP succeeded */ 344 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 345 /* Indicates Static IP failed */ 346 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 347 /* Indicates supplicant stop failed */ 348 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 349 /* Delayed stop to avoid shutting down driver too quick*/ 350 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 351 /* A delayed message sent to start driver when it fail to come up */ 352 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 353 354 /* Start the soft access point */ 355 static final int CMD_START_AP = BASE + 21; 356 /* Indicates soft ap start succeeded */ 357 static final int CMD_START_AP_SUCCESS = BASE + 22; 358 /* Indicates soft ap start failed */ 359 static final int CMD_START_AP_FAILURE = BASE + 23; 360 /* Stop the soft access point */ 361 static final int CMD_STOP_AP = BASE + 24; 362 /* Set the soft access point configuration */ 363 static final int CMD_SET_AP_CONFIG = BASE + 25; 364 /* Soft access point configuration set completed */ 365 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 366 /* Request the soft access point configuration */ 367 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 368 /* Response to access point configuration request */ 369 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 370 /* Invoked when getting a tether state change notification */ 371 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 372 /* A delayed message sent to indicate tether state change failed to arrive */ 373 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 374 375 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 376 377 /* Supplicant commands */ 378 /* Is supplicant alive ? */ 379 static final int CMD_PING_SUPPLICANT = BASE + 51; 380 /* Add/update a network configuration */ 381 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 382 /* Delete a network */ 383 static final int CMD_REMOVE_NETWORK = BASE + 53; 384 /* Enable a network. The device will attempt a connection to the given network. */ 385 static final int CMD_ENABLE_NETWORK = BASE + 54; 386 /* Enable all networks */ 387 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 388 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 389 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 390 /* Clear the blacklist network list */ 391 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 392 /* Save configuration */ 393 static final int CMD_SAVE_CONFIG = BASE + 58; 394 /* Get configured networks */ 395 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 396 /* Get available frequencies */ 397 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 398 399 /* Supplicant commands after driver start*/ 400 /* Initiate a scan */ 401 static final int CMD_START_SCAN = BASE + 71; 402 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 403 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 404 /* Disconnect from a network */ 405 static final int CMD_DISCONNECT = BASE + 73; 406 /* Reconnect to a network */ 407 static final int CMD_RECONNECT = BASE + 74; 408 /* Reassociate to a network */ 409 static final int CMD_REASSOCIATE = BASE + 75; 410 /* Controls suspend mode optimizations 411 * 412 * When high perf mode is enabled, suspend mode optimizations are disabled 413 * 414 * When high perf mode is disabled, suspend mode optimizations are enabled 415 * 416 * Suspend mode optimizations include: 417 * - packet filtering 418 * - turn off roaming 419 * - DTIM wake up settings 420 */ 421 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 422 /* Set the country code */ 423 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 424 /* Enables RSSI poll */ 425 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 426 /* RSSI poll */ 427 static final int CMD_RSSI_POLL = BASE + 83; 428 /* Set up packet filtering */ 429 static final int CMD_START_PACKET_FILTERING = BASE + 84; 430 /* Clear packet filter */ 431 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 432 /* Enable suspend mode optimizations in the driver */ 433 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 434 /* When there are no saved networks, we do a periodic scan to notify user of 435 * an open network */ 436 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 437 438 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 439 static final int MULTICAST_V6 = 1; 440 static final int MULTICAST_V4 = 0; 441 442 /* Set the frequency band */ 443 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 444 /* Enable background scan for configured networks */ 445 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; 446 /* Enable TDLS on a specific MAC address */ 447 static final int CMD_ENABLE_TDLS = BASE + 92; 448 449 /* Commands from/to the SupplicantStateTracker */ 450 /* Reset the supplicant state tracker */ 451 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 452 453 /* P2p commands */ 454 /* We are ok with no response here since we wont do much with it anyway */ 455 public static final int CMD_ENABLE_P2P = BASE + 131; 456 /* In order to shut down supplicant cleanly, we wait till p2p has 457 * been disabled */ 458 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 459 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 460 461 public static final int CMD_BOOT_COMPLETED = BASE + 134; 462 463 /* change the batch scan settings. 464 * arg1 = responsible UID 465 * arg2 = csph (channel scans per hour) 466 * obj = bundle with the new settings and the optional worksource 467 */ 468 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 469 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 470 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 471 472 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 473 public static final int CMD_NETLINK_UPDATE = BASE + 140; 474 475 /* Reload all networks and reconnect */ 476 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 477 478 static final int CMD_AUTO_CONNECT = BASE + 143; 479 480 static final int CMD_UNWANTED_NETWORK = BASE + 144; 481 482 static final int CMD_AUTO_ROAM = BASE + 145; 483 484 485 /* Wifi state machine modes of operation */ 486 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 487 public static final int CONNECT_MODE = 1; 488 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 489 public static final int SCAN_ONLY_MODE = 2; 490 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 491 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 492 493 private static final int SUCCESS = 1; 494 private static final int FAILURE = -1; 495 496 /** 497 * The maximum number of times we will retry a connection to an access point 498 * for which we have failed in acquiring an IP address from DHCP. A value of 499 * N means that we will make N+1 connection attempts in all. 500 * <p> 501 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 502 * value if a Settings value is not present. 503 */ 504 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 505 506 /* Tracks if suspend optimizations need to be disabled by DHCP, 507 * screen or due to high perf mode. 508 * When any of them needs to disable it, we keep the suspend optimizations 509 * disabled 510 */ 511 private int mSuspendOptNeedsDisabled = 0; 512 513 private static final int SUSPEND_DUE_TO_DHCP = 1; 514 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 515 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 516 517 /* Tracks if user has enabled suspend optimizations through settings */ 518 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 519 520 /** 521 * Default framework scan interval in milliseconds. This is used in the scenario in which 522 * wifi chipset does not support background scanning to set up a 523 * periodic wake up scan so that the device can connect to a new access 524 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 525 * override this. 526 */ 527 private final int mDefaultFrameworkScanIntervalMs; 528 529 /** 530 * Connected state framework scan interval in milliseconds. 531 * This is used for extended roaming, when screen is lit. 532 */ 533 private int mConnectedScanPeriodMs = 10000; 534 private int mDisconnectedScanPeriodMs = 10000; 535 536 /** 537 * Supplicant scan interval in milliseconds. 538 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 539 * from the default config if the setting is not set 540 */ 541 private long mSupplicantScanIntervalMs; 542 543 /** 544 * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit 545 */ 546 private long lastFullBandConnectedTimeMilli; 547 548 /** 549 * time interval to the next full band scan we will perform for autojoin while connected with screen lit 550 */ 551 private long fullBandConnectedTimeIntervalMilli; 552 553 /** 554 * max time interval to the next full band scan we will perform for autojoin while connected with screen lit 555 * Max time is 5 minutes 556 */ 557 private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5; 558 559 /** 560 * Minimum time interval between enabling all networks. 561 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 562 * due to enabling every time. We add a threshold to avoid this. 563 */ 564 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 565 private long mLastEnableAllNetworksTime; 566 567 /** 568 * Starting and shutting down driver too quick causes problems leading to driver 569 * being in a bad state. Delay driver stop. 570 */ 571 private final int mDriverStopDelayMs; 572 private int mDelayedStopCounter; 573 private boolean mInDelayedStop = false; 574 575 // sometimes telephony gives us this data before boot is complete and we can't store it 576 // until after, so the write is deferred 577 private volatile String mPersistedCountryCode; 578 579 // Supplicant doesn't like setting the same country code multiple times (it may drop 580 // currently connected network), so we save the country code here to avoid redundency 581 private String mLastSetCountryCode; 582 583 /* Default parent state */ 584 private State mDefaultState = new DefaultState(); 585 /* Temporary initial state */ 586 private State mInitialState = new InitialState(); 587 /* Driver loaded, waiting for supplicant to start */ 588 private State mSupplicantStartingState = new SupplicantStartingState(); 589 /* Driver loaded and supplicant ready */ 590 private State mSupplicantStartedState = new SupplicantStartedState(); 591 /* Waiting for supplicant to stop and monitor to exit */ 592 private State mSupplicantStoppingState = new SupplicantStoppingState(); 593 /* Driver start issued, waiting for completed event */ 594 private State mDriverStartingState = new DriverStartingState(); 595 /* Driver started */ 596 private State mDriverStartedState = new DriverStartedState(); 597 /* Wait until p2p is disabled 598 * This is a special state which is entered right after we exit out of DriverStartedState 599 * before transitioning to another state. 600 */ 601 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 602 /* Driver stopping */ 603 private State mDriverStoppingState = new DriverStoppingState(); 604 /* Driver stopped */ 605 private State mDriverStoppedState = new DriverStoppedState(); 606 /* Scan for networks, no connection will be established */ 607 private State mScanModeState = new ScanModeState(); 608 /* Connecting to an access point */ 609 private State mConnectModeState = new ConnectModeState(); 610 /* Connected at 802.11 (L2) level */ 611 private State mL2ConnectedState = new L2ConnectedState(); 612 /* fetching IP after connection to access point (assoc+auth complete) */ 613 private State mObtainingIpState = new ObtainingIpState(); 614 /* Waiting for link quality verification to be complete */ 615 private State mVerifyingLinkState = new VerifyingLinkState(); 616 /* Connected with IP addr */ 617 private State mConnectedState = new ConnectedState(); 618 /* Roaming */ 619 private State mRoamingState = new RoamingState(); 620 /* disconnect issued, waiting for network disconnect confirmation */ 621 private State mDisconnectingState = new DisconnectingState(); 622 /* Network is not connected, supplicant assoc+auth is not complete */ 623 private State mDisconnectedState = new DisconnectedState(); 624 /* Waiting for WPS to be completed*/ 625 private State mWpsRunningState = new WpsRunningState(); 626 627 /* Soft ap is starting up */ 628 private State mSoftApStartingState = new SoftApStartingState(); 629 /* Soft ap is running */ 630 private State mSoftApStartedState = new SoftApStartedState(); 631 /* Soft ap is running and we are waiting for tether notification */ 632 private State mTetheringState = new TetheringState(); 633 /* Soft ap is running and we are tethered through connectivity service */ 634 private State mTetheredState = new TetheredState(); 635 /* Waiting for untether confirmation before stopping soft Ap */ 636 private State mUntetheringState = new UntetheringState(); 637 638 private class TetherStateChange { 639 ArrayList<String> available; 640 ArrayList<String> active; 641 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 642 available = av; 643 active = ac; 644 } 645 } 646 647 648 /** 649 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 650 * {@link WifiManager#WIFI_STATE_DISABLING}, 651 * {@link WifiManager#WIFI_STATE_ENABLED}, 652 * {@link WifiManager#WIFI_STATE_ENABLING}, 653 * {@link WifiManager#WIFI_STATE_UNKNOWN} 654 * 655 */ 656 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 657 658 /** 659 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 660 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 661 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 662 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 663 * {@link WifiManager#WIFI_AP_STATE_FAILED} 664 * 665 */ 666 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 667 668 private static final int SCAN_REQUEST = 0; 669 private static final String ACTION_START_SCAN = 670 "com.android.server.WifiManager.action.START_SCAN"; 671 672 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 673 private static final int DRIVER_STOP_REQUEST = 0; 674 private static final String ACTION_DELAYED_DRIVER_STOP = 675 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 676 677 private static final String ACTION_REFRESH_BATCHED_SCAN = 678 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 679 /** 680 * Keep track of whether WIFI is running. 681 */ 682 private boolean mIsRunning = false; 683 684 /** 685 * Keep track of whether we last told the battery stats we had started. 686 */ 687 private boolean mReportedRunning = false; 688 689 /** 690 * Most recently set source of starting WIFI. 691 */ 692 private final WorkSource mRunningWifiUids = new WorkSource(); 693 694 /** 695 * The last reported UIDs that were responsible for starting WIFI. 696 */ 697 private final WorkSource mLastRunningWifiUids = new WorkSource(); 698 699 private final IBatteryStats mBatteryStats; 700 701 private BatchedScanSettings mBatchedScanSettings = null; 702 703 /** 704 * Track the worksource/cost of the current settings and track what's been noted 705 * to the battery stats, so we can mark the end of the previous when changing. 706 */ 707 private WorkSource mBatchedScanWorkSource = null; 708 private int mBatchedScanCsph = 0; 709 private WorkSource mNotedBatchedScanWorkSource = null; 710 private int mNotedBatchedScanCsph = 0; 711 712 private AtomicBoolean mFrameworkAutoJoin = new AtomicBoolean(true); //enable by default 713 714 public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller) { 715 super("WifiStateMachine"); 716 mContext = context; 717 mInterfaceName = wlanInterface; 718 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 719 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 720 BatteryStats.SERVICE_NAME)); 721 722 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 723 mNwService = INetworkManagementService.Stub.asInterface(b); 724 725 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 726 PackageManager.FEATURE_WIFI_DIRECT); 727 728 mWifiNative = new WifiNative(mInterfaceName); 729 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 730 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 731 mWifiConfigStore, trafficPoller, mWifiNative); 732 mWifiMonitor = new WifiMonitor(this, mWifiNative); 733 mWifiInfo = new WifiInfo(); 734 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 735 getHandler()); 736 mLinkProperties = new LinkProperties(); 737 738 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 739 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1); 740 741 IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE); 742 mPasspointServiceImpl = (WifiPasspointServiceImpl)IWifiPasspointManager.Stub.asInterface(s2); 743 744 mNetworkInfo.setIsAvailable(false); 745 mLastBssid = null; 746 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 747 mLastSignalLevel = -1; 748 749 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 750 public void update() { 751 sendMessage(CMD_NETLINK_UPDATE); 752 } 753 }); 754 try { 755 mNwService.registerObserver(mNetlinkTracker); 756 } catch (RemoteException e) { 757 loge("Couldn't register netlink tracker: " + e.toString()); 758 } 759 760 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 761 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 762 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 763 764 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 765 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 766 767 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 768 R.integer.config_wifi_framework_scan_interval); 769 770 mDriverStopDelayMs = mContext.getResources().getInteger( 771 R.integer.config_wifi_driver_stop_delay); 772 773 mBackgroundScanSupported = mContext.getResources().getBoolean( 774 R.bool.config_wifi_background_scan_support); 775 776 mPrimaryDeviceType = mContext.getResources().getString( 777 R.string.config_wifi_p2p_device_type); 778 779 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 780 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 781 782 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 783 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 1) == 1); 784 785 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 786 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 787 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 788 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 789 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 790 // TODO - needs to be a bit more dynamic 791 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 792 793 mContext.registerReceiver( 794 new BroadcastReceiver() { 795 @Override 796 public void onReceive(Context context, Intent intent) { 797 ArrayList<String> available = intent.getStringArrayListExtra( 798 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 799 ArrayList<String> active = intent.getStringArrayListExtra( 800 ConnectivityManager.EXTRA_ACTIVE_TETHER); 801 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 802 } 803 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 804 805 mContext.registerReceiver( 806 new BroadcastReceiver() { 807 @Override 808 public void onReceive(Context context, Intent intent) { 809 startScan(SCAN_ALARM_SOURCE, null, null); 810 if (VDBG) 811 loge("WiFiStateMachine SCAN ALARM"); 812 } 813 }, 814 new IntentFilter(ACTION_START_SCAN)); 815 816 IntentFilter filter = new IntentFilter(); 817 filter.addAction(Intent.ACTION_SCREEN_ON); 818 filter.addAction(Intent.ACTION_SCREEN_OFF); 819 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 820 mContext.registerReceiver( 821 new BroadcastReceiver() { 822 @Override 823 public void onReceive(Context context, Intent intent) { 824 String action = intent.getAction(); 825 826 if (action.equals(Intent.ACTION_SCREEN_ON)) { 827 handleScreenStateChanged(true); 828 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 829 handleScreenStateChanged(false); 830 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 831 startNextBatchedScanAsync(); 832 } 833 } 834 }, filter); 835 836 mContext.registerReceiver( 837 new BroadcastReceiver() { 838 @Override 839 public void onReceive(Context context, Intent intent) { 840 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 841 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 842 } 843 }, 844 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 845 846 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 847 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 848 new ContentObserver(getHandler()) { 849 @Override 850 public void onChange(boolean selfChange) { 851 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 852 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 853 } 854 }); 855 856 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 857 Settings.Global.WIFI_ENHANCED_AUTO_JOIN), false, 858 new ContentObserver(getHandler()) { 859 @Override 860 public void onChange(boolean selfChange) { 861 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 862 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 0) == 1); 863 } 864 }); 865 866 mContext.registerReceiver( 867 new BroadcastReceiver() { 868 @Override 869 public void onReceive(Context context, Intent intent) { 870 sendMessage(CMD_BOOT_COMPLETED); 871 } 872 }, 873 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 874 875 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 876 877 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 878 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 879 880 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 881 mSuspendWakeLock.setReferenceCounted(false); 882 883 addState(mDefaultState); 884 addState(mInitialState, mDefaultState); 885 addState(mSupplicantStartingState, mDefaultState); 886 addState(mSupplicantStartedState, mDefaultState); 887 addState(mDriverStartingState, mSupplicantStartedState); 888 addState(mDriverStartedState, mSupplicantStartedState); 889 addState(mScanModeState, mDriverStartedState); 890 addState(mConnectModeState, mDriverStartedState); 891 addState(mL2ConnectedState, mConnectModeState); 892 addState(mObtainingIpState, mL2ConnectedState); 893 addState(mVerifyingLinkState, mL2ConnectedState); 894 addState(mConnectedState, mL2ConnectedState); 895 addState(mRoamingState, mL2ConnectedState); 896 addState(mDisconnectingState, mConnectModeState); 897 addState(mDisconnectedState, mConnectModeState); 898 addState(mWpsRunningState, mConnectModeState); 899 addState(mWaitForP2pDisableState, mSupplicantStartedState); 900 addState(mDriverStoppingState, mSupplicantStartedState); 901 addState(mDriverStoppedState, mSupplicantStartedState); 902 addState(mSupplicantStoppingState, mDefaultState); 903 addState(mSoftApStartingState, mDefaultState); 904 addState(mSoftApStartedState, mDefaultState); 905 addState(mTetheringState, mSoftApStartedState); 906 addState(mTetheredState, mSoftApStartedState); 907 addState(mUntetheringState, mSoftApStartedState); 908 909 setInitialState(mInitialState); 910 911 setLogRecSize(2000); 912 setLogOnlyTransitions(false); 913 if (VDBG) setDbg(true); 914 915 //start the state machine 916 start(); 917 918 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 919 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 920 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 921 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 922 } 923 924 private int mVerboseLoggingLevel = 0; 925 926 int getVerboseLoggingLevel() { 927 return mVerboseLoggingLevel; 928 } 929 930 void enableVerboseLogging(int verbose) { 931 mVerboseLoggingLevel = verbose; 932 if (verbose > 0) { 933 DBG = true; 934 VDBG = true; 935 PDBG = true; 936 mLogMessages = true; 937 mWifiNative.setSupplicantLogLevel("DEBUG"); 938 } else { 939 DBG = false; 940 VDBG = false; 941 PDBG = false; 942 mLogMessages = false; 943 mWifiNative.setSupplicantLogLevel("INFO"); 944 } 945 mWifiAutoJoinController.enableVerboseLogging(verbose); 946 mWifiMonitor.enableVerboseLogging(verbose); 947 mWifiNative.enableVerboseLogging(verbose); 948 mWifiConfigStore.enableVerboseLogging(verbose); 949 mSupplicantStateTracker.enableVerboseLogging(verbose); 950 } 951 952 private int mAggressiveHandover = 0; 953 954 int getAggressiveHandover() { 955 return mAggressiveHandover; 956 } 957 958 void enableAggressiveHandover(int enabled) { 959 mAggressiveHandover = enabled; 960 } 961 962 private int mAllowScansWithTraffic = 1; 963 964 public void setAllowScansWithTraffic(int enabled) { 965 mAllowScansWithTraffic = enabled; 966 } 967 968 public int getAllowScansWithTraffic() { 969 return mAllowScansWithTraffic; 970 } 971 972 /* 973 * 974 * Framework scan control 975 */ 976 977 private boolean mAlarmEnabled = false; 978 /* This is set from the overlay config file or from a secure setting. 979 * A value of 0 disables scanning in the framework. 980 */ 981 private long mFrameworkScanIntervalMs = 10000; 982 983 private long mCurrentScanAlarmMs = 10000; 984 private void setScanAlarm(boolean enabled) { 985 if (PDBG) { 986 loge("setScanAlarm " + enabled + " period " + mCurrentScanAlarmMs); 987 } 988 if (mCurrentScanAlarmMs <= 0) enabled = false; 989 if (enabled == mAlarmEnabled) return; 990 if (enabled) { 991 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 992 System.currentTimeMillis() + mCurrentScanAlarmMs, 993 mCurrentScanAlarmMs, 994 mScanIntent); 995 mAlarmEnabled = true; 996 } else { 997 mAlarmManager.cancel(mScanIntent); 998 mAlarmEnabled = false; 999 } 1000 } 1001 1002 /********************************************************* 1003 * Methods exposed for public use 1004 ********************************************************/ 1005 1006 public Messenger getMessenger() { 1007 return new Messenger(getHandler()); 1008 } 1009 1010 public WifiMonitor getWifiMonitor() { 1011 return mWifiMonitor; 1012 } 1013 1014 /** 1015 * TODO: doc 1016 */ 1017 public boolean syncPingSupplicant(AsyncChannel channel) { 1018 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1019 boolean result = (resultMsg.arg1 != FAILURE); 1020 resultMsg.recycle(); 1021 return result; 1022 } 1023 1024 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1025 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1026 List<WifiChannel> list = null; 1027 if (resultMsg.obj != null) { 1028 list = new ArrayList<WifiChannel>(); 1029 String freqs = (String) resultMsg.obj; 1030 String[] lines = freqs.split("\n"); 1031 for (String line : lines) 1032 if (line.contains("MHz")) { 1033 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1034 WifiChannel c = new WifiChannel(); 1035 String[] prop = line.split(" "); 1036 if (prop.length < 5) continue; 1037 try { 1038 c.channelNum = Integer.parseInt(prop[1]); 1039 c.freqMHz = Integer.parseInt(prop[3]); 1040 } catch (NumberFormatException e) { } 1041 c.isDFS = line.contains("(DFS)"); 1042 list.add(c); 1043 } else if (line.contains("Mode[B] Channels:")) { 1044 // B channels are the same as G channels, skipped 1045 break; 1046 } 1047 } 1048 resultMsg.recycle(); 1049 return (list != null && list.size() > 0) ? list : null; 1050 } 1051 1052 1053 /** 1054 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1055 * given to callingUid. 1056 * 1057 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1058 * workSource is specified. 1059 * @param workSource If not null, blame is given to workSource. 1060 * @param settings Scan settings, see {@link ScanSettings}. 1061 */ 1062 public void startScan(int callingUid, ScanSettings settings, WorkSource workSource) { 1063 Bundle bundle = new Bundle(); 1064 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1065 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1066 sendMessage(CMD_START_SCAN, callingUid, 0, bundle); 1067 } 1068 1069 /** 1070 * start or stop batched scanning using the given settings 1071 */ 1072 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1073 WorkSource workSource) { 1074 Bundle bundle = new Bundle(); 1075 bundle.putParcelable(BATCHED_SETTING, settings); 1076 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1077 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1078 } 1079 1080 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1081 synchronized (mBatchedScanResults) { 1082 List<BatchedScanResult> batchedScanList = 1083 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1084 for(BatchedScanResult result: mBatchedScanResults) { 1085 batchedScanList.add(new BatchedScanResult(result)); 1086 } 1087 return batchedScanList; 1088 } 1089 } 1090 1091 public void requestBatchedScanPoll() { 1092 sendMessage(CMD_POLL_BATCHED_SCAN); 1093 } 1094 1095 private void startBatchedScan() { 1096 if (mBatchedScanSettings == null) return; 1097 1098 if (mDhcpActive) { 1099 if (DBG) log("not starting Batched Scans due to DHCP"); 1100 return; 1101 } 1102 1103 // first grab any existing data 1104 retrieveBatchedScanData(); 1105 1106 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1107 1108 1109 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1110 1111 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1112 try { 1113 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1114 setNextBatchedAlarm(mExpectedBatchedScans); 1115 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1116 } catch (NumberFormatException e) { 1117 stopBatchedScan(); 1118 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1119 } 1120 } 1121 1122 // called from BroadcastListener 1123 private void startNextBatchedScanAsync() { 1124 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1125 } 1126 1127 private void startNextBatchedScan() { 1128 // first grab any existing data 1129 retrieveBatchedScanData(); 1130 1131 setNextBatchedAlarm(mExpectedBatchedScans); 1132 } 1133 1134 private void handleBatchedScanPollRequest() { 1135 if (DBG) { 1136 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1137 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1138 mBatchedScanSettings); 1139 } 1140 // if there is no appropriate PollTime that's because we either aren't 1141 // batching or we've already set a time for a poll request 1142 if (mBatchedScanMinPollTime == 0) return; 1143 if (mBatchedScanSettings == null) return; 1144 1145 long now = System.currentTimeMillis(); 1146 1147 if (now > mBatchedScanMinPollTime) { 1148 // do the poll and reset our timers 1149 startNextBatchedScan(); 1150 } else { 1151 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1152 mBatchedScanIntervalIntent); 1153 mBatchedScanMinPollTime = 0; 1154 } 1155 } 1156 1157 // return true if new/different 1158 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1159 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1160 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1161 1162 if (DBG) { 1163 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1164 ", worksource=" + responsibleWorkSource); 1165 } 1166 if (settings != null) { 1167 if (settings.equals(mBatchedScanSettings)) return false; 1168 } else { 1169 if (mBatchedScanSettings == null) return false; 1170 } 1171 mBatchedScanSettings = settings; 1172 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1173 mBatchedScanWorkSource = responsibleWorkSource; 1174 mBatchedScanCsph = csph; 1175 return true; 1176 } 1177 1178 private void stopBatchedScan() { 1179 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1180 retrieveBatchedScanData(); 1181 mWifiNative.setBatchedScanSettings(null); 1182 noteBatchedScanStop(); 1183 } 1184 1185 private void setNextBatchedAlarm(int scansExpected) { 1186 1187 if (mBatchedScanSettings == null || scansExpected < 1) return; 1188 1189 mBatchedScanMinPollTime = System.currentTimeMillis() + 1190 mBatchedScanSettings.scanIntervalSec * 1000; 1191 1192 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1193 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1194 } 1195 1196 int secToFull = mBatchedScanSettings.scanIntervalSec; 1197 secToFull *= scansExpected; 1198 1199 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1200 if (debugPeriod > 0) secToFull = debugPeriod; 1201 1202 // set the alarm to do the next poll. We set it a little short as we'd rather 1203 // wake up wearly than miss a scan due to buffer overflow 1204 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1205 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1206 mBatchedScanIntervalIntent); 1207 } 1208 1209 /** 1210 * Start reading new scan data 1211 * Data comes in as: 1212 * "scancount=5\n" 1213 * "nextcount=5\n" 1214 * "apcount=3\n" 1215 * "trunc\n" (optional) 1216 * "bssid=...\n" 1217 * "ssid=...\n" 1218 * "freq=...\n" (in Mhz) 1219 * "level=...\n" 1220 * "dist=...\n" (in cm) 1221 * "distsd=...\n" (standard deviation, in cm) 1222 * "====" 1223 * "bssid=...\n" 1224 * etc 1225 * "====" 1226 * "bssid=...\n" 1227 * etc 1228 * "%%%%" 1229 * "apcount=2\n" 1230 * "bssid=...\n" 1231 * etc 1232 * "%%%% 1233 * etc 1234 * "----" 1235 */ 1236 private final static boolean DEBUG_PARSE = false; 1237 private void retrieveBatchedScanData() { 1238 String rawData = mWifiNative.getBatchedScanResults(); 1239 if (DEBUG_PARSE) log("rawData = " + rawData); 1240 mBatchedScanMinPollTime = 0; 1241 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1242 loge("Unexpected BatchedScanResults :" + rawData); 1243 return; 1244 } 1245 1246 int scanCount = 0; 1247 final String END_OF_BATCHES = "----"; 1248 final String SCANCOUNT = "scancount="; 1249 final String TRUNCATED = "trunc"; 1250 final String AGE = "age="; 1251 final String DIST = "dist="; 1252 final String DISTSD = "distSd="; 1253 1254 String splitData[] = rawData.split("\n"); 1255 int n = 0; 1256 if (splitData[n].startsWith(SCANCOUNT)) { 1257 try { 1258 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1259 } catch (NumberFormatException e) { 1260 loge("scancount parseInt Exception from " + splitData[n]); 1261 } 1262 } else log("scancount not found"); 1263 if (scanCount == 0) { 1264 loge("scanCount==0 - aborting"); 1265 return; 1266 } 1267 1268 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1269 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1270 1271 synchronized (mBatchedScanResults) { 1272 mBatchedScanResults.clear(); 1273 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1274 1275 String bssid = null; 1276 WifiSsid wifiSsid = null; 1277 int level = 0; 1278 int freq = 0; 1279 int dist, distSd; 1280 long tsf = 0; 1281 dist = distSd = ScanResult.UNSPECIFIED; 1282 final long now = SystemClock.elapsedRealtime(); 1283 final int bssidStrLen = BSSID_STR.length(); 1284 1285 while (true) { 1286 while (n < splitData.length) { 1287 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1288 if (splitData[n].equals(END_OF_BATCHES)) { 1289 if (n+1 != splitData.length) { 1290 loge("didn't consume " + (splitData.length-n)); 1291 } 1292 if (mBatchedScanResults.size() > 0) { 1293 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1294 } 1295 logd("retrieveBatchedScanResults X"); 1296 return; 1297 } 1298 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1299 if (bssid != null) { 1300 batchedScanResult.scanResults.add(new ScanResult( 1301 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1302 wifiSsid = null; 1303 bssid = null; 1304 level = 0; 1305 freq = 0; 1306 tsf = 0; 1307 dist = distSd = ScanResult.UNSPECIFIED; 1308 } 1309 if (splitData[n].equals(END_STR)) { 1310 if (batchedScanResult.scanResults.size() != 0) { 1311 mBatchedScanResults.add(batchedScanResult); 1312 batchedScanResult = new BatchedScanResult(); 1313 } else { 1314 logd("Found empty batch"); 1315 } 1316 } 1317 } else if (splitData[n].equals(TRUNCATED)) { 1318 batchedScanResult.truncated = true; 1319 } else if (splitData[n].startsWith(BSSID_STR)) { 1320 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1321 splitData[n].length() - bssidStrLen); 1322 } else if (splitData[n].startsWith(FREQ_STR)) { 1323 try { 1324 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1325 } catch (NumberFormatException e) { 1326 loge("Invalid freqency: " + splitData[n]); 1327 freq = 0; 1328 } 1329 } else if (splitData[n].startsWith(AGE)) { 1330 try { 1331 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1332 tsf *= 1000; // convert mS -> uS 1333 } catch (NumberFormatException e) { 1334 loge("Invalid timestamp: " + splitData[n]); 1335 tsf = 0; 1336 } 1337 } else if (splitData[n].startsWith(SSID_STR)) { 1338 wifiSsid = WifiSsid.createFromAsciiEncoded( 1339 splitData[n].substring(SSID_STR.length())); 1340 } else if (splitData[n].startsWith(LEVEL_STR)) { 1341 try { 1342 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1343 if (level > 0) level -= 256; 1344 } catch (NumberFormatException e) { 1345 loge("Invalid level: " + splitData[n]); 1346 level = 0; 1347 } 1348 } else if (splitData[n].startsWith(DIST)) { 1349 try { 1350 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1351 } catch (NumberFormatException e) { 1352 loge("Invalid distance: " + splitData[n]); 1353 dist = ScanResult.UNSPECIFIED; 1354 } 1355 } else if (splitData[n].startsWith(DISTSD)) { 1356 try { 1357 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1358 } catch (NumberFormatException e) { 1359 loge("Invalid distanceSd: " + splitData[n]); 1360 distSd = ScanResult.UNSPECIFIED; 1361 } 1362 } else { 1363 loge("Unable to parse batched scan result line: " + splitData[n]); 1364 } 1365 n++; 1366 } 1367 rawData = mWifiNative.getBatchedScanResults(); 1368 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1369 if (rawData == null) { 1370 loge("Unexpected null BatchedScanResults"); 1371 return; 1372 } 1373 splitData = rawData.split("\n"); 1374 if (splitData.length == 0 || splitData[0].equals("ok")) { 1375 loge("batch scan results just ended!"); 1376 if (mBatchedScanResults.size() > 0) { 1377 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1378 } 1379 return; 1380 } 1381 n = 0; 1382 } 1383 } 1384 } 1385 1386 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1387 private void noteScanStart(int callingUid, WorkSource workSource) { 1388 if (DBG) { 1389 long now = SystemClock.elapsedRealtimeNanos(); 1390 String ts = String.format("[%,d us]", now/1000); 1391 if (workSource != null) { 1392 loge(ts + " noteScanStart" + workSource.toString() 1393 + " uid " + Integer.toString(callingUid)); 1394 } else { 1395 loge(ts + " noteScanstart no scan source"); 1396 } 1397 } 1398 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE && callingUid != SCAN_ALARM_SOURCE) 1399 || workSource != null)) { 1400 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1401 try { 1402 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1403 } catch (RemoteException e) { 1404 log(e.toString()); 1405 } 1406 } 1407 } 1408 1409 private void noteScanEnd() { 1410 if (DBG) { 1411 long now = SystemClock.elapsedRealtimeNanos(); 1412 String ts = String.format("[%,d us]", now/1000); 1413 1414 if (mScanWorkSource != null) 1415 loge(ts + " noteScanEnd " + mScanWorkSource.toString()); 1416 else 1417 loge(ts + " noteScanEnd no scan source"); 1418 } 1419 if (mScanWorkSource != null) { 1420 try { 1421 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1422 } catch (RemoteException e) { 1423 log(e.toString()); 1424 } finally { 1425 mScanWorkSource = null; 1426 } 1427 } 1428 } 1429 1430 private void noteBatchedScanStart() { 1431 if (PDBG) loge("noteBatchedScanstart()"); 1432 // note the end of a previous scan set 1433 if (mNotedBatchedScanWorkSource != null && 1434 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1435 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1436 try { 1437 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1438 } catch (RemoteException e) { 1439 log(e.toString()); 1440 } finally { 1441 mNotedBatchedScanWorkSource = null; 1442 mNotedBatchedScanCsph = 0; 1443 } 1444 } 1445 // note the start of the new 1446 try { 1447 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1448 mBatchedScanCsph); 1449 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1450 mNotedBatchedScanCsph = mBatchedScanCsph; 1451 } catch (RemoteException e) { 1452 log(e.toString()); 1453 } 1454 } 1455 1456 private void noteBatchedScanStop() { 1457 if (PDBG) loge("noteBatchedScanstop()"); 1458 1459 if (mNotedBatchedScanWorkSource != null) { 1460 try { 1461 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1462 } catch (RemoteException e) { 1463 log(e.toString()); 1464 } finally { 1465 mNotedBatchedScanWorkSource = null; 1466 mNotedBatchedScanCsph = 0; 1467 } 1468 } 1469 } 1470 1471 private void handleScanRequest(int type, Message message) { 1472 // unbundle parameters 1473 Bundle bundle = (Bundle) message.obj; 1474 ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1475 WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1476 1477 // parse scan settings 1478 String freqs = null; 1479 if (settings != null && settings.channelSet != null) { 1480 StringBuilder sb = new StringBuilder(); 1481 boolean first = true; 1482 for (WifiChannel channel : settings.channelSet) { 1483 if (!first) sb.append(','); else first = false; 1484 sb.append(channel.freqMHz); 1485 } 1486 freqs = sb.toString(); 1487 } 1488 1489 // call wifi native to start the scan 1490 if (startScanNative(type, freqs)) { 1491 // only count battery consumption if scan request is accepted 1492 noteScanStart(message.arg1, workSource); 1493 // a full scan covers everything, clearing scan request buffer 1494 if (freqs == null) 1495 mBufferedScanMsg.clear(); 1496 return; 1497 } 1498 1499 // if reach here, scan request is rejected 1500 1501 if (!mIsScanOngoing) { 1502 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 1503 // discard this request and pop up the next one 1504 if (mBufferedScanMsg.size() > 0) 1505 sendMessage(mBufferedScanMsg.remove()); 1506 } else if (!mIsFullScanOngoing) { 1507 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 1508 // buffer the scan request to make sure specified channels will be scanned eventually 1509 if (freqs == null) 1510 mBufferedScanMsg.clear(); 1511 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 1512 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1513 mBufferedScanMsg.add(msg); 1514 } else { 1515 // if too many requests in buffer, combine them into a single full scan 1516 bundle = new Bundle(); 1517 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 1518 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1519 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1520 mBufferedScanMsg.clear(); 1521 mBufferedScanMsg.add(msg); 1522 } 1523 } 1524 } 1525 1526 1527 /** return true iff scan request is accepted */ 1528 private boolean startScanNative(int type, String freqs) { 1529 if (mWifiNative.scan(type, freqs)) { 1530 mIsScanOngoing = true; 1531 mIsFullScanOngoing = (freqs == null); 1532 return true; 1533 } 1534 return false; 1535 } 1536 1537 /** 1538 * TODO: doc 1539 */ 1540 public void setSupplicantRunning(boolean enable) { 1541 if (enable) { 1542 sendMessage(CMD_START_SUPPLICANT); 1543 } else { 1544 sendMessage(CMD_STOP_SUPPLICANT); 1545 } 1546 } 1547 1548 /** 1549 * TODO: doc 1550 */ 1551 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1552 if (enable) { 1553 sendMessage(CMD_START_AP, wifiConfig); 1554 } else { 1555 sendMessage(CMD_STOP_AP); 1556 } 1557 } 1558 1559 public void setWifiApConfiguration(WifiConfiguration config) { 1560 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1561 } 1562 1563 public WifiConfiguration syncGetWifiApConfiguration() { 1564 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1565 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1566 resultMsg.recycle(); 1567 return ret; 1568 } 1569 1570 /** 1571 * TODO: doc 1572 */ 1573 public int syncGetWifiState() { 1574 return mWifiState.get(); 1575 } 1576 1577 /** 1578 * TODO: doc 1579 */ 1580 public String syncGetWifiStateByName() { 1581 switch (mWifiState.get()) { 1582 case WIFI_STATE_DISABLING: 1583 return "disabling"; 1584 case WIFI_STATE_DISABLED: 1585 return "disabled"; 1586 case WIFI_STATE_ENABLING: 1587 return "enabling"; 1588 case WIFI_STATE_ENABLED: 1589 return "enabled"; 1590 case WIFI_STATE_UNKNOWN: 1591 return "unknown state"; 1592 default: 1593 return "[invalid state]"; 1594 } 1595 } 1596 1597 /** 1598 * TODO: doc 1599 */ 1600 public int syncGetWifiApState() { 1601 return mWifiApState.get(); 1602 } 1603 1604 /** 1605 * TODO: doc 1606 */ 1607 public String syncGetWifiApStateByName() { 1608 switch (mWifiApState.get()) { 1609 case WIFI_AP_STATE_DISABLING: 1610 return "disabling"; 1611 case WIFI_AP_STATE_DISABLED: 1612 return "disabled"; 1613 case WIFI_AP_STATE_ENABLING: 1614 return "enabling"; 1615 case WIFI_AP_STATE_ENABLED: 1616 return "enabled"; 1617 case WIFI_AP_STATE_FAILED: 1618 return "failed"; 1619 default: 1620 return "[invalid state]"; 1621 } 1622 } 1623 1624 /** 1625 * Get status information for the current connection, if any. 1626 * @return a {@link WifiInfo} object containing information about the current connection 1627 * 1628 */ 1629 public WifiInfo syncRequestConnectionInfo() { 1630 return mWifiInfo; 1631 } 1632 1633 public DhcpResults syncGetDhcpResults() { 1634 synchronized (mDhcpResultsLock) { 1635 return new DhcpResults(mDhcpResults); 1636 } 1637 } 1638 1639 /** 1640 * TODO: doc 1641 */ 1642 public void setDriverStart(boolean enable) { 1643 if (enable) { 1644 sendMessage(CMD_START_DRIVER); 1645 } else { 1646 sendMessage(CMD_STOP_DRIVER); 1647 } 1648 } 1649 1650 /** 1651 * TODO: doc 1652 */ 1653 public void setOperationalMode(int mode) { 1654 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1655 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1656 } 1657 1658 /** 1659 * TODO: doc 1660 */ 1661 public List<ScanResult> syncGetScanResultsList() { 1662 synchronized (mScanResultCache) { 1663 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1664 for(ScanResult result: mScanResults) { 1665 scanList.add(new ScanResult(result)); 1666 } 1667 return scanList; 1668 } 1669 } 1670 1671 /** 1672 * Disconnect from Access Point 1673 */ 1674 public void disconnectCommand() { 1675 sendMessage(CMD_DISCONNECT); 1676 } 1677 1678 /** 1679 * Initiate a reconnection to AP 1680 */ 1681 public void reconnectCommand() { 1682 sendMessage(CMD_RECONNECT); 1683 } 1684 1685 /** 1686 * Initiate a re-association to AP 1687 */ 1688 public void reassociateCommand() { 1689 sendMessage(CMD_REASSOCIATE); 1690 } 1691 1692 /** 1693 * Reload networks and then reconnect; helps load correct data for TLS networks 1694 */ 1695 1696 public void reloadTlsNetworksAndReconnect() { 1697 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1698 } 1699 1700 /** 1701 * Add a network synchronously 1702 * 1703 * @return network id of the new network 1704 */ 1705 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1706 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1707 int result = resultMsg.arg1; 1708 resultMsg.recycle(); 1709 return result; 1710 } 1711 1712 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1713 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1714 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1715 resultMsg.recycle(); 1716 return result; 1717 } 1718 1719 /** 1720 * Delete a network 1721 * 1722 * @param networkId id of the network to be removed 1723 */ 1724 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1725 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1726 boolean result = (resultMsg.arg1 != FAILURE); 1727 resultMsg.recycle(); 1728 return result; 1729 } 1730 1731 /** 1732 * Enable a network 1733 * 1734 * @param netId network id of the network 1735 * @param disableOthers true, if all other networks have to be disabled 1736 * @return {@code true} if the operation succeeds, {@code false} otherwise 1737 */ 1738 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1739 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1740 disableOthers ? 1 : 0); 1741 boolean result = (resultMsg.arg1 != FAILURE); 1742 resultMsg.recycle(); 1743 return result; 1744 } 1745 1746 /** 1747 * Disable a network 1748 * 1749 * @param netId network id of the network 1750 * @return {@code true} if the operation succeeds, {@code false} otherwise 1751 */ 1752 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1753 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1754 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1755 resultMsg.recycle(); 1756 return result; 1757 } 1758 1759 /** 1760 * Retrieves a WPS-NFC configuration token for the specified network 1761 * @return a hex string representation of the WPS-NFC configuration token 1762 */ 1763 public String syncGetWpsNfcConfigurationToken(int netId) { 1764 return mWifiNative.getNfcWpsConfigurationToken(netId); 1765 } 1766 1767 /** 1768 * Blacklist a BSSID. This will avoid the AP if there are 1769 * alternate APs to connect 1770 * 1771 * @param bssid BSSID of the network 1772 */ 1773 public void addToBlacklist(String bssid) { 1774 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1775 } 1776 1777 /** 1778 * Clear the blacklist list 1779 * 1780 */ 1781 public void clearBlacklist() { 1782 sendMessage(CMD_CLEAR_BLACKLIST); 1783 } 1784 1785 public void enableRssiPolling(boolean enabled) { 1786 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1787 } 1788 1789 public void enableBackgroundScanCommand(boolean enabled) { 1790 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1791 } 1792 1793 public void enableAllNetworks() { 1794 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1795 } 1796 1797 /** 1798 * Start filtering Multicast v4 packets 1799 */ 1800 public void startFilteringMulticastV4Packets() { 1801 mFilteringMulticastV4Packets.set(true); 1802 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1803 } 1804 1805 /** 1806 * Stop filtering Multicast v4 packets 1807 */ 1808 public void stopFilteringMulticastV4Packets() { 1809 mFilteringMulticastV4Packets.set(false); 1810 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1811 } 1812 1813 /** 1814 * Start filtering Multicast v4 packets 1815 */ 1816 public void startFilteringMulticastV6Packets() { 1817 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1818 } 1819 1820 /** 1821 * Stop filtering Multicast v4 packets 1822 */ 1823 public void stopFilteringMulticastV6Packets() { 1824 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1825 } 1826 1827 /** 1828 * Set high performance mode of operation. 1829 * Enabling would set active power mode and disable suspend optimizations; 1830 * disabling would set auto power mode and enable suspend optimizations 1831 * @param enable true if enable, false otherwise 1832 */ 1833 public void setHighPerfModeEnabled(boolean enable) { 1834 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1835 } 1836 1837 /** 1838 * Set the country code 1839 * @param countryCode following ISO 3166 format 1840 * @param persist {@code true} if the setting should be remembered. 1841 */ 1842 public void setCountryCode(String countryCode, boolean persist) { 1843 // If it's a good country code, apply after the current 1844 // wifi connection is terminated; ignore resetting of code 1845 // for now (it is unclear what the chipset should do when 1846 // country code is reset) 1847 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1848 if (TextUtils.isEmpty(countryCode)) { 1849 log("Ignoring resetting of country code"); 1850 } else { 1851 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1852 } 1853 } 1854 1855 /** 1856 * Set the operational frequency band 1857 * @param band 1858 * @param persist {@code true} if the setting should be remembered. 1859 */ 1860 public void setFrequencyBand(int band, boolean persist) { 1861 if (persist) { 1862 Settings.Global.putInt(mContext.getContentResolver(), 1863 Settings.Global.WIFI_FREQUENCY_BAND, 1864 band); 1865 } 1866 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 1867 } 1868 1869 /** 1870 * Enable TDLS for a specific MAC address 1871 */ 1872 public void enableTdls(String remoteMacAddress, boolean enable) { 1873 int enabler = enable ? 1 : 0; 1874 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 1875 } 1876 1877 /** 1878 * Returns the operational frequency band 1879 */ 1880 public int getFrequencyBand() { 1881 return mFrequencyBand.get(); 1882 } 1883 1884 /** 1885 * Returns the wifi configuration file 1886 */ 1887 public String getConfigFile() { 1888 return mWifiConfigStore.getConfigFile(); 1889 } 1890 1891 /** 1892 * Send a message indicating bluetooth adapter connection state changed 1893 */ 1894 public void sendBluetoothAdapterStateChange(int state) { 1895 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 1896 } 1897 1898 /** 1899 * Save configuration on supplicant 1900 * 1901 * @return {@code true} if the operation succeeds, {@code false} otherwise 1902 * 1903 * TODO: deprecate this 1904 */ 1905 public boolean syncSaveConfig(AsyncChannel channel) { 1906 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 1907 boolean result = (resultMsg.arg1 != FAILURE); 1908 resultMsg.recycle(); 1909 return result; 1910 } 1911 1912 public void updateBatteryWorkSource(WorkSource newSource) { 1913 synchronized (mRunningWifiUids) { 1914 try { 1915 if (newSource != null) { 1916 mRunningWifiUids.set(newSource); 1917 } 1918 if (mIsRunning) { 1919 if (mReportedRunning) { 1920 // If the work source has changed since last time, need 1921 // to remove old work from battery stats. 1922 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 1923 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 1924 mRunningWifiUids); 1925 mLastRunningWifiUids.set(mRunningWifiUids); 1926 } 1927 } else { 1928 // Now being started, report it. 1929 mBatteryStats.noteWifiRunning(mRunningWifiUids); 1930 mLastRunningWifiUids.set(mRunningWifiUids); 1931 mReportedRunning = true; 1932 } 1933 } else { 1934 if (mReportedRunning) { 1935 // Last reported we were running, time to stop. 1936 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 1937 mLastRunningWifiUids.clear(); 1938 mReportedRunning = false; 1939 } 1940 } 1941 mWakeLock.setWorkSource(newSource); 1942 } catch (RemoteException ignore) { 1943 } 1944 } 1945 } 1946 1947 @Override 1948 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1949 super.dump(fd, pw, args); 1950 mSupplicantStateTracker.dump(fd, pw, args); 1951 pw.println("mLinkProperties " + mLinkProperties); 1952 pw.println("mWifiInfo " + mWifiInfo); 1953 pw.println("mDhcpResults " + mDhcpResults); 1954 pw.println("mNetworkInfo " + mNetworkInfo); 1955 pw.println("mLastSignalLevel " + mLastSignalLevel); 1956 pw.println("mLastBssid " + mLastBssid); 1957 pw.println("mLastNetworkId " + mLastNetworkId); 1958 pw.println("mReconnectCount " + mReconnectCount); 1959 pw.println("mOperationalMode " + mOperationalMode); 1960 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 1961 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1962 pw.println("Supplicant status " + mWifiNative.status()); 1963 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 1964 pw.println("mLastSetCountryCode " + mLastSetCountryCode); 1965 pw.println("mPersistedCountryCode " + mPersistedCountryCode); 1966 pw.println(); 1967 mWifiConfigStore.dump(fd, pw, args); 1968 } 1969 1970 /********************************************************* 1971 * Internal private functions 1972 ********************************************************/ 1973 1974 private void logStateAndMessage(Message message, String state) { 1975 if (mLogMessages) { 1976 //long now = SystemClock.elapsedRealtimeNanos(); 1977 //String ts = String.format("[%,d us]", now/1000); 1978 1979 loge(/*ts + " " + */this.getClass().getSimpleName() 1980 + "state:" + state + " what:" + Integer.toString(message.what, 16) 1981 + " " + smToString(message) + " "); 1982 } 1983 } 1984 1985 private void handleScreenStateChanged(boolean screenOn) { 1986 mScreenOn = screenOn; 1987 if (PDBG) { 1988 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 1989 + "mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) 1990 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 1991 + " autojoin " + mFrameworkAutoJoin 1992 + " state " + getCurrentState().getName() 1993 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 1994 } 1995 enableRssiPolling(screenOn); 1996 if (mBackgroundScanSupported) { 1997 enableBackgroundScanCommand(screenOn == false); 1998 } 1999 2000 if (screenOn) enableAllNetworks(); 2001 if (mUserWantsSuspendOpt.get()) { 2002 if (screenOn) { 2003 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 2004 } else { 2005 //Allow 2s for suspend optimizations to be set 2006 mSuspendWakeLock.acquire(2000); 2007 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 2008 } 2009 } 2010 mScreenBroadcastReceived.set(true); 2011 2012 if (screenOn) { 2013 fullBandConnectedTimeIntervalMilli = 20 * 1000; //start at 20 seconds interval 2014 if (mFrameworkAutoJoin.get()) { 2015 //start the scan alarm so as to enable autojoin 2016 if (getCurrentState() == mConnectedState) { 2017 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 2018 } else if (getCurrentState() == mDisconnectedState) { 2019 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2020 //kick a scan right now 2021 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2022 } else if (getCurrentState() == mDisconnectingState) { 2023 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2024 //kick a scan right now 2025 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2026 } 2027 } 2028 setScanAlarm(true); 2029 2030 } else { 2031 setScanAlarm(false); 2032 } 2033 2034 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 2035 } 2036 2037 private void checkAndSetConnectivityInstance() { 2038 if (mCm == null) { 2039 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 2040 } 2041 } 2042 2043 private boolean startTethering(ArrayList<String> available) { 2044 2045 boolean wifiAvailable = false; 2046 2047 checkAndSetConnectivityInstance(); 2048 2049 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2050 2051 for (String intf : available) { 2052 for (String regex : wifiRegexs) { 2053 if (intf.matches(regex)) { 2054 2055 InterfaceConfiguration ifcg = null; 2056 try { 2057 ifcg = mNwService.getInterfaceConfig(intf); 2058 if (ifcg != null) { 2059 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 2060 ifcg.setLinkAddress(new LinkAddress( 2061 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 2062 ifcg.setInterfaceUp(); 2063 2064 mNwService.setInterfaceConfig(intf, ifcg); 2065 } 2066 } catch (Exception e) { 2067 loge("Error configuring interface " + intf + ", :" + e); 2068 return false; 2069 } 2070 2071 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2072 loge("Error tethering on " + intf); 2073 return false; 2074 } 2075 mTetherInterfaceName = intf; 2076 return true; 2077 } 2078 } 2079 } 2080 // We found no interfaces to tether 2081 return false; 2082 } 2083 2084 private void stopTethering() { 2085 2086 checkAndSetConnectivityInstance(); 2087 2088 /* Clear the interface config to allow dhcp correctly configure new 2089 ip settings */ 2090 InterfaceConfiguration ifcg = null; 2091 try { 2092 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 2093 if (ifcg != null) { 2094 ifcg.setLinkAddress( 2095 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 2096 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 2097 } 2098 } catch (Exception e) { 2099 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 2100 } 2101 2102 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2103 loge("Untether initiate failed!"); 2104 } 2105 } 2106 2107 private boolean isWifiTethered(ArrayList<String> active) { 2108 2109 checkAndSetConnectivityInstance(); 2110 2111 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2112 for (String intf : active) { 2113 for (String regex : wifiRegexs) { 2114 if (intf.matches(regex)) { 2115 return true; 2116 } 2117 } 2118 } 2119 // We found no interfaces that are tethered 2120 return false; 2121 } 2122 2123 /** 2124 * Set the country code from the system setting value, if any. 2125 */ 2126 private void setCountryCode() { 2127 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2128 Settings.Global.WIFI_COUNTRY_CODE); 2129 if (countryCode != null && !countryCode.isEmpty()) { 2130 setCountryCode(countryCode, false); 2131 } else { 2132 //use driver default 2133 } 2134 } 2135 2136 /** 2137 * Set the frequency band from the system setting value, if any. 2138 */ 2139 private void setFrequencyBand() { 2140 int band = Settings.Global.getInt(mContext.getContentResolver(), 2141 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 2142 setFrequencyBand(band, false); 2143 } 2144 2145 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 2146 if (DBG) { 2147 log("setSuspendOptimizationsNative: " + reason + " " + enabled 2148 + " -want " + mUserWantsSuspendOpt.get() 2149 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2150 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2151 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2152 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2153 } 2154 mWifiNative.setSuspendOptimizations(enabled); 2155 2156 if (enabled) { 2157 mSuspendOptNeedsDisabled &= ~reason; 2158 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 2159 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 2160 if (DBG) { 2161 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 2162 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2163 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2164 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2165 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2166 } 2167 mWifiNative.setSuspendOptimizations(true); 2168 } 2169 } else { 2170 mSuspendOptNeedsDisabled |= reason; 2171 mWifiNative.setSuspendOptimizations(false); 2172 } 2173 } 2174 2175 private void setSuspendOptimizations(int reason, boolean enabled) { 2176 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 2177 if (enabled) { 2178 mSuspendOptNeedsDisabled &= ~reason; 2179 } else { 2180 mSuspendOptNeedsDisabled |= reason; 2181 } 2182 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2183 } 2184 2185 private void setWifiState(int wifiState) { 2186 final int previousWifiState = mWifiState.get(); 2187 2188 try { 2189 if (wifiState == WIFI_STATE_ENABLED) { 2190 mBatteryStats.noteWifiOn(); 2191 } else if (wifiState == WIFI_STATE_DISABLED) { 2192 mBatteryStats.noteWifiOff(); 2193 } 2194 } catch (RemoteException e) { 2195 loge("Failed to note battery stats in wifi"); 2196 } 2197 2198 mWifiState.set(wifiState); 2199 2200 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 2201 2202 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 2203 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2204 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 2205 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 2206 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2207 } 2208 2209 private void setWifiApState(int wifiApState) { 2210 final int previousWifiApState = mWifiApState.get(); 2211 2212 try { 2213 if (wifiApState == WIFI_AP_STATE_ENABLED) { 2214 mBatteryStats.noteWifiOn(); 2215 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 2216 mBatteryStats.noteWifiOff(); 2217 } 2218 } catch (RemoteException e) { 2219 loge("Failed to note battery stats in wifi"); 2220 } 2221 2222 // Update state 2223 mWifiApState.set(wifiApState); 2224 2225 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 2226 2227 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 2228 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2229 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 2230 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 2231 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2232 } 2233 2234 private static final String ID_STR = "id="; 2235 private static final String BSSID_STR = "bssid="; 2236 private static final String FREQ_STR = "freq="; 2237 private static final String LEVEL_STR = "level="; 2238 private static final String TSF_STR = "tsf="; 2239 private static final String FLAGS_STR = "flags="; 2240 private static final String SSID_STR = "ssid="; 2241 private static final String DELIMITER_STR = "===="; 2242 private static final String END_STR = "####"; 2243 2244 /** 2245 * Format: 2246 * 2247 * id=1 2248 * bssid=68:7f:76:d7:1a:6e 2249 * freq=2412 2250 * level=-44 2251 * tsf=1344626243700342 2252 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2253 * ssid=zfdy 2254 * ==== 2255 * id=2 2256 * bssid=68:5f:74:d7:1a:6f 2257 * freq=5180 2258 * level=-73 2259 * tsf=1344626243700373 2260 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2261 * ssid=zuby 2262 * ==== 2263 */ 2264 private void setScanResults() { 2265 String bssid = ""; 2266 int level = 0; 2267 int freq = 0; 2268 long tsf = 0; 2269 String flags = ""; 2270 WifiSsid wifiSsid = null; 2271 String scanResults; 2272 String tmpResults; 2273 StringBuffer scanResultsBuf = new StringBuffer(); 2274 int sid = 0; 2275 2276 while (true) { 2277 tmpResults = mWifiNative.scanResults(sid); 2278 if (TextUtils.isEmpty(tmpResults)) break; 2279 scanResultsBuf.append(tmpResults); 2280 scanResultsBuf.append("\n"); 2281 String[] lines = tmpResults.split("\n"); 2282 sid = -1; 2283 for (int i=lines.length - 1; i >= 0; i--) { 2284 if (lines[i].startsWith(END_STR)) { 2285 break; 2286 } else if (lines[i].startsWith(ID_STR)) { 2287 try { 2288 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 2289 } catch (NumberFormatException e) { 2290 // Nothing to do 2291 } 2292 break; 2293 } 2294 } 2295 if (sid == -1) break; 2296 } 2297 2298 scanResults = scanResultsBuf.toString(); 2299 if (TextUtils.isEmpty(scanResults)) { 2300 return; 2301 } 2302 2303 // note that all these splits and substrings keep references to the original 2304 // huge string buffer while the amount we really want is generally pretty small 2305 // so make copies instead (one example b/11087956 wasted 400k of heap here). 2306 synchronized(mScanResultCache) { 2307 mScanResults = new ArrayList<ScanResult>(); 2308 String[] lines = scanResults.split("\n"); 2309 final int bssidStrLen = BSSID_STR.length(); 2310 final int flagLen = FLAGS_STR.length(); 2311 2312 for (String line : lines) { 2313 if (line.startsWith(BSSID_STR)) { 2314 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 2315 } else if (line.startsWith(FREQ_STR)) { 2316 try { 2317 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 2318 } catch (NumberFormatException e) { 2319 freq = 0; 2320 } 2321 } else if (line.startsWith(LEVEL_STR)) { 2322 try { 2323 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 2324 /* some implementations avoid negative values by adding 256 2325 * so we need to adjust for that here. 2326 */ 2327 if (level > 0) level -= 256; 2328 } catch(NumberFormatException e) { 2329 level = 0; 2330 } 2331 } else if (line.startsWith(TSF_STR)) { 2332 try { 2333 tsf = Long.parseLong(line.substring(TSF_STR.length())); 2334 } catch (NumberFormatException e) { 2335 tsf = 0; 2336 } 2337 } else if (line.startsWith(FLAGS_STR)) { 2338 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 2339 } else if (line.startsWith(SSID_STR)) { 2340 wifiSsid = WifiSsid.createFromAsciiEncoded( 2341 line.substring(SSID_STR.length())); 2342 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 2343 if (bssid != null) { 2344 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 2345 String key = bssid + ssid; 2346 ScanResult scanResult = mScanResultCache.get(key); 2347 if (scanResult != null) { 2348 scanResult.level = level; 2349 scanResult.wifiSsid = wifiSsid; 2350 // Keep existing API 2351 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 2352 WifiSsid.NONE; 2353 scanResult.capabilities = flags; 2354 scanResult.frequency = freq; 2355 scanResult.timestamp = tsf; 2356 scanResult.seen = System.currentTimeMillis(); 2357 } else { 2358 scanResult = 2359 new ScanResult( 2360 wifiSsid, bssid, flags, level, freq, tsf); 2361 mScanResultCache.put(key, scanResult); 2362 } 2363 mScanResults.add(scanResult); 2364 } 2365 bssid = null; 2366 level = 0; 2367 freq = 0; 2368 tsf = 0; 2369 flags = ""; 2370 wifiSsid = null; 2371 } 2372 } 2373 } 2374 if (mFrameworkAutoJoin.get() == true) 2375 mWifiAutoJoinController.newSupplicantResults(); 2376 2377 } 2378 2379 /* 2380 * Fetch RSSI, linkspeed, and frequency on current connection 2381 */ 2382 private void fetchRssiLinkSpeedAndFrequencyNative() { 2383 int newRssi = -1; 2384 int newLinkSpeed = -1; 2385 int newFrequency = -1; 2386 2387 String signalPoll = mWifiNative.signalPoll(); 2388 2389 if (signalPoll != null) { 2390 String[] lines = signalPoll.split("\n"); 2391 for (String line : lines) { 2392 String[] prop = line.split("="); 2393 if (prop.length < 2) continue; 2394 try { 2395 if (prop[0].equals("RSSI")) { 2396 newRssi = Integer.parseInt(prop[1]); 2397 } else if (prop[0].equals("LINKSPEED")) { 2398 newLinkSpeed = Integer.parseInt(prop[1]); 2399 } else if (prop[0].equals("FREQUENCY")) { 2400 newFrequency = Integer.parseInt(prop[1]); 2401 } 2402 } catch (NumberFormatException e) { 2403 //Ignore, defaults on rssi and linkspeed are assigned 2404 } 2405 } 2406 } 2407 2408 if (PDBG) { 2409 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 2410 + Integer.toString(newRssi) + " linkspeed=" 2411 + Integer.toString(newLinkSpeed)); 2412 } 2413 2414 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 2415 // screen out invalid values 2416 /* some implementations avoid negative values by adding 256 2417 * so we need to adjust for that here. 2418 */ 2419 if (newRssi > 0) newRssi -= 256; 2420 mWifiInfo.setRssi(newRssi); 2421 /* 2422 * Rather then sending the raw RSSI out every time it 2423 * changes, we precalculate the signal level that would 2424 * be displayed in the status bar, and only send the 2425 * broadcast if that much more coarse-grained number 2426 * changes. This cuts down greatly on the number of 2427 * broadcasts, at the cost of not informing others 2428 * interested in RSSI of all the changes in signal 2429 * level. 2430 */ 2431 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2432 if (newSignalLevel != mLastSignalLevel) { 2433 sendRssiChangeBroadcast(newRssi); 2434 } 2435 mLastSignalLevel = newSignalLevel; 2436 } else { 2437 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 2438 } 2439 2440 if (newLinkSpeed != -1) { 2441 mWifiInfo.setLinkSpeed(newLinkSpeed); 2442 } 2443 if (newFrequency > 0) { 2444 mWifiInfo.setFrequency(newFrequency); 2445 } 2446 } 2447 2448 /* determine if we need to switch network: 2449 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 2450 * - match the uregncy of the switch versus the packet usage at the interface 2451 */ 2452 boolean shouldSwitchNetwork(int networkDelta) { 2453 int delta; 2454 if (networkDelta <= 0) { 2455 return false; 2456 } 2457 delta = networkDelta; 2458 if (mWifiInfo != null) { 2459 //TODO: look at per AC packet count, do not switch if VO/VI traffic is present at the interface 2460 //TODO: discriminate between ucast and mcast, since the rxSuccessRate include all the bonjour and Ipv6 2461 //TODO: broadcasts 2462 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 2463 delta -= 999; 2464 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 2465 delta -= 6; 2466 } 2467 loge("WifiStateMachine shouldSwitchNetwork " 2468 + " txSuccessRate=" + String.format( "%.2f", mWifiInfo.txSuccessRate) 2469 + " rxSuccessRate=" +String.format( "%.2f", mWifiInfo.rxSuccessRate) 2470 + " delta " + networkDelta + " -> " + delta); 2471 } else { 2472 loge("WifiStateMachine shouldSwitchNetwork " 2473 + " delta " + networkDelta + " -> " + delta); 2474 } 2475 if (delta > 0) { 2476 return true; 2477 } 2478 return false; 2479 } 2480 2481 private void calculateWifiScore(WifiLinkLayerStats stats) { 2482 2483 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 2484 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 2485 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 2486 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 2487 2488 } else { 2489 mWifiInfo.updatePacketRates(stats); 2490 } 2491 int score = 56; //starting score, temporarily hardcoded in between 50 and 60 2492 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 2493 && mWifiInfo.getLinkSpeed() < 6) 2494 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() < 12); 2495 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 2496 && mWifiInfo.getLinkSpeed() >= 24) 2497 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() >= 48); 2498 2499 2500 //we want to make sure that we use the 24GHz RSSI thresholds is 2501 //there are 2.4GHz scan results 2502 //otherwise we end up lowering the score based on 5GHz values 2503 //which may cause a switch to LTE before roaming has a chance to try 2.4GHz 2504 //We also might unblacklist the configuation based on 2.4GHz 2505 //thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 2506 boolean use24Thresholds = false; 2507 boolean homeNetworkBoost = false; 2508 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 2509 if (currentConfiguration != null 2510 && currentConfiguration.scanResultCache != null) { 2511 currentConfiguration.setVisibility(12000); 2512 if (currentConfiguration.visibility != null) { 2513 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 2514 && currentConfiguration.visibility.rssi24 2515 >= (currentConfiguration.visibility.rssi5-2)) { 2516 use24Thresholds = true; 2517 } 2518 } 2519 if (currentConfiguration.scanResultCache.size() <= 4 2520 && currentConfiguration.allowedKeyManagement.cardinality() == 1 2521 && currentConfiguration.allowedKeyManagement. 2522 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 2523 //a PSK network with less than 4 known BSSIDs 2524 //This is most likely a home network and thus we want to stick to wifi more 2525 homeNetworkBoost = true; 2526 } 2527 } 2528 2529 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 2530 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 2531 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 2532 2533 boolean isBadRSSI = (is24GHz && rssi < WifiConfiguration.BAD_RSSI_24 ) 2534 || (!is24GHz && rssi < WifiConfiguration.BAD_RSSI_5); 2535 boolean isLowRSSI = (is24GHz && rssi < WifiConfiguration.LOW_RSSI_24) 2536 || (!is24GHz && mWifiInfo.getRssi() < WifiConfiguration.LOW_RSSI_5); 2537 boolean isHighRSSI = (is24GHz && rssi >= WifiConfiguration.GOOD_RSSI_24) 2538 || (!is24GHz && mWifiInfo.getRssi() >= WifiConfiguration.GOOD_RSSI_5); 2539 2540 if (PDBG) { 2541 String rssiStatus = ""; 2542 if (isBadRSSI) rssiStatus += " badRSSI "; 2543 else if (isHighRSSI) rssiStatus += " highRSSI "; 2544 else if (isLowRSSI) rssiStatus += " lowRSSI "; 2545 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 2546 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 2547 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 2548 + " score=" + Integer.toString(mWifiInfo.score) 2549 + rssiStatus 2550 + " -> txbadrate=" + String.format( "%.2f", mWifiInfo.txBadRate ) 2551 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 2552 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 2553 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 2554 ); 2555 } 2556 2557 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 2558 && (isBadRSSI || isLowRSSI)) { 2559 //link is stuck 2560 if (mWifiInfo.linkStuckCount < 5) 2561 mWifiInfo.linkStuckCount += 1; 2562 if (PDBG) loge(" bad link -> stuck count =" 2563 + Integer.toString(mWifiInfo.linkStuckCount)); 2564 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 2565 if (mWifiInfo.linkStuckCount > 0) 2566 mWifiInfo.linkStuckCount -= 1; 2567 if (PDBG) loge(" good link -> stuck count =" 2568 + Integer.toString(mWifiInfo.linkStuckCount)); 2569 2570 } 2571 2572 if (mWifiInfo.linkStuckCount > 1) { 2573 //once link gets stuck for more than 3 seconds, start reducing the score 2574 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 2575 } 2576 2577 if (isBadLinkspeed) { 2578 score -= 4; 2579 if (PDBG) loge(" isBadLinkspeed ---> score=" + Integer.toString(score)); 2580 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 2581 score += 4; //so as bad rssi alone dont kill us 2582 } 2583 2584 if (isBadRSSI) { 2585 if (mWifiInfo.badRssiCount < 7) 2586 mWifiInfo.badRssiCount += 1; 2587 } else if (isLowRSSI) { 2588 mWifiInfo.lowRssiCount = 1; //dont increment 2589 if (mWifiInfo.badRssiCount > 0) { 2590 mWifiInfo.badRssiCount -= 1; 2591 } 2592 } else { 2593 mWifiInfo.badRssiCount = 0; 2594 mWifiInfo.lowRssiCount = 0; 2595 } 2596 2597 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount ; 2598 2599 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 2600 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 2601 + " --> score " + Integer.toString(score)); 2602 2603 2604 if (isHighRSSI) { 2605 score += 5; 2606 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 2607 } 2608 2609 //sanitize boundaries 2610 if (score > NetworkAgent.WIFI_BASE_SCORE) 2611 score = NetworkAgent.WIFI_BASE_SCORE; 2612 if (score < 0) 2613 score = 0; 2614 2615 //report score 2616 if (score != mWifiInfo.score) { 2617 if (DBG) { 2618 loge("calculateWifiScore() report new score " + Integer.toString(score)); 2619 } 2620 mWifiInfo.score = score; 2621 mNetworkAgent.sendNetworkScore(score); 2622 } 2623 } 2624 2625 public double getTxPacketRate() { 2626 if (mWifiInfo != null) { 2627 return mWifiInfo.txSuccessRate; 2628 } 2629 return -1; 2630 } 2631 2632 public double getRxPacketRate() { 2633 if (mWifiInfo != null) { 2634 return mWifiInfo.rxSuccessRate; 2635 } 2636 return -1; 2637 } 2638 2639 /* 2640 * Fetch TX packet counters on current connection 2641 */ 2642 private void fetchPktcntNative(RssiPacketCountInfo info) { 2643 String pktcntPoll = mWifiNative.pktcntPoll(); 2644 2645 if (pktcntPoll != null) { 2646 String[] lines = pktcntPoll.split("\n"); 2647 for (String line : lines) { 2648 String[] prop = line.split("="); 2649 if (prop.length < 2) continue; 2650 try { 2651 if (prop[0].equals("TXGOOD")) { 2652 info.txgood = Integer.parseInt(prop[1]); 2653 } else if (prop[0].equals("TXBAD")) { 2654 info.txbad = Integer.parseInt(prop[1]); 2655 } 2656 } catch (NumberFormatException e) { 2657 //Ignore 2658 } 2659 } 2660 } 2661 } 2662 2663 /** 2664 * Updates mLinkProperties by merging information from various sources. 2665 * 2666 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 2667 * netlink, static configuration, ...). When one of these sources of information has updated 2668 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 2669 * information that came from other sources. Instead, when one of those sources has new 2670 * information, we update the object that tracks the information from that source and then 2671 * call this method to apply the change to mLinkProperties. 2672 * 2673 * The information in mLinkProperties is currently obtained as follows: 2674 * - Interface name: set in the constructor. 2675 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 2676 * - IPv4 routes, DNS servers, and domains: DHCP. 2677 * - IPv6 routes: netlink, passed in by mNetlinkTracker. 2678 * - HTTP proxy: the wifi config store. 2679 */ 2680 private void updateLinkProperties() { 2681 LinkProperties newLp = new LinkProperties(); 2682 2683 // Interface name and proxy are locally configured. 2684 newLp.setInterfaceName(mInterfaceName); 2685 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 2686 2687 // IPv4/v6 addresses and IPv6 routes come from netlink. 2688 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 2689 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 2690 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 2691 newLp.addRoute(route); 2692 } 2693 2694 // For now, DNS only comes from DHCP or static configuration. In the future, we'll need to 2695 // merge IPv6 DNS servers and domains coming from netlink. 2696 synchronized (mDhcpResultsLock) { 2697 // Even when we're using static configuration, we don't need to look at the config 2698 // store, because static IP configuration also populates mDhcpResults. 2699 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 2700 LinkProperties lp = mDhcpResults.linkProperties; 2701 for (RouteInfo route : lp.getRoutes()) { 2702 newLp.addRoute(route); 2703 } 2704 for (InetAddress dns : lp.getDnsServers()) { 2705 newLp.addDnsServer(dns); 2706 } 2707 newLp.setDomains(lp.getDomains()); 2708 } 2709 } 2710 2711 // If anything has changed, and we're already connected, send out a notification. 2712 // If we're still connecting, apps will be notified when we connect. 2713 if (!newLp.equals(mLinkProperties)) { 2714 if (DBG) { 2715 log("Link configuration changed for netId: " + mLastNetworkId 2716 + " old: " + mLinkProperties + "new: " + newLp); 2717 } 2718 mLinkProperties = newLp; 2719 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 2720 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 2721 sendLinkConfigurationChangedBroadcast(); 2722 } 2723 } 2724 } 2725 /** 2726 * Clears all our link properties. 2727 */ 2728 private void clearLinkProperties() { 2729 // If the network used DHCP, clear the LinkProperties we stored in the config store. 2730 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 2731 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 2732 } 2733 2734 // Clear the link properties obtained from DHCP and netlink. 2735 synchronized (mDhcpResultsLock) { 2736 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 2737 mDhcpResults.linkProperties.clear(); 2738 } 2739 } 2740 mNetlinkTracker.clearLinkProperties(); 2741 2742 // Now clear the merged link properties. 2743 mLinkProperties.clear(); 2744 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 2745 } 2746 2747 /** 2748 * try to update default route MAC address. 2749 */ 2750 private String updateDefaultRouteMacAddress(int timeout) { 2751 String address = null; 2752 for (RouteInfo route : mLinkProperties.getRoutes()) { 2753 if (route.isDefaultRoute() && route.hasGateway()) { 2754 InetAddress gateway = route.getGateway(); 2755 if (gateway instanceof Inet4Address) { 2756 if (PDBG) { 2757 loge("updateDefaultRouteMacAddress found Ipv4 default :" 2758 + gateway.getHostAddress()); 2759 } 2760 address = macAddressFromRoute(gateway.getHostAddress()); 2761 /* the gateway's MAC address is known */ 2762 if ((address == null) && (timeout > 0)) { 2763 boolean reachable = false; 2764 try { 2765 reachable = gateway.isReachable(timeout); 2766 } catch (Exception e) { 2767 loge("updateDefaultRouteMacAddress exception reaching :" 2768 + gateway.getHostAddress()); 2769 2770 } finally { 2771 if (reachable == true) { 2772 2773 address = macAddressFromRoute(gateway.getHostAddress()); 2774 if (PDBG) { 2775 loge("updateDefaultRouteMacAddress reachable (tried again) :" 2776 + gateway.getHostAddress() + " found " + address); 2777 } 2778 } 2779 } 2780 } 2781 if (address != null) { 2782 mWifiConfigStore.setLinkProperties(mLastNetworkId, 2783 new LinkProperties(mLinkProperties)); 2784 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 2785 2786 } 2787 } 2788 } 2789 } 2790 return address; 2791 } 2792 2793 private int getMaxDhcpRetries() { 2794 return Settings.Global.getInt(mContext.getContentResolver(), 2795 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 2796 DEFAULT_MAX_DHCP_RETRIES); 2797 } 2798 2799 private void sendScanResultsAvailableBroadcast() { 2800 noteScanEnd(); 2801 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 2802 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2803 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2804 } 2805 2806 private void sendRssiChangeBroadcast(final int newRssi) { 2807 try { 2808 mBatteryStats.noteWifiRssiChanged(newRssi); 2809 } catch (RemoteException e) { 2810 // Won't happen. 2811 } 2812 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 2813 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2814 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 2815 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2816 } 2817 2818 private void sendNetworkStateChangeBroadcast(String bssid) { 2819 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 2820 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2821 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2822 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 2823 if (bssid != null) 2824 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 2825 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 2826 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 2827 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 2828 } 2829 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2830 } 2831 2832 private void sendLinkConfigurationChangedBroadcast() { 2833 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 2834 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2835 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 2836 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2837 } 2838 2839 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 2840 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 2841 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2842 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 2843 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2844 } 2845 2846 /** 2847 * Record the detailed state of a network. 2848 * @param state the new {@code DetailedState} 2849 */ 2850 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 2851 if (DBG) { 2852 log("setDetailed state, old =" 2853 + mNetworkInfo.getDetailedState() + " and new state=" + state); 2854 } 2855 2856 if (state != mNetworkInfo.getDetailedState()) { 2857 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 2858 if (mNetworkAgent != null) { 2859 if (!isRoaming() || 2860 (state != DetailedState.DISCONNECTED && state != DetailedState.DISCONNECTING) ) { 2861 //don't tell the Network agent if we are doing a disconnect-roam 2862 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 2863 } 2864 } 2865 } 2866 } 2867 2868 private DetailedState getNetworkDetailedState() { 2869 return mNetworkInfo.getDetailedState(); 2870 } 2871 2872 2873 private SupplicantState handleSupplicantStateChange(Message message) { 2874 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2875 SupplicantState state = stateChangeResult.state; 2876 // Supplicant state change 2877 // [31-13] Reserved for future use 2878 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2879 // 50023 supplicant_state_changed (custom|1|5) 2880 mWifiInfo.setSupplicantState(state); 2881 // Network id is only valid when we start connecting 2882 if (SupplicantState.isConnecting(state)) { 2883 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2884 } else { 2885 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2886 } 2887 2888 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2889 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 2890 2891 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 2892 2893 return state; 2894 } 2895 2896 /** 2897 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 2898 * using the interface, stopping DHCP & disabling interface 2899 */ 2900 private void handleNetworkDisconnect() { 2901 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 2902 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2903 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2904 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2905 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2906 2907 stopDhcp(); 2908 2909 try { 2910 mNwService.clearInterfaceAddresses(mInterfaceName); 2911 mNwService.disableIpv6(mInterfaceName); 2912 } catch (Exception e) { 2913 loge("Failed to clear addresses or disable ipv6" + e); 2914 } 2915 2916 /* Reset data structures */ 2917 mWifiInfo.reset(); 2918 2919 setNetworkDetailedState(DetailedState.DISCONNECTED); 2920 if (mNetworkAgent != null) { 2921 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 2922 mNetworkAgent = null; 2923 } 2924 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 2925 2926 /* Clear network properties */ 2927 clearLinkProperties(); 2928 2929 /* send event to CM & network change broadcast */ 2930 sendNetworkStateChangeBroadcast(mLastBssid); 2931 2932 //cancel auto roam requests 2933 autoRoamSetBSSID(mLastNetworkId, "any"); 2934 2935 //reset roaming parameters 2936 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 2937 fullBandConnectedTimeIntervalMilli = 20 * 1000; //start at 20 seconds interval 2938 2939 mLastBssid= null; 2940 registerDisconnected(); 2941 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2942 } 2943 2944 private void handleSupplicantConnectionLoss() { 2945 /* Socket connection can be lost when we do a graceful shutdown 2946 * or when the driver is hung. Ensure supplicant is stopped here. 2947 */ 2948 mWifiMonitor.killSupplicant(mP2pSupported); 2949 mWifiNative.closeSupplicantConnection(); 2950 sendSupplicantConnectionChangedBroadcast(false); 2951 setWifiState(WIFI_STATE_DISABLED); 2952 } 2953 2954 void handlePreDhcpSetup() { 2955 mDhcpActive = true; 2956 if (!mBluetoothConnectionActive) { 2957 /* 2958 * There are problems setting the Wi-Fi driver's power 2959 * mode to active when bluetooth coexistence mode is 2960 * enabled or sense. 2961 * <p> 2962 * We set Wi-Fi to active mode when 2963 * obtaining an IP address because we've found 2964 * compatibility issues with some routers with low power 2965 * mode. 2966 * <p> 2967 * In order for this active power mode to properly be set, 2968 * we disable coexistence mode until we're done with 2969 * obtaining an IP address. One exception is if we 2970 * are currently connected to a headset, since disabling 2971 * coexistence would interrupt that connection. 2972 */ 2973 // Disable the coexistence mode 2974 mWifiNative.setBluetoothCoexistenceMode( 2975 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2976 } 2977 2978 /* Disable power save and suspend optimizations during DHCP */ 2979 // Note: The order here is important for now. Brcm driver changes 2980 // power settings when we control suspend mode optimizations. 2981 // TODO: Remove this comment when the driver is fixed. 2982 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 2983 mWifiNative.setPowerSave(false); 2984 2985 stopBatchedScan(); 2986 WifiNative.pauseScan(); 2987 2988 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 2989 Message msg = new Message(); 2990 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 2991 msg.arg1 = WifiP2pServiceImpl.ENABLED; 2992 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 2993 msg.obj = mDhcpStateMachine; 2994 mWifiP2pChannel.sendMessage(msg); 2995 } 2996 2997 2998 void startDhcp() { 2999 if (mDhcpStateMachine == null) { 3000 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3001 mContext, WifiStateMachine.this, mInterfaceName); 3002 3003 } 3004 mDhcpStateMachine.registerForPreDhcpNotification(); 3005 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 3006 } 3007 3008 void renewDhcp() { 3009 if (mDhcpStateMachine == null) { 3010 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3011 mContext, WifiStateMachine.this, mInterfaceName); 3012 3013 } 3014 mDhcpStateMachine.registerForPreDhcpNotification(); 3015 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 3016 } 3017 3018 void stopDhcp() { 3019 if (mDhcpStateMachine != null) { 3020 /* In case we were in middle of DHCP operation restore back powermode */ 3021 handlePostDhcpSetup(); 3022 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 3023 } 3024 } 3025 3026 void handlePostDhcpSetup() { 3027 /* Restore power save and suspend optimizations */ 3028 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 3029 mWifiNative.setPowerSave(true); 3030 3031 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 3032 3033 // Set the coexistence mode back to its default value 3034 mWifiNative.setBluetoothCoexistenceMode( 3035 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 3036 3037 mDhcpActive = false; 3038 3039 startBatchedScan(); 3040 WifiNative.restartScan(); 3041 } 3042 3043 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { 3044 3045 if (PDBG) { 3046 loge("handleSuccessfulIpConfiguration <" + dhcpResults.toString() 3047 + "> linkaddress num " + dhcpResults.linkProperties.getLinkAddresses().size()); 3048 for (LinkAddress linkAddress : dhcpResults.linkProperties.getLinkAddresses()) { 3049 loge("link address " + linkAddress.toString()); 3050 } 3051 } 3052 3053 mLastSignalLevel = -1; // force update of signal strength 3054 mReconnectCount = 0; //Reset IP failure tracking 3055 synchronized (mDhcpResultsLock) { 3056 mDhcpResults = dhcpResults; 3057 } 3058 LinkProperties linkProperties = dhcpResults.linkProperties; 3059 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 3060 InetAddress addr = null; 3061 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 3062 if (addrs.hasNext()) { 3063 addr = addrs.next(); 3064 } 3065 3066 if (isRoaming()) { 3067 if (addr instanceof Inet4Address) { 3068 int previousAddress = mWifiInfo.getIpAddress(); 3069 int newAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); 3070 if (previousAddress != newAddress) { 3071 loge("handleSuccessfulIpConfiguration, roaming and address changed" + 3072 mWifiInfo + " got: " + addr); 3073 } else { 3074 3075 } 3076 } else { 3077 loge("handleSuccessfulIpConfiguration, roaming and didnt get an IPv4 address" + 3078 addr.toString()); 3079 3080 3081 } 3082 } 3083 mWifiInfo.setInetAddress(addr); 3084 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 3085 updateLinkProperties(); 3086 } 3087 3088 private void handleFailedIpConfiguration() { 3089 3090 mWifiInfo.setInetAddress(null); 3091 mWifiInfo.setMeteredHint(false); 3092 /** 3093 * If we've exceeded the maximum number of retries for DHCP 3094 * to a given network, disable the network 3095 */ 3096 int maxRetries = getMaxDhcpRetries(); 3097 // maxRetries == 0 means keep trying forever 3098 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 3099 loge("Failed " + 3100 mReconnectCount + " times, Disabling " + mLastNetworkId); 3101 mWifiConfigStore.disableNetwork(mLastNetworkId, 3102 WifiConfiguration.DISABLED_DHCP_FAILURE); 3103 mReconnectCount = 0; 3104 } 3105 3106 /* DHCP times out after about 30 seconds, we do a 3107 * disconnect and an immediate reconnect to try again 3108 */ 3109 mWifiNative.disconnect(); 3110 mWifiNative.reconnect(); 3111 } 3112 3113 /* Current design is to not set the config on a running hostapd but instead 3114 * stop and start tethering when user changes config on a running access point 3115 * 3116 * TODO: Add control channel setup through hostapd that allows changing config 3117 * on a running daemon 3118 */ 3119 private void startSoftApWithConfig(final WifiConfiguration config) { 3120 // start hostapd on a seperate thread 3121 new Thread(new Runnable() { 3122 public void run() { 3123 try { 3124 mNwService.startAccessPoint(config, mInterfaceName); 3125 } catch (Exception e) { 3126 loge("Exception in softap start " + e); 3127 try { 3128 mNwService.stopAccessPoint(mInterfaceName); 3129 mNwService.startAccessPoint(config, mInterfaceName); 3130 } catch (Exception e1) { 3131 loge("Exception in softap re-start " + e1); 3132 sendMessage(CMD_START_AP_FAILURE); 3133 return; 3134 } 3135 } 3136 if (DBG) log("Soft AP start successful"); 3137 sendMessage(CMD_START_AP_SUCCESS); 3138 } 3139 }).start(); 3140 } 3141 3142 3143 /* 3144 * Read a MAC address in /proc/arp/table, used by WifistateMachine 3145 * so as to record MAC address of default gateway. 3146 **/ 3147 private String macAddressFromRoute(String ipAddress) { 3148 String macAddress = null; 3149 BufferedReader reader = null; 3150 try { 3151 reader = new BufferedReader(new FileReader("/proc/net/arp")); 3152 3153 // Skip over the line bearing colum titles 3154 String line = reader.readLine(); 3155 3156 while ((line = reader.readLine()) != null) { 3157 String[] tokens = line.split("[ ]+"); 3158 if (tokens.length < 6) { 3159 continue; 3160 } 3161 3162 // ARP column format is 3163 // Address HWType HWAddress Flags Mask IFace 3164 String ip = tokens[0]; 3165 String mac = tokens[3]; 3166 3167 if (ipAddress.equals(ip)) { 3168 macAddress = mac; 3169 break; 3170 } 3171 } 3172 3173 if (macAddress == null) { 3174 loge("Did not find remoteAddress {" + ipAddress + "} in " + 3175 "/proc/net/arp"); 3176 } 3177 3178 } catch (FileNotFoundException e) { 3179 loge("Could not open /proc/net/arp to lookup mac address"); 3180 } catch (IOException e) { 3181 loge("Could not read /proc/net/arp to lookup mac address"); 3182 } finally { 3183 try { 3184 if (reader != null) { 3185 reader.close(); 3186 } 3187 } catch (IOException e) { 3188 // Do nothing 3189 } 3190 } 3191 return macAddress; 3192 3193 } 3194 3195 private class WifiNetworkFactory extends NetworkFactory { 3196 public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { 3197 super(l, c, TAG, f); 3198 } 3199 protected void startNetwork() { 3200 // TODO 3201 // enter association mode. 3202 } 3203 protected void stopNetwork() { 3204 // TODO 3205 // stop associating. 3206 } 3207 } 3208 /******************************************************** 3209 * HSM states 3210 *******************************************************/ 3211 3212 class DefaultState extends State { 3213 @Override 3214 public boolean processMessage(Message message) { 3215 logStateAndMessage(message, getClass().getSimpleName()); 3216 3217 switch (message.what) { 3218 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 3219 AsyncChannel ac = (AsyncChannel) message.obj; 3220 if (ac == mWifiP2pChannel) { 3221 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 3222 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 3223 } else { 3224 loge("WifiP2pService connection failure, error=" + message.arg1); 3225 } 3226 } else { 3227 loge("got HALF_CONNECTED for unknown channel"); 3228 } 3229 break; 3230 } 3231 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 3232 AsyncChannel ac = (AsyncChannel) message.obj; 3233 if (ac == mWifiP2pChannel) { 3234 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 3235 //TODO: Re-establish connection to state machine after a delay 3236 //mWifiP2pChannel.connect(mContext, getHandler(), 3237 // mWifiP2pManager.getMessenger()); 3238 } 3239 break; 3240 } 3241 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3242 mBluetoothConnectionActive = (message.arg1 != 3243 BluetoothAdapter.STATE_DISCONNECTED); 3244 break; 3245 /* Synchronous call returns */ 3246 case CMD_PING_SUPPLICANT: 3247 case CMD_ENABLE_NETWORK: 3248 case CMD_ADD_OR_UPDATE_NETWORK: 3249 case CMD_REMOVE_NETWORK: 3250 case CMD_SAVE_CONFIG: 3251 replyToMessage(message, message.what, FAILURE); 3252 break; 3253 case CMD_GET_CAPABILITY_FREQ: 3254 replyToMessage(message, message.what, null); 3255 break; 3256 case CMD_GET_CONFIGURED_NETWORKS: 3257 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 3258 break; 3259 case CMD_ENABLE_RSSI_POLL: 3260 mEnableRssiPolling = (message.arg1 == 1); 3261 break; 3262 case CMD_ENABLE_BACKGROUND_SCAN: 3263 mEnableBackgroundScan = (message.arg1 == 1); 3264 break; 3265 case CMD_SET_HIGH_PERF_MODE: 3266 if (message.arg1 == 1) { 3267 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 3268 } else { 3269 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 3270 } 3271 break; 3272 case CMD_BOOT_COMPLETED: 3273 String countryCode = mPersistedCountryCode; 3274 if (TextUtils.isEmpty(countryCode) == false) { 3275 Settings.Global.putString(mContext.getContentResolver(), 3276 Settings.Global.WIFI_COUNTRY_CODE, 3277 countryCode); 3278 // it may be that the state transition that should send this info 3279 // to the driver happened between mPersistedCountryCode getting set 3280 // and now, so simply persisting it here would mean we have sent 3281 // nothing to the driver. Send the cmd so it might be set now. 3282 int sequenceNum = mCountryCodeSequence.incrementAndGet(); 3283 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, 3284 sequenceNum, 0, countryCode); 3285 } 3286 3287 checkAndSetConnectivityInstance(); 3288 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, 3289 NETWORKTYPE, mNetworkCapabilitiesFilter); 3290 mNetworkFactory.setScoreFilter(60); 3291 mCm.registerNetworkFactory(new Messenger(mNetworkFactory), NETWORKTYPE); 3292 break; 3293 case CMD_SET_BATCHED_SCAN: 3294 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 3295 break; 3296 case CMD_POLL_BATCHED_SCAN: 3297 handleBatchedScanPollRequest(); 3298 break; 3299 case CMD_START_NEXT_BATCHED_SCAN: 3300 startNextBatchedScan(); 3301 break; 3302 /* Discard */ 3303 case CMD_START_SCAN: 3304 case CMD_START_SUPPLICANT: 3305 case CMD_STOP_SUPPLICANT: 3306 case CMD_STOP_SUPPLICANT_FAILED: 3307 case CMD_START_DRIVER: 3308 case CMD_STOP_DRIVER: 3309 case CMD_DELAYED_STOP_DRIVER: 3310 case CMD_DRIVER_START_TIMED_OUT: 3311 case CMD_START_AP: 3312 case CMD_START_AP_SUCCESS: 3313 case CMD_START_AP_FAILURE: 3314 case CMD_STOP_AP: 3315 case CMD_TETHER_STATE_CHANGE: 3316 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3317 case CMD_DISCONNECT: 3318 case CMD_RECONNECT: 3319 case CMD_REASSOCIATE: 3320 case CMD_RELOAD_TLS_AND_RECONNECT: 3321 case WifiMonitor.SUP_CONNECTION_EVENT: 3322 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3323 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3324 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3325 case WifiMonitor.SCAN_RESULTS_EVENT: 3326 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3327 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3328 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3329 case WifiMonitor.WPS_OVERLAP_EVENT: 3330 case CMD_BLACKLIST_NETWORK: 3331 case CMD_CLEAR_BLACKLIST: 3332 case CMD_SET_OPERATIONAL_MODE: 3333 case CMD_SET_COUNTRY_CODE: 3334 case CMD_SET_FREQUENCY_BAND: 3335 case CMD_RSSI_POLL: 3336 case CMD_ENABLE_ALL_NETWORKS: 3337 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3338 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3339 /* Handled by WifiApConfigStore */ 3340 case CMD_SET_AP_CONFIG: 3341 case CMD_SET_AP_CONFIG_COMPLETED: 3342 case CMD_REQUEST_AP_CONFIG: 3343 case CMD_RESPONSE_AP_CONFIG: 3344 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3345 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3346 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3347 case CMD_DISABLE_P2P_RSP: 3348 break; 3349 case DhcpStateMachine.CMD_ON_QUIT: 3350 mDhcpStateMachine = null; 3351 break; 3352 case CMD_SET_SUSPEND_OPT_ENABLED: 3353 if (message.arg1 == 1) { 3354 mSuspendWakeLock.release(); 3355 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 3356 } else { 3357 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 3358 } 3359 break; 3360 case WifiMonitor.DRIVER_HUNG_EVENT: 3361 setSupplicantRunning(false); 3362 setSupplicantRunning(true); 3363 break; 3364 case WifiManager.CONNECT_NETWORK: 3365 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3366 WifiManager.BUSY); 3367 break; 3368 case WifiManager.FORGET_NETWORK: 3369 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3370 WifiManager.BUSY); 3371 break; 3372 case WifiManager.SAVE_NETWORK: 3373 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3374 WifiManager.BUSY); 3375 break; 3376 case WifiManager.START_WPS: 3377 replyToMessage(message, WifiManager.WPS_FAILED, 3378 WifiManager.BUSY); 3379 break; 3380 case WifiManager.CANCEL_WPS: 3381 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 3382 WifiManager.BUSY); 3383 break; 3384 case WifiManager.DISABLE_NETWORK: 3385 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3386 WifiManager.BUSY); 3387 break; 3388 case WifiManager.RSSI_PKTCNT_FETCH: 3389 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 3390 WifiManager.BUSY); 3391 break; 3392 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 3393 NetworkInfo info = (NetworkInfo) message.obj; 3394 mP2pConnected.set(info.isConnected()); 3395 break; 3396 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3397 mTemporarilyDisconnectWifi = (message.arg1 == 1); 3398 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 3399 break; 3400 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 3401 case CMD_NETLINK_UPDATE: 3402 updateLinkProperties(); 3403 break; 3404 default: 3405 loge("Error! unhandled message" + message); 3406 break; 3407 } 3408 return HANDLED; 3409 } 3410 } 3411 3412 class InitialState extends State { 3413 @Override 3414 public void enter() { 3415 mWifiNative.unloadDriver(); 3416 3417 if (mWifiP2pChannel == null) { 3418 mWifiP2pChannel = new AsyncChannel(); 3419 mWifiP2pChannel.connect(mContext, getHandler(), 3420 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 3421 } 3422 3423 if (mWifiApConfigChannel == null) { 3424 mWifiApConfigChannel = new AsyncChannel(); 3425 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 3426 mContext, getHandler()); 3427 wifiApConfigStore.loadApConfiguration(); 3428 mWifiApConfigChannel.connectSync(mContext, getHandler(), 3429 wifiApConfigStore.getMessenger()); 3430 } 3431 } 3432 @Override 3433 public boolean processMessage(Message message) { 3434 logStateAndMessage(message, getClass().getSimpleName()); 3435 switch (message.what) { 3436 case CMD_START_SUPPLICANT: 3437 if (mWifiNative.loadDriver()) { 3438 try { 3439 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 3440 } catch (Exception e) { 3441 loge("Failed to reload STA firmware " + e); 3442 // continue 3443 } 3444 3445 try { 3446 // A runtime crash can leave the interface up and 3447 // this affects connectivity when supplicant starts up. 3448 // Ensure interface is down before a supplicant start. 3449 mNwService.setInterfaceDown(mInterfaceName); 3450 // Set privacy extensions 3451 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 3452 3453 // IPv6 is enabled only as long as access point is connected since: 3454 // - IPv6 addresses and routes stick around after disconnection 3455 // - kernel is unaware when connected and fails to start IPv6 negotiation 3456 // - kernel can start autoconfiguration when 802.1x is not complete 3457 mNwService.disableIpv6(mInterfaceName); 3458 } catch (RemoteException re) { 3459 loge("Unable to change interface settings: " + re); 3460 } catch (IllegalStateException ie) { 3461 loge("Unable to change interface settings: " + ie); 3462 } 3463 3464 /* Stop a running supplicant after a runtime restart 3465 * Avoids issues with drivers that do not handle interface down 3466 * on a running supplicant properly. 3467 */ 3468 mWifiMonitor.killSupplicant(mP2pSupported); 3469 if(mWifiNative.startSupplicant(mP2pSupported)) { 3470 setWifiState(WIFI_STATE_ENABLING); 3471 if (DBG) log("Supplicant start successful"); 3472 mWifiMonitor.startMonitoring(); 3473 transitionTo(mSupplicantStartingState); 3474 } else { 3475 loge("Failed to start supplicant!"); 3476 } 3477 } else { 3478 loge("Failed to load driver"); 3479 } 3480 break; 3481 case CMD_START_AP: 3482 if (mWifiNative.loadDriver()) { 3483 setWifiApState(WIFI_AP_STATE_ENABLING); 3484 transitionTo(mSoftApStartingState); 3485 } else { 3486 loge("Failed to load driver for softap"); 3487 } 3488 default: 3489 return NOT_HANDLED; 3490 } 3491 return HANDLED; 3492 } 3493 } 3494 3495 class SupplicantStartingState extends State { 3496 private void initializeWpsDetails() { 3497 String detail; 3498 detail = SystemProperties.get("ro.product.name", ""); 3499 if (!mWifiNative.setDeviceName(detail)) { 3500 loge("Failed to set device name " + detail); 3501 } 3502 detail = SystemProperties.get("ro.product.manufacturer", ""); 3503 if (!mWifiNative.setManufacturer(detail)) { 3504 loge("Failed to set manufacturer " + detail); 3505 } 3506 detail = SystemProperties.get("ro.product.model", ""); 3507 if (!mWifiNative.setModelName(detail)) { 3508 loge("Failed to set model name " + detail); 3509 } 3510 detail = SystemProperties.get("ro.product.model", ""); 3511 if (!mWifiNative.setModelNumber(detail)) { 3512 loge("Failed to set model number " + detail); 3513 } 3514 detail = SystemProperties.get("ro.serialno", ""); 3515 if (!mWifiNative.setSerialNumber(detail)) { 3516 loge("Failed to set serial number " + detail); 3517 } 3518 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 3519 loge("Failed to set WPS config methods"); 3520 } 3521 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 3522 loge("Failed to set primary device type " + mPrimaryDeviceType); 3523 } 3524 } 3525 3526 @Override 3527 public boolean processMessage(Message message) { 3528 logStateAndMessage(message, getClass().getSimpleName()); 3529 3530 switch(message.what) { 3531 case WifiMonitor.SUP_CONNECTION_EVENT: 3532 if (DBG) log("Supplicant connection established"); 3533 setWifiState(WIFI_STATE_ENABLED); 3534 mSupplicantRestartCount = 0; 3535 /* Reset the supplicant state to indicate the supplicant 3536 * state is not known at this time */ 3537 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3538 /* Initialize data structures */ 3539 mLastBssid = null; 3540 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 3541 mLastSignalLevel = -1; 3542 3543 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 3544 mWifiNative.enableSaveConfig(); 3545 mWifiConfigStore.loadAndEnableAllNetworks(); 3546 initializeWpsDetails(); 3547 3548 sendSupplicantConnectionChangedBroadcast(true); 3549 transitionTo(mDriverStartedState); 3550 break; 3551 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3552 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 3553 loge("Failed to setup control channel, restart supplicant"); 3554 mWifiMonitor.killSupplicant(mP2pSupported); 3555 transitionTo(mInitialState); 3556 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 3557 } else { 3558 loge("Failed " + mSupplicantRestartCount + 3559 " times to start supplicant, unload driver"); 3560 mSupplicantRestartCount = 0; 3561 setWifiState(WIFI_STATE_UNKNOWN); 3562 transitionTo(mInitialState); 3563 } 3564 break; 3565 case CMD_START_SUPPLICANT: 3566 case CMD_STOP_SUPPLICANT: 3567 case CMD_START_AP: 3568 case CMD_STOP_AP: 3569 case CMD_START_DRIVER: 3570 case CMD_STOP_DRIVER: 3571 case CMD_SET_OPERATIONAL_MODE: 3572 case CMD_SET_COUNTRY_CODE: 3573 case CMD_SET_FREQUENCY_BAND: 3574 case CMD_START_PACKET_FILTERING: 3575 case CMD_STOP_PACKET_FILTERING: 3576 deferMessage(message); 3577 break; 3578 default: 3579 return NOT_HANDLED; 3580 } 3581 return HANDLED; 3582 } 3583 } 3584 3585 class SupplicantStartedState extends State { 3586 @Override 3587 public void enter() { 3588 /* Wifi is available as long as we have a connection to supplicant */ 3589 mNetworkInfo.setIsAvailable(true); 3590 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3591 3592 int defaultInterval = mContext.getResources().getInteger( 3593 R.integer.config_wifi_supplicant_scan_interval); 3594 3595 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 3596 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 3597 defaultInterval); 3598 3599 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 3600 3601 if (mFrameworkAutoJoin.get()) { 3602 mWifiNative.enableAutoConnect(false); 3603 } 3604 3605 } 3606 @Override 3607 public boolean processMessage(Message message) { 3608 logStateAndMessage(message, getClass().getSimpleName()); 3609 3610 switch(message.what) { 3611 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 3612 if (mP2pSupported) { 3613 transitionTo(mWaitForP2pDisableState); 3614 } else { 3615 transitionTo(mSupplicantStoppingState); 3616 } 3617 break; 3618 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 3619 loge("Connection lost, restart supplicant"); 3620 handleSupplicantConnectionLoss(); 3621 handleNetworkDisconnect(); 3622 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3623 if (mP2pSupported) { 3624 transitionTo(mWaitForP2pDisableState); 3625 } else { 3626 transitionTo(mInitialState); 3627 } 3628 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 3629 break; 3630 case WifiMonitor.SCAN_RESULTS_EVENT: 3631 setScanResults(); 3632 sendScanResultsAvailableBroadcast(); 3633 mIsScanOngoing = false; 3634 mIsFullScanOngoing = false; 3635 if (mBufferedScanMsg.size() > 0) 3636 sendMessage(mBufferedScanMsg.remove()); 3637 break; 3638 case CMD_PING_SUPPLICANT: 3639 boolean ok = mWifiNative.ping(); 3640 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3641 break; 3642 case CMD_GET_CAPABILITY_FREQ: 3643 String freqs = mWifiNative.getFreqCapability(); 3644 replyToMessage(message, message.what, freqs); 3645 break; 3646 case CMD_START_AP: 3647 /* Cannot start soft AP while in client mode */ 3648 loge("Failed to start soft AP with a running supplicant"); 3649 setWifiApState(WIFI_AP_STATE_FAILED); 3650 break; 3651 case CMD_SET_OPERATIONAL_MODE: 3652 mOperationalMode = message.arg1; 3653 break; 3654 default: 3655 return NOT_HANDLED; 3656 } 3657 return HANDLED; 3658 } 3659 3660 @Override 3661 public void exit() { 3662 mNetworkInfo.setIsAvailable(false); 3663 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3664 } 3665 } 3666 3667 class SupplicantStoppingState extends State { 3668 @Override 3669 public void enter() { 3670 /* Send any reset commands to supplicant before shutting it down */ 3671 handleNetworkDisconnect(); 3672 if (mDhcpStateMachine != null) { 3673 mDhcpStateMachine.doQuit(); 3674 } 3675 3676 if (DBG) log("stopping supplicant"); 3677 mWifiMonitor.stopSupplicant(); 3678 3679 /* Send ourselves a delayed message to indicate failure after a wait time */ 3680 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 3681 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 3682 setWifiState(WIFI_STATE_DISABLING); 3683 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3684 } 3685 @Override 3686 public boolean processMessage(Message message) { 3687 logStateAndMessage(message, getClass().getSimpleName()); 3688 3689 switch(message.what) { 3690 case WifiMonitor.SUP_CONNECTION_EVENT: 3691 loge("Supplicant connection received while stopping"); 3692 break; 3693 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3694 if (DBG) log("Supplicant connection lost"); 3695 handleSupplicantConnectionLoss(); 3696 transitionTo(mInitialState); 3697 break; 3698 case CMD_STOP_SUPPLICANT_FAILED: 3699 if (message.arg1 == mSupplicantStopFailureToken) { 3700 loge("Timed out on a supplicant stop, kill and proceed"); 3701 handleSupplicantConnectionLoss(); 3702 transitionTo(mInitialState); 3703 } 3704 break; 3705 case CMD_START_SUPPLICANT: 3706 case CMD_STOP_SUPPLICANT: 3707 case CMD_START_AP: 3708 case CMD_STOP_AP: 3709 case CMD_START_DRIVER: 3710 case CMD_STOP_DRIVER: 3711 case CMD_SET_OPERATIONAL_MODE: 3712 case CMD_SET_COUNTRY_CODE: 3713 case CMD_SET_FREQUENCY_BAND: 3714 case CMD_START_PACKET_FILTERING: 3715 case CMD_STOP_PACKET_FILTERING: 3716 deferMessage(message); 3717 break; 3718 default: 3719 return NOT_HANDLED; 3720 } 3721 return HANDLED; 3722 } 3723 } 3724 3725 class DriverStartingState extends State { 3726 private int mTries; 3727 @Override 3728 public void enter() { 3729 mTries = 1; 3730 /* Send ourselves a delayed message to start driver a second time */ 3731 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 3732 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 3733 } 3734 @Override 3735 public boolean processMessage(Message message) { 3736 logStateAndMessage(message, getClass().getSimpleName()); 3737 3738 switch(message.what) { 3739 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3740 SupplicantState state = handleSupplicantStateChange(message); 3741 /* If suplicant is exiting out of INTERFACE_DISABLED state into 3742 * a state that indicates driver has started, it is ready to 3743 * receive driver commands 3744 */ 3745 if (SupplicantState.isDriverActive(state)) { 3746 transitionTo(mDriverStartedState); 3747 } 3748 break; 3749 case CMD_DRIVER_START_TIMED_OUT: 3750 if (message.arg1 == mDriverStartToken) { 3751 if (mTries >= 2) { 3752 loge("Failed to start driver after " + mTries); 3753 transitionTo(mDriverStoppedState); 3754 } else { 3755 loge("Driver start failed, retrying"); 3756 mWakeLock.acquire(); 3757 mWifiNative.startDriver(); 3758 mWakeLock.release(); 3759 3760 ++mTries; 3761 /* Send ourselves a delayed message to start driver again */ 3762 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 3763 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 3764 } 3765 } 3766 break; 3767 /* Queue driver commands & connection events */ 3768 case CMD_START_DRIVER: 3769 case CMD_STOP_DRIVER: 3770 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3771 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3772 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3773 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3774 case WifiMonitor.WPS_OVERLAP_EVENT: 3775 case CMD_SET_COUNTRY_CODE: 3776 case CMD_SET_FREQUENCY_BAND: 3777 case CMD_START_PACKET_FILTERING: 3778 case CMD_STOP_PACKET_FILTERING: 3779 case CMD_START_SCAN: 3780 case CMD_DISCONNECT: 3781 case CMD_REASSOCIATE: 3782 case CMD_RECONNECT: 3783 deferMessage(message); 3784 break; 3785 default: 3786 return NOT_HANDLED; 3787 } 3788 return HANDLED; 3789 } 3790 } 3791 3792 class DriverStartedState extends State { 3793 @Override 3794 public void enter() { 3795 3796 if (PDBG) { 3797 loge("Driverstarted State enter"); 3798 } 3799 mIsRunning = true; 3800 mInDelayedStop = false; 3801 mDelayedStopCounter++; 3802 updateBatteryWorkSource(null); 3803 /** 3804 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 3805 * When this mode is on, some of the low-level scan parameters used by the 3806 * driver are changed to reduce interference with bluetooth 3807 */ 3808 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3809 /* set country code */ 3810 setCountryCode(); 3811 /* set frequency band of operation */ 3812 setFrequencyBand(); 3813 /* initialize network state */ 3814 setNetworkDetailedState(DetailedState.DISCONNECTED); 3815 3816 /* Remove any filtering on Multicast v6 at start */ 3817 mWifiNative.stopFilteringMulticastV6Packets(); 3818 3819 /* Reset Multicast v4 filtering state */ 3820 if (mFilteringMulticastV4Packets.get()) { 3821 mWifiNative.startFilteringMulticastV4Packets(); 3822 } else { 3823 mWifiNative.stopFilteringMulticastV4Packets(); 3824 } 3825 3826 mDhcpActive = false; 3827 3828 startBatchedScan(); 3829 3830 if (mOperationalMode != CONNECT_MODE) { 3831 mWifiNative.disconnect(); 3832 mWifiConfigStore.disableAllNetworks(); 3833 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3834 setWifiState(WIFI_STATE_DISABLED); 3835 } 3836 transitionTo(mScanModeState); 3837 } else { 3838 /* Driver stop may have disabled networks, enable right after start */ 3839 mWifiConfigStore.enableAllNetworks(); 3840 3841 if (DBG) loge("Attempting to reconnect to wifi network .."); 3842 mWifiNative.reconnect(); 3843 3844 // Status pulls in the current supplicant state and network connection state 3845 // events over the monitor connection. This helps framework sync up with 3846 // current supplicant state 3847 mWifiNative.status(); 3848 transitionTo(mDisconnectedState); 3849 } 3850 3851 // We may have missed screen update at boot 3852 if (mScreenBroadcastReceived.get() == false) { 3853 PowerManager powerManager = (PowerManager)mContext.getSystemService( 3854 Context.POWER_SERVICE); 3855 handleScreenStateChanged(powerManager.isScreenOn()); 3856 } else { 3857 // Set the right suspend mode settings 3858 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 3859 && mUserWantsSuspendOpt.get()); 3860 } 3861 mWifiNative.setPowerSave(true); 3862 3863 if (mP2pSupported) { 3864 if (mOperationalMode == CONNECT_MODE) { 3865 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 3866 } else { 3867 // P2P statemachine starts in disabled state, and is not enabled until 3868 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 3869 // keep it disabled. 3870 } 3871 } 3872 3873 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3874 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3875 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 3876 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3877 3878 if (PDBG) { 3879 loge("Driverstarted State enter done"); 3880 } 3881 } 3882 3883 @Override 3884 public boolean processMessage(Message message) { 3885 logStateAndMessage(message, getClass().getSimpleName()); 3886 3887 switch(message.what) { 3888 case CMD_START_SCAN: 3889 if (mFrameworkAutoJoin.get()) { 3890 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 3891 } else { 3892 handleScanRequest(WifiNative.SCAN_WITH_CONNECTION_SETUP, message); 3893 } 3894 break; 3895 case CMD_SET_BATCHED_SCAN: 3896 if (recordBatchedScanSettings(message.arg1, message.arg2, 3897 (Bundle)message.obj)) { 3898 if (mBatchedScanSettings != null) { 3899 startBatchedScan(); 3900 } else { 3901 stopBatchedScan(); 3902 } 3903 } 3904 break; 3905 case CMD_SET_COUNTRY_CODE: 3906 String country = (String) message.obj; 3907 final boolean persist = (message.arg2 == 1); 3908 final int sequence = message.arg1; 3909 if (sequence != mCountryCodeSequence.get()) { 3910 if (DBG) log("set country code ignored due to sequnce num"); 3911 break; 3912 } 3913 if (DBG) log("set country code " + country); 3914 if (persist) { 3915 mPersistedCountryCode = country; 3916 Settings.Global.putString(mContext.getContentResolver(), 3917 Settings.Global.WIFI_COUNTRY_CODE, 3918 country); 3919 } 3920 country = country.toUpperCase(Locale.ROOT); 3921 if (mLastSetCountryCode == null 3922 || country.equals(mLastSetCountryCode) == false) { 3923 if (mWifiNative.setCountryCode(country)) { 3924 mLastSetCountryCode = country; 3925 } else { 3926 loge("Failed to set country code " + country); 3927 } 3928 } 3929 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 3930 break; 3931 case CMD_SET_FREQUENCY_BAND: 3932 int band = message.arg1; 3933 if (DBG) log("set frequency band " + band); 3934 if (mWifiNative.setBand(band)) { 3935 3936 if (PDBG) loge("did set frequency band " + band); 3937 3938 mFrequencyBand.set(band); 3939 // flush old data - like scan results 3940 mWifiNative.bssFlush(); 3941 // fetch the latest scan results when frequency band is set 3942 if (mFrameworkAutoJoin.get()) 3943 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 3944 else 3945 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP, null); 3946 if (PDBG) loge("done set frequency band " + band); 3947 3948 } else { 3949 loge("Failed to set frequency band " + band); 3950 } 3951 break; 3952 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3953 mBluetoothConnectionActive = (message.arg1 != 3954 BluetoothAdapter.STATE_DISCONNECTED); 3955 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3956 break; 3957 case CMD_STOP_DRIVER: 3958 int mode = message.arg1; 3959 3960 /* Already doing a delayed stop */ 3961 if (mInDelayedStop) { 3962 if (DBG) log("Already in delayed stop"); 3963 break; 3964 } 3965 /* disconnect right now, but leave the driver running for a bit */ 3966 mWifiConfigStore.disableAllNetworks(); 3967 3968 mInDelayedStop = true; 3969 mDelayedStopCounter++; 3970 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 3971 3972 /* send regular delayed shut down */ 3973 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 3974 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 3975 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 3976 DRIVER_STOP_REQUEST, driverStopIntent, 3977 PendingIntent.FLAG_UPDATE_CURRENT); 3978 3979 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 3980 + mDriverStopDelayMs, mDriverStopIntent); 3981 break; 3982 case CMD_START_DRIVER: 3983 if (mInDelayedStop) { 3984 mInDelayedStop = false; 3985 mDelayedStopCounter++; 3986 mAlarmManager.cancel(mDriverStopIntent); 3987 if (DBG) log("Delayed stop ignored due to start"); 3988 if (mOperationalMode == CONNECT_MODE) { 3989 mWifiConfigStore.enableAllNetworks(); 3990 } 3991 } 3992 break; 3993 case CMD_DELAYED_STOP_DRIVER: 3994 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 3995 if (message.arg1 != mDelayedStopCounter) break; 3996 if (getCurrentState() != mDisconnectedState) { 3997 mWifiNative.disconnect(); 3998 handleNetworkDisconnect(); 3999 } 4000 mWakeLock.acquire(); 4001 mWifiNative.stopDriver(); 4002 mWakeLock.release(); 4003 if (mP2pSupported) { 4004 transitionTo(mWaitForP2pDisableState); 4005 } else { 4006 transitionTo(mDriverStoppingState); 4007 } 4008 break; 4009 case CMD_START_PACKET_FILTERING: 4010 if (message.arg1 == MULTICAST_V6) { 4011 mWifiNative.startFilteringMulticastV6Packets(); 4012 } else if (message.arg1 == MULTICAST_V4) { 4013 mWifiNative.startFilteringMulticastV4Packets(); 4014 } else { 4015 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 4016 } 4017 break; 4018 case CMD_STOP_PACKET_FILTERING: 4019 if (message.arg1 == MULTICAST_V6) { 4020 mWifiNative.stopFilteringMulticastV6Packets(); 4021 } else if (message.arg1 == MULTICAST_V4) { 4022 mWifiNative.stopFilteringMulticastV4Packets(); 4023 } else { 4024 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 4025 } 4026 break; 4027 case CMD_SET_SUSPEND_OPT_ENABLED: 4028 if (message.arg1 == 1) { 4029 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 4030 mSuspendWakeLock.release(); 4031 } else { 4032 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 4033 } 4034 break; 4035 case CMD_SET_HIGH_PERF_MODE: 4036 if (message.arg1 == 1) { 4037 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 4038 } else { 4039 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 4040 } 4041 break; 4042 case CMD_ENABLE_TDLS: 4043 if (message.obj != null) { 4044 String remoteAddress = (String) message.obj; 4045 boolean enable = (message.arg1 == 1); 4046 mWifiNative.startTdls(remoteAddress, enable); 4047 } 4048 break; 4049 default: 4050 return NOT_HANDLED; 4051 } 4052 return HANDLED; 4053 } 4054 @Override 4055 public void exit() { 4056 mIsRunning = false; 4057 updateBatteryWorkSource(null); 4058 mScanResults = new ArrayList<ScanResult>(); 4059 4060 stopBatchedScan(); 4061 4062 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 4063 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4064 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 4065 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4066 noteScanEnd(); // wrap up any pending request. 4067 mBufferedScanMsg.clear(); 4068 4069 mLastSetCountryCode = null; 4070 } 4071 } 4072 4073 class WaitForP2pDisableState extends State { 4074 private State mTransitionToState; 4075 @Override 4076 public void enter() { 4077 switch (getCurrentMessage().what) { 4078 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4079 mTransitionToState = mInitialState; 4080 break; 4081 case CMD_DELAYED_STOP_DRIVER: 4082 mTransitionToState = mDriverStoppingState; 4083 break; 4084 case CMD_STOP_SUPPLICANT: 4085 mTransitionToState = mSupplicantStoppingState; 4086 break; 4087 default: 4088 mTransitionToState = mDriverStoppingState; 4089 break; 4090 } 4091 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 4092 } 4093 @Override 4094 public boolean processMessage(Message message) { 4095 logStateAndMessage(message, getClass().getSimpleName()); 4096 4097 switch(message.what) { 4098 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 4099 transitionTo(mTransitionToState); 4100 break; 4101 /* Defer wifi start/shut and driver commands */ 4102 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4103 case CMD_START_SUPPLICANT: 4104 case CMD_STOP_SUPPLICANT: 4105 case CMD_START_AP: 4106 case CMD_STOP_AP: 4107 case CMD_START_DRIVER: 4108 case CMD_STOP_DRIVER: 4109 case CMD_SET_OPERATIONAL_MODE: 4110 case CMD_SET_COUNTRY_CODE: 4111 case CMD_SET_FREQUENCY_BAND: 4112 case CMD_START_PACKET_FILTERING: 4113 case CMD_STOP_PACKET_FILTERING: 4114 case CMD_START_SCAN: 4115 case CMD_DISCONNECT: 4116 case CMD_REASSOCIATE: 4117 case CMD_RECONNECT: 4118 deferMessage(message); 4119 break; 4120 default: 4121 return NOT_HANDLED; 4122 } 4123 return HANDLED; 4124 } 4125 } 4126 4127 class DriverStoppingState extends State { 4128 @Override 4129 public boolean processMessage(Message message) { 4130 logStateAndMessage(message, getClass().getSimpleName()); 4131 4132 switch(message.what) { 4133 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4134 SupplicantState state = handleSupplicantStateChange(message); 4135 if (state == SupplicantState.INTERFACE_DISABLED) { 4136 transitionTo(mDriverStoppedState); 4137 } 4138 break; 4139 /* Queue driver commands */ 4140 case CMD_START_DRIVER: 4141 case CMD_STOP_DRIVER: 4142 case CMD_SET_COUNTRY_CODE: 4143 case CMD_SET_FREQUENCY_BAND: 4144 case CMD_START_PACKET_FILTERING: 4145 case CMD_STOP_PACKET_FILTERING: 4146 case CMD_START_SCAN: 4147 case CMD_DISCONNECT: 4148 case CMD_REASSOCIATE: 4149 case CMD_RECONNECT: 4150 deferMessage(message); 4151 break; 4152 default: 4153 return NOT_HANDLED; 4154 } 4155 return HANDLED; 4156 } 4157 } 4158 4159 class DriverStoppedState extends State { 4160 @Override 4161 public boolean processMessage(Message message) { 4162 logStateAndMessage(message, getClass().getSimpleName()); 4163 switch (message.what) { 4164 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4165 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4166 SupplicantState state = stateChangeResult.state; 4167 // A WEXT bug means that we can be back to driver started state 4168 // unexpectedly 4169 if (SupplicantState.isDriverActive(state)) { 4170 transitionTo(mDriverStartedState); 4171 } 4172 break; 4173 case CMD_START_DRIVER: 4174 mWakeLock.acquire(); 4175 mWifiNative.startDriver(); 4176 mWakeLock.release(); 4177 transitionTo(mDriverStartingState); 4178 break; 4179 default: 4180 return NOT_HANDLED; 4181 } 4182 return HANDLED; 4183 } 4184 } 4185 4186 class ScanModeState extends State { 4187 private int mLastOperationMode; 4188 @Override 4189 public void enter() { 4190 mLastOperationMode = mOperationalMode; 4191 } 4192 @Override 4193 public boolean processMessage(Message message) { 4194 logStateAndMessage(message, getClass().getSimpleName()); 4195 4196 switch(message.what) { 4197 case CMD_SET_OPERATIONAL_MODE: 4198 if (message.arg1 == CONNECT_MODE) { 4199 4200 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4201 setWifiState(WIFI_STATE_ENABLED); 4202 // Load and re-enable networks when going back to enabled state 4203 // This is essential for networks to show up after restore 4204 mWifiConfigStore.loadAndEnableAllNetworks(); 4205 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 4206 } else { 4207 mWifiConfigStore.enableAllNetworks(); 4208 } 4209 4210 mWifiNative.reconnect(); 4211 4212 mOperationalMode = CONNECT_MODE; 4213 transitionTo(mDisconnectedState); 4214 } else { 4215 // Nothing to do 4216 return HANDLED; 4217 } 4218 break; 4219 // Handle scan. All the connection related commands are 4220 // handled only in ConnectModeState 4221 case CMD_START_SCAN: 4222 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 4223 break; 4224 default: 4225 return NOT_HANDLED; 4226 } 4227 return HANDLED; 4228 } 4229 } 4230 4231 4232 String smToString(Message message) { 4233 String s = "unknown"; 4234 switch(message.what) { 4235 4236 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 4237 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED"; 4238 break; 4239 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 4240 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED"; 4241 break; 4242 case CMD_SET_FREQUENCY_BAND: 4243 s = "CMD_SET_FREQUENCY_BAND"; 4244 break; 4245 case CMD_START_DRIVER: 4246 s = "CMD_START_DRIVER"; 4247 break; 4248 case CMD_STOP_DRIVER: 4249 s = "CMD_STOP_DRIVER"; 4250 break; 4251 case CMD_STOP_SUPPLICANT: 4252 s = "CMD_STOP_SUPPLICANT"; 4253 break; 4254 case CMD_START_SUPPLICANT: 4255 s = "CMD_START_SUPPLICANT"; 4256 break; 4257 case CMD_REQUEST_AP_CONFIG: 4258 s = "CMD_REQUEST_AP_CONFIG"; 4259 break; 4260 case CMD_RESPONSE_AP_CONFIG: 4261 s = "CMD_RESPONSE_AP_CONFIG"; 4262 break; 4263 case CMD_TETHER_STATE_CHANGE: 4264 s = "CMD_TETHER_STATE_CHANGE"; 4265 break; 4266 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4267 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT"; 4268 break; 4269 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 4270 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE"; 4271 break; 4272 case CMD_ADD_OR_UPDATE_NETWORK: 4273 s= "CMD_ADD_OR_UPDATE_NETWORK"; 4274 break; 4275 case CMD_REMOVE_NETWORK: 4276 s= "CMD_REMOVE_NETWORK"; 4277 break; 4278 case CMD_ENABLE_NETWORK: 4279 s= "CMD_ENABLE_NETWORK"; 4280 break; 4281 case CMD_ENABLE_ALL_NETWORKS: 4282 s= "CMD_ENABLE_ALL_NETWORKS"; 4283 break; 4284 case CMD_AUTO_CONNECT: 4285 s = "CMD_AUTO_CONNECT"; 4286 break; 4287 case CMD_AUTO_ROAM: 4288 s = "CMD_AUTO_ROAM"; 4289 break; 4290 case CMD_BOOT_COMPLETED: 4291 s = "CMD_BOOT_COMPLETED"; 4292 break; 4293 case DhcpStateMachine.CMD_START_DHCP: 4294 s = "DhcpStateMachine.CMD_START_DHCP"; 4295 break; 4296 case DhcpStateMachine.CMD_STOP_DHCP: 4297 s = "DhcpStateMachine.CMD_STOP_DHCP"; 4298 break; 4299 case DhcpStateMachine.CMD_RENEW_DHCP: 4300 s = "DhcpStateMachine.CMD_RENEW_DHCP"; 4301 break; 4302 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 4303 s = "DhcpStateMachine.CMD_PRE_DHCP_ACTION"; 4304 break; 4305 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 4306 s = "DhcpStateMachine.CMD_POST_DHCP_ACTION"; 4307 break; 4308 case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE: 4309 s = "DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE"; 4310 break; 4311 case DhcpStateMachine.CMD_ON_QUIT: 4312 s = "DhcpStateMachine.CMD_ON_QUIT"; 4313 break; 4314 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4315 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST"; 4316 break; 4317 case WifiManager.DISABLE_NETWORK: 4318 s="WifiManager.DISABLE_NETWORK"; 4319 break; 4320 case CMD_BLACKLIST_NETWORK: 4321 s="CMD_BLACKLIST_NETWORK"; 4322 break; 4323 case CMD_CLEAR_BLACKLIST: 4324 s="CMD_CLEAR_BLACKLIST"; 4325 break; 4326 case CMD_SAVE_CONFIG: 4327 s="CMD_SAVE_CONFIG"; 4328 break; 4329 case CMD_GET_CONFIGURED_NETWORKS: 4330 s="CMD_GET_CONFIGURED_NETWORKS"; 4331 break; 4332 case CMD_DISCONNECT: 4333 s="CMD_DISCONNECT"; 4334 break; 4335 case CMD_RECONNECT: 4336 s= "CMD_RECONNECT"; 4337 break; 4338 case CMD_REASSOCIATE: 4339 s= "CMD_REASSOCIATE"; 4340 break; 4341 case CMD_SET_HIGH_PERF_MODE: 4342 s="CMD_SET_HIGH_PERF_MODE"; 4343 break; 4344 case CMD_SET_COUNTRY_CODE: 4345 s="CMD_SET_COUNTRY_CODE"; 4346 break; 4347 case CMD_ENABLE_RSSI_POLL: 4348 s="CMD_ENABLE_RSSI_POLL"; 4349 break; 4350 case CMD_RSSI_POLL: 4351 s="CMD_RSSI_POLL"; 4352 break; 4353 case CMD_START_PACKET_FILTERING: 4354 s="CMD_START_PACKET_FILTERING"; 4355 break; 4356 case CMD_STOP_PACKET_FILTERING: 4357 s="CMD_STOP_PACKET_FILTERING"; 4358 break; 4359 case CMD_SET_SUSPEND_OPT_ENABLED: 4360 s="CMD_SET_SUSPEND_OPT_ENABLED"; 4361 break; 4362 case CMD_NO_NETWORKS_PERIODIC_SCAN: 4363 s="CMD_NO_NETWORKS_PERIODIC_SCAN"; 4364 break; 4365 case CMD_SET_BATCHED_SCAN: 4366 s="CMD_SET_BATCHED_SCAN"; 4367 break; 4368 case CMD_START_NEXT_BATCHED_SCAN: 4369 s="CMD_START_NEXT_BATCHED_SCAN"; 4370 break; 4371 case CMD_POLL_BATCHED_SCAN: 4372 s="CMD_POLL_BATCHED_SCAN"; 4373 break; 4374 case CMD_NETLINK_UPDATE: 4375 s="CMD_NETLINK_UPDATE"; 4376 break; 4377 case CMD_RELOAD_TLS_AND_RECONNECT: 4378 s= "CMD_RELOAD_TLS_AND_RECONNECT"; 4379 break; 4380 case WifiManager.CONNECT_NETWORK: 4381 s= "WifiManager.CONNECT_NETWORK"; 4382 break; 4383 case WifiManager.SAVE_NETWORK: 4384 s= "WifiManager.SAVE_NETWORK"; 4385 break; 4386 case WifiManager.FORGET_NETWORK: 4387 s = "WifiManager.FORGET_NETWORK"; 4388 break; 4389 case WifiManager.START_WPS: 4390 s= "WifiManager.START_WPS"; 4391 break; 4392 case WifiMonitor.SUP_CONNECTION_EVENT: 4393 s= "WifiMonitor.SUP_CONNECTION_EVENT"; 4394 break; 4395 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4396 s= "WifiMonitor.SUP_DISCONNECTION_EVENT"; 4397 break; 4398 case WifiMonitor.SCAN_RESULTS_EVENT: 4399 s= "WifiMonitor.SCAN_RESULTS_EVENT"; 4400 break; 4401 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4402 s= "WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT"; 4403 break; 4404 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4405 s= "WifiMonitor.AUTHENTICATION_FAILURE_EVENT"; 4406 break; 4407 case WifiMonitor.SSID_TEMP_DISABLED: 4408 s= "WifiMonitor.SSID_TEMP_DISABLED"; 4409 break; 4410 case WifiMonitor.SSID_REENABLED: 4411 s= "WifiMonitor.SSID_REENABLED"; 4412 break; 4413 case WifiMonitor.WPS_SUCCESS_EVENT: 4414 s= "WPS_SUCCESS_EVENT"; 4415 break; 4416 case WifiMonitor.WPS_FAIL_EVENT: 4417 s= "WPS_FAIL_EVENT"; 4418 break; 4419 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4420 s= "networkConnectionEvent"; 4421 break; 4422 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4423 s="networkDisconnectionEvent"; 4424 break; 4425 case CMD_SET_OPERATIONAL_MODE: 4426 s="CMD_SET_OPERATIONAL_MODE"; 4427 break; 4428 case CMD_START_SCAN: 4429 s="CMD_START_SCAN"; 4430 break; 4431 case CMD_ENABLE_BACKGROUND_SCAN: 4432 s="CMD_ENABLE_BACKGROUND_SCAN"; 4433 break; 4434 } 4435 return s; 4436 } 4437 4438 void registerConnected() { 4439 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 4440 long now_ms = System.currentTimeMillis(); 4441 //we are switching away from this configuration, 4442 //hence record the time we were connected last 4443 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 4444 if (config != null) { 4445 config.lastConnected = System.currentTimeMillis(); 4446 } 4447 } 4448 } 4449 4450 void registerDisconnected() { 4451 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 4452 long now_ms = System.currentTimeMillis(); 4453 //we are switching away from this configuration, 4454 //hence record the time we were connected last 4455 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 4456 if (config != null) { 4457 config.lastDisconnected = System.currentTimeMillis(); 4458 } 4459 } 4460 } 4461 4462 WifiConfiguration getCurrentWifiConfiguration() { 4463 if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 4464 return null; 4465 } 4466 return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 4467 } 4468 4469 String getCurrentBSSID() { 4470 return mLastBssid; 4471 } 4472 4473 class ConnectModeState extends State { 4474 @Override 4475 public boolean processMessage(Message message) { 4476 WifiConfiguration config; 4477 int netId; 4478 boolean ok; 4479 NetworkUpdateResult result; 4480 logStateAndMessage(message, getClass().getSimpleName()); 4481 4482 switch(message.what) { 4483 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 4484 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 4485 break; 4486 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4487 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 4488 break; 4489 case WifiMonitor.SSID_TEMP_DISABLED: 4490 case WifiMonitor.SSID_REENABLED: 4491 String substr = (String)message.obj; 4492 String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ? 4493 "temp-disabled" : "re-enabled"; 4494 loge("ConnectModeState SSID state=" + en + " nid=" 4495 + Integer.toString(message.arg1) + " [" + substr + "]"); 4496 mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what == 4497 WifiMonitor.SSID_REENABLED, substr); 4498 break; 4499 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4500 SupplicantState state = handleSupplicantStateChange(message); 4501 // A driver/firmware hang can now put the interface in a down state. 4502 // We detect the interface going down and recover from it 4503 if (!SupplicantState.isDriverActive(state)) { 4504 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 4505 handleNetworkDisconnect(); 4506 } 4507 log("Detected an interface down, restart driver"); 4508 transitionTo(mDriverStoppedState); 4509 sendMessage(CMD_START_DRIVER); 4510 break; 4511 } 4512 4513 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 4514 // when authentication times out after a successful connection, 4515 // we can figure this from the supplicant state. If supplicant 4516 // state is DISCONNECTED, but the mNetworkInfo says we are not 4517 // disconnected, we need to handle a disconnection 4518 if (state == SupplicantState.DISCONNECTED && 4519 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 4520 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 4521 handleNetworkDisconnect(); 4522 transitionTo(mDisconnectedState); 4523 } 4524 break; 4525 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4526 if (message.arg1 == 1) { 4527 mWifiNative.disconnect(); 4528 mTemporarilyDisconnectWifi = true; 4529 } else { 4530 mWifiNative.reconnect(); 4531 mTemporarilyDisconnectWifi = false; 4532 } 4533 break; 4534 case CMD_ADD_OR_UPDATE_NETWORK: 4535 config = (WifiConfiguration) message.obj; 4536 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 4537 mWifiConfigStore.addOrUpdateNetwork(config)); 4538 break; 4539 case CMD_REMOVE_NETWORK: 4540 ok = mWifiConfigStore.removeNetwork(message.arg1); 4541 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4542 break; 4543 case CMD_ENABLE_NETWORK: 4544 boolean others = message.arg2 == 1; 4545 // Tell autojoin the user did try to select to that network 4546 // However, do NOT persist the choice by bumping the priority of the network 4547 if (others && mFrameworkAutoJoin.get()) { 4548 mWifiAutoJoinController. 4549 updateConfigurationHistory(message.arg1, true, false); 4550 } 4551 // Set the last selected configuration so as to allow the system to 4552 // stick the last user choice without persisting the choice 4553 mWifiConfigStore.setLastSelectedConfiguration(message.arg1); 4554 4555 //cancel auto roam requests 4556 autoRoamSetBSSID(message.arg1, "any"); 4557 4558 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 4559 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4560 break; 4561 case CMD_ENABLE_ALL_NETWORKS: 4562 long time = android.os.SystemClock.elapsedRealtime(); 4563 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 4564 mWifiConfigStore.enableAllNetworks(); 4565 mLastEnableAllNetworksTime = time; 4566 } 4567 break; 4568 case WifiManager.DISABLE_NETWORK: 4569 if (mWifiConfigStore.disableNetwork(message.arg1, 4570 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 4571 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 4572 } else { 4573 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 4574 WifiManager.ERROR); 4575 } 4576 break; 4577 case CMD_BLACKLIST_NETWORK: 4578 mWifiNative.addToBlacklist((String)message.obj); 4579 break; 4580 case CMD_CLEAR_BLACKLIST: 4581 mWifiNative.clearBlacklist(); 4582 break; 4583 case CMD_SAVE_CONFIG: 4584 ok = mWifiConfigStore.saveConfig(); 4585 4586 loge("wifistatemachine did save config " + ok); 4587 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 4588 4589 // Inform the backup manager about a data change 4590 IBackupManager ibm = IBackupManager.Stub.asInterface( 4591 ServiceManager.getService(Context.BACKUP_SERVICE)); 4592 if (ibm != null) { 4593 try { 4594 ibm.dataChanged("com.android.providers.settings"); 4595 } catch (Exception e) { 4596 // Try again later 4597 } 4598 } 4599 break; 4600 case CMD_GET_CONFIGURED_NETWORKS: 4601 replyToMessage(message, message.what, 4602 mWifiConfigStore.getConfiguredNetworks()); 4603 break; 4604 /* Do a redundant disconnect without transition */ 4605 case CMD_DISCONNECT: 4606 mWifiConfigStore.setLastSelectedConfiguration 4607 (WifiConfiguration.INVALID_NETWORK_ID); 4608 mWifiNative.disconnect(); 4609 break; 4610 case CMD_RECONNECT: 4611 mWifiNative.reconnect(); 4612 break; 4613 case CMD_REASSOCIATE: 4614 mWifiNative.reassociate(); 4615 break; 4616 case CMD_RELOAD_TLS_AND_RECONNECT: 4617 if (mWifiConfigStore.needsUnlockedKeyStore()) { 4618 logd("Reconnecting to give a chance to un-connected TLS networks"); 4619 mWifiNative.disconnect(); 4620 mWifiNative.reconnect(); 4621 } 4622 break; 4623 case CMD_AUTO_ROAM: 4624 return HANDLED; 4625 case CMD_AUTO_CONNECT: 4626 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 4627 * associated status thus the STATUS command but somehow-someplace still thinks 4628 * it is associated and thus will ignore select/reconnect command with 4629 * following message: 4630 * "Already associated with the selected network - do nothing" 4631 * 4632 * Hence, sends a disconnect to supplicant first. 4633 */ 4634 mWifiNative.disconnect(); 4635 4636 /* connect command coming from auto-join */ 4637 config = (WifiConfiguration) message.obj; 4638 netId = message.arg1; 4639 int roam = message.arg2; 4640 loge("CMD_AUTO_CONNECT sup state " 4641 + mSupplicantStateTracker.getSupplicantStateName() 4642 + " my state " + getCurrentState().getName() 4643 + " nid=" + Integer.toString(netId) 4644 + " roam=" + Integer.toString(roam)); 4645 if (config == null) { 4646 loge("AUTO_CONNECT and no config, bail out..."); 4647 break; 4648 } 4649 4650 /* make sure we cancel any previous roam request */ 4651 autoRoamSetBSSID(config, "any"); 4652 4653 /* Save the network config */ 4654 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 4655 + " nid=" + Integer.toString(netId)); 4656 result = mWifiConfigStore.saveNetwork(config); 4657 netId = result.getNetworkId(); 4658 loge("CMD_AUTO_CONNECT did save config -> " 4659 + " nid=" + Integer.toString(netId)); 4660 4661 if (mWifiConfigStore.selectNetwork(netId) && 4662 mWifiNative.reconnect()) { 4663 // we selected a better config, 4664 // maybe because we could not see the last user 4665 // selection, then forget it. We will remember the selection 4666 // only if it was persisted. 4667 mWifiConfigStore. 4668 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 4669 4670 /* The state tracker handles enabling networks upon completion/failure */ 4671 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 4672 //replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 4673 mAutoRoaming = roam; 4674 if (isRoaming()) { 4675 transitionTo(mRoamingState); 4676 } else { 4677 transitionTo(mDisconnectingState); 4678 } 4679 } else { 4680 loge("Failed to connect config: " + config + " netId: " + netId); 4681 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 4682 WifiManager.ERROR); 4683 break; 4684 } 4685 break; 4686 case WifiManager.CONNECT_NETWORK: 4687 /* The connect message can contain a network id passed as arg1 on message or 4688 * or a config passed as obj on message. 4689 * For a new network, a config is passed to create and connect. 4690 * For an existing network, a network id is passed 4691 */ 4692 netId = message.arg1; 4693 config = (WifiConfiguration) message.obj; 4694 4695 if (config == null) { 4696 loge("CONNECT_NETWORK id=" + Integer.toString(netId) + " " 4697 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 4698 + getCurrentState().getName()); 4699 } else { 4700 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 4701 + " config=" + config.SSID 4702 + " cnid=" + config.networkId 4703 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4704 + " my state " + getCurrentState().getName()); 4705 } 4706 4707 autoRoamSetBSSID(netId, "any"); 4708 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 4709 4710 /* Save the network config */ 4711 if (config != null) { 4712 result = mWifiConfigStore.saveNetwork(config); 4713 netId = result.getNetworkId(); 4714 } 4715 if (mFrameworkAutoJoin.get()) { 4716 /* Tell autojoin the user did try to connect to that network */ 4717 mWifiAutoJoinController.updateConfigurationHistory(netId, true, true); 4718 } 4719 mWifiConfigStore.setLastSelectedConfiguration(netId); 4720 4721 if (mWifiConfigStore.selectNetwork(netId) && 4722 mWifiNative.reconnect()) { 4723 /* The state tracker handles enabling networks upon completion/failure */ 4724 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 4725 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 4726 /* Expect a disconnection from the old connection */ 4727 transitionTo(mDisconnectingState); 4728 } else { 4729 loge("Failed to connect config: " + config + " netId: " + netId); 4730 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 4731 WifiManager.ERROR); 4732 break; 4733 } 4734 break; 4735 case WifiManager.SAVE_NETWORK: 4736 config = (WifiConfiguration) message.obj; 4737 int nid = config.networkId; 4738 if (config == null) { 4739 loge("SAVE_NETWORK id=" + Integer.toString(nid) 4740 + " " + mSupplicantStateTracker.getSupplicantStateName() 4741 + " my state " + getCurrentState().getName()); 4742 } else { 4743 loge("SAVE_NETWORK id=" + Integer.toString(nid) 4744 + " config=" + config.SSID 4745 + " cnid=" + config.networkId 4746 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4747 + " my state " + getCurrentState().getName()); 4748 } 4749 4750 result = mWifiConfigStore.saveNetwork(config); 4751 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 4752 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 4753 if (VDBG) { 4754 loge("Success save network nid=" 4755 + Integer.toString(result.getNetworkId()) 4756 + " autojoin " + mFrameworkAutoJoin.get()); 4757 } 4758 if (mFrameworkAutoJoin.get()) { 4759 /* Tell autojoin the user did try to modify and save that network */ 4760 mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() 4761 ,true, false); 4762 mWifiAutoJoinController.attemptAutoJoin(); 4763 } 4764 } else { 4765 loge("Failed to save network"); 4766 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 4767 WifiManager.ERROR); 4768 } 4769 break; 4770 case WifiManager.FORGET_NETWORK: 4771 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 4772 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 4773 } else { 4774 loge("Failed to forget network"); 4775 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 4776 WifiManager.ERROR); 4777 } 4778 break; 4779 case WifiManager.START_WPS: 4780 WpsInfo wpsInfo = (WpsInfo) message.obj; 4781 WpsResult wpsResult; 4782 switch (wpsInfo.setup) { 4783 case WpsInfo.PBC: 4784 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 4785 break; 4786 case WpsInfo.KEYPAD: 4787 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 4788 break; 4789 case WpsInfo.DISPLAY: 4790 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 4791 break; 4792 default: 4793 wpsResult = new WpsResult(Status.FAILURE); 4794 loge("Invalid setup for WPS"); 4795 break; 4796 } 4797 mWifiConfigStore.setLastSelectedConfiguration 4798 (WifiConfiguration.INVALID_NETWORK_ID); 4799 if (wpsResult.status == Status.SUCCESS) { 4800 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 4801 transitionTo(mWpsRunningState); 4802 } else { 4803 loge("Failed to start WPS with config " + wpsInfo.toString()); 4804 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 4805 } 4806 break; 4807 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4808 if (DBG) log("Network connection established"); 4809 mLastNetworkId = message.arg1; 4810 mLastBssid = (String) message.obj; 4811 4812 mWifiInfo.setBSSID(mLastBssid); 4813 mWifiInfo.setNetworkId(mLastNetworkId); 4814 /* send event to CM & network change broadcast */ 4815 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 4816 sendNetworkStateChangeBroadcast(mLastBssid); 4817 transitionTo(mObtainingIpState); 4818 break; 4819 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4820 if (DBG) log("Network connection lost"); 4821 handleNetworkDisconnect(); 4822 transitionTo(mDisconnectedState); 4823 break; 4824 default: 4825 return NOT_HANDLED; 4826 } 4827 return HANDLED; 4828 } 4829 } 4830 4831 private class WifiNetworkAgent extends NetworkAgent { 4832 public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, 4833 NetworkCapabilities nc, LinkProperties lp, int score) { 4834 super(l, c, TAG, ni, nc, lp, score); 4835 } 4836 protected void unwanted() { 4837 // ignore if we're not the current networkAgent. 4838 if (this != mNetworkAgent) return; 4839 // TODO - don't want this network. What to do? 4840 if (DBG) log("WifiNetworkAgent -> Wifi unwanted score " 4841 + Integer.toString(mWifiInfo.score)); 4842 unwantedNetwork(); 4843 } 4844 } 4845 4846 void unwantedNetwork() { 4847 sendMessage(CMD_UNWANTED_NETWORK); 4848 } 4849 4850 class L2ConnectedState extends State { 4851 @Override 4852 public void enter() { 4853 mRssiPollToken++; 4854 if (mEnableRssiPolling) { 4855 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 4856 } 4857 if (mNetworkAgent != null) { 4858 loge("Have NetworkAgent when entering L2Connected"); 4859 setNetworkDetailedState(DetailedState.DISCONNECTED); 4860 } 4861 setNetworkDetailedState(DetailedState.CONNECTING); 4862 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 4863 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 4864 mLinkProperties, 60); 4865 } 4866 4867 @Override 4868 public void exit() { 4869 handleNetworkDisconnect(); 4870 } 4871 4872 @Override 4873 public boolean processMessage(Message message) { 4874 logStateAndMessage(message, getClass().getSimpleName()); 4875 4876 switch (message.what) { 4877 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 4878 handlePreDhcpSetup(); 4879 break; 4880 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 4881 handlePostDhcpSetup(); 4882 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 4883 if (DBG) log("DHCP successful"); 4884 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 4885 transitionTo(mVerifyingLinkState); 4886 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 4887 if (DBG) log("DHCP failed"); 4888 handleFailedIpConfiguration(); 4889 transitionTo(mDisconnectingState); 4890 } 4891 break; 4892 case CMD_DISCONNECT: 4893 mWifiNative.disconnect(); 4894 transitionTo(mDisconnectingState); 4895 break; 4896 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4897 if (message.arg1 == 1) { 4898 mWifiNative.disconnect(); 4899 mTemporarilyDisconnectWifi = true; 4900 transitionTo(mDisconnectingState); 4901 } 4902 break; 4903 case CMD_SET_OPERATIONAL_MODE: 4904 if (message.arg1 != CONNECT_MODE) { 4905 sendMessage(CMD_DISCONNECT); 4906 deferMessage(message); 4907 } 4908 break; 4909 case CMD_SET_COUNTRY_CODE: 4910 deferMessage(message); 4911 break; 4912 case CMD_START_SCAN: 4913 if (DBG) { 4914 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 4915 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 4916 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 4917 + " BSSID=" + mTargetRoamBSSID 4918 + " RSSI=" + mWifiInfo.getRssi()); 4919 } 4920 if (message.arg1 == SCAN_ALARM_SOURCE) { 4921 boolean tryFullBandScan = false; 4922 boolean restrictChannelList = false; 4923 long now_ms = System.currentTimeMillis(); 4924 if (mWifiInfo != null) { 4925 if ((now_ms - lastFullBandConnectedTimeMilli) 4926 > fullBandConnectedTimeIntervalMilli) { 4927 if (DBG) { 4928 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 4929 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 4930 + " interval=" + fullBandConnectedTimeIntervalMilli); 4931 } 4932 tryFullBandScan = true; 4933 } 4934 4935 //TODO: really tune the logic 4936 //TODO: right now we discriminate only between full band and partial 4937 //TODO: scans however partial scans can have many channels 4938 //TODO: and be almost same as full band 4939 //TODO: also look and exclude broadcast Rx packets 4940 if (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 30) { 4941 // too much traffic at the interface, hence no full band scan 4942 if (DBG) { 4943 loge("WifiStateMachine CMD_START_SCAN " + 4944 "prevent full band scan due to pkt rate"); 4945 } 4946 tryFullBandScan = false; 4947 } 4948 4949 if (mWifiInfo.txSuccessRate > 25 || mWifiInfo.rxSuccessRate > 80) { 4950 // don't scan aggressively if lots of packets are being sent 4951 restrictChannelList = true; 4952 if (mAllowScansWithTraffic == 0 4953 || (getCurrentWifiConfiguration().scanResultCache == null 4954 || getCurrentWifiConfiguration().scanResultCache.size() > 4 4955 || mWifiInfo.getRssi() 4956 > (WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD - 5))) { 4957 //there is no need to scan because, either the configuration 4958 //has many 4959 //BSSIDs and thus roaming is left to the chip, 4960 //or, 4961 //RSSI is very good and then the potential roaming gain is not 4962 //high enough to outweigh the negative impact on traffic 4963 if (DBG) { 4964 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 4965 + " ...and ignore scans" 4966 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 4967 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 4968 } 4969 return HANDLED; 4970 } 4971 } 4972 } 4973 4974 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 4975 if (currentConfiguration != null) { 4976 if (tryFullBandScan) { 4977 lastFullBandConnectedTimeMilli = now_ms; 4978 if (fullBandConnectedTimeIntervalMilli < 20 * 1000) { 4979 //paranoia, make sure interval is not less than 20 seconds 4980 fullBandConnectedTimeIntervalMilli = 20 * 1000; 4981 } 4982 if (fullBandConnectedTimeIntervalMilli 4983 < maxFullBandConnectedTimeIntervalMilli) { 4984 //increase the interval 4985 fullBandConnectedTimeIntervalMilli 4986 = fullBandConnectedTimeIntervalMilli * 3 / 2; 4987 } 4988 handleScanRequest( 4989 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 4990 } else { 4991 HashSet<Integer> channels 4992 = mWifiConfigStore.makeChannelList(currentConfiguration, 4993 ONE_HOUR_MILLI, restrictChannelList); 4994 if (channels != null && channels.size() != 0) { 4995 StringBuilder freqs = new StringBuilder(); 4996 boolean first = true; 4997 for (Integer channel : channels) { 4998 if (!first) 4999 freqs.append(","); 5000 freqs.append(channel.toString()); 5001 first = false; 5002 } 5003 if (DBG) { 5004 loge("WifiStateMachine starting scan with " + freqs); 5005 } 5006 // call wifi native to start the scan 5007 if (startScanNative(SCAN_ONLY_MODE, freqs.toString())) { 5008 // only count battery consumption if scan request is accepted 5009 noteScanStart(SCAN_ALARM_SOURCE, null); 5010 } 5011 } else { 5012 if (DBG) { 5013 loge("WifiStateMachine starting scan, did not find channels"); 5014 } 5015 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5016 } 5017 } 5018 } 5019 } else { 5020 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5021 } 5022 break; 5023 /* Ignore connection to same network */ 5024 case WifiManager.CONNECT_NETWORK: 5025 int netId = message.arg1; 5026 if (mWifiInfo.getNetworkId() == netId) { 5027 break; 5028 } 5029 return NOT_HANDLED; 5030 case WifiManager.SAVE_NETWORK: 5031 WifiConfiguration config = (WifiConfiguration) message.obj; 5032 int nid = config.networkId; 5033 if (config == null) { 5034 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5035 + " " + mSupplicantStateTracker.getSupplicantStateName() 5036 + " my state " + getCurrentState().getName()); 5037 } else { 5038 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5039 + " SSID=" + config.SSID 5040 + " cnid=" + config.networkId 5041 + " autojoin=" + Integer.toString(config.autoJoinStatus) 5042 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5043 + " my state " + getCurrentState().getName() 5044 + " uid " + Integer.toString(config.creatorUid)); 5045 } 5046 5047 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 5048 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 5049 if (result.hasIpChanged()) { 5050 log("Reconfiguring IP on connection"); 5051 transitionTo(mObtainingIpState); 5052 } 5053 if (result.hasProxyChanged()) { 5054 log("Reconfiguring proxy on connection"); 5055 updateLinkProperties(); 5056 } 5057 } 5058 5059 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 5060 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 5061 if (VDBG) { 5062 loge("Success save network l2 nid=" 5063 + Integer.toString(result.getNetworkId()) 5064 + " autojoin " + mFrameworkAutoJoin.get()); 5065 } 5066 if (mFrameworkAutoJoin.get()) { 5067 /* Tell autojoin the user did try to modify and save that network */ 5068 mWifiAutoJoinController.updateConfigurationHistory(config.networkId, 5069 true, false); 5070 mWifiAutoJoinController.attemptAutoJoin(); 5071 } 5072 } else { 5073 loge("Failed to save network"); 5074 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5075 WifiManager.ERROR); 5076 } 5077 break; 5078 /* Ignore */ 5079 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5080 break; 5081 case CMD_RSSI_POLL: 5082 if (message.arg1 == mRssiPollToken) { 5083 WifiLinkLayerStats stats = null; 5084 //try a reading L2 stats a couple of time, allow for a few failures 5085 //in case the HAL/drivers are not completely initialized once we get there 5086 if (mWifiLinkLayerStatsSupported > 0) { 5087 stats = mWifiNative.getWifiLinkLayerStats(); 5088 if (stats == null && mWifiLinkLayerStatsSupported > 0) { 5089 mWifiLinkLayerStatsSupported -= 1; 5090 } 5091 } 5092 // Get Info and continue polling 5093 fetchRssiLinkSpeedAndFrequencyNative(); 5094 calculateWifiScore(stats); 5095 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5096 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5097 } else { 5098 // Polling has completed 5099 } 5100 break; 5101 case CMD_ENABLE_RSSI_POLL: 5102 mEnableRssiPolling = (message.arg1 == 1); 5103 mRssiPollToken++; 5104 if (mEnableRssiPolling) { 5105 // first poll 5106 fetchRssiLinkSpeedAndFrequencyNative(); 5107 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5108 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5109 } 5110 break; 5111 case WifiManager.RSSI_PKTCNT_FETCH: 5112 RssiPacketCountInfo info = new RssiPacketCountInfo(); 5113 fetchRssiLinkSpeedAndFrequencyNative(); 5114 info.rssi = mWifiInfo.getRssi(); 5115 fetchPktcntNative(info); 5116 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 5117 break; 5118 case CMD_UNWANTED_NETWORK: 5119 //mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 5120 //disconnecting is probably too rough and reduce the chance we recover quickly. 5121 //we should not have to disconnect, instead rely on network stack to send data 5122 //traffic somewhere else but remember that this network is roamable with a 5123 //low wifi score threshold 5124 sendMessage(CMD_DISCONNECT); 5125 break; 5126 default: 5127 return NOT_HANDLED; 5128 } 5129 5130 return HANDLED; 5131 } 5132 } 5133 5134 class ObtainingIpState extends State { 5135 @Override 5136 public void enter() { 5137 if (DBG) { 5138 String key = ""; 5139 if (getCurrentWifiConfiguration() != null) { 5140 key = getCurrentWifiConfiguration().configKey(); 5141 } 5142 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 5143 + " " + key + " " 5144 + " roam=" + mAutoRoaming 5145 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId)); 5146 } 5147 5148 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 5149 // TODO: If we're switching between static IP configuration and DHCP, remove the 5150 // static configuration first. 5151 if (isRoaming()) { 5152 renewDhcp(); 5153 } else { 5154 startDhcp(); 5155 } 5156 } else { 5157 // stop any running dhcp before assigning static IP 5158 stopDhcp(); 5159 DhcpResults dhcpResults = new DhcpResults( 5160 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 5161 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 5162 Iterator<LinkAddress> addrs = 5163 dhcpResults.linkProperties.getLinkAddresses().iterator(); 5164 if (!addrs.hasNext()) { 5165 loge("Static IP lacks address"); 5166 sendMessage(CMD_STATIC_IP_FAILURE); 5167 } else { 5168 ifcg.setLinkAddress(addrs.next()); 5169 ifcg.setInterfaceUp(); 5170 try { 5171 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 5172 if (DBG) log("Static IP configuration succeeded"); 5173 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 5174 } catch (RemoteException re) { 5175 loge("Static IP configuration failed: " + re); 5176 sendMessage(CMD_STATIC_IP_FAILURE); 5177 } catch (IllegalStateException e) { 5178 loge("Static IP configuration failed: " + e); 5179 sendMessage(CMD_STATIC_IP_FAILURE); 5180 } 5181 } 5182 } 5183 } 5184 @Override 5185 public boolean processMessage(Message message) { 5186 logStateAndMessage(message, getClass().getSimpleName()); 5187 5188 switch(message.what) { 5189 case CMD_STATIC_IP_SUCCESS: 5190 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 5191 transitionTo(mVerifyingLinkState); 5192 break; 5193 case CMD_STATIC_IP_FAILURE: 5194 handleFailedIpConfiguration(); 5195 transitionTo(mDisconnectingState); 5196 break; 5197 case WifiManager.SAVE_NETWORK: 5198 deferMessage(message); 5199 break; 5200 /* Defer any power mode changes since we must keep active power mode at DHCP */ 5201 case CMD_SET_HIGH_PERF_MODE: 5202 deferMessage(message); 5203 break; 5204 /* Defer scan request since we should not switch to other channels at DHCP */ 5205 case CMD_START_SCAN: 5206 deferMessage(message); 5207 break; 5208 default: 5209 return NOT_HANDLED; 5210 } 5211 return HANDLED; 5212 } 5213 } 5214 5215 class VerifyingLinkState extends State { 5216 @Override 5217 public void enter() { 5218 log(getName() + " enter"); 5219 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 5220 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 5221 sendNetworkStateChangeBroadcast(mLastBssid); 5222 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 5223 } 5224 @Override 5225 public boolean processMessage(Message message) { 5226 logStateAndMessage(message, getClass().getSimpleName()); 5227 5228 switch (message.what) { 5229 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5230 //stay here 5231 log(getName() + " POOR_LINK_DETECTED: no transition"); 5232 break; 5233 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 5234 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 5235 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 5236 // existing behaviour. The captive portal check really happens after we 5237 // transition into DetailedState.CONNECTED. 5238 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 5239 mWifiConfigStore.updateStatus(mLastNetworkId, 5240 DetailedState.CAPTIVE_PORTAL_CHECK); 5241 sendNetworkStateChangeBroadcast(mLastBssid); 5242 5243 // NOTE: This might look like an odd place to enable IPV6 but this is in 5244 // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable 5245 // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. 5246 try { 5247 mNwService.enableIpv6(mInterfaceName); 5248 } catch (RemoteException re) { 5249 loge("Failed to enable IPv6: " + re); 5250 } catch (IllegalStateException e) { 5251 loge("Failed to enable IPv6: " + e); 5252 } 5253 5254 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 5255 setNetworkDetailedState(DetailedState.CONNECTED); 5256 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 5257 sendNetworkStateChangeBroadcast(mLastBssid); 5258 transitionTo(mConnectedState); 5259 5260 break; 5261 default: 5262 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 5263 return NOT_HANDLED; 5264 } 5265 return HANDLED; 5266 } 5267 } 5268 5269 class RoamingState extends State { 5270 @Override 5271 public void enter() { 5272 if (DBG) { 5273 log("RoamingState Enter" 5274 + " mScreenOn=" + mScreenOn ); 5275 } 5276 setScanAlarm(false); 5277 //TODO: actually implement an alarm, but so as to disconnect if roaming fails 5278 } 5279 @Override 5280 public boolean processMessage(Message message) { 5281 logStateAndMessage(message, getClass().getSimpleName()); 5282 5283 switch (message.what) { 5284 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5285 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 5286 return HANDLED; 5287 case CMD_UNWANTED_NETWORK: 5288 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 5289 return HANDLED; 5290 case CMD_SET_OPERATIONAL_MODE: 5291 if (message.arg1 != CONNECT_MODE) { 5292 deferMessage(message); 5293 } 5294 break; 5295 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5296 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 5297 * we have missed the network disconnection, transition to mDisconnectedState 5298 * and handle the rest of the events there 5299 */ 5300 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 5301 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 5302 break; 5303 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5304 if (DBG) log("roaming and Network connection established"); 5305 mLastNetworkId = message.arg1; 5306 mLastBssid = (String) message.obj; 5307 5308 mWifiInfo.setBSSID(mLastBssid); 5309 mWifiInfo.setNetworkId(mLastNetworkId); 5310 /* send event to CM & network change broadcast */ 5311 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 5312 sendNetworkStateChangeBroadcast(mLastBssid); 5313 transitionTo(mObtainingIpState); 5314 break; 5315 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5316 //throw away but only if it correspond to the network we're roaming to 5317 String bssid = (String)message.obj; 5318 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 5319 handleNetworkDisconnect(); 5320 } 5321 break; 5322 case WifiMonitor.SSID_TEMP_DISABLED: 5323 //auith error while roaming 5324 if (message.arg1 == mLastNetworkId) { 5325 loge("DISABLED while roaming nid=" + Integer.toString(mLastNetworkId)); 5326 sendMessage(CMD_DISCONNECT); 5327 transitionTo(mDisconnectingState); 5328 } 5329 return NOT_HANDLED; 5330 default: 5331 return NOT_HANDLED; 5332 } 5333 return HANDLED; 5334 } 5335 5336 @Override 5337 public void exit() { 5338 loge("WifiStateMachine: Leaving Roaming state"); 5339 5340 /* Request a CS wakelock during transition to mobile */ 5341 //checkAndSetConnectivityInstance(); 5342 //mCm.requestNetworkTransitionWakelock(getName()); 5343 } 5344 } 5345 5346 class ConnectedState extends State { 5347 @Override 5348 public void enter() { 5349 String address; 5350 updateDefaultRouteMacAddress(1000); 5351 if (DBG) { 5352 log("ConnectedState Enter autojoin=" + mFrameworkAutoJoin.get() 5353 + " mScreenOn=" + mScreenOn 5354 + " scanperiod=" + Integer.toString(mConnectedScanPeriodMs) ); 5355 } 5356 if (mFrameworkAutoJoin.get() && mScreenOn) { 5357 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 5358 setScanAlarm(true); 5359 } else { 5360 mCurrentScanAlarmMs = 0; 5361 } 5362 registerConnected(); 5363 } 5364 @Override 5365 public boolean processMessage(Message message) { 5366 logStateAndMessage(message, getClass().getSimpleName()); 5367 5368 switch (message.what) { 5369 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5370 if (DBG) log("Watchdog reports poor link"); 5371 try { 5372 mNwService.disableIpv6(mInterfaceName); 5373 } catch (RemoteException re) { 5374 loge("Failed to disable IPv6: " + re); 5375 } catch (IllegalStateException e) { 5376 loge("Failed to disable IPv6: " + e); 5377 } 5378 /* Report a disconnect */ 5379 setNetworkDetailedState(DetailedState.DISCONNECTED); 5380 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 5381 sendNetworkStateChangeBroadcast(mLastBssid); 5382 5383 transitionTo(mVerifyingLinkState); 5384 break; 5385 case CMD_UNWANTED_NETWORK: 5386 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 5387 //disconnecting is probably too rough and reduce the chance we recover quickly. 5388 //we should not have to disconnect, instead rely on network stack to send data 5389 //traffic somewhere else but remember that this network is roamable with a 5390 //low wifi score threshold 5391 sendMessage(CMD_DISCONNECT); 5392 return HANDLED; 5393 case CMD_AUTO_ROAM: 5394 /* this will happen similarly to an Auto_CONNECT, except we specify the BSSID */ 5395 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 5396 * associated status thus the STATUS command but somehow-someplace still thinks 5397 * it is associated and thus will ignore select/reconnect command with 5398 * following message: 5399 * "Already associated with the selected network - do nothing" 5400 * 5401 * Hence, sends a disconnect to supplicant first. 5402 */ 5403 //mWifiNative.disconnect(); 5404 5405 /* connect command coming from auto-join */ 5406 String bssid = (String) message.obj; 5407 int netId = mLastNetworkId; 5408 WifiConfiguration config = getCurrentWifiConfiguration(); 5409 5410 loge("CMD_AUTO_ROAM sup state " 5411 + mSupplicantStateTracker.getSupplicantStateName() 5412 + " my state " + getCurrentState().getName() 5413 + " nid=" + Integer.toString(netId) 5414 + " roam=" + Integer.toString(message.arg2) 5415 + bssid); 5416 if (config == null) { 5417 loge("AUTO_ROAM and no config, bail out..."); 5418 break; 5419 } 5420 5421 /* save the BSSID so as to lock it @ firmware */ 5422 autoRoamSetBSSID(config, bssid); 5423 5424 /* Save the network config */ 5425 loge("CMD_AUTO_ROAM will save config -> " + config.SSID 5426 + " nid=" + Integer.toString(netId)); 5427 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 5428 netId = result.getNetworkId(); 5429 loge("CMD_AUTO_ROAM did save config -> " 5430 + " nid=" + Integer.toString(netId)); 5431 5432 if (mWifiConfigStore.selectNetwork(netId) && 5433 mWifiNative.reassociate()) { 5434 5435 /* The state tracker handles enabling networks upon completion/failure */ 5436 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 5437 //replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 5438 mAutoRoaming = message.arg2; 5439 transitionTo(mRoamingState); 5440 5441 } else { 5442 loge("Failed to connect config: " + config + " netId: " + netId); 5443 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5444 WifiManager.ERROR); 5445 break; 5446 } 5447 break; 5448 default: 5449 return NOT_HANDLED; 5450 } 5451 return HANDLED; 5452 } 5453 5454 @Override 5455 public void exit() { 5456 loge("WifiStateMachine: Leaving Connected state"); 5457 setScanAlarm(false); 5458 5459 /* Request a CS wakelock during transition to mobile */ 5460 checkAndSetConnectivityInstance(); 5461 mCm.requestNetworkTransitionWakelock(getName()); 5462 loge("WifiStateMachine: Left Connected state"); 5463 5464 } 5465 } 5466 5467 class DisconnectingState extends State { 5468 5469 @Override 5470 public void enter() { 5471 if (mFrameworkAutoJoin.get()) { 5472 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 5473 } else { 5474 5475 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 5476 } 5477 5478 if (PDBG) { 5479 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 5480 + " mEnableBackgroundScan= " + mEnableBackgroundScan 5481 + " screenOn=" + mScreenOn); 5482 } 5483 if (mScreenOn) 5484 setScanAlarm(true); 5485 } 5486 5487 @Override 5488 public boolean processMessage(Message message) { 5489 logStateAndMessage(message, getClass().getSimpleName()); 5490 switch (message.what) { 5491 case CMD_SET_OPERATIONAL_MODE: 5492 if (message.arg1 != CONNECT_MODE) { 5493 deferMessage(message); 5494 } 5495 break; 5496 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5497 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 5498 * we have missed the network disconnection, transition to mDisconnectedState 5499 * and handle the rest of the events there 5500 */ 5501 deferMessage(message); 5502 handleNetworkDisconnect(); 5503 transitionTo(mDisconnectedState); 5504 break; 5505 default: 5506 return NOT_HANDLED; 5507 } 5508 return HANDLED; 5509 } 5510 5511 @Override 5512 public void exit() { 5513 mCurrentScanAlarmMs = 0; 5514 } 5515 } 5516 5517 class DisconnectedState extends State { 5518 @Override 5519 public void enter() { 5520 // We dont scan frequently if this is a temporary disconnect 5521 // due to p2p 5522 if (mTemporarilyDisconnectWifi) { 5523 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 5524 return; 5525 } 5526 5527 // loose the last selection choice 5528 // mWifiAutoJoinController.setLastSelectedConfiguration 5529 // (WifiConfiguration.INVALID_NETWORK_ID); 5530 5531 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 5532 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 5533 mDefaultFrameworkScanIntervalMs); 5534 5535 if (mFrameworkAutoJoin.get()) { 5536 if (mScreenOn) 5537 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 5538 } else { 5539 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 5540 } 5541 5542 if (PDBG) { 5543 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 5544 + " mEnableBackgroundScan= " + mEnableBackgroundScan 5545 + " screenOn=" + mScreenOn); 5546 } 5547 5548 /** clear the roaming state, if we were roaming, we failed */ 5549 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 5550 5551 /* 5552 * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, 5553 * otherwise we initiate an infrequent scan that wakes up the device to ensure 5554 * a user connects to an access point on the move 5555 * 5556 * mFrameworkAutoJoin is True: 5557 * - screen dark and PNO supported => scan alarm disabled 5558 * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period 5559 */ 5560 if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) { 5561 /* If a regular scan result is pending, do not initiate background 5562 * scan until the scan results are returned. This is needed because 5563 * initiating a background scan will cancel the regular scan and 5564 * scan results will not be returned until background scanning is 5565 * cleared 5566 */ 5567 if (!mIsScanOngoing) { 5568 mWifiNative.enableBackgroundScan(true); 5569 } 5570 } else { 5571 setScanAlarm(true); 5572 } 5573 5574 if (mFrameworkAutoJoin.get() && mScreenOn) { 5575 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 5576 } 5577 5578 /** 5579 * If we have no networks saved, the supplicant stops doing the periodic scan. 5580 * The scans are useful to notify the user of the presence of an open network. 5581 * Note that these are not wake up scans. 5582 */ 5583 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 5584 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5585 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5586 } 5587 } 5588 @Override 5589 public boolean processMessage(Message message) { 5590 boolean ret = HANDLED; 5591 5592 logStateAndMessage(message, getClass().getSimpleName()); 5593 5594 switch (message.what) { 5595 case CMD_NO_NETWORKS_PERIODIC_SCAN: 5596 if (mP2pConnected.get()) break; 5597 if (message.arg1 == mPeriodicScanToken && 5598 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 5599 startScan(UNKNOWN_SCAN_SOURCE, null, null); 5600 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5601 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5602 } 5603 break; 5604 case WifiManager.FORGET_NETWORK: 5605 case CMD_REMOVE_NETWORK: 5606 // Set up a delayed message here. After the forget/remove is handled 5607 // the handled delayed message will determine if there is a need to 5608 // scan and continue 5609 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5610 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5611 ret = NOT_HANDLED; 5612 break; 5613 case CMD_SET_OPERATIONAL_MODE: 5614 if (message.arg1 != CONNECT_MODE) { 5615 mOperationalMode = message.arg1; 5616 5617 mWifiConfigStore.disableAllNetworks(); 5618 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 5619 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 5620 setWifiState(WIFI_STATE_DISABLED); 5621 } 5622 5623 transitionTo(mScanModeState); 5624 } 5625 break; 5626 case CMD_ENABLE_BACKGROUND_SCAN: 5627 mEnableBackgroundScan = (message.arg1 == 1); 5628 loge("enableBackgroundScanCommand enabled=" + mEnableBackgroundScan 5629 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 5630 5631 if (mEnableBackgroundScan) { 5632 mWifiNative.enableBackgroundScan(true); 5633 setScanAlarm(false); 5634 } else { 5635 if (mFrameworkAutoJoin.get()) { 5636 // tell supplicant to disconnect so as it doesnt start scanning 5637 // for connection upon disabling background scan 5638 mWifiNative.disconnect(); 5639 } 5640 mWifiNative.enableBackgroundScan(false); 5641 setScanAlarm(true); 5642 } 5643 break; 5644 /* Ignore network disconnect */ 5645 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5646 break; 5647 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5648 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 5649 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 5650 /* ConnectModeState does the rest of the handling */ 5651 ret = NOT_HANDLED; 5652 break; 5653 case CMD_START_SCAN: 5654 /* Disable background scan temporarily during a regular scan */ 5655 if (mEnableBackgroundScan) { 5656 mWifiNative.enableBackgroundScan(false); 5657 } 5658 /* Handled in parent state */ 5659 ret = NOT_HANDLED; 5660 break; 5661 case WifiMonitor.SCAN_RESULTS_EVENT: 5662 /* Re-enable background scan when a pending scan result is received */ 5663 if (mEnableBackgroundScan && mIsScanOngoing) { 5664 mWifiNative.enableBackgroundScan(true); 5665 } 5666 /* Handled in parent state */ 5667 ret = NOT_HANDLED; 5668 break; 5669 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 5670 NetworkInfo info = (NetworkInfo) message.obj; 5671 mP2pConnected.set(info.isConnected()); 5672 if (mP2pConnected.get()) { 5673 int defaultInterval = mContext.getResources().getInteger( 5674 R.integer.config_wifi_scan_interval_p2p_connected); 5675 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 5676 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 5677 defaultInterval); 5678 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 5679 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 5680 if (DBG) log("Turn on scanning after p2p disconnected"); 5681 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5682 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5683 } 5684 case CMD_RECONNECT: 5685 case CMD_REASSOCIATE: 5686 if (mTemporarilyDisconnectWifi) { 5687 // Drop a third party reconnect/reassociate if STA is 5688 // temporarily disconnected for p2p 5689 break; 5690 } else { 5691 // ConnectModeState handles it 5692 ret = NOT_HANDLED; 5693 } 5694 break; 5695 default: 5696 ret = NOT_HANDLED; 5697 } 5698 return ret; 5699 } 5700 5701 @Override 5702 public void exit() { 5703 /* No need for a background scan upon exit from a disconnected state */ 5704 if (mEnableBackgroundScan) { 5705 mWifiNative.enableBackgroundScan(false); 5706 } 5707 mCurrentScanAlarmMs = 0; 5708 setScanAlarm(false); 5709 } 5710 } 5711 5712 class WpsRunningState extends State { 5713 //Tracks the source to provide a reply 5714 private Message mSourceMessage; 5715 @Override 5716 public void enter() { 5717 mSourceMessage = Message.obtain(getCurrentMessage()); 5718 } 5719 @Override 5720 public boolean processMessage(Message message) { 5721 logStateAndMessage(message, getClass().getSimpleName()); 5722 5723 switch (message.what) { 5724 case WifiMonitor.WPS_SUCCESS_EVENT: 5725 // Ignore intermediate success, wait for full connection 5726 break; 5727 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5728 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 5729 mSourceMessage.recycle(); 5730 mSourceMessage = null; 5731 deferMessage(message); 5732 transitionTo(mDisconnectedState); 5733 break; 5734 case WifiMonitor.WPS_OVERLAP_EVENT: 5735 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 5736 WifiManager.WPS_OVERLAP_ERROR); 5737 mSourceMessage.recycle(); 5738 mSourceMessage = null; 5739 transitionTo(mDisconnectedState); 5740 break; 5741 case WifiMonitor.WPS_FAIL_EVENT: 5742 //arg1 has the reason for the failure 5743 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 5744 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 5745 mSourceMessage.recycle(); 5746 mSourceMessage = null; 5747 transitionTo(mDisconnectedState); 5748 } else { 5749 if (DBG) log("Ignore unspecified fail event during WPS connection"); 5750 } 5751 break; 5752 case WifiMonitor.WPS_TIMEOUT_EVENT: 5753 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 5754 WifiManager.WPS_TIMED_OUT); 5755 mSourceMessage.recycle(); 5756 mSourceMessage = null; 5757 transitionTo(mDisconnectedState); 5758 break; 5759 case WifiManager.START_WPS: 5760 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 5761 break; 5762 case WifiManager.CANCEL_WPS: 5763 if (mWifiNative.cancelWps()) { 5764 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 5765 } else { 5766 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 5767 } 5768 transitionTo(mDisconnectedState); 5769 break; 5770 /* Defer all commands that can cause connections to a different network 5771 * or put the state machine out of connect mode 5772 */ 5773 case CMD_STOP_DRIVER: 5774 case CMD_SET_OPERATIONAL_MODE: 5775 case WifiManager.CONNECT_NETWORK: 5776 case CMD_ENABLE_NETWORK: 5777 case CMD_RECONNECT: 5778 case CMD_REASSOCIATE: 5779 deferMessage(message); 5780 break; 5781 case CMD_AUTO_CONNECT: 5782 if (DBG) log("Ignore auto connect command while WpsRunningState"); 5783 break; 5784 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5785 if (DBG) log("Network connection lost"); 5786 handleNetworkDisconnect(); 5787 break; 5788 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5789 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 5790 break; 5791 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5792 // Disregard auth failure events during WPS connection. The 5793 // EAP sequence is retried several times, and there might be 5794 // failures (especially for wps pin). We will get a WPS_XXX 5795 // event at the end of the sequence anyway. 5796 if (DBG) log("Ignore auth failure during WPS connection"); 5797 break; 5798 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5799 //Throw away supplicant state changes when WPS is running. 5800 //We will start getting supplicant state changes once we get 5801 //a WPS success or failure 5802 break; 5803 default: 5804 return NOT_HANDLED; 5805 } 5806 return HANDLED; 5807 } 5808 5809 @Override 5810 public void exit() { 5811 mWifiConfigStore.enableAllNetworks(); 5812 mWifiConfigStore.loadConfiguredNetworks(); 5813 } 5814 } 5815 5816 class SoftApStartingState extends State { 5817 @Override 5818 public void enter() { 5819 final Message message = getCurrentMessage(); 5820 if (message.what == CMD_START_AP) { 5821 final WifiConfiguration config = (WifiConfiguration) message.obj; 5822 5823 if (config == null) { 5824 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 5825 } else { 5826 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 5827 startSoftApWithConfig(config); 5828 } 5829 } else { 5830 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 5831 } 5832 } 5833 @Override 5834 public boolean processMessage(Message message) { 5835 logStateAndMessage(message, getClass().getSimpleName()); 5836 5837 switch(message.what) { 5838 case CMD_START_SUPPLICANT: 5839 case CMD_STOP_SUPPLICANT: 5840 case CMD_START_AP: 5841 case CMD_STOP_AP: 5842 case CMD_START_DRIVER: 5843 case CMD_STOP_DRIVER: 5844 case CMD_SET_OPERATIONAL_MODE: 5845 case CMD_SET_COUNTRY_CODE: 5846 case CMD_SET_FREQUENCY_BAND: 5847 case CMD_START_PACKET_FILTERING: 5848 case CMD_STOP_PACKET_FILTERING: 5849 case CMD_TETHER_STATE_CHANGE: 5850 deferMessage(message); 5851 break; 5852 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 5853 WifiConfiguration config = (WifiConfiguration) message.obj; 5854 if (config != null) { 5855 startSoftApWithConfig(config); 5856 } else { 5857 loge("Softap config is null!"); 5858 sendMessage(CMD_START_AP_FAILURE); 5859 } 5860 break; 5861 case CMD_START_AP_SUCCESS: 5862 setWifiApState(WIFI_AP_STATE_ENABLED); 5863 transitionTo(mSoftApStartedState); 5864 break; 5865 case CMD_START_AP_FAILURE: 5866 setWifiApState(WIFI_AP_STATE_FAILED); 5867 transitionTo(mInitialState); 5868 break; 5869 default: 5870 return NOT_HANDLED; 5871 } 5872 return HANDLED; 5873 } 5874 } 5875 5876 class SoftApStartedState extends State { 5877 @Override 5878 public boolean processMessage(Message message) { 5879 logStateAndMessage(message, getClass().getSimpleName()); 5880 5881 switch(message.what) { 5882 case CMD_STOP_AP: 5883 if (DBG) log("Stopping Soft AP"); 5884 /* We have not tethered at this point, so we just shutdown soft Ap */ 5885 try { 5886 mNwService.stopAccessPoint(mInterfaceName); 5887 } catch(Exception e) { 5888 loge("Exception in stopAccessPoint()"); 5889 } 5890 setWifiApState(WIFI_AP_STATE_DISABLED); 5891 transitionTo(mInitialState); 5892 break; 5893 case CMD_START_AP: 5894 // Ignore a start on a running access point 5895 break; 5896 /* Fail client mode operation when soft AP is enabled */ 5897 case CMD_START_SUPPLICANT: 5898 loge("Cannot start supplicant with a running soft AP"); 5899 setWifiState(WIFI_STATE_UNKNOWN); 5900 break; 5901 case CMD_TETHER_STATE_CHANGE: 5902 TetherStateChange stateChange = (TetherStateChange) message.obj; 5903 if (startTethering(stateChange.available)) { 5904 transitionTo(mTetheringState); 5905 } 5906 break; 5907 default: 5908 return NOT_HANDLED; 5909 } 5910 return HANDLED; 5911 } 5912 } 5913 5914 class TetheringState extends State { 5915 @Override 5916 public void enter() { 5917 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 5918 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 5919 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 5920 } 5921 @Override 5922 public boolean processMessage(Message message) { 5923 logStateAndMessage(message, getClass().getSimpleName()); 5924 5925 switch(message.what) { 5926 case CMD_TETHER_STATE_CHANGE: 5927 TetherStateChange stateChange = (TetherStateChange) message.obj; 5928 if (isWifiTethered(stateChange.active)) { 5929 transitionTo(mTetheredState); 5930 } 5931 return HANDLED; 5932 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5933 if (message.arg1 == mTetherToken) { 5934 loge("Failed to get tether update, shutdown soft access point"); 5935 transitionTo(mSoftApStartedState); 5936 // Needs to be first thing handled 5937 sendMessageAtFrontOfQueue(CMD_STOP_AP); 5938 } 5939 break; 5940 case CMD_START_SUPPLICANT: 5941 case CMD_STOP_SUPPLICANT: 5942 case CMD_START_AP: 5943 case CMD_STOP_AP: 5944 case CMD_START_DRIVER: 5945 case CMD_STOP_DRIVER: 5946 case CMD_SET_OPERATIONAL_MODE: 5947 case CMD_SET_COUNTRY_CODE: 5948 case CMD_SET_FREQUENCY_BAND: 5949 case CMD_START_PACKET_FILTERING: 5950 case CMD_STOP_PACKET_FILTERING: 5951 deferMessage(message); 5952 break; 5953 default: 5954 return NOT_HANDLED; 5955 } 5956 return HANDLED; 5957 } 5958 } 5959 5960 class TetheredState extends State { 5961 @Override 5962 public boolean processMessage(Message message) { 5963 logStateAndMessage(message, getClass().getSimpleName()); 5964 5965 switch(message.what) { 5966 case CMD_TETHER_STATE_CHANGE: 5967 TetherStateChange stateChange = (TetherStateChange) message.obj; 5968 if (!isWifiTethered(stateChange.active)) { 5969 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 5970 setHostApRunning(null, false); 5971 setHostApRunning(null, true); 5972 } 5973 return HANDLED; 5974 case CMD_STOP_AP: 5975 if (DBG) log("Untethering before stopping AP"); 5976 setWifiApState(WIFI_AP_STATE_DISABLING); 5977 stopTethering(); 5978 transitionTo(mUntetheringState); 5979 // More work to do after untethering 5980 deferMessage(message); 5981 break; 5982 default: 5983 return NOT_HANDLED; 5984 } 5985 return HANDLED; 5986 } 5987 } 5988 5989 class UntetheringState extends State { 5990 @Override 5991 public void enter() { 5992 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 5993 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 5994 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 5995 5996 } 5997 @Override 5998 public boolean processMessage(Message message) { 5999 logStateAndMessage(message, getClass().getSimpleName()); 6000 6001 switch(message.what) { 6002 case CMD_TETHER_STATE_CHANGE: 6003 TetherStateChange stateChange = (TetherStateChange) message.obj; 6004 6005 /* Wait till wifi is untethered */ 6006 if (isWifiTethered(stateChange.active)) break; 6007 6008 transitionTo(mSoftApStartedState); 6009 break; 6010 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6011 if (message.arg1 == mTetherToken) { 6012 loge("Failed to get tether update, force stop access point"); 6013 transitionTo(mSoftApStartedState); 6014 } 6015 break; 6016 case CMD_START_SUPPLICANT: 6017 case CMD_STOP_SUPPLICANT: 6018 case CMD_START_AP: 6019 case CMD_STOP_AP: 6020 case CMD_START_DRIVER: 6021 case CMD_STOP_DRIVER: 6022 case CMD_SET_OPERATIONAL_MODE: 6023 case CMD_SET_COUNTRY_CODE: 6024 case CMD_SET_FREQUENCY_BAND: 6025 case CMD_START_PACKET_FILTERING: 6026 case CMD_STOP_PACKET_FILTERING: 6027 deferMessage(message); 6028 break; 6029 default: 6030 return NOT_HANDLED; 6031 } 6032 return HANDLED; 6033 } 6034 } 6035 6036 //State machine initiated requests can have replyTo set to null indicating 6037 //there are no recepients, we ignore those reply actions 6038 private void replyToMessage(Message msg, int what) { 6039 if (msg.replyTo == null) return; 6040 Message dstMsg = obtainMessageWithArg2(msg); 6041 dstMsg.what = what; 6042 mReplyChannel.replyToMessage(msg, dstMsg); 6043 } 6044 6045 private void replyToMessage(Message msg, int what, int arg1) { 6046 if (msg.replyTo == null) return; 6047 Message dstMsg = obtainMessageWithArg2(msg); 6048 dstMsg.what = what; 6049 dstMsg.arg1 = arg1; 6050 mReplyChannel.replyToMessage(msg, dstMsg); 6051 } 6052 6053 private void replyToMessage(Message msg, int what, Object obj) { 6054 if (msg.replyTo == null) return; 6055 Message dstMsg = obtainMessageWithArg2(msg); 6056 dstMsg.what = what; 6057 dstMsg.obj = obj; 6058 mReplyChannel.replyToMessage(msg, dstMsg); 6059 } 6060 6061 /** 6062 * arg2 on the source message has a unique id that needs to be retained in replies 6063 * to match the request 6064 6065 * see WifiManager for details 6066 */ 6067 private Message obtainMessageWithArg2(Message srcMsg) { 6068 Message msg = Message.obtain(); 6069 msg.arg2 = srcMsg.arg2; 6070 return msg; 6071 } 6072} 6073