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