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