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