WifiStateMachine.java revision 6f1f2a48fe6e88179062760b1075af31ab46822b
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25/** 26 * TODO: 27 * Deprecate WIFI_STATE_UNKNOWN 28 */ 29import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 30import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 31import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 32import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 33import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 34 35import android.app.AlarmManager; 36import android.app.PendingIntent; 37import android.app.backup.IBackupManager; 38import android.bluetooth.BluetoothAdapter; 39import android.content.BroadcastReceiver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.database.ContentObserver; 45import android.net.ConnectivityManager; 46import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; 47import android.net.DhcpResults; 48import android.net.DhcpStateMachine; 49import android.net.InterfaceConfiguration; 50import android.net.LinkAddress; 51import android.net.LinkProperties; 52import android.net.NetworkAgent; 53import android.net.NetworkCapabilities; 54import android.net.NetworkInfo; 55import android.net.NetworkInfo.DetailedState; 56import android.net.NetworkRequest; 57import android.net.NetworkUtils; 58import android.net.RouteInfo; 59import android.net.wifi.BatchedScanResult; 60import android.net.wifi.BatchedScanSettings; 61import android.net.wifi.RssiPacketCountInfo; 62import android.net.wifi.ScanResult; 63import android.net.wifi.ScanSettings; 64import android.net.wifi.WifiChannel; 65import android.net.wifi.SupplicantState; 66import android.net.wifi.WifiConfiguration; 67import android.net.wifi.WifiInfo; 68import android.net.wifi.WifiLinkLayerStats; 69import android.net.wifi.WifiManager; 70import android.net.wifi.WifiSsid; 71import android.net.wifi.WpsInfo; 72import android.net.wifi.WpsResult; 73import android.net.wifi.WpsResult.Status; 74import android.net.wifi.p2p.IWifiP2pManager; 75import android.os.BatteryStats; 76import android.os.Bundle; 77import android.os.IBinder; 78import android.os.INetworkManagementService; 79import android.os.Message; 80import android.os.Messenger; 81import android.os.PowerManager; 82import android.os.RemoteException; 83import android.os.ServiceManager; 84import android.os.SystemClock; 85import android.os.SystemProperties; 86import android.os.UserHandle; 87import android.os.WorkSource; 88import android.provider.Settings; 89import android.util.LruCache; 90import android.text.TextUtils; 91import android.util.Log; 92import android.os.Build; 93 94import com.android.internal.R; 95import com.android.internal.app.IBatteryStats; 96import com.android.internal.util.AsyncChannel; 97import com.android.internal.util.Protocol; 98import com.android.internal.util.State; 99import com.android.internal.util.StateMachine; 100import com.android.server.net.BaseNetworkObserver; 101import com.android.server.wifi.p2p.WifiP2pServiceImpl; 102 103import java.io.FileDescriptor; 104import java.io.PrintWriter; 105import java.net.InetAddress; 106import java.util.ArrayList; 107import java.util.LinkedList; 108import java.util.List; 109import java.util.Locale; 110import java.util.Queue; 111import java.util.concurrent.atomic.AtomicInteger; 112import java.util.concurrent.atomic.AtomicBoolean; 113import java.util.Iterator; 114import java.util.regex.Pattern; 115import java.io.FileReader; 116import java.io.BufferedReader; 117import java.io.FileNotFoundException; 118import java.io.IOException; 119 120import java.net.InetAddress; 121import java.net.Inet4Address; 122import java.net.Inet6Address; 123 124/** 125 * Track the state of Wifi connectivity. All event handling is done here, 126 * and all changes in connectivity state are initiated here. 127 * 128 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 129 * In the current implementation, we support concurrent wifi p2p and wifi operation. 130 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 131 * handles p2p operation. 132 * 133 * @hide 134 */ 135public class WifiStateMachine extends StateMachine { 136 137 private static final String NETWORKTYPE = "WIFI"; 138 private static boolean DBG = false; 139 private static boolean VDBG = false; 140 private static boolean mLogMessages = false; 141 142 /* temporary debug flag - best network selection development */ 143 private static boolean PDBG = false; 144 /** 145 * Log with error attribute 146 * 147 * @param s is string log 148 */ 149 protected void loge(String s) { 150 long now = SystemClock.elapsedRealtimeNanos(); 151 String ts = String.format("[%,d us] ", now/1000); 152 Log.e(getName(), ts + s); 153 } 154 protected void log(String s) { 155 long now = SystemClock.elapsedRealtimeNanos(); 156 String ts = String.format("[%,d us] ", now/1000); 157 Log.e(getName(), ts + s); 158 } 159 160 private WifiMonitor mWifiMonitor; 161 private WifiNative mWifiNative; 162 private WifiConfigStore mWifiConfigStore; 163 private WifiAutoJoinController mWifiAutoJoinController; 164 private INetworkManagementService mNwService; 165 private ConnectivityManager mCm; 166 167 private final boolean mP2pSupported; 168 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 169 private boolean mTemporarilyDisconnectWifi = false; 170 private final String mPrimaryDeviceType; 171 172 /* Scan results handling */ 173 private List<ScanResult> mScanResults = new ArrayList<ScanResult>(); 174 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 175 private static final int SCAN_RESULT_CACHE_SIZE = 80; 176 private final LruCache<String, ScanResult> mScanResultCache; 177 178 /* Batch scan results */ 179 private final List<BatchedScanResult> mBatchedScanResults = 180 new ArrayList<BatchedScanResult>(); 181 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 182 private int mExpectedBatchedScans = 0; 183 private long mBatchedScanMinPollTime = 0; 184 185 private boolean mScreenOn = false; 186 187 /* Chipset supports background scan */ 188 private final boolean mBackgroundScanSupported; 189 190 private String mInterfaceName; 191 /* Tethering interface could be separate from wlan interface */ 192 private String mTetherInterfaceName; 193 194 private int mLastSignalLevel = -1; 195 private String mLastBssid; 196 private int mLastNetworkId; 197 private boolean mEnableRssiPolling = false; 198 private boolean mEnableBackgroundScan = false; 199 private int mRssiPollToken = 0; 200 private int mReconnectCount = 0; 201 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 202 * In CONNECT_MODE, the STA can scan and connect to an access point 203 * In SCAN_ONLY_MODE, the STA can only scan for access points 204 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 205 */ 206 private int mOperationalMode = CONNECT_MODE; 207 private boolean mIsScanOngoing = false; 208 private boolean mIsFullScanOngoing = false; 209 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 210 private WorkSource mScanWorkSource = null; 211 private static final int UNKNOWN_SCAN_SOURCE = -1; 212 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 213 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 214 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 215 private static final String BATCHED_SETTING = "batched_settings"; 216 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 217 218 /* Tracks if state machine has received any screen state change broadcast yet. 219 * We can miss one of these at boot. 220 */ 221 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 222 223 private boolean mBluetoothConnectionActive = false; 224 225 private PowerManager.WakeLock mSuspendWakeLock; 226 227 /** 228 * Interval in milliseconds between polling for RSSI 229 * and linkspeed information 230 */ 231 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 232 233 /** 234 * Delay between supplicant restarts upon failure to establish connection 235 */ 236 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 237 238 /** 239 * Number of times we attempt to restart supplicant 240 */ 241 private static final int SUPPLICANT_RESTART_TRIES = 5; 242 243 private int mSupplicantRestartCount = 0; 244 /* Tracks sequence number on stop failure message */ 245 private int mSupplicantStopFailureToken = 0; 246 247 /** 248 * Tether state change notification time out 249 */ 250 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 251 252 /* Tracks sequence number on a tether notification time out */ 253 private int mTetherToken = 0; 254 255 /** 256 * Driver start time out. 257 */ 258 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 259 260 /* Tracks sequence number on a driver time out */ 261 private int mDriverStartToken = 0; 262 263 /** 264 * The link properties of the wifi interface. 265 * Do not modify this directly; use updateLinkProperties instead. 266 */ 267 private LinkProperties mLinkProperties; 268 269 /** 270 * Subset of link properties coming from netlink. 271 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 272 * and domains obtained from router advertisements (RFC 6106). 273 */ 274 private final LinkProperties mNetlinkLinkProperties; 275 276 /* Tracks sequence number on a periodic scan message */ 277 private int mPeriodicScanToken = 0; 278 279 // Wakelock held during wifi start/stop and driver load/unload 280 private PowerManager.WakeLock mWakeLock; 281 282 private Context mContext; 283 284 private final Object mDhcpResultsLock = new Object(); 285 private DhcpResults mDhcpResults; 286 private WifiInfo mWifiInfo; 287 private NetworkInfo mNetworkInfo; 288 private NetworkCapabilities mNetworkCapabilities; 289 private SupplicantStateTracker mSupplicantStateTracker; 290 private DhcpStateMachine mDhcpStateMachine; 291 private boolean mDhcpActive = false; 292 293 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 294 295 private class InterfaceObserver extends BaseNetworkObserver { 296 private WifiStateMachine mWifiStateMachine; 297 298 InterfaceObserver(WifiStateMachine wifiStateMachine) { 299 super(); 300 mWifiStateMachine = wifiStateMachine; 301 } 302 303 private void maybeLog(String operation, String iface, LinkAddress address) { 304 if (DBG) { 305 log(operation + ": " + address + " on " + iface + 306 " flags " + address.getFlags() + " scope " + address.getScope()); 307 } 308 } 309 310 @Override 311 public void addressUpdated(String iface, LinkAddress address) { 312 if (PDBG) { 313 loge(" addressUpdated " + iface + " " + address.toString()); 314 } 315 316 if (mWifiStateMachine.mInterfaceName.equals(iface)) { 317 maybeLog("addressUpdated", iface, address); 318 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, address); 319 } 320 } 321 322 @Override 323 public void addressRemoved(String iface, LinkAddress address) { 324 if (mWifiStateMachine.mInterfaceName.equals(iface)) { 325 maybeLog("addressRemoved", iface, address); 326 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, address); 327 } 328 } 329 } 330 331 private InterfaceObserver mInterfaceObserver; 332 333 private AlarmManager mAlarmManager; 334 private PendingIntent mScanIntent; 335 private PendingIntent mDriverStopIntent; 336 private PendingIntent mBatchedScanIntervalIntent; 337 338 /* Tracks current frequency mode */ 339 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 340 341 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 342 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 343 344 // Channel for sending replies. 345 private AsyncChannel mReplyChannel = new AsyncChannel(); 346 347 private WifiP2pServiceImpl mWifiP2pServiceImpl; 348 349 // Used to initiate a connection with WifiP2pService 350 private AsyncChannel mWifiP2pChannel; 351 private AsyncChannel mWifiApConfigChannel; 352 353 private NetworkAgent mNetworkAgent; 354 355 // Used to filter out requests we couldn't possibly satisfy. 356 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 357 358 /* The base for wifi message types */ 359 static final int BASE = Protocol.BASE_WIFI; 360 /* Start the supplicant */ 361 static final int CMD_START_SUPPLICANT = BASE + 11; 362 /* Stop the supplicant */ 363 static final int CMD_STOP_SUPPLICANT = BASE + 12; 364 /* Start the driver */ 365 static final int CMD_START_DRIVER = BASE + 13; 366 /* Stop the driver */ 367 static final int CMD_STOP_DRIVER = BASE + 14; 368 /* Indicates Static IP succeeded */ 369 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 370 /* Indicates Static IP failed */ 371 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 372 /* Indicates supplicant stop failed */ 373 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 374 /* Delayed stop to avoid shutting down driver too quick*/ 375 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 376 /* A delayed message sent to start driver when it fail to come up */ 377 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 378 379 /* Start the soft access point */ 380 static final int CMD_START_AP = BASE + 21; 381 /* Indicates soft ap start succeeded */ 382 static final int CMD_START_AP_SUCCESS = BASE + 22; 383 /* Indicates soft ap start failed */ 384 static final int CMD_START_AP_FAILURE = BASE + 23; 385 /* Stop the soft access point */ 386 static final int CMD_STOP_AP = BASE + 24; 387 /* Set the soft access point configuration */ 388 static final int CMD_SET_AP_CONFIG = BASE + 25; 389 /* Soft access point configuration set completed */ 390 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 391 /* Request the soft access point configuration */ 392 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 393 /* Response to access point configuration request */ 394 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 395 /* Invoked when getting a tether state change notification */ 396 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 397 /* A delayed message sent to indicate tether state change failed to arrive */ 398 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 399 400 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 401 402 /* Supplicant commands */ 403 /* Is supplicant alive ? */ 404 static final int CMD_PING_SUPPLICANT = BASE + 51; 405 /* Add/update a network configuration */ 406 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 407 /* Delete a network */ 408 static final int CMD_REMOVE_NETWORK = BASE + 53; 409 /* Enable a network. The device will attempt a connection to the given network. */ 410 static final int CMD_ENABLE_NETWORK = BASE + 54; 411 /* Enable all networks */ 412 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 413 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 414 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 415 /* Clear the blacklist network list */ 416 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 417 /* Save configuration */ 418 static final int CMD_SAVE_CONFIG = BASE + 58; 419 /* Get configured networks */ 420 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 421 /* Get available frequencies */ 422 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 423 424 /* Supplicant commands after driver start*/ 425 /* Initiate a scan */ 426 static final int CMD_START_SCAN = BASE + 71; 427 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 428 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 429 /* Disconnect from a network */ 430 static final int CMD_DISCONNECT = BASE + 73; 431 /* Reconnect to a network */ 432 static final int CMD_RECONNECT = BASE + 74; 433 /* Reassociate to a network */ 434 static final int CMD_REASSOCIATE = BASE + 75; 435 /* Controls suspend mode optimizations 436 * 437 * When high perf mode is enabled, suspend mode optimizations are disabled 438 * 439 * When high perf mode is disabled, suspend mode optimizations are enabled 440 * 441 * Suspend mode optimizations include: 442 * - packet filtering 443 * - turn off roaming 444 * - DTIM wake up settings 445 */ 446 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 447 /* Set the country code */ 448 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 449 /* Enables RSSI poll */ 450 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 451 /* RSSI poll */ 452 static final int CMD_RSSI_POLL = BASE + 83; 453 /* Set up packet filtering */ 454 static final int CMD_START_PACKET_FILTERING = BASE + 84; 455 /* Clear packet filter */ 456 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 457 /* Enable suspend mode optimizations in the driver */ 458 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 459 /* When there are no saved networks, we do a periodic scan to notify user of 460 * an open network */ 461 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 462 463 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 464 static final int MULTICAST_V6 = 1; 465 static final int MULTICAST_V4 = 0; 466 467 /* Set the frequency band */ 468 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 469 /* Enable background scan for configured networks */ 470 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; 471 /* Enable TDLS on a specific MAC address */ 472 static final int CMD_ENABLE_TDLS = BASE + 92; 473 474 /* Commands from/to the SupplicantStateTracker */ 475 /* Reset the supplicant state tracker */ 476 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 477 478 /* P2p commands */ 479 /* We are ok with no response here since we wont do much with it anyway */ 480 public static final int CMD_ENABLE_P2P = BASE + 131; 481 /* In order to shut down supplicant cleanly, we wait till p2p has 482 * been disabled */ 483 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 484 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 485 486 public static final int CMD_BOOT_COMPLETED = BASE + 134; 487 488 /* change the batch scan settings. 489 * arg1 = responsible UID 490 * arg2 = csph (channel scans per hour) 491 * obj = bundle with the new settings and the optional worksource 492 */ 493 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 494 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 495 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 496 497 /* Link configuration (IP address, DNS, ...) changes */ 498 /* An new IP address was added to our interface, or an existing IP address was updated */ 499 static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; 500 /* An IP address was removed from our interface */ 501 static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; 502 /* Reload all networks and reconnect */ 503 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 504 505 static final int CMD_AUTO_CONNECT = BASE + 143; 506 507 /* Wifi state machine modes of operation */ 508 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 509 public static final int CONNECT_MODE = 1; 510 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 511 public static final int SCAN_ONLY_MODE = 2; 512 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 513 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 514 515 private static final int SUCCESS = 1; 516 private static final int FAILURE = -1; 517 518 /** 519 * The maximum number of times we will retry a connection to an access point 520 * for which we have failed in acquiring an IP address from DHCP. A value of 521 * N means that we will make N+1 connection attempts in all. 522 * <p> 523 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 524 * value if a Settings value is not present. 525 */ 526 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 527 528 /* Tracks if suspend optimizations need to be disabled by DHCP, 529 * screen or due to high perf mode. 530 * When any of them needs to disable it, we keep the suspend optimizations 531 * disabled 532 */ 533 private int mSuspendOptNeedsDisabled = 0; 534 535 private static final int SUSPEND_DUE_TO_DHCP = 1; 536 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 537 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 538 539 /* Tracks if user has enabled suspend optimizations through settings */ 540 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 541 542 /** 543 * Default framework scan interval in milliseconds. This is used in the scenario in which 544 * wifi chipset does not support background scanning to set up a 545 * periodic wake up scan so that the device can connect to a new access 546 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 547 * override this. 548 */ 549 private final int mDefaultFrameworkScanIntervalMs; 550 551 /** 552 * Connected state framework scan interval in milliseconds. 553 * This is used for extended roaming, when screen is lit. 554 */ 555 private int mConnectedScanPeriodMs = 20000; 556 private int mDisconnectedScanPeriodMs = 10000; 557 558 /** 559 * Supplicant scan interval in milliseconds. 560 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 561 * from the default config if the setting is not set 562 */ 563 private long mSupplicantScanIntervalMs; 564 565 /** 566 * Minimum time interval between enabling all networks. 567 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 568 * due to enabling every time. We add a threshold to avoid this. 569 */ 570 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 571 private long mLastEnableAllNetworksTime; 572 573 /** 574 * Starting and shutting down driver too quick causes problems leading to driver 575 * being in a bad state. Delay driver stop. 576 */ 577 private final int mDriverStopDelayMs; 578 private int mDelayedStopCounter; 579 private boolean mInDelayedStop = false; 580 581 // sometimes telephony gives us this data before boot is complete and we can't store it 582 // until after, so the write is deferred 583 private volatile String mPersistedCountryCode; 584 585 // Supplicant doesn't like setting the same country code multiple times (it may drop 586 // currently connected network), so we save the country code here to avoid redundency 587 private String mLastSetCountryCode; 588 589 private static final int MIN_RSSI = -200; 590 private static final int MAX_RSSI = 256; 591 592 /* Default parent state */ 593 private State mDefaultState = new DefaultState(); 594 /* Temporary initial state */ 595 private State mInitialState = new InitialState(); 596 /* Driver loaded, waiting for supplicant to start */ 597 private State mSupplicantStartingState = new SupplicantStartingState(); 598 /* Driver loaded and supplicant ready */ 599 private State mSupplicantStartedState = new SupplicantStartedState(); 600 /* Waiting for supplicant to stop and monitor to exit */ 601 private State mSupplicantStoppingState = new SupplicantStoppingState(); 602 /* Driver start issued, waiting for completed event */ 603 private State mDriverStartingState = new DriverStartingState(); 604 /* Driver started */ 605 private State mDriverStartedState = new DriverStartedState(); 606 /* Wait until p2p is disabled 607 * This is a special state which is entered right after we exit out of DriverStartedState 608 * before transitioning to another state. 609 */ 610 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 611 /* Driver stopping */ 612 private State mDriverStoppingState = new DriverStoppingState(); 613 /* Driver stopped */ 614 private State mDriverStoppedState = new DriverStoppedState(); 615 /* Scan for networks, no connection will be established */ 616 private State mScanModeState = new ScanModeState(); 617 /* Connecting to an access point */ 618 private State mConnectModeState = new ConnectModeState(); 619 /* Connected at 802.11 (L2) level */ 620 private State mL2ConnectedState = new L2ConnectedState(); 621 /* fetching IP after connection to access point (assoc+auth complete) */ 622 private State mObtainingIpState = new ObtainingIpState(); 623 /* Waiting for link quality verification to be complete */ 624 private State mVerifyingLinkState = new VerifyingLinkState(); 625 /* Connected with IP addr */ 626 private State mConnectedState = new ConnectedState(); 627 /* disconnect issued, waiting for network disconnect confirmation */ 628 private State mDisconnectingState = new DisconnectingState(); 629 /* Network is not connected, supplicant assoc+auth is not complete */ 630 private State mDisconnectedState = new DisconnectedState(); 631 /* Waiting for WPS to be completed*/ 632 private State mWpsRunningState = new WpsRunningState(); 633 634 /* Soft ap is starting up */ 635 private State mSoftApStartingState = new SoftApStartingState(); 636 /* Soft ap is running */ 637 private State mSoftApStartedState = new SoftApStartedState(); 638 /* Soft ap is running and we are waiting for tether notification */ 639 private State mTetheringState = new TetheringState(); 640 /* Soft ap is running and we are tethered through connectivity service */ 641 private State mTetheredState = new TetheredState(); 642 /* Waiting for untether confirmation before stopping soft Ap */ 643 private State mUntetheringState = new UntetheringState(); 644 645 private class TetherStateChange { 646 ArrayList<String> available; 647 ArrayList<String> active; 648 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 649 available = av; 650 active = ac; 651 } 652 } 653 654 655 /** 656 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 657 * {@link WifiManager#WIFI_STATE_DISABLING}, 658 * {@link WifiManager#WIFI_STATE_ENABLED}, 659 * {@link WifiManager#WIFI_STATE_ENABLING}, 660 * {@link WifiManager#WIFI_STATE_UNKNOWN} 661 * 662 */ 663 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 664 665 /** 666 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 667 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 668 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 669 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 670 * {@link WifiManager#WIFI_AP_STATE_FAILED} 671 * 672 */ 673 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 674 675 private static final int SCAN_REQUEST = 0; 676 private static final String ACTION_START_SCAN = 677 "com.android.server.WifiManager.action.START_SCAN"; 678 679 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 680 private static final int DRIVER_STOP_REQUEST = 0; 681 private static final String ACTION_DELAYED_DRIVER_STOP = 682 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 683 684 private static final String ACTION_REFRESH_BATCHED_SCAN = 685 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 686 /** 687 * Keep track of whether WIFI is running. 688 */ 689 private boolean mIsRunning = false; 690 691 /** 692 * Keep track of whether we last told the battery stats we had started. 693 */ 694 private boolean mReportedRunning = false; 695 696 /** 697 * Most recently set source of starting WIFI. 698 */ 699 private final WorkSource mRunningWifiUids = new WorkSource(); 700 701 /** 702 * The last reported UIDs that were responsible for starting WIFI. 703 */ 704 private final WorkSource mLastRunningWifiUids = new WorkSource(); 705 706 private final IBatteryStats mBatteryStats; 707 708 private BatchedScanSettings mBatchedScanSettings = null; 709 710 /** 711 * Track the worksource/cost of the current settings and track what's been noted 712 * to the battery stats, so we can mark the end of the previous when changing. 713 */ 714 private WorkSource mBatchedScanWorkSource = null; 715 private int mBatchedScanCsph = 0; 716 private WorkSource mNotedBatchedScanWorkSource = null; 717 private int mNotedBatchedScanCsph = 0; 718 719 private AtomicBoolean mFrameworkAutoJoin = new AtomicBoolean(true); //enable by default 720 721 public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller) { 722 super("WifiStateMachine"); 723 mContext = context; 724 mInterfaceName = wlanInterface; 725 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 726 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 727 BatteryStats.SERVICE_NAME)); 728 729 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 730 mNwService = INetworkManagementService.Stub.asInterface(b); 731 732 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 733 PackageManager.FEATURE_WIFI_DIRECT); 734 735 mWifiNative = new WifiNative(mInterfaceName); 736 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 737 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 738 mWifiConfigStore, trafficPoller, mWifiNative); 739 mWifiMonitor = new WifiMonitor(this, mWifiNative); 740 mWifiInfo = new WifiInfo(); 741 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 742 getHandler()); 743 mLinkProperties = new LinkProperties(); 744 mNetlinkLinkProperties = new LinkProperties(); 745 746 IBinder s = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 747 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s); 748 749 mNetworkInfo.setIsAvailable(false); 750 mLastBssid = null; 751 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 752 mLastSignalLevel = -1; 753 754 mInterfaceObserver = new InterfaceObserver(this); 755 try { 756 mNwService.registerObserver(mInterfaceObserver); 757 } catch (RemoteException e) { 758 loge("Couldn't register interface observer: " + e.toString()); 759 } 760 761 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 762 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 763 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 764 765 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 766 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 767 768 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 769 R.integer.config_wifi_framework_scan_interval); 770 771 mDriverStopDelayMs = mContext.getResources().getInteger( 772 R.integer.config_wifi_driver_stop_delay); 773 774 mBackgroundScanSupported = mContext.getResources().getBoolean( 775 R.bool.config_wifi_background_scan_support); 776 777 mPrimaryDeviceType = mContext.getResources().getString( 778 R.string.config_wifi_p2p_device_type); 779 780 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 781 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 782 783 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 784 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 1) == 1); 785 786 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 787 mNetworkCapabilitiesFilter.addNetworkCapability( 788 NetworkCapabilities.NET_CAPABILITY_INTERNET); 789 mNetworkCapabilitiesFilter.addNetworkCapability( 790 NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 791 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 792 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 793 // TODO - needs to be a bit more dynamic 794 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 795 796 mNetworkAgent = new NetworkAgent(getHandler().getLooper(), mContext, 797 "WifiNetworkAgent") { 798 protected void connect() { 799 if (DBG) log("WifiNetworkAgent -> reconnect wifi"); 800 setDriverStart(true); 801 reconnectCommand(); 802 } 803 protected void disconnect() { 804 if (DBG) log("WifiNetworkAgent -> Wifi disconnected"); 805 //setDriverStart(false); 806 } 807 }; 808 // TODO - this needs to be dynamic - do when we integrate with wifi selection change. 809 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 810 // TODO - this is a const value to mimic old behavior - cell is using 50, wifi trumps it. 811 // This will be replaced by constants from the NetworkScore class post integration. 812 // For now, be better than the 50 in DcTracker.java 813 mNetworkAgent.sendNetworkScore(60); 814 815 mContext.registerReceiver( 816 new BroadcastReceiver() { 817 @Override 818 public void onReceive(Context context, Intent intent) { 819 ArrayList<String> available = intent.getStringArrayListExtra( 820 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 821 ArrayList<String> active = intent.getStringArrayListExtra( 822 ConnectivityManager.EXTRA_ACTIVE_TETHER); 823 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 824 } 825 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 826 827 mContext.registerReceiver( 828 new BroadcastReceiver() { 829 @Override 830 public void onReceive(Context context, Intent intent) { 831 startScan(UNKNOWN_SCAN_SOURCE, null, null); 832 if (VDBG) 833 loge("WiFiStateMachine SCAN ALARM"); 834 } 835 }, 836 new IntentFilter(ACTION_START_SCAN)); 837 838 IntentFilter filter = new IntentFilter(); 839 filter.addAction(Intent.ACTION_SCREEN_ON); 840 filter.addAction(Intent.ACTION_SCREEN_OFF); 841 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 842 mContext.registerReceiver( 843 new BroadcastReceiver() { 844 @Override 845 public void onReceive(Context context, Intent intent) { 846 String action = intent.getAction(); 847 848 if (action.equals(Intent.ACTION_SCREEN_ON)) { 849 handleScreenStateChanged(true); 850 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 851 handleScreenStateChanged(false); 852 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 853 startNextBatchedScanAsync(); 854 } 855 } 856 }, filter); 857 858 mContext.registerReceiver( 859 new BroadcastReceiver() { 860 @Override 861 public void onReceive(Context context, Intent intent) { 862 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 863 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 864 } 865 }, 866 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 867 868 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 869 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 870 new ContentObserver(getHandler()) { 871 @Override 872 public void onChange(boolean selfChange) { 873 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 874 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 875 } 876 }); 877 878 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 879 Settings.Global.WIFI_ENHANCED_AUTO_JOIN), false, 880 new ContentObserver(getHandler()) { 881 @Override 882 public void onChange(boolean selfChange) { 883 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 884 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 0) == 1); 885 } 886 }); 887 888 mContext.registerReceiver( 889 new BroadcastReceiver() { 890 @Override 891 public void onReceive(Context context, Intent intent) { 892 sendMessage(CMD_BOOT_COMPLETED); 893 } 894 }, 895 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 896 897 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 898 899 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 900 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 901 902 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 903 mSuspendWakeLock.setReferenceCounted(false); 904 905 addState(mDefaultState); 906 addState(mInitialState, mDefaultState); 907 addState(mSupplicantStartingState, mDefaultState); 908 addState(mSupplicantStartedState, mDefaultState); 909 addState(mDriverStartingState, mSupplicantStartedState); 910 addState(mDriverStartedState, mSupplicantStartedState); 911 addState(mScanModeState, mDriverStartedState); 912 addState(mConnectModeState, mDriverStartedState); 913 addState(mL2ConnectedState, mConnectModeState); 914 addState(mObtainingIpState, mL2ConnectedState); 915 addState(mVerifyingLinkState, mL2ConnectedState); 916 addState(mConnectedState, mL2ConnectedState); 917 addState(mDisconnectingState, mConnectModeState); 918 addState(mDisconnectedState, mConnectModeState); 919 addState(mWpsRunningState, mConnectModeState); 920 addState(mWaitForP2pDisableState, mSupplicantStartedState); 921 addState(mDriverStoppingState, mSupplicantStartedState); 922 addState(mDriverStoppedState, mSupplicantStartedState); 923 addState(mSupplicantStoppingState, mDefaultState); 924 addState(mSoftApStartingState, mDefaultState); 925 addState(mSoftApStartedState, mDefaultState); 926 addState(mTetheringState, mSoftApStartedState); 927 addState(mTetheredState, mSoftApStartedState); 928 addState(mUntetheringState, mSoftApStartedState); 929 930 setInitialState(mInitialState); 931 932 setLogRecSize(2000); 933 setLogOnlyTransitions(false); 934 if (VDBG) setDbg(true); 935 936 // On molly, do not enable auto-join driven scanning while associated as this interfere 937 // with streaming. Bug: 14696701 938 String build = Build.PRODUCT; 939 if (build != null) { 940 if (build.contains("molly")) { 941 loge("Molly is there, product=" + build + ", disable associated auto-join scanning."); 942 mConnectedScanPeriodMs = 0; 943 } 944 } 945 946 //start the state machine 947 start(); 948 949 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 950 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 951 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 952 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 953 } 954 955 private int mVerboseLoggingLevel = 0; 956 957 int getVerboseLoggingLevel() { 958 return mVerboseLoggingLevel; 959 } 960 961 void enableVerboseLogging(int verbose) { 962 mVerboseLoggingLevel = verbose; 963 if (verbose > 0) { 964 DBG = true; 965 VDBG = true; 966 PDBG = true; 967 mLogMessages = true; 968 mWifiAutoJoinController.enableVerboseLogging(verbose); 969 mWifiMonitor.enableVerboseLogging(verbose); 970 mWifiNative.enableVerboseLogging(verbose); 971 } else { 972 DBG = false; 973 VDBG = false; 974 PDBG = false; 975 mLogMessages = false; 976 mWifiAutoJoinController.enableVerboseLogging(verbose); 977 mWifiMonitor.enableVerboseLogging(verbose); 978 mWifiNative.enableVerboseLogging(verbose); 979 } 980 } 981 982 /* 983 * 984 * Framework scan control 985 */ 986 987 private boolean mAlarmEnabled = false; 988 /* This is set from the overlay config file or from a secure setting. 989 * A value of 0 disables scanning in the framework. 990 */ 991 private long mFrameworkScanIntervalMs = 10000; 992 993 private long mCurrentScanAlarmMs = 10000; 994 995 996 private void setScanAlarm(boolean enabled) { 997 if (PDBG) { 998 loge("setScanAlarm " + enabled + " period " + mCurrentScanAlarmMs); 999 } 1000 if (mCurrentScanAlarmMs <= 0) enabled = false; 1001 if (enabled == mAlarmEnabled) return; 1002 if (enabled) { 1003 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 1004 System.currentTimeMillis() + mCurrentScanAlarmMs, 1005 mCurrentScanAlarmMs, 1006 mScanIntent); 1007 mAlarmEnabled = true; 1008 } else { 1009 mAlarmManager.cancel(mScanIntent); 1010 mAlarmEnabled = false; 1011 } 1012 } 1013 1014 /********************************************************* 1015 * Methods exposed for public use 1016 ********************************************************/ 1017 1018 public Messenger getMessenger() { 1019 return new Messenger(getHandler()); 1020 } 1021 1022 // STOPSHIP: temp solution before supplicant manager 1023 public WifiMonitor getMonitor() { 1024 return mWifiMonitor; 1025 } 1026 1027 /** 1028 * TODO: doc 1029 */ 1030 public boolean syncPingSupplicant(AsyncChannel channel) { 1031 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1032 boolean result = (resultMsg.arg1 != FAILURE); 1033 resultMsg.recycle(); 1034 return result; 1035 } 1036 1037 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1038 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1039 List<WifiChannel> list = null; 1040 if (resultMsg.obj != null) { 1041 list = new ArrayList<WifiChannel>(); 1042 String freqs = (String) resultMsg.obj; 1043 String[] lines = freqs.split("\n"); 1044 for (String line : lines) 1045 if (line.contains("MHz")) { 1046 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1047 WifiChannel c = new WifiChannel(); 1048 String[] prop = line.split(" "); 1049 if (prop.length < 5) continue; 1050 try { 1051 c.channelNum = Integer.parseInt(prop[1]); 1052 c.freqMHz = Integer.parseInt(prop[3]); 1053 } catch (NumberFormatException e) { } 1054 c.isDFS = line.contains("(DFS)"); 1055 list.add(c); 1056 } else if (line.contains("Mode[B] Channels:")) { 1057 // B channels are the same as G channels, skipped 1058 break; 1059 } 1060 } 1061 resultMsg.recycle(); 1062 return (list != null && list.size() > 0) ? list : null; 1063 } 1064 1065 1066 /** 1067 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1068 * given to callingUid. 1069 * 1070 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1071 * workSource is specified. 1072 * @param workSource If not null, blame is given to workSource. 1073 * @param settings Scan settings, see {@link ScanSettings}. 1074 */ 1075 public void startScan(int callingUid, ScanSettings settings, WorkSource workSource) { 1076 Bundle bundle = new Bundle(); 1077 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1078 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1079 sendMessage(CMD_START_SCAN, callingUid, 0, bundle); 1080 } 1081 1082 /** 1083 * start or stop batched scanning using the given settings 1084 */ 1085 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1086 WorkSource workSource) { 1087 Bundle bundle = new Bundle(); 1088 bundle.putParcelable(BATCHED_SETTING, settings); 1089 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1090 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1091 } 1092 1093 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1094 synchronized (mBatchedScanResults) { 1095 List<BatchedScanResult> batchedScanList = 1096 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1097 for(BatchedScanResult result: mBatchedScanResults) { 1098 batchedScanList.add(new BatchedScanResult(result)); 1099 } 1100 return batchedScanList; 1101 } 1102 } 1103 1104 public void requestBatchedScanPoll() { 1105 sendMessage(CMD_POLL_BATCHED_SCAN); 1106 } 1107 1108 private void startBatchedScan() { 1109 if (mBatchedScanSettings == null) return; 1110 1111 if (mDhcpActive) { 1112 if (DBG) log("not starting Batched Scans due to DHCP"); 1113 return; 1114 } 1115 1116 // first grab any existing data 1117 retrieveBatchedScanData(); 1118 1119 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1120 1121 1122 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1123 1124 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1125 try { 1126 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1127 setNextBatchedAlarm(mExpectedBatchedScans); 1128 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1129 } catch (NumberFormatException e) { 1130 stopBatchedScan(); 1131 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1132 } 1133 } 1134 1135 // called from BroadcastListener 1136 private void startNextBatchedScanAsync() { 1137 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1138 } 1139 1140 private void startNextBatchedScan() { 1141 // first grab any existing data 1142 retrieveBatchedScanData(); 1143 1144 setNextBatchedAlarm(mExpectedBatchedScans); 1145 } 1146 1147 private void handleBatchedScanPollRequest() { 1148 if (DBG) { 1149 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1150 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1151 mBatchedScanSettings); 1152 } 1153 // if there is no appropriate PollTime that's because we either aren't 1154 // batching or we've already set a time for a poll request 1155 if (mBatchedScanMinPollTime == 0) return; 1156 if (mBatchedScanSettings == null) return; 1157 1158 long now = System.currentTimeMillis(); 1159 1160 if (now > mBatchedScanMinPollTime) { 1161 // do the poll and reset our timers 1162 startNextBatchedScan(); 1163 } else { 1164 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1165 mBatchedScanIntervalIntent); 1166 mBatchedScanMinPollTime = 0; 1167 } 1168 } 1169 1170 // return true if new/different 1171 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1172 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1173 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1174 1175 if (DBG) { 1176 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1177 ", worksource=" + responsibleWorkSource); 1178 } 1179 if (settings != null) { 1180 if (settings.equals(mBatchedScanSettings)) return false; 1181 } else { 1182 if (mBatchedScanSettings == null) return false; 1183 } 1184 mBatchedScanSettings = settings; 1185 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1186 mBatchedScanWorkSource = responsibleWorkSource; 1187 mBatchedScanCsph = csph; 1188 return true; 1189 } 1190 1191 private void stopBatchedScan() { 1192 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1193 retrieveBatchedScanData(); 1194 mWifiNative.setBatchedScanSettings(null); 1195 noteBatchedScanStop(); 1196 } 1197 1198 private void setNextBatchedAlarm(int scansExpected) { 1199 1200 if (mBatchedScanSettings == null || scansExpected < 1) return; 1201 1202 mBatchedScanMinPollTime = System.currentTimeMillis() + 1203 mBatchedScanSettings.scanIntervalSec * 1000; 1204 1205 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1206 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1207 } 1208 1209 int secToFull = mBatchedScanSettings.scanIntervalSec; 1210 secToFull *= scansExpected; 1211 1212 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1213 if (debugPeriod > 0) secToFull = debugPeriod; 1214 1215 // set the alarm to do the next poll. We set it a little short as we'd rather 1216 // wake up wearly than miss a scan due to buffer overflow 1217 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1218 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1219 mBatchedScanIntervalIntent); 1220 } 1221 1222 /** 1223 * Start reading new scan data 1224 * Data comes in as: 1225 * "scancount=5\n" 1226 * "nextcount=5\n" 1227 * "apcount=3\n" 1228 * "trunc\n" (optional) 1229 * "bssid=...\n" 1230 * "ssid=...\n" 1231 * "freq=...\n" (in Mhz) 1232 * "level=...\n" 1233 * "dist=...\n" (in cm) 1234 * "distsd=...\n" (standard deviation, in cm) 1235 * "====" 1236 * "bssid=...\n" 1237 * etc 1238 * "====" 1239 * "bssid=...\n" 1240 * etc 1241 * "%%%%" 1242 * "apcount=2\n" 1243 * "bssid=...\n" 1244 * etc 1245 * "%%%% 1246 * etc 1247 * "----" 1248 */ 1249 private final static boolean DEBUG_PARSE = false; 1250 private void retrieveBatchedScanData() { 1251 String rawData = mWifiNative.getBatchedScanResults(); 1252 if (DEBUG_PARSE) log("rawData = " + rawData); 1253 mBatchedScanMinPollTime = 0; 1254 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1255 loge("Unexpected BatchedScanResults :" + rawData); 1256 return; 1257 } 1258 1259 int scanCount = 0; 1260 final String END_OF_BATCHES = "----"; 1261 final String SCANCOUNT = "scancount="; 1262 final String TRUNCATED = "trunc"; 1263 final String AGE = "age="; 1264 final String DIST = "dist="; 1265 final String DISTSD = "distSd="; 1266 1267 String splitData[] = rawData.split("\n"); 1268 int n = 0; 1269 if (splitData[n].startsWith(SCANCOUNT)) { 1270 try { 1271 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1272 } catch (NumberFormatException e) { 1273 loge("scancount parseInt Exception from " + splitData[n]); 1274 } 1275 } else log("scancount not found"); 1276 if (scanCount == 0) { 1277 loge("scanCount==0 - aborting"); 1278 return; 1279 } 1280 1281 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1282 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1283 1284 synchronized (mBatchedScanResults) { 1285 mBatchedScanResults.clear(); 1286 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1287 1288 String bssid = null; 1289 WifiSsid wifiSsid = null; 1290 int level = 0; 1291 int freq = 0; 1292 int dist, distSd; 1293 long tsf = 0; 1294 dist = distSd = ScanResult.UNSPECIFIED; 1295 final long now = SystemClock.elapsedRealtime(); 1296 final int bssidStrLen = BSSID_STR.length(); 1297 1298 while (true) { 1299 while (n < splitData.length) { 1300 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1301 if (splitData[n].equals(END_OF_BATCHES)) { 1302 if (n+1 != splitData.length) { 1303 loge("didn't consume " + (splitData.length-n)); 1304 } 1305 if (mBatchedScanResults.size() > 0) { 1306 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1307 } 1308 logd("retrieveBatchedScanResults X"); 1309 return; 1310 } 1311 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1312 if (bssid != null) { 1313 batchedScanResult.scanResults.add(new ScanResult( 1314 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1315 wifiSsid = null; 1316 bssid = null; 1317 level = 0; 1318 freq = 0; 1319 tsf = 0; 1320 dist = distSd = ScanResult.UNSPECIFIED; 1321 } 1322 if (splitData[n].equals(END_STR)) { 1323 if (batchedScanResult.scanResults.size() != 0) { 1324 mBatchedScanResults.add(batchedScanResult); 1325 batchedScanResult = new BatchedScanResult(); 1326 } else { 1327 logd("Found empty batch"); 1328 } 1329 } 1330 } else if (splitData[n].equals(TRUNCATED)) { 1331 batchedScanResult.truncated = true; 1332 } else if (splitData[n].startsWith(BSSID_STR)) { 1333 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1334 splitData[n].length() - bssidStrLen); 1335 } else if (splitData[n].startsWith(FREQ_STR)) { 1336 try { 1337 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1338 } catch (NumberFormatException e) { 1339 loge("Invalid freqency: " + splitData[n]); 1340 freq = 0; 1341 } 1342 } else if (splitData[n].startsWith(AGE)) { 1343 try { 1344 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1345 tsf *= 1000; // convert mS -> uS 1346 } catch (NumberFormatException e) { 1347 loge("Invalid timestamp: " + splitData[n]); 1348 tsf = 0; 1349 } 1350 } else if (splitData[n].startsWith(SSID_STR)) { 1351 wifiSsid = WifiSsid.createFromAsciiEncoded( 1352 splitData[n].substring(SSID_STR.length())); 1353 } else if (splitData[n].startsWith(LEVEL_STR)) { 1354 try { 1355 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1356 if (level > 0) level -= 256; 1357 } catch (NumberFormatException e) { 1358 loge("Invalid level: " + splitData[n]); 1359 level = 0; 1360 } 1361 } else if (splitData[n].startsWith(DIST)) { 1362 try { 1363 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1364 } catch (NumberFormatException e) { 1365 loge("Invalid distance: " + splitData[n]); 1366 dist = ScanResult.UNSPECIFIED; 1367 } 1368 } else if (splitData[n].startsWith(DISTSD)) { 1369 try { 1370 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1371 } catch (NumberFormatException e) { 1372 loge("Invalid distanceSd: " + splitData[n]); 1373 distSd = ScanResult.UNSPECIFIED; 1374 } 1375 } else { 1376 loge("Unable to parse batched scan result line: " + splitData[n]); 1377 } 1378 n++; 1379 } 1380 rawData = mWifiNative.getBatchedScanResults(); 1381 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1382 if (rawData == null) { 1383 loge("Unexpected null BatchedScanResults"); 1384 return; 1385 } 1386 splitData = rawData.split("\n"); 1387 if (splitData.length == 0 || splitData[0].equals("ok")) { 1388 loge("batch scan results just ended!"); 1389 if (mBatchedScanResults.size() > 0) { 1390 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1391 } 1392 return; 1393 } 1394 n = 0; 1395 } 1396 } 1397 } 1398 1399 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1400 private void noteScanStart(int callingUid, WorkSource workSource) { 1401 if (DBG) { 1402 long now = SystemClock.elapsedRealtimeNanos(); 1403 String ts = String.format("[%,d us]", now/1000); 1404 if (workSource != null) { 1405 loge(ts + " noteScanStart" + workSource.toString() 1406 + " uid " + Integer.toString(callingUid)); 1407 } else { 1408 loge(ts + " noteScanstart no scan source"); 1409 } 1410 } 1411 if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) { 1412 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1413 try { 1414 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1415 } catch (RemoteException e) { 1416 log(e.toString()); 1417 } 1418 } 1419 } 1420 1421 private void noteScanEnd() { 1422 if (DBG) { 1423 long now = SystemClock.elapsedRealtimeNanos(); 1424 String ts = String.format("[%,d us]", now/1000); 1425 1426 if (mScanWorkSource != null) 1427 loge(ts + " noteScanEnd " + mScanWorkSource.toString()); 1428 else 1429 loge(ts + " noteScanEnd no scan source"); 1430 } 1431 if (mScanWorkSource != null) { 1432 try { 1433 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1434 } catch (RemoteException e) { 1435 log(e.toString()); 1436 } finally { 1437 mScanWorkSource = null; 1438 } 1439 } 1440 } 1441 1442 private void noteBatchedScanStart() { 1443 if (PDBG) loge("noteBatchedScanstart()"); 1444 // note the end of a previous scan set 1445 if (mNotedBatchedScanWorkSource != null && 1446 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1447 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1448 try { 1449 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1450 } catch (RemoteException e) { 1451 log(e.toString()); 1452 } finally { 1453 mNotedBatchedScanWorkSource = null; 1454 mNotedBatchedScanCsph = 0; 1455 } 1456 } 1457 // note the start of the new 1458 try { 1459 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1460 mBatchedScanCsph); 1461 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1462 mNotedBatchedScanCsph = mBatchedScanCsph; 1463 } catch (RemoteException e) { 1464 log(e.toString()); 1465 } 1466 } 1467 1468 private void noteBatchedScanStop() { 1469 if (PDBG) loge("noteBatchedScanstop()"); 1470 1471 if (mNotedBatchedScanWorkSource != null) { 1472 try { 1473 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1474 } catch (RemoteException e) { 1475 log(e.toString()); 1476 } finally { 1477 mNotedBatchedScanWorkSource = null; 1478 mNotedBatchedScanCsph = 0; 1479 } 1480 } 1481 } 1482 1483 private void handleScanRequest(int type, Message message) { 1484 // unbundle parameters 1485 Bundle bundle = (Bundle) message.obj; 1486 ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1487 WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1488 1489 // parse scan settings 1490 String freqs = null; 1491 if (settings != null && settings.channelSet != null) { 1492 StringBuilder sb = new StringBuilder(); 1493 boolean first = true; 1494 for (WifiChannel channel : settings.channelSet) { 1495 if (!first) sb.append(','); else first = false; 1496 sb.append(channel.freqMHz); 1497 } 1498 freqs = sb.toString(); 1499 } 1500 1501 // call wifi native to start the scan 1502 if (startScanNative(type, freqs)) { 1503 // only count battery consumption if scan request is accepted 1504 noteScanStart(message.arg1, workSource); 1505 // a full scan covers everything, clearing scan request buffer 1506 if (freqs == null) 1507 mBufferedScanMsg.clear(); 1508 return; 1509 } 1510 1511 // if reach here, scan request is rejected 1512 1513 if (!mIsScanOngoing) { 1514 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 1515 // discard this request and pop up the next one 1516 if (mBufferedScanMsg.size() > 0) 1517 sendMessage(mBufferedScanMsg.remove()); 1518 } else if (!mIsFullScanOngoing) { 1519 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 1520 // buffer the scan request to make sure specified channels will be scanned eventually 1521 if (freqs == null) 1522 mBufferedScanMsg.clear(); 1523 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 1524 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1525 mBufferedScanMsg.add(msg); 1526 } else { 1527 // if too many requests in buffer, combine them into a single full scan 1528 bundle = new Bundle(); 1529 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 1530 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1531 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1532 mBufferedScanMsg.clear(); 1533 mBufferedScanMsg.add(msg); 1534 } 1535 } 1536 } 1537 1538 1539 /** return true iff scan request is accepted */ 1540 private boolean startScanNative(int type, String freqs) { 1541 if (mWifiNative.scan(type, freqs)) { 1542 mIsScanOngoing = true; 1543 mIsFullScanOngoing = (freqs == null); 1544 return true; 1545 } 1546 return false; 1547 } 1548 1549 /** 1550 * TODO: doc 1551 */ 1552 public void setSupplicantRunning(boolean enable) { 1553 if (enable) { 1554 sendMessage(CMD_START_SUPPLICANT); 1555 } else { 1556 sendMessage(CMD_STOP_SUPPLICANT); 1557 } 1558 } 1559 1560 /** 1561 * TODO: doc 1562 */ 1563 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1564 if (enable) { 1565 sendMessage(CMD_START_AP, wifiConfig); 1566 } else { 1567 sendMessage(CMD_STOP_AP); 1568 } 1569 } 1570 1571 public void setWifiApConfiguration(WifiConfiguration config) { 1572 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1573 } 1574 1575 public WifiConfiguration syncGetWifiApConfiguration() { 1576 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1577 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1578 resultMsg.recycle(); 1579 return ret; 1580 } 1581 1582 /** 1583 * TODO: doc 1584 */ 1585 public int syncGetWifiState() { 1586 return mWifiState.get(); 1587 } 1588 1589 /** 1590 * TODO: doc 1591 */ 1592 public String syncGetWifiStateByName() { 1593 switch (mWifiState.get()) { 1594 case WIFI_STATE_DISABLING: 1595 return "disabling"; 1596 case WIFI_STATE_DISABLED: 1597 return "disabled"; 1598 case WIFI_STATE_ENABLING: 1599 return "enabling"; 1600 case WIFI_STATE_ENABLED: 1601 return "enabled"; 1602 case WIFI_STATE_UNKNOWN: 1603 return "unknown state"; 1604 default: 1605 return "[invalid state]"; 1606 } 1607 } 1608 1609 /** 1610 * TODO: doc 1611 */ 1612 public int syncGetWifiApState() { 1613 return mWifiApState.get(); 1614 } 1615 1616 /** 1617 * TODO: doc 1618 */ 1619 public String syncGetWifiApStateByName() { 1620 switch (mWifiApState.get()) { 1621 case WIFI_AP_STATE_DISABLING: 1622 return "disabling"; 1623 case WIFI_AP_STATE_DISABLED: 1624 return "disabled"; 1625 case WIFI_AP_STATE_ENABLING: 1626 return "enabling"; 1627 case WIFI_AP_STATE_ENABLED: 1628 return "enabled"; 1629 case WIFI_AP_STATE_FAILED: 1630 return "failed"; 1631 default: 1632 return "[invalid state]"; 1633 } 1634 } 1635 1636 /** 1637 * Get status information for the current connection, if any. 1638 * @return a {@link WifiInfo} object containing information about the current connection 1639 * 1640 */ 1641 public WifiInfo syncRequestConnectionInfo() { 1642 return mWifiInfo; 1643 } 1644 1645 public DhcpResults syncGetDhcpResults() { 1646 synchronized (mDhcpResultsLock) { 1647 return new DhcpResults(mDhcpResults); 1648 } 1649 } 1650 1651 /** 1652 * TODO: doc 1653 */ 1654 public void setDriverStart(boolean enable) { 1655 if (enable) { 1656 sendMessage(CMD_START_DRIVER); 1657 } else { 1658 sendMessage(CMD_STOP_DRIVER); 1659 } 1660 } 1661 1662 /** 1663 * TODO: doc 1664 */ 1665 public void setOperationalMode(int mode) { 1666 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1667 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1668 } 1669 1670 /** 1671 * TODO: doc 1672 */ 1673 public List<ScanResult> syncGetScanResultsList() { 1674 synchronized (mScanResultCache) { 1675 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1676 for(ScanResult result: mScanResults) { 1677 scanList.add(new ScanResult(result)); 1678 } 1679 return scanList; 1680 } 1681 } 1682 1683 /** 1684 * Disconnect from Access Point 1685 */ 1686 public void disconnectCommand() { 1687 sendMessage(CMD_DISCONNECT); 1688 } 1689 1690 /** 1691 * Initiate a reconnection to AP 1692 */ 1693 public void reconnectCommand() { 1694 sendMessage(CMD_RECONNECT); 1695 } 1696 1697 /** 1698 * Initiate a re-association to AP 1699 */ 1700 public void reassociateCommand() { 1701 sendMessage(CMD_REASSOCIATE); 1702 } 1703 1704 /** 1705 * Reload networks and then reconnect; helps load correct data for TLS networks 1706 */ 1707 1708 public void reloadTlsNetworksAndReconnect() { 1709 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1710 } 1711 1712 /** 1713 * Add a network synchronously 1714 * 1715 * @return network id of the new network 1716 */ 1717 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1718 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1719 int result = resultMsg.arg1; 1720 resultMsg.recycle(); 1721 return result; 1722 } 1723 1724 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1725 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1726 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1727 resultMsg.recycle(); 1728 return result; 1729 } 1730 1731 /** 1732 * Delete a network 1733 * 1734 * @param networkId id of the network to be removed 1735 */ 1736 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1737 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1738 boolean result = (resultMsg.arg1 != FAILURE); 1739 resultMsg.recycle(); 1740 return result; 1741 } 1742 1743 /** 1744 * Enable a network 1745 * 1746 * @param netId network id of the network 1747 * @param disableOthers true, if all other networks have to be disabled 1748 * @return {@code true} if the operation succeeds, {@code false} otherwise 1749 */ 1750 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1751 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1752 disableOthers ? 1 : 0); 1753 boolean result = (resultMsg.arg1 != FAILURE); 1754 resultMsg.recycle(); 1755 return result; 1756 } 1757 1758 /** 1759 * Disable a network 1760 * 1761 * @param netId network id of the network 1762 * @return {@code true} if the operation succeeds, {@code false} otherwise 1763 */ 1764 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1765 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1766 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1767 resultMsg.recycle(); 1768 return result; 1769 } 1770 1771 /** 1772 * Retrieves a WPS-NFC configuration token for the specified network 1773 * @return a hex string representation of the WPS-NFC configuration token 1774 */ 1775 public String syncGetWpsNfcConfigurationToken(int netId) { 1776 return mWifiNative.getNfcWpsConfigurationToken(netId); 1777 } 1778 1779 /** 1780 * Blacklist a BSSID. This will avoid the AP if there are 1781 * alternate APs to connect 1782 * 1783 * @param bssid BSSID of the network 1784 */ 1785 public void addToBlacklist(String bssid) { 1786 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1787 } 1788 1789 /** 1790 * Clear the blacklist list 1791 * 1792 */ 1793 public void clearBlacklist() { 1794 sendMessage(CMD_CLEAR_BLACKLIST); 1795 } 1796 1797 public void enableRssiPolling(boolean enabled) { 1798 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1799 } 1800 1801 public void enableBackgroundScanCommand(boolean enabled) { 1802 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1803 } 1804 1805 public void enableAllNetworks() { 1806 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1807 } 1808 1809 /** 1810 * Start filtering Multicast v4 packets 1811 */ 1812 public void startFilteringMulticastV4Packets() { 1813 mFilteringMulticastV4Packets.set(true); 1814 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1815 } 1816 1817 /** 1818 * Stop filtering Multicast v4 packets 1819 */ 1820 public void stopFilteringMulticastV4Packets() { 1821 mFilteringMulticastV4Packets.set(false); 1822 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1823 } 1824 1825 /** 1826 * Start filtering Multicast v4 packets 1827 */ 1828 public void startFilteringMulticastV6Packets() { 1829 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1830 } 1831 1832 /** 1833 * Stop filtering Multicast v4 packets 1834 */ 1835 public void stopFilteringMulticastV6Packets() { 1836 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1837 } 1838 1839 /** 1840 * Set high performance mode of operation. 1841 * Enabling would set active power mode and disable suspend optimizations; 1842 * disabling would set auto power mode and enable suspend optimizations 1843 * @param enable true if enable, false otherwise 1844 */ 1845 public void setHighPerfModeEnabled(boolean enable) { 1846 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1847 } 1848 1849 /** 1850 * Set the country code 1851 * @param countryCode following ISO 3166 format 1852 * @param persist {@code true} if the setting should be remembered. 1853 */ 1854 public void setCountryCode(String countryCode, boolean persist) { 1855 // If it's a good country code, apply after the current 1856 // wifi connection is terminated; ignore resetting of code 1857 // for now (it is unclear what the chipset should do when 1858 // country code is reset) 1859 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1860 if (TextUtils.isEmpty(countryCode)) { 1861 log("Ignoring resetting of country code"); 1862 } else { 1863 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1864 } 1865 } 1866 1867 /** 1868 * Set the operational frequency band 1869 * @param band 1870 * @param persist {@code true} if the setting should be remembered. 1871 */ 1872 public void setFrequencyBand(int band, boolean persist) { 1873 if (persist) { 1874 Settings.Global.putInt(mContext.getContentResolver(), 1875 Settings.Global.WIFI_FREQUENCY_BAND, 1876 band); 1877 } 1878 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 1879 } 1880 1881 /** 1882 * Enable TDLS for a specific MAC address 1883 */ 1884 public void enableTdls(String remoteMacAddress, boolean enable) { 1885 int enabler = enable ? 1 : 0; 1886 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 1887 } 1888 1889 /** 1890 * Returns the operational frequency band 1891 */ 1892 public int getFrequencyBand() { 1893 return mFrequencyBand.get(); 1894 } 1895 1896 /** 1897 * Returns the wifi configuration file 1898 */ 1899 public String getConfigFile() { 1900 return mWifiConfigStore.getConfigFile(); 1901 } 1902 1903 /** 1904 * Send a message indicating bluetooth adapter connection state changed 1905 */ 1906 public void sendBluetoothAdapterStateChange(int state) { 1907 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 1908 } 1909 1910 /** 1911 * Save configuration on supplicant 1912 * 1913 * @return {@code true} if the operation succeeds, {@code false} otherwise 1914 * 1915 * TODO: deprecate this 1916 */ 1917 public boolean syncSaveConfig(AsyncChannel channel) { 1918 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 1919 boolean result = (resultMsg.arg1 != FAILURE); 1920 resultMsg.recycle(); 1921 return result; 1922 } 1923 1924 public void updateBatteryWorkSource(WorkSource newSource) { 1925 synchronized (mRunningWifiUids) { 1926 try { 1927 if (newSource != null) { 1928 mRunningWifiUids.set(newSource); 1929 } 1930 if (mIsRunning) { 1931 if (mReportedRunning) { 1932 // If the work source has changed since last time, need 1933 // to remove old work from battery stats. 1934 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 1935 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 1936 mRunningWifiUids); 1937 mLastRunningWifiUids.set(mRunningWifiUids); 1938 } 1939 } else { 1940 // Now being started, report it. 1941 mBatteryStats.noteWifiRunning(mRunningWifiUids); 1942 mLastRunningWifiUids.set(mRunningWifiUids); 1943 mReportedRunning = true; 1944 } 1945 } else { 1946 if (mReportedRunning) { 1947 // Last reported we were running, time to stop. 1948 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 1949 mLastRunningWifiUids.clear(); 1950 mReportedRunning = false; 1951 } 1952 } 1953 mWakeLock.setWorkSource(newSource); 1954 } catch (RemoteException ignore) { 1955 } 1956 } 1957 } 1958 1959 @Override 1960 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1961 super.dump(fd, pw, args); 1962 mSupplicantStateTracker.dump(fd, pw, args); 1963 pw.println("mLinkProperties " + mLinkProperties); 1964 pw.println("mWifiInfo " + mWifiInfo); 1965 pw.println("mDhcpResults " + mDhcpResults); 1966 pw.println("mNetworkInfo " + mNetworkInfo); 1967 pw.println("mLastSignalLevel " + mLastSignalLevel); 1968 pw.println("mLastBssid " + mLastBssid); 1969 pw.println("mLastNetworkId " + mLastNetworkId); 1970 pw.println("mReconnectCount " + mReconnectCount); 1971 pw.println("mOperationalMode " + mOperationalMode); 1972 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 1973 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1974 pw.println("Supplicant status " + mWifiNative.status()); 1975 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 1976 pw.println("mLastSetCountryCode " + mLastSetCountryCode); 1977 pw.println("mPersistedCountryCode " + mPersistedCountryCode); 1978 pw.println(); 1979 mWifiConfigStore.dump(fd, pw, args); 1980 } 1981 1982 /********************************************************* 1983 * Internal private functions 1984 ********************************************************/ 1985 1986 private void logStateAndMessage(Message message, String state) { 1987 if (mLogMessages) { 1988 //long now = SystemClock.elapsedRealtimeNanos(); 1989 //String ts = String.format("[%,d us]", now/1000); 1990 1991 loge(/*ts + " " + */this.getClass().getSimpleName() 1992 + "state:" + state + " what:" + Integer.toString(message.what, 16) 1993 + " " + smToString(message) + " "); 1994 } 1995 } 1996 1997 private void handleScreenStateChanged(boolean screenOn) { 1998 mScreenOn = screenOn; 1999 if (PDBG) { 2000 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 2001 + "mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) 2002 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 2003 + " autojoin " + mFrameworkAutoJoin 2004 + " state " + getCurrentState().getName() 2005 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 2006 } 2007 enableRssiPolling(screenOn); 2008 if (mBackgroundScanSupported) { 2009 enableBackgroundScanCommand(screenOn == false); 2010 } 2011 2012 if (screenOn) enableAllNetworks(); 2013 if (mUserWantsSuspendOpt.get()) { 2014 if (screenOn) { 2015 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 2016 } else { 2017 //Allow 2s for suspend optimizations to be set 2018 mSuspendWakeLock.acquire(2000); 2019 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 2020 } 2021 } 2022 mScreenBroadcastReceived.set(true); 2023 2024 if (screenOn) { 2025 if (mFrameworkAutoJoin.get()) { 2026 //start the scan alarm so as to enable autojoin 2027 if (getCurrentState() == mConnectedState) { 2028 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 2029 } else if (getCurrentState() == mDisconnectedState) { 2030 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2031 //kick a scan right now 2032 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2033 } else if (getCurrentState() == mDisconnectingState) { 2034 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2035 //kick a scan right now 2036 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2037 } 2038 } 2039 setScanAlarm(true); 2040 2041 } else { 2042 setScanAlarm(false); 2043 } 2044 2045 2046 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 2047 2048 } 2049 2050 private void checkAndSetConnectivityInstance() { 2051 if (mCm == null) { 2052 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 2053 } 2054 } 2055 2056 private boolean startTethering(ArrayList<String> available) { 2057 2058 boolean wifiAvailable = false; 2059 2060 checkAndSetConnectivityInstance(); 2061 2062 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2063 2064 for (String intf : available) { 2065 for (String regex : wifiRegexs) { 2066 if (intf.matches(regex)) { 2067 2068 InterfaceConfiguration ifcg = null; 2069 try { 2070 ifcg = mNwService.getInterfaceConfig(intf); 2071 if (ifcg != null) { 2072 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 2073 ifcg.setLinkAddress(new LinkAddress( 2074 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 2075 ifcg.setInterfaceUp(); 2076 2077 mNwService.setInterfaceConfig(intf, ifcg); 2078 } 2079 } catch (Exception e) { 2080 loge("Error configuring interface " + intf + ", :" + e); 2081 return false; 2082 } 2083 2084 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2085 loge("Error tethering on " + intf); 2086 return false; 2087 } 2088 mTetherInterfaceName = intf; 2089 return true; 2090 } 2091 } 2092 } 2093 // We found no interfaces to tether 2094 return false; 2095 } 2096 2097 private void stopTethering() { 2098 2099 checkAndSetConnectivityInstance(); 2100 2101 /* Clear the interface config to allow dhcp correctly configure new 2102 ip settings */ 2103 InterfaceConfiguration ifcg = null; 2104 try { 2105 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 2106 if (ifcg != null) { 2107 ifcg.setLinkAddress( 2108 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 2109 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 2110 } 2111 } catch (Exception e) { 2112 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 2113 } 2114 2115 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2116 loge("Untether initiate failed!"); 2117 } 2118 } 2119 2120 private boolean isWifiTethered(ArrayList<String> active) { 2121 2122 checkAndSetConnectivityInstance(); 2123 2124 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2125 for (String intf : active) { 2126 for (String regex : wifiRegexs) { 2127 if (intf.matches(regex)) { 2128 return true; 2129 } 2130 } 2131 } 2132 // We found no interfaces that are tethered 2133 return false; 2134 } 2135 2136 /** 2137 * Set the country code from the system setting value, if any. 2138 */ 2139 private void setCountryCode() { 2140 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2141 Settings.Global.WIFI_COUNTRY_CODE); 2142 if (countryCode != null && !countryCode.isEmpty()) { 2143 setCountryCode(countryCode, false); 2144 } else { 2145 //use driver default 2146 } 2147 } 2148 2149 /** 2150 * Set the frequency band from the system setting value, if any. 2151 */ 2152 private void setFrequencyBand() { 2153 int band = Settings.Global.getInt(mContext.getContentResolver(), 2154 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 2155 setFrequencyBand(band, false); 2156 } 2157 2158 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 2159 if (DBG) { 2160 log("setSuspendOptimizationsNative: " + reason + " " + enabled 2161 + " -want " + mUserWantsSuspendOpt.get() 2162 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2163 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2164 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2165 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2166 } 2167 mWifiNative.setSuspendOptimizations(enabled); 2168 2169 if (enabled) { 2170 mSuspendOptNeedsDisabled &= ~reason; 2171 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 2172 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 2173 if (DBG) { 2174 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 2175 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2176 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2177 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2178 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2179 } 2180 mWifiNative.setSuspendOptimizations(true); 2181 } 2182 } else { 2183 mSuspendOptNeedsDisabled |= reason; 2184 mWifiNative.setSuspendOptimizations(false); 2185 } 2186 } 2187 2188 private void setSuspendOptimizations(int reason, boolean enabled) { 2189 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 2190 if (enabled) { 2191 mSuspendOptNeedsDisabled &= ~reason; 2192 } else { 2193 mSuspendOptNeedsDisabled |= reason; 2194 } 2195 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2196 } 2197 2198 private void setWifiState(int wifiState) { 2199 final int previousWifiState = mWifiState.get(); 2200 2201 try { 2202 if (wifiState == WIFI_STATE_ENABLED) { 2203 mBatteryStats.noteWifiOn(); 2204 } else if (wifiState == WIFI_STATE_DISABLED) { 2205 mBatteryStats.noteWifiOff(); 2206 } 2207 } catch (RemoteException e) { 2208 loge("Failed to note battery stats in wifi"); 2209 } 2210 2211 mWifiState.set(wifiState); 2212 2213 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 2214 2215 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 2216 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2217 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 2218 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 2219 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2220 } 2221 2222 private void setWifiApState(int wifiApState) { 2223 final int previousWifiApState = mWifiApState.get(); 2224 2225 try { 2226 if (wifiApState == WIFI_AP_STATE_ENABLED) { 2227 mBatteryStats.noteWifiOn(); 2228 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 2229 mBatteryStats.noteWifiOff(); 2230 } 2231 } catch (RemoteException e) { 2232 loge("Failed to note battery stats in wifi"); 2233 } 2234 2235 // Update state 2236 mWifiApState.set(wifiApState); 2237 2238 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 2239 2240 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 2241 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2242 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 2243 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 2244 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2245 } 2246 2247 private static final String ID_STR = "id="; 2248 private static final String BSSID_STR = "bssid="; 2249 private static final String FREQ_STR = "freq="; 2250 private static final String LEVEL_STR = "level="; 2251 private static final String TSF_STR = "tsf="; 2252 private static final String FLAGS_STR = "flags="; 2253 private static final String SSID_STR = "ssid="; 2254 private static final String DELIMITER_STR = "===="; 2255 private static final String END_STR = "####"; 2256 2257 /** 2258 * Format: 2259 * 2260 * id=1 2261 * bssid=68:7f:76:d7:1a:6e 2262 * freq=2412 2263 * level=-44 2264 * tsf=1344626243700342 2265 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2266 * ssid=zfdy 2267 * ==== 2268 * id=2 2269 * bssid=68:5f:74:d7:1a:6f 2270 * freq=5180 2271 * level=-73 2272 * tsf=1344626243700373 2273 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2274 * ssid=zuby 2275 * ==== 2276 */ 2277 private void setScanResults() { 2278 String bssid = ""; 2279 int level = 0; 2280 int freq = 0; 2281 long tsf = 0; 2282 String flags = ""; 2283 WifiSsid wifiSsid = null; 2284 String scanResults; 2285 String tmpResults; 2286 StringBuffer scanResultsBuf = new StringBuffer(); 2287 int sid = 0; 2288 2289 while (true) { 2290 tmpResults = mWifiNative.scanResults(sid); 2291 if (TextUtils.isEmpty(tmpResults)) break; 2292 scanResultsBuf.append(tmpResults); 2293 scanResultsBuf.append("\n"); 2294 String[] lines = tmpResults.split("\n"); 2295 sid = -1; 2296 for (int i=lines.length - 1; i >= 0; i--) { 2297 if (lines[i].startsWith(END_STR)) { 2298 break; 2299 } else if (lines[i].startsWith(ID_STR)) { 2300 try { 2301 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 2302 } catch (NumberFormatException e) { 2303 // Nothing to do 2304 } 2305 break; 2306 } 2307 } 2308 if (sid == -1) break; 2309 } 2310 2311 scanResults = scanResultsBuf.toString(); 2312 if (TextUtils.isEmpty(scanResults)) { 2313 return; 2314 } 2315 2316 // note that all these splits and substrings keep references to the original 2317 // huge string buffer while the amount we really want is generally pretty small 2318 // so make copies instead (one example b/11087956 wasted 400k of heap here). 2319 synchronized(mScanResultCache) { 2320 mScanResults = new ArrayList<ScanResult>(); 2321 String[] lines = scanResults.split("\n"); 2322 final int bssidStrLen = BSSID_STR.length(); 2323 final int flagLen = FLAGS_STR.length(); 2324 2325 for (String line : lines) { 2326 if (line.startsWith(BSSID_STR)) { 2327 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 2328 } else if (line.startsWith(FREQ_STR)) { 2329 try { 2330 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 2331 } catch (NumberFormatException e) { 2332 freq = 0; 2333 } 2334 } else if (line.startsWith(LEVEL_STR)) { 2335 try { 2336 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 2337 /* some implementations avoid negative values by adding 256 2338 * so we need to adjust for that here. 2339 */ 2340 if (level > 0) level -= 256; 2341 } catch(NumberFormatException e) { 2342 level = 0; 2343 } 2344 } else if (line.startsWith(TSF_STR)) { 2345 try { 2346 tsf = Long.parseLong(line.substring(TSF_STR.length())); 2347 } catch (NumberFormatException e) { 2348 tsf = 0; 2349 } 2350 } else if (line.startsWith(FLAGS_STR)) { 2351 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 2352 } else if (line.startsWith(SSID_STR)) { 2353 wifiSsid = WifiSsid.createFromAsciiEncoded( 2354 line.substring(SSID_STR.length())); 2355 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 2356 if (bssid != null) { 2357 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 2358 String key = bssid + ssid; 2359 ScanResult scanResult = mScanResultCache.get(key); 2360 if (scanResult != null) { 2361 scanResult.level = level; 2362 scanResult.wifiSsid = wifiSsid; 2363 // Keep existing API 2364 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 2365 WifiSsid.NONE; 2366 scanResult.capabilities = flags; 2367 scanResult.frequency = freq; 2368 scanResult.timestamp = tsf; 2369 scanResult.seen = System.currentTimeMillis(); 2370 } else { 2371 scanResult = 2372 new ScanResult( 2373 wifiSsid, bssid, flags, level, freq, tsf); 2374 mScanResultCache.put(key, scanResult); 2375 } 2376 mScanResults.add(scanResult); 2377 } 2378 bssid = null; 2379 level = 0; 2380 freq = 0; 2381 tsf = 0; 2382 flags = ""; 2383 wifiSsid = null; 2384 } 2385 } 2386 } 2387 if (mFrameworkAutoJoin.get() == true) 2388 mWifiAutoJoinController.newSupplicantResults(); 2389 2390 } 2391 2392 /* 2393 * Fetch RSSI, linkspeed, and frequency on current connection 2394 */ 2395 private void fetchRssiLinkSpeedAndFrequencyNative() { 2396 int newRssi = -1; 2397 int newLinkSpeed = -1; 2398 int newFrequency = -1; 2399 2400 String signalPoll = mWifiNative.signalPoll(); 2401 2402 if (signalPoll != null) { 2403 String[] lines = signalPoll.split("\n"); 2404 for (String line : lines) { 2405 String[] prop = line.split("="); 2406 if (prop.length < 2) continue; 2407 try { 2408 if (prop[0].equals("RSSI")) { 2409 newRssi = Integer.parseInt(prop[1]); 2410 } else if (prop[0].equals("LINKSPEED")) { 2411 newLinkSpeed = Integer.parseInt(prop[1]); 2412 } else if (prop[0].equals("FREQUENCY")) { 2413 newFrequency = Integer.parseInt(prop[1]); 2414 } 2415 } catch (NumberFormatException e) { 2416 //Ignore, defaults on rssi and linkspeed are assigned 2417 } 2418 } 2419 } 2420 2421 if (PDBG) { 2422 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 2423 + Integer.toString(newRssi) + " linkspeed=" 2424 + Integer.toString(newLinkSpeed)); 2425 } 2426 2427 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values 2428 /* some implementations avoid negative values by adding 256 2429 * so we need to adjust for that here. 2430 */ 2431 if (newRssi > 0) newRssi -= 256; 2432 mWifiInfo.setRssi(newRssi); 2433 /* 2434 * Rather then sending the raw RSSI out every time it 2435 * changes, we precalculate the signal level that would 2436 * be displayed in the status bar, and only send the 2437 * broadcast if that much more coarse-grained number 2438 * changes. This cuts down greatly on the number of 2439 * broadcasts, at the cost of not informing others 2440 * interested in RSSI of all the changes in signal 2441 * level. 2442 */ 2443 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2444 if (newSignalLevel != mLastSignalLevel) { 2445 sendRssiChangeBroadcast(newRssi); 2446 } 2447 mLastSignalLevel = newSignalLevel; 2448 } else { 2449 mWifiInfo.setRssi(MIN_RSSI); 2450 } 2451 2452 if (newLinkSpeed != -1) { 2453 mWifiInfo.setLinkSpeed(newLinkSpeed); 2454 } 2455 if (newFrequency > 0) { 2456 mWifiInfo.setFrequency(newFrequency); 2457 } 2458 } 2459 2460 /* 2461 * Fetch TX packet counters on current connection 2462 */ 2463 private void fetchPktcntNative(RssiPacketCountInfo info) { 2464 String pktcntPoll = mWifiNative.pktcntPoll(); 2465 2466 if (pktcntPoll != null) { 2467 String[] lines = pktcntPoll.split("\n"); 2468 for (String line : lines) { 2469 String[] prop = line.split("="); 2470 if (prop.length < 2) continue; 2471 try { 2472 if (prop[0].equals("TXGOOD")) { 2473 info.txgood = Integer.parseInt(prop[1]); 2474 } else if (prop[0].equals("TXBAD")) { 2475 info.txbad = Integer.parseInt(prop[1]); 2476 } 2477 } catch (NumberFormatException e) { 2478 //Ignore 2479 } 2480 } 2481 } 2482 } 2483 2484 /** 2485 * Updates mLinkProperties by merging information from various sources. 2486 * 2487 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 2488 * netlink, static configuration, ...). When one of these sources of information has updated 2489 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 2490 * information that came from other sources. Instead, when one of those sources has new 2491 * information, we update the object that tracks the information from that source and then 2492 * call this method to apply the change to mLinkProperties. 2493 * 2494 * The information in mLinkProperties is currently obtained as follows: 2495 * - Interface name: set in the constructor. 2496 * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver. 2497 * - IPv4 routes, DNS servers, and domains: DHCP. 2498 * - HTTP proxy: the wifi config store. 2499 */ 2500 private void updateLinkProperties() { 2501 LinkProperties newLp = new LinkProperties(); 2502 2503 // Interface name and proxy are locally configured. 2504 newLp.setInterfaceName(mInterfaceName); 2505 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 2506 2507 // IPv4 and IPv6 addresses come from netlink. 2508 newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses()); 2509 2510 // For now, routing and DNS only come from DHCP or static configuration. In the future, 2511 // we'll need to merge IPv6 DNS servers and domains coming from netlink. 2512 synchronized (mDhcpResultsLock) { 2513 // Even when we're using static configuration, we don't need to look at the config 2514 // store, because static IP configuration also populates mDhcpResults. 2515 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 2516 LinkProperties lp = mDhcpResults.linkProperties; 2517 for (RouteInfo route: lp.getRoutes()) { 2518 newLp.addRoute(route); 2519 } 2520 for (InetAddress dns: lp.getDnses()) { 2521 newLp.addDns(dns); 2522 } 2523 newLp.setDomains(lp.getDomains()); 2524 } 2525 } 2526 2527 // If anything has changed, and we're already connected, send out a notification. 2528 // If we're still connecting, apps will be notified when we connect. 2529 if (!newLp.equals(mLinkProperties)) { 2530 if (DBG) { 2531 log("Link configuration changed for netId: " + mLastNetworkId 2532 + " old: " + mLinkProperties + "new: " + newLp); 2533 } 2534 mLinkProperties = newLp; 2535 mNetworkAgent.sendLinkProperties(mLinkProperties); 2536 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 2537 sendLinkConfigurationChangedBroadcast(); 2538 } 2539 } 2540 } 2541 /** 2542 * Clears all our link properties. 2543 */ 2544 private void clearLinkProperties() { 2545 // If the network used DHCP, clear the LinkProperties we stored in the config store. 2546 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 2547 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 2548 } 2549 2550 // Clear the link properties obtained from DHCP and netlink. 2551 synchronized(mDhcpResultsLock) { 2552 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 2553 mDhcpResults.linkProperties.clear(); 2554 } 2555 } 2556 mNetlinkLinkProperties.clear(); 2557 2558 // Now clear the merged link properties. 2559 mLinkProperties.clear(); 2560 mNetworkAgent.sendLinkProperties(mLinkProperties); 2561 } 2562 2563 /** 2564 * try to update default route MAC address. 2565 */ 2566 private String updateDefaultRouteMacAddress(int timeout) { 2567 String address = null; 2568 2569 for (RouteInfo route: mLinkProperties.getRoutes()) { 2570 if (route.isDefaultRoute() && route.hasGateway()) { 2571 InetAddress gateway = route.getGateway(); 2572 2573 if (gateway instanceof Inet4Address) { 2574 if (PDBG) { 2575 loge("updateDefaultRouteMacAddress found Ipv4 default :" 2576 + gateway.getHostAddress()); 2577 } 2578 address = macAddressFromRoute(gateway.getHostAddress()); 2579 /* the gateway's MAC address is known */ 2580 if ((address == null) && (timeout > 0)) { 2581 boolean reachable = false; 2582 try { 2583 reachable = gateway.isReachable(timeout); 2584 } catch (Exception e) { 2585 loge("updateDefaultRouteMacAddress exception reaching :" 2586 + gateway.getHostAddress()); 2587 2588 } finally { 2589 if (reachable == true) { 2590 2591 address = macAddressFromRoute(gateway.getHostAddress()); 2592 if(PDBG) { 2593 loge("updateDefaultRouteMacAddress reachable (tried again) :" 2594 + gateway.getHostAddress() + " found " + address); 2595 } 2596 } 2597 } 2598 } 2599 if (address != null) { 2600 mWifiConfigStore.setLinkProperties(mLastNetworkId, 2601 new LinkProperties(mLinkProperties)); 2602 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 2603 2604 } 2605 } 2606 } 2607 } 2608 return address; 2609 } 2610 2611 private int getMaxDhcpRetries() { 2612 return Settings.Global.getInt(mContext.getContentResolver(), 2613 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 2614 DEFAULT_MAX_DHCP_RETRIES); 2615 } 2616 2617 private void sendScanResultsAvailableBroadcast() { 2618 noteScanEnd(); 2619 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 2620 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2621 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2622 } 2623 2624 private void sendRssiChangeBroadcast(final int newRssi) { 2625 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 2626 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2627 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 2628 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2629 } 2630 2631 private void sendNetworkStateChangeBroadcast(String bssid) { 2632 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 2633 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2634 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2635 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 2636 if (bssid != null) 2637 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 2638 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 2639 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 2640 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 2641 } 2642 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2643 } 2644 2645 private void sendLinkConfigurationChangedBroadcast() { 2646 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 2647 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2648 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 2649 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2650 } 2651 2652 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 2653 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 2654 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2655 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 2656 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2657 } 2658 2659 /** 2660 * Record the detailed state of a network. 2661 * @param state the new {@code DetailedState} 2662 */ 2663 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 2664 if (DBG) { 2665 log("setDetailed state, old =" 2666 + mNetworkInfo.getDetailedState() + " and new state=" + state); 2667 } 2668 2669 if (state != mNetworkInfo.getDetailedState()) { 2670 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 2671 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 2672 } 2673 } 2674 2675 private DetailedState getNetworkDetailedState() { 2676 return mNetworkInfo.getDetailedState(); 2677 } 2678 2679 2680 private SupplicantState handleSupplicantStateChange(Message message) { 2681 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2682 SupplicantState state = stateChangeResult.state; 2683 // Supplicant state change 2684 // [31-13] Reserved for future use 2685 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2686 // 50023 supplicant_state_changed (custom|1|5) 2687 mWifiInfo.setSupplicantState(state); 2688 // Network id is only valid when we start connecting 2689 if (SupplicantState.isConnecting(state)) { 2690 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2691 } else { 2692 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2693 } 2694 2695 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2696 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 2697 2698 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 2699 2700 return state; 2701 } 2702 2703 /** 2704 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 2705 * using the interface, stopping DHCP & disabling interface 2706 */ 2707 private void handleNetworkDisconnect() { 2708 if (DBG) log("Stopping DHCP and clearing IP"); 2709 2710 stopDhcp(); 2711 2712 try { 2713 mNwService.clearInterfaceAddresses(mInterfaceName); 2714 mNwService.disableIpv6(mInterfaceName); 2715 } catch (Exception e) { 2716 loge("Failed to clear addresses or disable ipv6" + e); 2717 } 2718 2719 /* Reset data structures */ 2720 // TODO: use a WifiInfo.reset(), although it would require moving the 2721 // MIN_RSSI to WifiInfo. 2722 mWifiInfo.setInetAddress(null); 2723 mWifiInfo.setBSSID(null); 2724 mWifiInfo.setSSID(null); 2725 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2726 mWifiInfo.setRssi(MIN_RSSI); 2727 mWifiInfo.setLinkSpeed(-1); 2728 mWifiInfo.setFrequency(-1); 2729 mWifiInfo.setMeteredHint(false); 2730 2731 setNetworkDetailedState(DetailedState.DISCONNECTED); 2732 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 2733 2734 /* Clear network properties */ 2735 clearLinkProperties(); 2736 2737 /* send event to CM & network change broadcast */ 2738 sendNetworkStateChangeBroadcast(mLastBssid); 2739 2740 mLastBssid= null; 2741 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2742 } 2743 2744 private void handleSupplicantConnectionLoss() { 2745 /* Socket connection can be lost when we do a graceful shutdown 2746 * or when the driver is hung. Ensure supplicant is stopped here. 2747 */ 2748 mWifiMonitor.killSupplicant(mP2pSupported); 2749 mWifiNative.closeSupplicantConnection(); 2750 sendSupplicantConnectionChangedBroadcast(false); 2751 setWifiState(WIFI_STATE_DISABLED); 2752 } 2753 2754 void handlePreDhcpSetup() { 2755 mDhcpActive = true; 2756 if (!mBluetoothConnectionActive) { 2757 /* 2758 * There are problems setting the Wi-Fi driver's power 2759 * mode to active when bluetooth coexistence mode is 2760 * enabled or sense. 2761 * <p> 2762 * We set Wi-Fi to active mode when 2763 * obtaining an IP address because we've found 2764 * compatibility issues with some routers with low power 2765 * mode. 2766 * <p> 2767 * In order for this active power mode to properly be set, 2768 * we disable coexistence mode until we're done with 2769 * obtaining an IP address. One exception is if we 2770 * are currently connected to a headset, since disabling 2771 * coexistence would interrupt that connection. 2772 */ 2773 // Disable the coexistence mode 2774 mWifiNative.setBluetoothCoexistenceMode( 2775 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2776 } 2777 2778 /* Disable power save and suspend optimizations during DHCP */ 2779 // Note: The order here is important for now. Brcm driver changes 2780 // power settings when we control suspend mode optimizations. 2781 // TODO: Remove this comment when the driver is fixed. 2782 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 2783 mWifiNative.setPowerSave(false); 2784 2785 stopBatchedScan(); 2786 2787 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 2788 Message msg = new Message(); 2789 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 2790 msg.arg1 = WifiP2pServiceImpl.ENABLED; 2791 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 2792 msg.obj = mDhcpStateMachine; 2793 mWifiP2pChannel.sendMessage(msg); 2794 } 2795 2796 2797 void startDhcp() { 2798 if (mDhcpStateMachine == null) { 2799 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 2800 mContext, WifiStateMachine.this, mInterfaceName); 2801 2802 } 2803 mDhcpStateMachine.registerForPreDhcpNotification(); 2804 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 2805 } 2806 2807 void stopDhcp() { 2808 if (mDhcpStateMachine != null) { 2809 /* In case we were in middle of DHCP operation restore back powermode */ 2810 handlePostDhcpSetup(); 2811 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 2812 } 2813 } 2814 2815 void handlePostDhcpSetup() { 2816 /* Restore power save and suspend optimizations */ 2817 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 2818 mWifiNative.setPowerSave(true); 2819 2820 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 2821 2822 // Set the coexistence mode back to its default value 2823 mWifiNative.setBluetoothCoexistenceMode( 2824 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 2825 2826 mDhcpActive = false; 2827 2828 startBatchedScan(); 2829 } 2830 2831 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { 2832 2833 if (PDBG) { 2834 loge("handleSuccessfulIpConfiguration <" + dhcpResults.toString() 2835 + "> linkaddress num " + dhcpResults.linkProperties.getLinkAddresses().size()); 2836 for (LinkAddress linkAddress : dhcpResults.linkProperties.getLinkAddresses()) { 2837 loge("link address " + linkAddress.toString()); 2838 } 2839 } 2840 2841 mLastSignalLevel = -1; // force update of signal strength 2842 mReconnectCount = 0; //Reset IP failure tracking 2843 synchronized (mDhcpResultsLock) { 2844 mDhcpResults = dhcpResults; 2845 } 2846 LinkProperties linkProperties = dhcpResults.linkProperties; 2847 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 2848 InetAddress addr = null; 2849 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 2850 if (addrs.hasNext()) { 2851 addr = addrs.next(); 2852 } 2853 mWifiInfo.setInetAddress(addr); 2854 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 2855 updateLinkProperties(); 2856 } 2857 2858 private void handleFailedIpConfiguration() { 2859 2860 mWifiInfo.setInetAddress(null); 2861 mWifiInfo.setMeteredHint(false); 2862 /** 2863 * If we've exceeded the maximum number of retries for DHCP 2864 * to a given network, disable the network 2865 */ 2866 int maxRetries = getMaxDhcpRetries(); 2867 // maxRetries == 0 means keep trying forever 2868 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 2869 loge("Failed " + 2870 mReconnectCount + " times, Disabling " + mLastNetworkId); 2871 mWifiConfigStore.disableNetwork(mLastNetworkId, 2872 WifiConfiguration.DISABLED_DHCP_FAILURE); 2873 mReconnectCount = 0; 2874 } 2875 2876 /* DHCP times out after about 30 seconds, we do a 2877 * disconnect and an immediate reconnect to try again 2878 */ 2879 mWifiNative.disconnect(); 2880 mWifiNative.reconnect(); 2881 } 2882 2883 /* Current design is to not set the config on a running hostapd but instead 2884 * stop and start tethering when user changes config on a running access point 2885 * 2886 * TODO: Add control channel setup through hostapd that allows changing config 2887 * on a running daemon 2888 */ 2889 private void startSoftApWithConfig(final WifiConfiguration config) { 2890 // start hostapd on a seperate thread 2891 new Thread(new Runnable() { 2892 public void run() { 2893 try { 2894 mNwService.startAccessPoint(config, mInterfaceName); 2895 } catch (Exception e) { 2896 loge("Exception in softap start " + e); 2897 try { 2898 mNwService.stopAccessPoint(mInterfaceName); 2899 mNwService.startAccessPoint(config, mInterfaceName); 2900 } catch (Exception e1) { 2901 loge("Exception in softap re-start " + e1); 2902 sendMessage(CMD_START_AP_FAILURE); 2903 return; 2904 } 2905 } 2906 if (DBG) log("Soft AP start successful"); 2907 sendMessage(CMD_START_AP_SUCCESS); 2908 } 2909 }).start(); 2910 } 2911 2912 2913 /* 2914 * Read a MAC address in /proc/arp/table, used by WifistateMachine 2915 * so as to record MAC address of default gateway. 2916 **/ 2917 private String macAddressFromRoute(String ipAddress) { 2918 String macAddress = null; 2919 BufferedReader reader = null; 2920 try { 2921 reader = new BufferedReader(new FileReader("/proc/net/arp")); 2922 2923 // Skip over the line bearing colum titles 2924 String line = reader.readLine(); 2925 2926 while ((line = reader.readLine()) != null) { 2927 String[] tokens = line.split("[ ]+"); 2928 if (tokens.length < 6) { 2929 continue; 2930 } 2931 2932 // ARP column format is 2933 // Address HWType HWAddress Flags Mask IFace 2934 String ip = tokens[0]; 2935 String mac = tokens[3]; 2936 2937 if (ipAddress.equals(ip)) { 2938 macAddress = mac; 2939 break; 2940 } 2941 } 2942 2943 if (macAddress == null) { 2944 loge("Did not find remoteAddress {" + ipAddress + "} in " + 2945 "/proc/net/arp"); 2946 } 2947 2948 } catch (FileNotFoundException e) { 2949 loge("Could not open /proc/net/arp to lookup mac address"); 2950 } catch (IOException e) { 2951 loge("Could not read /proc/net/arp to lookup mac address"); 2952 } finally { 2953 try { 2954 if (reader != null) { 2955 reader.close(); 2956 } 2957 } catch (IOException e) { 2958 // Do nothing 2959 } 2960 } 2961 return macAddress; 2962 2963 } 2964 /******************************************************** 2965 * HSM states 2966 *******************************************************/ 2967 2968 class DefaultState extends State { 2969 @Override 2970 public boolean processMessage(Message message) { 2971 logStateAndMessage(message, getClass().getSimpleName()); 2972 2973 switch (message.what) { 2974 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 2975 AsyncChannel ac = (AsyncChannel) message.obj; 2976 if (ac == mWifiP2pChannel) { 2977 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 2978 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 2979 } else { 2980 loge("WifiP2pService connection failure, error=" + message.arg1); 2981 } 2982 } else { 2983 loge("got HALF_CONNECTED for unknown channel"); 2984 } 2985 break; 2986 } 2987 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 2988 AsyncChannel ac = (AsyncChannel) message.obj; 2989 if (ac == mWifiP2pChannel) { 2990 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 2991 //TODO: Re-establish connection to state machine after a delay 2992 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2993 } 2994 break; 2995 } 2996 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2997 mBluetoothConnectionActive = (message.arg1 != 2998 BluetoothAdapter.STATE_DISCONNECTED); 2999 break; 3000 /* Synchronous call returns */ 3001 case CMD_PING_SUPPLICANT: 3002 case CMD_ENABLE_NETWORK: 3003 case CMD_ADD_OR_UPDATE_NETWORK: 3004 case CMD_REMOVE_NETWORK: 3005 case CMD_SAVE_CONFIG: 3006 replyToMessage(message, message.what, FAILURE); 3007 break; 3008 case CMD_GET_CAPABILITY_FREQ: 3009 replyToMessage(message, message.what, null); 3010 break; 3011 case CMD_GET_CONFIGURED_NETWORKS: 3012 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 3013 break; 3014 case CMD_ENABLE_RSSI_POLL: 3015 mEnableRssiPolling = (message.arg1 == 1); 3016 break; 3017 case CMD_ENABLE_BACKGROUND_SCAN: 3018 mEnableBackgroundScan = (message.arg1 == 1); 3019 break; 3020 case CMD_SET_HIGH_PERF_MODE: 3021 if (message.arg1 == 1) { 3022 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 3023 } else { 3024 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 3025 } 3026 break; 3027 case CMD_BOOT_COMPLETED: 3028 String countryCode = mPersistedCountryCode; 3029 if (TextUtils.isEmpty(countryCode) == false) { 3030 Settings.Global.putString(mContext.getContentResolver(), 3031 Settings.Global.WIFI_COUNTRY_CODE, 3032 countryCode); 3033 // it may be that the state transition that should send this info 3034 // to the driver happened between mPersistedCountryCode getting set 3035 // and now, so simply persisting it here would mean we have sent 3036 // nothing to the driver. Send the cmd so it might be set now. 3037 int sequenceNum = mCountryCodeSequence.incrementAndGet(); 3038 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, 3039 sequenceNum, 0, countryCode); 3040 } 3041 3042 checkAndSetConnectivityInstance(); 3043 mCm.registerNetworkFactory(new Messenger(getHandler()), NETWORKTYPE); 3044 // 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 // We should tell autojoin the user did try to connect to that network 4294 // However, it seems that this API is designed to NOT persist, 4295 // so don't tell anything to autojoin 4296 // if (others && mFrameworkAutoJoin.get()) { 4297 // mWifiAutoJoinController. 4298 // updateConfigurationHistory(message.arg1, true, true); 4299 // } 4300 4301 // As this command is ultimately coming from WifiManager public API, 4302 // setting the last selected configuration allows the system to 4303 // remember the last user choice without persisting 4304 mWifiConfigStore.setLastSelectedConfiguration(message.arg1); 4305 4306 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 4307 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4308 break; 4309 case CMD_ENABLE_ALL_NETWORKS: 4310 long time = android.os.SystemClock.elapsedRealtime(); 4311 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 4312 mWifiConfigStore.enableAllNetworks(); 4313 mLastEnableAllNetworksTime = time; 4314 } 4315 break; 4316 case WifiManager.DISABLE_NETWORK: 4317 if (mWifiConfigStore.disableNetwork(message.arg1, 4318 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 4319 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 4320 } else { 4321 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 4322 WifiManager.ERROR); 4323 } 4324 break; 4325 case CMD_BLACKLIST_NETWORK: 4326 mWifiNative.addToBlacklist((String)message.obj); 4327 break; 4328 case CMD_CLEAR_BLACKLIST: 4329 mWifiNative.clearBlacklist(); 4330 break; 4331 case CMD_SAVE_CONFIG: 4332 ok = mWifiConfigStore.saveConfig(); 4333 4334 loge("wifistatemachine did save config " + ok); 4335 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 4336 4337 // Inform the backup manager about a data change 4338 IBackupManager ibm = IBackupManager.Stub.asInterface( 4339 ServiceManager.getService(Context.BACKUP_SERVICE)); 4340 if (ibm != null) { 4341 try { 4342 ibm.dataChanged("com.android.providers.settings"); 4343 } catch (Exception e) { 4344 // Try again later 4345 } 4346 } 4347 break; 4348 case CMD_GET_CONFIGURED_NETWORKS: 4349 replyToMessage(message, message.what, 4350 mWifiConfigStore.getConfiguredNetworks()); 4351 break; 4352 /* Do a redundant disconnect without transition */ 4353 case CMD_DISCONNECT: 4354 mWifiConfigStore.setLastSelectedConfiguration 4355 (WifiConfiguration.INVALID_NETWORK_ID); 4356 mWifiNative.disconnect(); 4357 break; 4358 case CMD_RECONNECT: 4359 mWifiNative.reconnect(); 4360 break; 4361 case CMD_REASSOCIATE: 4362 mWifiNative.reassociate(); 4363 break; 4364 case CMD_RELOAD_TLS_AND_RECONNECT: 4365 if (mWifiConfigStore.needsUnlockedKeyStore()) { 4366 logd("Reconnecting to give a chance to un-connected TLS networks"); 4367 mWifiNative.disconnect(); 4368 mWifiNative.reconnect(); 4369 } 4370 break; 4371 case CMD_AUTO_CONNECT: 4372 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 4373 * associated status thus the STATUS command but somehow-someplace still thinks 4374 * it is associated and thus will ignore select/reconnect command with 4375 * following message: 4376 * "Already associated with the selected network - do nothing" 4377 * 4378 * Hence, sends a disconnect to supplicant first. 4379 */ 4380 mWifiNative.disconnect(); 4381 4382 /* connect command coming from auto-join */ 4383 config = (WifiConfiguration) message.obj; 4384 netId = message.arg1; 4385 4386 loge("CMD_AUTO_CONNECT sup state " 4387 + mSupplicantStateTracker.getSupplicantStateName() 4388 + " my state " + getCurrentState().getName() 4389 + " nid=" + Integer.toString(netId)); 4390 4391 /* Save the network config */ 4392 if (config != null) { 4393 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 4394 + " nid=" + Integer.toString(netId)); 4395 4396 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4397 netId = result.getNetworkId(); 4398 loge("CMD_AUTO_CONNECT did save config -> " 4399 + " nid=" + Integer.toString(netId)); 4400 } 4401 4402 if (mWifiConfigStore.selectNetwork(netId) && 4403 mWifiNative.reconnect()) { 4404 // we selected a better config, maybe because we could not see the last user 4405 // selection, then forget it. We will remember the selection 4406 // only if it was persisted. 4407 mWifiConfigStore. 4408 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 4409 4410 /* The state tracker handles enabling networks upon completion/failure */ 4411 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 4412 //replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 4413 /* Expect a disconnection from the old connection */ 4414 transitionTo(mDisconnectingState); 4415 } else { 4416 loge("Failed to connect config: " + config + " netId: " + netId); 4417 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 4418 WifiManager.ERROR); 4419 break; 4420 } 4421 break; 4422 case WifiManager.CONNECT_NETWORK: 4423 /* The connect message can contain a network id passed as arg1 on message or 4424 * or a config passed as obj on message. 4425 * For a new network, a config is passed to create and connect. 4426 * For an existing network, a network id is passed 4427 */ 4428 netId = message.arg1; 4429 config = (WifiConfiguration) message.obj; 4430 4431 if (config == null) { 4432 loge("CONNECT_NETWORK id=" + Integer.toString(netId) + " " 4433 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 4434 + getCurrentState().getName()); 4435 } else { 4436 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 4437 + " config=" + config.SSID 4438 + " cnid=" + config.networkId 4439 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4440 + " my state " + getCurrentState().getName()); 4441 } 4442 4443 /* Save the network config */ 4444 if (config != null) { 4445 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4446 netId = result.getNetworkId(); 4447 } 4448 if (mFrameworkAutoJoin.get()) { 4449 /* Tell autojoin the user did try to connect to that network */ 4450 mWifiAutoJoinController.updateConfigurationHistory(netId, true, true); 4451 } 4452 mWifiConfigStore.setLastSelectedConfiguration(netId); 4453 4454 if (mWifiConfigStore.selectNetwork(netId) && 4455 mWifiNative.reconnect()) { 4456 /* The state tracker handles enabling networks upon completion/failure */ 4457 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 4458 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 4459 /* Expect a disconnection from the old connection */ 4460 transitionTo(mDisconnectingState); 4461 } else { 4462 loge("Failed to connect config: " + config + " netId: " + netId); 4463 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 4464 WifiManager.ERROR); 4465 break; 4466 } 4467 break; 4468 case WifiManager.SAVE_NETWORK: 4469 config = (WifiConfiguration) message.obj; 4470 int nid = config.networkId; 4471 if (config == null) { 4472 loge("SAVE_NETWORK id=" + Integer.toString(nid) 4473 + " " + mSupplicantStateTracker.getSupplicantStateName() 4474 + " my state " + getCurrentState().getName()); 4475 } else { 4476 loge("SAVE_NETWORK id=" + Integer.toString(nid) 4477 + " config=" + config.SSID 4478 + " cnid=" + config.networkId 4479 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4480 + " my state " + getCurrentState().getName()); 4481 } 4482 4483 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4484 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 4485 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 4486 if (mFrameworkAutoJoin.get()) { 4487 /* Tell autojoin the user did try to modify and save that network */ 4488 mWifiAutoJoinController.updateConfigurationHistory(config.networkId, 4489 true, false); 4490 4491 mWifiAutoJoinController.attemptAutoJoin(); 4492 mWifiConfigStore.writeKnownNetworkHistory(); 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 } 4641 4642 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4643 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 4644 if (result.hasIpChanged()) { 4645 log("Reconfiguring IP on connection"); 4646 transitionTo(mObtainingIpState); 4647 } 4648 if (result.hasProxyChanged()) { 4649 log("Reconfiguring proxy on connection"); 4650 updateLinkProperties(); 4651 } 4652 } 4653 4654 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 4655 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 4656 if (mFrameworkAutoJoin.get()) { 4657 /* Tell autojoin the user did try to modify and save that network */ 4658 mWifiAutoJoinController.updateConfigurationHistory(config.networkId, 4659 true, false); 4660 } 4661 } else { 4662 loge("Failed to save network"); 4663 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 4664 WifiManager.ERROR); 4665 } 4666 break; 4667 /* Ignore */ 4668 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4669 break; 4670 case CMD_RSSI_POLL: 4671 if (message.arg1 == mRssiPollToken) { 4672 // Get Info and continue polling 4673 fetchRssiLinkSpeedAndFrequencyNative(); 4674 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 4675 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 4676 } else { 4677 // Polling has completed 4678 } 4679 break; 4680 case CMD_ENABLE_RSSI_POLL: 4681 mEnableRssiPolling = (message.arg1 == 1); 4682 mRssiPollToken++; 4683 if (mEnableRssiPolling) { 4684 // first poll 4685 fetchRssiLinkSpeedAndFrequencyNative(); 4686 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 4687 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 4688 } 4689 break; 4690 case WifiManager.RSSI_PKTCNT_FETCH: 4691 RssiPacketCountInfo info = new RssiPacketCountInfo(); 4692 fetchRssiLinkSpeedAndFrequencyNative(); 4693 info.rssi = mWifiInfo.getRssi(); 4694 fetchPktcntNative(info); 4695 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 4696 break; 4697 default: 4698 return NOT_HANDLED; 4699 } 4700 4701 return HANDLED; 4702 } 4703 } 4704 4705 class ObtainingIpState extends State { 4706 @Override 4707 public void enter() { 4708 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 4709 // TODO: If we're switching between static IP configuration and DHCP, remove the 4710 // static configuration first. 4711 startDhcp(); 4712 } else { 4713 // stop any running dhcp before assigning static IP 4714 stopDhcp(); 4715 DhcpResults dhcpResults = new DhcpResults( 4716 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 4717 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 4718 Iterator<LinkAddress> addrs = 4719 dhcpResults.linkProperties.getLinkAddresses().iterator(); 4720 if (!addrs.hasNext()) { 4721 loge("Static IP lacks address"); 4722 sendMessage(CMD_STATIC_IP_FAILURE); 4723 } else { 4724 ifcg.setLinkAddress(addrs.next()); 4725 ifcg.setInterfaceUp(); 4726 try { 4727 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 4728 if (DBG) log("Static IP configuration succeeded"); 4729 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 4730 } catch (RemoteException re) { 4731 loge("Static IP configuration failed: " + re); 4732 sendMessage(CMD_STATIC_IP_FAILURE); 4733 } catch (IllegalStateException e) { 4734 loge("Static IP configuration failed: " + e); 4735 sendMessage(CMD_STATIC_IP_FAILURE); 4736 } 4737 } 4738 } 4739 } 4740 @Override 4741 public boolean processMessage(Message message) { 4742 logStateAndMessage(message, getClass().getSimpleName()); 4743 4744 switch(message.what) { 4745 case CMD_STATIC_IP_SUCCESS: 4746 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 4747 transitionTo(mVerifyingLinkState); 4748 break; 4749 case CMD_STATIC_IP_FAILURE: 4750 handleFailedIpConfiguration(); 4751 transitionTo(mDisconnectingState); 4752 break; 4753 case WifiManager.SAVE_NETWORK: 4754 deferMessage(message); 4755 break; 4756 /* Defer any power mode changes since we must keep active power mode at DHCP */ 4757 case CMD_SET_HIGH_PERF_MODE: 4758 deferMessage(message); 4759 break; 4760 /* Defer scan request since we should not switch to other channels at DHCP */ 4761 case CMD_START_SCAN: 4762 deferMessage(message); 4763 break; 4764 default: 4765 return NOT_HANDLED; 4766 } 4767 return HANDLED; 4768 } 4769 } 4770 4771 class VerifyingLinkState extends State { 4772 @Override 4773 public void enter() { 4774 log(getName() + " enter"); 4775 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 4776 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 4777 sendNetworkStateChangeBroadcast(mLastBssid); 4778 } 4779 @Override 4780 public boolean processMessage(Message message) { 4781 logStateAndMessage(message, getClass().getSimpleName()); 4782 4783 switch (message.what) { 4784 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 4785 //stay here 4786 log(getName() + " POOR_LINK_DETECTED: no transition"); 4787 break; 4788 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 4789 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 4790 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 4791 // existing behaviour. The captive portal check really happens after we 4792 // transition into DetailedState.CONNECTED. 4793 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 4794 mWifiConfigStore.updateStatus(mLastNetworkId, 4795 DetailedState.CAPTIVE_PORTAL_CHECK); 4796 sendNetworkStateChangeBroadcast(mLastBssid); 4797 4798 // NOTE: This might look like an odd place to enable IPV6 but this is in 4799 // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable 4800 // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. 4801 try { 4802 mNwService.enableIpv6(mInterfaceName); 4803 } catch (RemoteException re) { 4804 loge("Failed to enable IPv6: " + re); 4805 } catch (IllegalStateException e) { 4806 loge("Failed to enable IPv6: " + e); 4807 } 4808 4809 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 4810 setNetworkDetailedState(DetailedState.CONNECTED); 4811 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 4812 sendNetworkStateChangeBroadcast(mLastBssid); 4813 transitionTo(mConnectedState); 4814 4815 break; 4816 default: 4817 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 4818 return NOT_HANDLED; 4819 } 4820 return HANDLED; 4821 } 4822 } 4823 4824 class ConnectedState extends State { 4825 @Override 4826 public void enter() { 4827 // Verify we should be here. There were some conditions at boot time that 4828 // caused us to end here, but those races should be resolved. Left in 4829 // as a belt-and-suspenders measure. TODO - remove if not longer hit. 4830 if (mNetworkAgent.isConnectionRequested() == false) { 4831 loge("Wifi hit ConnectedState when it should not be connecting"); 4832 sendMessage(CMD_STOP_DRIVER); 4833 } 4834 4835 String address; 4836 updateDefaultRouteMacAddress(1000); 4837 if (DBG) { 4838 log("ConnectedState Enter autojoin=" + mFrameworkAutoJoin.get() 4839 + " mScreenOn=" + mScreenOn 4840 + " scanperiod=" + Integer.toString(mConnectedScanPeriodMs) ); 4841 } 4842 if (mFrameworkAutoJoin.get() && mScreenOn) { 4843 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 4844 setScanAlarm(true); 4845 } else { 4846 mCurrentScanAlarmMs = 0; 4847 } 4848 } 4849 @Override 4850 public boolean processMessage(Message message) { 4851 logStateAndMessage(message, getClass().getSimpleName()); 4852 4853 switch (message.what) { 4854 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 4855 if (DBG) log("Watchdog reports poor link"); 4856 try { 4857 mNwService.disableIpv6(mInterfaceName); 4858 } catch (RemoteException re) { 4859 loge("Failed to disable IPv6: " + re); 4860 } catch (IllegalStateException e) { 4861 loge("Failed to disable IPv6: " + e); 4862 } 4863 /* Report a disconnect */ 4864 setNetworkDetailedState(DetailedState.DISCONNECTED); 4865 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 4866 sendNetworkStateChangeBroadcast(mLastBssid); 4867 4868 transitionTo(mVerifyingLinkState); 4869 break; 4870 default: 4871 return NOT_HANDLED; 4872 } 4873 return HANDLED; 4874 } 4875 4876 @Override 4877 public void exit() { 4878 loge("WifiStateMachine: Leaving Connected state"); 4879 setScanAlarm(false); 4880 4881 /* Request a CS wakelock during transition to mobile */ 4882 checkAndSetConnectivityInstance(); 4883 mCm.requestNetworkTransitionWakelock(getName()); 4884 } 4885 } 4886 4887 class DisconnectingState extends State { 4888 4889 @Override 4890 public void enter() { 4891 if (mFrameworkAutoJoin.get()) { 4892 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 4893 } else { 4894 4895 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 4896 } 4897 4898 if (PDBG) { 4899 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 4900 + " mEnableBackgroundScan= " + mEnableBackgroundScan 4901 + " screenOn=" + mScreenOn); 4902 } 4903 if (mScreenOn) 4904 setScanAlarm(true); 4905 } 4906 4907 @Override 4908 public boolean processMessage(Message message) { 4909 logStateAndMessage(message, getClass().getSimpleName()); 4910 switch (message.what) { 4911 case CMD_SET_OPERATIONAL_MODE: 4912 if (message.arg1 != CONNECT_MODE) { 4913 deferMessage(message); 4914 } 4915 break; 4916 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4917 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 4918 * we have missed the network disconnection, transition to mDisconnectedState 4919 * and handle the rest of the events there 4920 */ 4921 deferMessage(message); 4922 handleNetworkDisconnect(); 4923 transitionTo(mDisconnectedState); 4924 break; 4925 default: 4926 return NOT_HANDLED; 4927 } 4928 return HANDLED; 4929 } 4930 4931 @Override 4932 public void exit() { 4933 mCurrentScanAlarmMs = 0; 4934 } 4935 } 4936 4937 class DisconnectedState extends State { 4938 @Override 4939 public void enter() { 4940 // We dont scan frequently if this is a temporary disconnect 4941 // due to p2p 4942 if (mTemporarilyDisconnectWifi) { 4943 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 4944 return; 4945 } 4946 4947 // loose the last selection choice 4948 // mWifiAutoJoinController.setLastSelectedConfiguration 4949 // (WifiConfiguration.INVALID_NETWORK_ID); 4950 4951 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4952 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 4953 mDefaultFrameworkScanIntervalMs); 4954 4955 if (mFrameworkAutoJoin.get()) { 4956 if (mScreenOn) 4957 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 4958 } else { 4959 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 4960 } 4961 4962 if (PDBG) { 4963 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 4964 + " mEnableBackgroundScan= " + mEnableBackgroundScan 4965 + " screenOn=" + mScreenOn); 4966 } 4967 4968 /* 4969 * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, 4970 * otherwise we initiate an infrequent scan that wakes up the device to ensure 4971 * a user connects to an access point on the move 4972 * 4973 * mFrameworkAutoJoin is True: 4974 * - screen dark and PNO supported => scan alarm disabled 4975 * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period 4976 */ 4977 if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) { 4978 /* If a regular scan result is pending, do not initiate background 4979 * scan until the scan results are returned. This is needed because 4980 * initiating a background scan will cancel the regular scan and 4981 * scan results will not be returned until background scanning is 4982 * cleared 4983 */ 4984 if (!mIsScanOngoing) { 4985 mWifiNative.enableBackgroundScan(true); 4986 } 4987 } else { 4988 setScanAlarm(true); 4989 } 4990 4991 if (mFrameworkAutoJoin.get() && mScreenOn) { 4992 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 4993 } 4994 4995 /** 4996 * If we have no networks saved, the supplicant stops doing the periodic scan. 4997 * The scans are useful to notify the user of the presence of an open network. 4998 * Note that these are not wake up scans. 4999 */ 5000 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 5001 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5002 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5003 } 5004 } 5005 @Override 5006 public boolean processMessage(Message message) { 5007 boolean ret = HANDLED; 5008 5009 logStateAndMessage(message, getClass().getSimpleName()); 5010 5011 switch (message.what) { 5012 case CMD_NO_NETWORKS_PERIODIC_SCAN: 5013 if (mP2pConnected.get()) break; 5014 if (message.arg1 == mPeriodicScanToken && 5015 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 5016 startScan(UNKNOWN_SCAN_SOURCE, null, null); 5017 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5018 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5019 } 5020 break; 5021 case WifiManager.FORGET_NETWORK: 5022 case CMD_REMOVE_NETWORK: 5023 // Set up a delayed message here. After the forget/remove is handled 5024 // the handled delayed message will determine if there is a need to 5025 // scan and continue 5026 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5027 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5028 ret = NOT_HANDLED; 5029 break; 5030 case CMD_SET_OPERATIONAL_MODE: 5031 if (message.arg1 != CONNECT_MODE) { 5032 mOperationalMode = message.arg1; 5033 5034 mWifiConfigStore.disableAllNetworks(); 5035 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 5036 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 5037 setWifiState(WIFI_STATE_DISABLED); 5038 } 5039 5040 transitionTo(mScanModeState); 5041 } 5042 break; 5043 case CMD_ENABLE_BACKGROUND_SCAN: 5044 mEnableBackgroundScan = (message.arg1 == 1); 5045 loge("enableBackgroundScanCommand enabled=" + mEnableBackgroundScan 5046 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 5047 5048 if (mEnableBackgroundScan) { 5049 mWifiNative.enableBackgroundScan(true); 5050 setScanAlarm(false); 5051 } else { 5052 if (mFrameworkAutoJoin.get()) { 5053 // tell supplicant to disconnect so as it doesnt start scanning 5054 // for connection upon disabling background scan 5055 mWifiNative.disconnect(); 5056 } 5057 mWifiNative.enableBackgroundScan(false); 5058 setScanAlarm(true); 5059 } 5060 break; 5061 /* Ignore network disconnect */ 5062 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5063 break; 5064 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5065 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 5066 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 5067 /* ConnectModeState does the rest of the handling */ 5068 ret = NOT_HANDLED; 5069 break; 5070 case CMD_START_SCAN: 5071 /* Disable background scan temporarily during a regular scan */ 5072 if (mEnableBackgroundScan) { 5073 mWifiNative.enableBackgroundScan(false); 5074 } 5075 /* Handled in parent state */ 5076 ret = NOT_HANDLED; 5077 break; 5078 case WifiMonitor.SCAN_RESULTS_EVENT: 5079 /* Re-enable background scan when a pending scan result is received */ 5080 if (mEnableBackgroundScan && mIsScanOngoing) { 5081 mWifiNative.enableBackgroundScan(true); 5082 } 5083 /* Handled in parent state */ 5084 ret = NOT_HANDLED; 5085 break; 5086 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 5087 NetworkInfo info = (NetworkInfo) message.obj; 5088 mP2pConnected.set(info.isConnected()); 5089 if (mP2pConnected.get()) { 5090 int defaultInterval = mContext.getResources().getInteger( 5091 R.integer.config_wifi_scan_interval_p2p_connected); 5092 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 5093 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 5094 defaultInterval); 5095 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 5096 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 5097 if (DBG) log("Turn on scanning after p2p disconnected"); 5098 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 5099 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 5100 } 5101 case CMD_RECONNECT: 5102 case CMD_REASSOCIATE: 5103 if (mTemporarilyDisconnectWifi) { 5104 // Drop a third party reconnect/reassociate if STA is 5105 // temporarily disconnected for p2p 5106 break; 5107 } else { 5108 // ConnectModeState handles it 5109 ret = NOT_HANDLED; 5110 } 5111 break; 5112 default: 5113 ret = NOT_HANDLED; 5114 } 5115 return ret; 5116 } 5117 5118 @Override 5119 public void exit() { 5120 /* No need for a background scan upon exit from a disconnected state */ 5121 if (mEnableBackgroundScan) { 5122 mWifiNative.enableBackgroundScan(false); 5123 } 5124 mCurrentScanAlarmMs = 0; 5125 setScanAlarm(false); 5126 } 5127 } 5128 5129 class WpsRunningState extends State { 5130 //Tracks the source to provide a reply 5131 private Message mSourceMessage; 5132 @Override 5133 public void enter() { 5134 mSourceMessage = Message.obtain(getCurrentMessage()); 5135 } 5136 @Override 5137 public boolean processMessage(Message message) { 5138 logStateAndMessage(message, getClass().getSimpleName()); 5139 5140 switch (message.what) { 5141 case WifiMonitor.WPS_SUCCESS_EVENT: 5142 // Ignore intermediate success, wait for full connection 5143 break; 5144 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5145 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 5146 mSourceMessage.recycle(); 5147 mSourceMessage = null; 5148 deferMessage(message); 5149 transitionTo(mDisconnectedState); 5150 break; 5151 case WifiMonitor.WPS_OVERLAP_EVENT: 5152 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 5153 WifiManager.WPS_OVERLAP_ERROR); 5154 mSourceMessage.recycle(); 5155 mSourceMessage = null; 5156 transitionTo(mDisconnectedState); 5157 break; 5158 case WifiMonitor.WPS_FAIL_EVENT: 5159 //arg1 has the reason for the failure 5160 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 5161 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 5162 mSourceMessage.recycle(); 5163 mSourceMessage = null; 5164 transitionTo(mDisconnectedState); 5165 } else { 5166 if (DBG) log("Ignore unspecified fail event during WPS connection"); 5167 } 5168 break; 5169 case WifiMonitor.WPS_TIMEOUT_EVENT: 5170 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 5171 WifiManager.WPS_TIMED_OUT); 5172 mSourceMessage.recycle(); 5173 mSourceMessage = null; 5174 transitionTo(mDisconnectedState); 5175 break; 5176 case WifiManager.START_WPS: 5177 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 5178 break; 5179 case WifiManager.CANCEL_WPS: 5180 if (mWifiNative.cancelWps()) { 5181 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 5182 } else { 5183 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 5184 } 5185 transitionTo(mDisconnectedState); 5186 break; 5187 /* Defer all commands that can cause connections to a different network 5188 * or put the state machine out of connect mode 5189 */ 5190 case CMD_STOP_DRIVER: 5191 case CMD_SET_OPERATIONAL_MODE: 5192 case WifiManager.CONNECT_NETWORK: 5193 case CMD_ENABLE_NETWORK: 5194 case CMD_RECONNECT: 5195 case CMD_REASSOCIATE: 5196 deferMessage(message); 5197 break; 5198 case CMD_AUTO_CONNECT: 5199 if (DBG) log("Ignore auto connect command while WpsRunningState"); 5200 break; 5201 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5202 if (DBG) log("Network connection lost"); 5203 handleNetworkDisconnect(); 5204 break; 5205 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5206 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 5207 break; 5208 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5209 // Disregard auth failure events during WPS connection. The 5210 // EAP sequence is retried several times, and there might be 5211 // failures (especially for wps pin). We will get a WPS_XXX 5212 // event at the end of the sequence anyway. 5213 if (DBG) log("Ignore auth failure during WPS connection"); 5214 break; 5215 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5216 //Throw away supplicant state changes when WPS is running. 5217 //We will start getting supplicant state changes once we get 5218 //a WPS success or failure 5219 break; 5220 default: 5221 return NOT_HANDLED; 5222 } 5223 return HANDLED; 5224 } 5225 5226 @Override 5227 public void exit() { 5228 mWifiConfigStore.enableAllNetworks(); 5229 mWifiConfigStore.loadConfiguredNetworks(); 5230 } 5231 } 5232 5233 class SoftApStartingState extends State { 5234 @Override 5235 public void enter() { 5236 final Message message = getCurrentMessage(); 5237 if (message.what == CMD_START_AP) { 5238 final WifiConfiguration config = (WifiConfiguration) message.obj; 5239 5240 if (config == null) { 5241 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 5242 } else { 5243 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 5244 startSoftApWithConfig(config); 5245 } 5246 } else { 5247 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 5248 } 5249 } 5250 @Override 5251 public boolean processMessage(Message message) { 5252 logStateAndMessage(message, getClass().getSimpleName()); 5253 5254 switch(message.what) { 5255 case CMD_START_SUPPLICANT: 5256 case CMD_STOP_SUPPLICANT: 5257 case CMD_START_AP: 5258 case CMD_STOP_AP: 5259 case CMD_START_DRIVER: 5260 case CMD_STOP_DRIVER: 5261 case CMD_SET_OPERATIONAL_MODE: 5262 case CMD_SET_COUNTRY_CODE: 5263 case CMD_SET_FREQUENCY_BAND: 5264 case CMD_START_PACKET_FILTERING: 5265 case CMD_STOP_PACKET_FILTERING: 5266 case CMD_TETHER_STATE_CHANGE: 5267 deferMessage(message); 5268 break; 5269 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 5270 WifiConfiguration config = (WifiConfiguration) message.obj; 5271 if (config != null) { 5272 startSoftApWithConfig(config); 5273 } else { 5274 loge("Softap config is null!"); 5275 sendMessage(CMD_START_AP_FAILURE); 5276 } 5277 break; 5278 case CMD_START_AP_SUCCESS: 5279 setWifiApState(WIFI_AP_STATE_ENABLED); 5280 transitionTo(mSoftApStartedState); 5281 break; 5282 case CMD_START_AP_FAILURE: 5283 setWifiApState(WIFI_AP_STATE_FAILED); 5284 transitionTo(mInitialState); 5285 break; 5286 default: 5287 return NOT_HANDLED; 5288 } 5289 return HANDLED; 5290 } 5291 } 5292 5293 class SoftApStartedState extends State { 5294 @Override 5295 public boolean processMessage(Message message) { 5296 logStateAndMessage(message, getClass().getSimpleName()); 5297 5298 switch(message.what) { 5299 case CMD_STOP_AP: 5300 if (DBG) log("Stopping Soft AP"); 5301 /* We have not tethered at this point, so we just shutdown soft Ap */ 5302 try { 5303 mNwService.stopAccessPoint(mInterfaceName); 5304 } catch(Exception e) { 5305 loge("Exception in stopAccessPoint()"); 5306 } 5307 setWifiApState(WIFI_AP_STATE_DISABLED); 5308 transitionTo(mInitialState); 5309 break; 5310 case CMD_START_AP: 5311 // Ignore a start on a running access point 5312 break; 5313 /* Fail client mode operation when soft AP is enabled */ 5314 case CMD_START_SUPPLICANT: 5315 loge("Cannot start supplicant with a running soft AP"); 5316 setWifiState(WIFI_STATE_UNKNOWN); 5317 break; 5318 case CMD_TETHER_STATE_CHANGE: 5319 TetherStateChange stateChange = (TetherStateChange) message.obj; 5320 if (startTethering(stateChange.available)) { 5321 transitionTo(mTetheringState); 5322 } 5323 break; 5324 default: 5325 return NOT_HANDLED; 5326 } 5327 return HANDLED; 5328 } 5329 } 5330 5331 class TetheringState extends State { 5332 @Override 5333 public void enter() { 5334 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 5335 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 5336 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 5337 } 5338 @Override 5339 public boolean processMessage(Message message) { 5340 logStateAndMessage(message, getClass().getSimpleName()); 5341 5342 switch(message.what) { 5343 case CMD_TETHER_STATE_CHANGE: 5344 TetherStateChange stateChange = (TetherStateChange) message.obj; 5345 if (isWifiTethered(stateChange.active)) { 5346 transitionTo(mTetheredState); 5347 } 5348 return HANDLED; 5349 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5350 if (message.arg1 == mTetherToken) { 5351 loge("Failed to get tether update, shutdown soft access point"); 5352 transitionTo(mSoftApStartedState); 5353 // Needs to be first thing handled 5354 sendMessageAtFrontOfQueue(CMD_STOP_AP); 5355 } 5356 break; 5357 case CMD_START_SUPPLICANT: 5358 case CMD_STOP_SUPPLICANT: 5359 case CMD_START_AP: 5360 case CMD_STOP_AP: 5361 case CMD_START_DRIVER: 5362 case CMD_STOP_DRIVER: 5363 case CMD_SET_OPERATIONAL_MODE: 5364 case CMD_SET_COUNTRY_CODE: 5365 case CMD_SET_FREQUENCY_BAND: 5366 case CMD_START_PACKET_FILTERING: 5367 case CMD_STOP_PACKET_FILTERING: 5368 deferMessage(message); 5369 break; 5370 default: 5371 return NOT_HANDLED; 5372 } 5373 return HANDLED; 5374 } 5375 } 5376 5377 class TetheredState extends State { 5378 @Override 5379 public boolean processMessage(Message message) { 5380 logStateAndMessage(message, getClass().getSimpleName()); 5381 5382 switch(message.what) { 5383 case CMD_TETHER_STATE_CHANGE: 5384 TetherStateChange stateChange = (TetherStateChange) message.obj; 5385 if (!isWifiTethered(stateChange.active)) { 5386 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 5387 setHostApRunning(null, false); 5388 setHostApRunning(null, true); 5389 } 5390 return HANDLED; 5391 case CMD_STOP_AP: 5392 if (DBG) log("Untethering before stopping AP"); 5393 setWifiApState(WIFI_AP_STATE_DISABLING); 5394 stopTethering(); 5395 transitionTo(mUntetheringState); 5396 // More work to do after untethering 5397 deferMessage(message); 5398 break; 5399 default: 5400 return NOT_HANDLED; 5401 } 5402 return HANDLED; 5403 } 5404 } 5405 5406 class UntetheringState extends State { 5407 @Override 5408 public void enter() { 5409 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 5410 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 5411 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 5412 5413 } 5414 @Override 5415 public boolean processMessage(Message message) { 5416 logStateAndMessage(message, getClass().getSimpleName()); 5417 5418 switch(message.what) { 5419 case CMD_TETHER_STATE_CHANGE: 5420 TetherStateChange stateChange = (TetherStateChange) message.obj; 5421 5422 /* Wait till wifi is untethered */ 5423 if (isWifiTethered(stateChange.active)) break; 5424 5425 transitionTo(mSoftApStartedState); 5426 break; 5427 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5428 if (message.arg1 == mTetherToken) { 5429 loge("Failed to get tether update, force stop access point"); 5430 transitionTo(mSoftApStartedState); 5431 } 5432 break; 5433 case CMD_START_SUPPLICANT: 5434 case CMD_STOP_SUPPLICANT: 5435 case CMD_START_AP: 5436 case CMD_STOP_AP: 5437 case CMD_START_DRIVER: 5438 case CMD_STOP_DRIVER: 5439 case CMD_SET_OPERATIONAL_MODE: 5440 case CMD_SET_COUNTRY_CODE: 5441 case CMD_SET_FREQUENCY_BAND: 5442 case CMD_START_PACKET_FILTERING: 5443 case CMD_STOP_PACKET_FILTERING: 5444 deferMessage(message); 5445 break; 5446 default: 5447 return NOT_HANDLED; 5448 } 5449 return HANDLED; 5450 } 5451 } 5452 5453 //State machine initiated requests can have replyTo set to null indicating 5454 //there are no recepients, we ignore those reply actions 5455 private void replyToMessage(Message msg, int what) { 5456 if (msg.replyTo == null) return; 5457 Message dstMsg = obtainMessageWithArg2(msg); 5458 dstMsg.what = what; 5459 mReplyChannel.replyToMessage(msg, dstMsg); 5460 } 5461 5462 private void replyToMessage(Message msg, int what, int arg1) { 5463 if (msg.replyTo == null) return; 5464 Message dstMsg = obtainMessageWithArg2(msg); 5465 dstMsg.what = what; 5466 dstMsg.arg1 = arg1; 5467 mReplyChannel.replyToMessage(msg, dstMsg); 5468 } 5469 5470 private void replyToMessage(Message msg, int what, Object obj) { 5471 if (msg.replyTo == null) return; 5472 Message dstMsg = obtainMessageWithArg2(msg); 5473 dstMsg.what = what; 5474 dstMsg.obj = obj; 5475 mReplyChannel.replyToMessage(msg, dstMsg); 5476 } 5477 5478 /** 5479 * arg2 on the source message has a unique id that needs to be retained in replies 5480 * to match the request 5481 5482 * see WifiManager for details 5483 */ 5484 private Message obtainMessageWithArg2(Message srcMsg) { 5485 Message msg = Message.obtain(); 5486 msg.arg2 = srcMsg.arg2; 5487 return msg; 5488 } 5489} 5490