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