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