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