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