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