WifiStateMachine.java revision ab99a7a345781a9f3ff07335744c1f2073c44ac6
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_AP_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 24import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 25import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 26import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 27import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 28/** 29 * TODO: 30 * Deprecate WIFI_STATE_UNKNOWN 31 */ 32import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 33 34import android.app.ActivityManager; 35import android.app.AlarmManager; 36import android.app.AlertDialog; 37import android.app.PendingIntent; 38import android.app.backup.IBackupManager; 39import android.bluetooth.BluetoothAdapter; 40import android.content.BroadcastReceiver; 41import android.content.Context; 42import android.content.DialogInterface; 43import android.content.Intent; 44import android.content.IntentFilter; 45import android.content.pm.ApplicationInfo; 46import android.content.pm.PackageManager; 47import android.content.pm.PackageManager.NameNotFoundException; 48import android.database.ContentObserver; 49import android.net.ConnectivityManager; 50import android.net.DhcpResults; 51import android.net.BaseDhcpStateMachine; 52import android.net.DhcpStateMachine; 53import android.net.Network; 54import android.net.dhcp.DhcpClient; 55import android.net.InterfaceConfiguration; 56import android.net.LinkAddress; 57import android.net.LinkProperties; 58import android.net.NetworkAgent; 59import android.net.NetworkCapabilities; 60import android.net.NetworkFactory; 61import android.net.NetworkInfo; 62import android.net.NetworkInfo.DetailedState; 63import android.net.NetworkRequest; 64import android.net.NetworkUtils; 65import android.net.RouteInfo; 66import android.net.StaticIpConfiguration; 67import android.net.TrafficStats; 68import android.net.wifi.BatchedScanResult; 69import android.net.wifi.BatchedScanSettings; 70import android.net.wifi.RssiPacketCountInfo; 71import android.net.wifi.ScanResult; 72import android.net.wifi.ScanSettings; 73import android.net.wifi.SupplicantState; 74import android.net.wifi.WifiChannel; 75import android.net.wifi.WifiConfiguration; 76import android.net.wifi.WifiConnectionStatistics; 77import android.net.wifi.WifiEnterpriseConfig; 78import android.net.wifi.WifiInfo; 79import android.net.wifi.WifiLinkLayerStats; 80import android.net.wifi.WifiManager; 81import android.net.wifi.WifiScanner; 82import android.net.wifi.WifiSsid; 83import android.net.wifi.WpsInfo; 84import android.net.wifi.WpsResult; 85import android.net.wifi.WpsResult.Status; 86import android.net.wifi.p2p.IWifiP2pManager; 87import android.net.wifi.passpoint.IWifiPasspointManager; 88import android.net.wifi.IWifiScanner; 89import android.os.BatteryStats; 90import android.os.Bundle; 91import android.os.IBinder; 92import android.os.INetworkManagementService; 93import android.os.Looper; 94import android.os.Message; 95import android.os.Messenger; 96import android.os.PowerManager; 97import android.os.Process; 98import android.os.RemoteException; 99import android.os.ServiceManager; 100import android.os.SystemClock; 101import android.os.SystemProperties; 102import android.os.UserHandle; 103import android.os.WorkSource; 104import android.provider.Settings; 105import android.telephony.TelephonyManager; 106import android.text.TextUtils; 107import android.util.Log; 108import android.util.LruCache; 109import android.view.WindowManager; 110 111import com.android.internal.R; 112import com.android.internal.app.IBatteryStats; 113import com.android.internal.util.AsyncChannel; 114import com.android.internal.util.Protocol; 115import com.android.internal.util.State; 116import com.android.internal.util.StateMachine; 117import com.android.server.net.NetlinkTracker; 118import com.android.server.wifi.hotspot2.NetworkDetail; 119import com.android.server.wifi.hotspot2.SupplicantBridge; 120import com.android.server.wifi.p2p.WifiP2pServiceImpl; 121 122import java.io.BufferedReader; 123import java.io.FileDescriptor; 124import java.io.FileNotFoundException; 125import java.io.FileReader; 126import java.io.IOException; 127import java.io.PrintWriter; 128import java.net.Inet4Address; 129import java.net.InetAddress; 130import java.net.SocketException; 131import java.nio.BufferUnderflowException; 132import java.util.ArrayList; 133import java.util.Calendar; 134import java.util.HashSet; 135import java.util.LinkedList; 136import java.util.List; 137import java.util.Locale; 138import java.util.Queue; 139import java.util.Random; 140import java.util.concurrent.atomic.AtomicBoolean; 141import java.util.concurrent.atomic.AtomicInteger; 142import java.util.regex.Matcher; 143import java.util.regex.Pattern; 144 145/** 146 * Track the state of Wifi connectivity. All event handling is done here, 147 * and all changes in connectivity state are initiated here. 148 * 149 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 150 * In the current implementation, we support concurrent wifi p2p and wifi operation. 151 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 152 * handles p2p operation. 153 * 154 * @hide 155 */ 156public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler { 157 158 private static final String NETWORKTYPE = "WIFI"; 159 private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT"; 160 private static boolean DBG = true; 161 private static boolean VDBG = false; 162 private static boolean VVDBG = false; 163 private static boolean mLogMessages = false; 164 private static final String TAG = "WifiStateMachine"; 165 166 private static final int ONE_HOUR_MILLI = 1000 * 60 * 60; 167 168 private static final String GOOGLE_OUI = "DA-A1-19"; 169 170 /* temporary debug flag - best network selection development */ 171 private static boolean PDBG = false; 172 173 /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting 174 * the corresponding BSSID. 175 */ 176 private boolean didBlackListBSSID = false; 177 178 /** 179 * Log with error attribute 180 * 181 * @param s is string log 182 */ 183 protected void loge(String s) { 184 Log.e(getName(), s); 185 } 186 protected void logd(String s) { 187 Log.d(getName(), s); 188 } 189 protected void log(String s) {; 190 Log.d(getName(), s); 191 } 192 193 private WifiMonitor mWifiMonitor; 194 private WifiNative mWifiNative; 195 private WifiConfigStore mWifiConfigStore; 196 private WifiAutoJoinController mWifiAutoJoinController; 197 private INetworkManagementService mNwService; 198 private ConnectivityManager mCm; 199 private WifiLogger mWifiLogger; 200 201 private final boolean mP2pSupported; 202 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 203 private boolean mTemporarilyDisconnectWifi = false; 204 private final String mPrimaryDeviceType; 205 206 /* Scan results handling */ 207 private List<ScanDetail> mScanResults = new ArrayList<>(); 208 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 209 private static final int SCAN_RESULT_CACHE_SIZE = 160; 210 private final LruCache<NetworkDetail, ScanDetail> mScanResultCache; 211 // For debug, number of known scan results that were found as part of last scan result event, 212 // as well the number of scans results returned by the supplicant with that message 213 private int mNumScanResultsKnown; 214 private int mNumScanResultsReturned; 215 216 /* Batch scan results */ 217 private final List<BatchedScanResult> mBatchedScanResults = 218 new ArrayList<BatchedScanResult>(); 219 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 220 private int mExpectedBatchedScans = 0; 221 private long mBatchedScanMinPollTime = 0; 222 223 private boolean mScreenOn = false; 224 225 /* Chipset supports background scan */ 226 private final boolean mBackgroundScanSupported; 227 228 private String mInterfaceName; 229 /* Tethering interface could be separate from wlan interface */ 230 private String mTetherInterfaceName; 231 232 private int mLastSignalLevel = -1; 233 private String mLastBssid; 234 private int mLastNetworkId; // The network Id we successfully joined 235 private boolean linkDebouncing = false; 236 237 private boolean mAlwaysOnPnoSupported = false; 238 private int mHalFeatureSet = 0; 239 private static int mPnoResultFound = 0; 240 241 @Override 242 public void onPnoNetworkFound(ScanResult results[]) { 243 if (DBG) { 244 Log.e(TAG, "onPnoNetworkFound event received num = " + results.length); 245 for (int i = 0; i < results.length; i++) { 246 Log.e(TAG, results[i].toString()); 247 } 248 } 249 sendMessage(CMD_PNO_NETWORK_FOUND, results.length, 0, results); 250 } 251 252 public void processPnoNetworkFound(ScanResult results[]) { 253 ScanSettings settings = new ScanSettings(); 254 settings.channelSet = new ArrayList<WifiChannel>(); 255 256 for (int i=0; i<results.length; i++) { 257 WifiChannel channel = new WifiChannel(); 258 channel.freqMHz = results[i].frequency; 259 settings.channelSet.add(channel); 260 } 261 262 stopPno(); 263 264 Log.e(TAG, "processPnoNetworkFound starting scan cnt=" + mPnoResultFound); 265 startScan(PNO_NETWORK_FOUND_SOURCE, mPnoResultFound, settings, null); 266 mPnoResultFound ++; 267 //sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 268 269 // restart Pno after 30ms 270 sendMessageDelayed(CMD_START_PNO, 30 * 1000); 271 } 272 273 // Testing various network disconnect cases by sending lots of spurious 274 // disconnect to supplicant 275 private boolean testNetworkDisconnect = false; 276 277 private boolean mEnableRssiPolling = false; 278 private boolean mEnableBackgroundScan = false; 279 private int mRssiPollToken = 0; 280 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 281 * In CONNECT_MODE, the STA can scan and connect to an access point 282 * In SCAN_ONLY_MODE, the STA can only scan for access points 283 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 284 */ 285 private int mOperationalMode = CONNECT_MODE; 286 private boolean mIsScanOngoing = false; 287 private boolean mIsFullScanOngoing = false; 288 private boolean mSendScanResultsBroadcast = false; 289 290 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 291 private WorkSource mScanWorkSource = null; 292 private static final int UNKNOWN_SCAN_SOURCE = -1; 293 private static final int SCAN_ALARM_SOURCE = -2; 294 private static final int ADD_OR_UPDATE_SOURCE = -3; 295 private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4; 296 private static final int ENABLE_WIFI = -5; 297 public static final int DFS_RESTRICTED_SCAN_REQUEST = -6; 298 public static final int PNO_NETWORK_FOUND_SOURCE = -7; 299 300 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 301 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 302 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 303 private static final String SCAN_REQUEST_TIME = "scan_request_time"; 304 305 private static final String BATCHED_SETTING = "batched_settings"; 306 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 307 308 /* Tracks if state machine has received any screen state change broadcast yet. 309 * We can miss one of these at boot. 310 */ 311 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 312 313 private boolean mBluetoothConnectionActive = false; 314 315 private PowerManager.WakeLock mSuspendWakeLock; 316 317 /** 318 * Interval in milliseconds between polling for RSSI 319 * and linkspeed information 320 */ 321 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 322 323 /** 324 * Interval in milliseconds between receiving a disconnect event 325 * while connected to a good AP, and handling the disconnect proper 326 */ 327 private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000; 328 329 /** 330 * Delay between supplicant restarts upon failure to establish connection 331 */ 332 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 333 334 /** 335 * Number of times we attempt to restart supplicant 336 */ 337 private static final int SUPPLICANT_RESTART_TRIES = 5; 338 339 private int mSupplicantRestartCount = 0; 340 /* Tracks sequence number on stop failure message */ 341 private int mSupplicantStopFailureToken = 0; 342 343 /** 344 * Tether state change notification time out 345 */ 346 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 347 348 /* Tracks sequence number on a tether notification time out */ 349 private int mTetherToken = 0; 350 351 /** 352 * Driver start time out. 353 */ 354 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 355 356 /* Tracks sequence number on a driver time out */ 357 private int mDriverStartToken = 0; 358 359 /** 360 * The link properties of the wifi interface. 361 * Do not modify this directly; use updateLinkProperties instead. 362 */ 363 private LinkProperties mLinkProperties; 364 365 /* Tracks sequence number on a periodic scan message */ 366 private int mPeriodicScanToken = 0; 367 368 // Wakelock held during wifi start/stop and driver load/unload 369 private PowerManager.WakeLock mWakeLock; 370 371 private Context mContext; 372 373 private final Object mDhcpResultsLock = new Object(); 374 private DhcpResults mDhcpResults; 375 private WifiInfo mWifiInfo; 376 private NetworkInfo mNetworkInfo; 377 private NetworkCapabilities mNetworkCapabilities; 378 private SupplicantStateTracker mSupplicantStateTracker; 379 private BaseDhcpStateMachine mDhcpStateMachine; 380 private boolean mDhcpActive = false; 381 382 private int mWifiLinkLayerStatsSupported = 4; // Temporary disable 383 384 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 385 386 // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress 387 private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 388 389 // Roaming failure count 390 private int mRoamFailCount = 0; 391 392 // This is the BSSID we are trying to associate to, it can be set to "any" 393 // if we havent selected a BSSID for joining. 394 // if we havent selected a BSSID for joining. 395 // The BSSID we are associated to is found in mWifiInfo 396 private String mTargetRoamBSSID = "any"; 397 398 private long mLastDriverRoamAttempt = 0; 399 400 private WifiConfiguration targetWificonfiguration = null; 401 402 // Used as debug to indicate which configuration last was saved 403 private WifiConfiguration lastSavedConfigurationAttempt = null; 404 405 // Used as debug to indicate which configuration last was removed 406 private WifiConfiguration lastForgetConfigurationAttempt = null; 407 408 //Random used by softAP channel Selection 409 private static Random mRandom = new Random(Calendar.getInstance().getTimeInMillis()); 410 411 boolean isRoaming() { 412 return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING 413 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING; 414 } 415 416 public void autoRoamSetBSSID(int netId, String bssid) { 417 autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid); 418 } 419 420 public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) { 421 boolean ret = true; 422 if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any"; 423 if (bssid == null) bssid = "any"; 424 if (config == null) return false; // Nothing to do 425 426 if (mTargetRoamBSSID != null && bssid == mTargetRoamBSSID && bssid == config.BSSID) { 427 return false; // We didnt change anything 428 } 429 if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) { 430 // Changing to ANY 431 if (!mWifiConfigStore.roamOnAny) { 432 ret = false; // Nothing to do 433 } 434 } 435 if (VDBG) { 436 loge("autoRoamSetBSSID " + bssid 437 + " key=" + config.configKey()); 438 } 439 config.autoJoinBSSID = bssid; 440 mTargetRoamBSSID = bssid; 441 mWifiConfigStore.saveWifiConfigBSSID(config); 442 return ret; 443 } 444 445 /** 446 * Save the UID correctly depending on if this is a new or existing network. 447 * @return true if operation is authorized, false otherwise 448 */ 449 boolean recordUidIfAuthorized(WifiConfiguration config, int uid) { 450 if (!mWifiConfigStore.isNetworkConfigured(config)) { 451 config.creatorUid = uid; 452 config.creatorName = mContext.getPackageManager().getNameForUid(uid); 453 } else if (!mWifiConfigStore.canModifyNetwork(uid, config)) { 454 return false; 455 } 456 457 config.lastUpdateUid = uid; 458 config.lastUpdateName = mContext.getPackageManager().getNameForUid(uid); 459 460 return true; 461 462 } 463 464 /** 465 * Checks to see if user has specified if the apps configuration is connectable. 466 * If the user hasn't specified we query the user and return true. 467 * 468 * @param message The message to be deffered 469 * @param netId Network id of the configuration to check against 470 * @param allowOverride If true we won't defer to the user if the uid of the message holds the 471 * CONFIG_OVERRIDE_PERMISSION 472 * @return True if we are waiting for user feedback or netId is invalid. False otherwise. 473 */ 474 boolean deferForUserInput(Message message, int netId, boolean allowOverride){ 475 final WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(netId); 476 477 // We can only evaluate saved configurations. 478 if (config == null) { 479 loge("deferForUserInput: configuration for netId="+netId+" not stored"); 480 return true; 481 } 482 483 switch (config.userApproved) { 484 case WifiConfiguration.USER_APPROVED: 485 case WifiConfiguration.USER_BANNED: 486 return false; 487 case WifiConfiguration.USER_PENDING: 488 default: // USER_UNSPECIFIED 489 /* the intention was to ask user here; but a dialog box is * 490 * too invasive; so we are going to allow connection for now */ 491 config.userApproved = WifiConfiguration.USER_APPROVED; 492 return false; 493 } 494 } 495 496 /** 497 * Subset of link properties coming from netlink. 498 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 499 * and domains obtained from router advertisements (RFC 6106). 500 */ 501 private NetlinkTracker mNetlinkTracker; 502 503 private AlarmManager mAlarmManager; 504 private PendingIntent mScanIntent; 505 private PendingIntent mDriverStopIntent; 506 private PendingIntent mBatchedScanIntervalIntent; 507 508 /* Tracks current frequency mode */ 509 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 510 511 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 512 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 513 514 // Channel for sending replies. 515 private AsyncChannel mReplyChannel = new AsyncChannel(); 516 517 private WifiP2pServiceImpl mWifiP2pServiceImpl; 518 519 // Used to initiate a connection with WifiP2pService 520 private AsyncChannel mWifiP2pChannel; 521 private AsyncChannel mWifiApConfigChannel; 522 523 private WifiScanner mWifiScanner; 524 525 private int mConnectionRequests = 0; 526 private WifiNetworkFactory mNetworkFactory; 527 private UntrustedWifiNetworkFactory mUntrustedNetworkFactory; 528 private WifiNetworkAgent mNetworkAgent; 529 530 // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi 531 // We should really persist that into the networkHistory.txt file, and read it back when 532 // WifiStateMachine starts up 533 private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics(); 534 535 // Used to filter out requests we couldn't possibly satisfy. 536 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 537 538 /* The base for wifi message types */ 539 static final int BASE = Protocol.BASE_WIFI; 540 /* Start the supplicant */ 541 static final int CMD_START_SUPPLICANT = BASE + 11; 542 /* Stop the supplicant */ 543 static final int CMD_STOP_SUPPLICANT = BASE + 12; 544 /* Start the driver */ 545 static final int CMD_START_DRIVER = BASE + 13; 546 /* Stop the driver */ 547 static final int CMD_STOP_DRIVER = BASE + 14; 548 /* Indicates Static IP succeeded */ 549 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 550 /* Indicates Static IP failed */ 551 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 552 /* Indicates supplicant stop failed */ 553 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 554 /* Delayed stop to avoid shutting down driver too quick*/ 555 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 556 /* A delayed message sent to start driver when it fail to come up */ 557 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 558 559 /* Start the soft access point */ 560 static final int CMD_START_AP = BASE + 21; 561 /* Indicates soft ap start succeeded */ 562 static final int CMD_START_AP_SUCCESS = BASE + 22; 563 /* Indicates soft ap start failed */ 564 static final int CMD_START_AP_FAILURE = BASE + 23; 565 /* Stop the soft access point */ 566 static final int CMD_STOP_AP = BASE + 24; 567 /* Set the soft access point configuration */ 568 static final int CMD_SET_AP_CONFIG = BASE + 25; 569 /* Soft access point configuration set completed */ 570 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 571 /* Request the soft access point configuration */ 572 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 573 /* Response to access point configuration request */ 574 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 575 /* Invoked when getting a tether state change notification */ 576 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 577 /* A delayed message sent to indicate tether state change failed to arrive */ 578 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 579 580 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 581 582 /* Supplicant commands */ 583 /* Is supplicant alive ? */ 584 static final int CMD_PING_SUPPLICANT = BASE + 51; 585 /* Add/update a network configuration */ 586 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 587 /* Delete a network */ 588 static final int CMD_REMOVE_NETWORK = BASE + 53; 589 /* Enable a network. The device will attempt a connection to the given network. */ 590 static final int CMD_ENABLE_NETWORK = BASE + 54; 591 /* Enable all networks */ 592 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 593 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 594 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 595 /* Clear the blacklist network list */ 596 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 597 /* Save configuration */ 598 static final int CMD_SAVE_CONFIG = BASE + 58; 599 /* Get configured networks */ 600 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 601 /* Get available frequencies */ 602 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 603 /* Get adaptors */ 604 static final int CMD_GET_SUPPORTED_FEATURES = BASE + 61; 605 /* Get configured networks with real preSharedKey */ 606 static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62; 607 /* Get Link Layer Stats thru HAL */ 608 static final int CMD_GET_LINK_LAYER_STATS = BASE + 63; 609 /* Supplicant commands after driver start*/ 610 /* Initiate a scan */ 611 static final int CMD_START_SCAN = BASE + 71; 612 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 613 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 614 /* Disconnect from a network */ 615 static final int CMD_DISCONNECT = BASE + 73; 616 /* Reconnect to a network */ 617 static final int CMD_RECONNECT = BASE + 74; 618 /* Reassociate to a network */ 619 static final int CMD_REASSOCIATE = BASE + 75; 620 /* Get Connection Statistis */ 621 static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76; 622 623 /* Controls suspend mode optimizations 624 * 625 * When high perf mode is enabled, suspend mode optimizations are disabled 626 * 627 * When high perf mode is disabled, suspend mode optimizations are enabled 628 * 629 * Suspend mode optimizations include: 630 * - packet filtering 631 * - turn off roaming 632 * - DTIM wake up settings 633 */ 634 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 635 /* Set the country code */ 636 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 637 /* Enables RSSI poll */ 638 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 639 /* RSSI poll */ 640 static final int CMD_RSSI_POLL = BASE + 83; 641 /* Set up packet filtering */ 642 static final int CMD_START_PACKET_FILTERING = BASE + 84; 643 /* Clear packet filter */ 644 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 645 /* Enable suspend mode optimizations in the driver */ 646 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 647 /* Delayed NETWORK_DISCONNECT */ 648 static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87; 649 /* When there are no saved networks, we do a periodic scan to notify user of 650 * an open network */ 651 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 652 /* Test network Disconnection NETWORK_DISCONNECT */ 653 static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89; 654 private int testNetworkDisconnectCounter = 0; 655 656 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 657 static final int MULTICAST_V6 = 1; 658 static final int MULTICAST_V4 = 0; 659 660 /* Set the frequency band */ 661 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 662 /* Enable TDLS on a specific MAC address */ 663 static final int CMD_ENABLE_TDLS = BASE + 92; 664 /* DHCP/IP configuration watchdog */ 665 static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93; 666 /* Remove a packages associated configrations */ 667 static final int CMD_REMOVE_APP_CONFIGURATIONS = BASE + 97; 668 /* Remove a packages associated configrations */ 669 static final int CMD_REMOVE_USER_CONFIGURATIONS = BASE + 152; 670 671 /** 672 * Make this timer 40 seconds, which is about the normal DHCP timeout. 673 * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress 674 * for more than 30 seconds. 675 */ 676 static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 40000; 677 678 int obtainingIpWatchdogCount = 0; 679 680 /* Commands from/to the SupplicantStateTracker */ 681 /* Reset the supplicant state tracker */ 682 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 683 684 685 /** 686 * Watchdog for protecting against b/16823537 687 * Leave time for 4-ways handshake to succeed 688 */ 689 static final int ROAM_GUARD_TIMER_MSEC = 15000; 690 691 int roamWatchdogCount = 0; 692 /* Roam state watchdog */ 693 static final int CMD_ROAM_WATCHDOG_TIMER = BASE + 94; 694 /* Screen change intent handling */ 695 static final int CMD_SCREEN_STATE_CHANGED = BASE + 95; 696 697 int disconnectingWatchdogCount = 0; 698 static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000; 699 700 /* Disconnecting state watchdog */ 701 static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96; 702 703 /* Disable an ephemeral network */ 704 static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98; 705 706 /* Get matching network */ 707 static final int CMD_GET_MATCHING_CONFIG = BASE + 99; 708 709 /* P2p commands */ 710 /* We are ok with no response here since we wont do much with it anyway */ 711 public static final int CMD_ENABLE_P2P = BASE + 131; 712 /* In order to shut down supplicant cleanly, we wait till p2p has 713 * been disabled */ 714 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 715 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 716 717 public static final int CMD_BOOT_COMPLETED = BASE + 134; 718 719 /* change the batch scan settings. 720 * arg1 = responsible UID 721 * arg2 = csph (channel scans per hour) 722 * obj = bundle with the new settings and the optional worksource 723 */ 724 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 725 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 726 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 727 728 /* We now have a valid IP configuration. */ 729 static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138; 730 /* We no longer have a valid IP configuration. */ 731 static final int CMD_IP_CONFIGURATION_LOST = BASE + 139; 732 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 733 static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140; 734 735 /* Supplicant is trying to associate to a given BSSID */ 736 static final int CMD_TARGET_BSSID = BASE + 141; 737 738 /* Reload all networks and reconnect */ 739 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 740 741 static final int CMD_AUTO_CONNECT = BASE + 143; 742 743 static final int network_status_unwanted_disconnect = 0; 744 static final int network_status_unwanted_disable_autojoin = 1; 745 746 static final int CMD_UNWANTED_NETWORK = BASE + 144; 747 748 static final int CMD_AUTO_ROAM = BASE + 145; 749 750 static final int CMD_AUTO_SAVE_NETWORK = BASE + 146; 751 752 static final int CMD_ASSOCIATED_BSSID = BASE + 147; 753 754 static final int CMD_NETWORK_STATUS = BASE + 148; 755 756 /* Note: BASE + 152 in use by CMD_REMOVE_USER_CONFIGURATIONS */ 757 758 static final int CMD_ACCEPT_UNVALIDATED = BASE + 153; 759 static final int CMD_START_PNO = BASE + 154; /* used to restart PNO when it was 760 stopped due to association attempt */ 761 762 static final int CMD_STARTED_PNO_DBG = BASE + 155; /* used to log if PNO was started */ 763 764 static final int CMD_PNO_NETWORK_FOUND = BASE + 156; 765 766 767 /* Wifi state machine modes of operation */ 768 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 769 public static final int CONNECT_MODE = 1; 770 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 771 public static final int SCAN_ONLY_MODE = 2; 772 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 773 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 774 775 private static final int SUCCESS = 1; 776 private static final int FAILURE = -1; 777 778 /* Tracks if suspend optimizations need to be disabled by DHCP, 779 * screen or due to high perf mode. 780 * When any of them needs to disable it, we keep the suspend optimizations 781 * disabled 782 */ 783 private int mSuspendOptNeedsDisabled = 0; 784 785 private static final int SUSPEND_DUE_TO_DHCP = 1; 786 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1; 787 private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2; 788 789 /* Tracks if user has enabled suspend optimizations through settings */ 790 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 791 792 /** 793 * Default framework scan interval in milliseconds. This is used in the scenario in which 794 * wifi chipset does not support background scanning to set up a 795 * periodic wake up scan so that the device can connect to a new access 796 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 797 * override this. 798 */ 799 private final int mDefaultFrameworkScanIntervalMs; 800 801 /** 802 * Supplicant scan interval in milliseconds. 803 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 804 * from the default config if the setting is not set 805 */ 806 private long mSupplicantScanIntervalMs; 807 808 /** 809 * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit 810 */ 811 private long lastFullBandConnectedTimeMilli; 812 813 /** 814 * time interval to the next full band scan we will perform for 815 * autojoin while connected with screen lit 816 */ 817 private long fullBandConnectedTimeIntervalMilli; 818 819 /** 820 * max time interval to the next full band scan we will perform for 821 * autojoin while connected with screen lit 822 * Max time is 5 minutes 823 */ 824 private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5; 825 826 /** 827 * Minimum time interval between enabling all networks. 828 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 829 * due to enabling every time. We add a threshold to avoid this. 830 */ 831 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 832 private long mLastEnableAllNetworksTime; 833 834 int mRunningBeaconCount = 0; 835 836 /** 837 * Starting and shutting down driver too quick causes problems leading to driver 838 * being in a bad state. Delay driver stop. 839 */ 840 private final int mDriverStopDelayMs; 841 private int mDelayedStopCounter; 842 private boolean mInDelayedStop = false; 843 844 // there is a delay between StateMachine change country code and Supplicant change country code 845 // here save the current WifiStateMachine set country code 846 private volatile String mSetCountryCode = null; 847 848 // Supplicant doesn't like setting the same country code multiple times (it may drop 849 // currently connected network), so we save the current device set country code here to avoid 850 // redundency 851 private String mDriverSetCountryCode = null; 852 853 /* Default parent state */ 854 private State mDefaultState = new DefaultState(); 855 /* Temporary initial state */ 856 private State mInitialState = new InitialState(); 857 /* Driver loaded, waiting for supplicant to start */ 858 private State mSupplicantStartingState = new SupplicantStartingState(); 859 /* Driver loaded and supplicant ready */ 860 private State mSupplicantStartedState = new SupplicantStartedState(); 861 /* Waiting for supplicant to stop and monitor to exit */ 862 private State mSupplicantStoppingState = new SupplicantStoppingState(); 863 /* Driver start issued, waiting for completed event */ 864 private State mDriverStartingState = new DriverStartingState(); 865 /* Driver started */ 866 private State mDriverStartedState = new DriverStartedState(); 867 /* Wait until p2p is disabled 868 * This is a special state which is entered right after we exit out of DriverStartedState 869 * before transitioning to another state. 870 */ 871 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 872 /* Driver stopping */ 873 private State mDriverStoppingState = new DriverStoppingState(); 874 /* Driver stopped */ 875 private State mDriverStoppedState = new DriverStoppedState(); 876 /* Scan for networks, no connection will be established */ 877 private State mScanModeState = new ScanModeState(); 878 /* Connecting to an access point */ 879 private State mConnectModeState = new ConnectModeState(); 880 /* Connected at 802.11 (L2) level */ 881 private State mL2ConnectedState = new L2ConnectedState(); 882 /* fetching IP after connection to access point (assoc+auth complete) */ 883 private State mObtainingIpState = new ObtainingIpState(); 884 /* Waiting for link quality verification to be complete */ 885 private State mVerifyingLinkState = new VerifyingLinkState(); 886 /* Connected with IP addr */ 887 private State mConnectedState = new ConnectedState(); 888 /* Roaming */ 889 private State mRoamingState = new RoamingState(); 890 /* disconnect issued, waiting for network disconnect confirmation */ 891 private State mDisconnectingState = new DisconnectingState(); 892 /* Network is not connected, supplicant assoc+auth is not complete */ 893 private State mDisconnectedState = new DisconnectedState(); 894 /* Waiting for WPS to be completed*/ 895 private State mWpsRunningState = new WpsRunningState(); 896 897 /* Soft ap is starting up */ 898 private State mSoftApStartingState = new SoftApStartingState(); 899 /* Soft ap is running */ 900 private State mSoftApStartedState = new SoftApStartedState(); 901 /* Soft ap is running and we are waiting for tether notification */ 902 private State mTetheringState = new TetheringState(); 903 /* Soft ap is running and we are tethered through connectivity service */ 904 private State mTetheredState = new TetheredState(); 905 /* Waiting for untether confirmation before stopping soft Ap */ 906 private State mUntetheringState = new UntetheringState(); 907 908 909 910 private class WifiScanListener implements WifiScanner.ScanListener { 911 @Override 912 public void onSuccess() { 913 Log.e(TAG, "WifiScanListener onSuccess"); 914 }; 915 @Override 916 public void onFailure(int reason, String description) { 917 Log.e(TAG, "WifiScanListener onFailure"); 918 }; 919 @Override 920 public void onPeriodChanged(int periodInMs) { 921 Log.e(TAG, "WifiScanListener onPeriodChanged period=" + periodInMs); 922 } 923 @Override 924 public void onResults(WifiScanner.ScanData[] results) { 925 Log.e(TAG, "WifiScanListener onResults2 " + results.length); 926 } 927 @Override 928 public void onFullResult(ScanResult fullScanResult) { 929 Log.e(TAG, "WifiScanListener onFullResult " + fullScanResult.toString()); 930 } 931 932 WifiScanListener() {} 933 } 934 935 WifiScanListener mWifiScanListener = new WifiScanListener(); 936 937 938 private class TetherStateChange { 939 ArrayList<String> available; 940 ArrayList<String> active; 941 942 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 943 available = av; 944 active = ac; 945 } 946 } 947 948 public static class SimAuthRequestData { 949 int networkId; 950 int protocol; 951 String ssid; 952 // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges 953 // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge 954 String[] data; 955 } 956 957 /** 958 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 959 * {@link WifiManager#WIFI_STATE_DISABLING}, 960 * {@link WifiManager#WIFI_STATE_ENABLED}, 961 * {@link WifiManager#WIFI_STATE_ENABLING}, 962 * {@link WifiManager#WIFI_STATE_UNKNOWN} 963 */ 964 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 965 966 /** 967 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 968 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 969 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 970 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 971 * {@link WifiManager#WIFI_AP_STATE_FAILED} 972 */ 973 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 974 975 private static final int SCAN_REQUEST = 0; 976 private static final String ACTION_START_SCAN = 977 "com.android.server.WifiManager.action.START_SCAN"; 978 979 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 980 private static final int DRIVER_STOP_REQUEST = 0; 981 private static final String ACTION_DELAYED_DRIVER_STOP = 982 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 983 984 private static final String ACTION_REFRESH_BATCHED_SCAN = 985 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 986 /** 987 * Keep track of whether WIFI is running. 988 */ 989 private boolean mIsRunning = false; 990 991 /** 992 * Keep track of whether we last told the battery stats we had started. 993 */ 994 private boolean mReportedRunning = false; 995 996 /** 997 * Most recently set source of starting WIFI. 998 */ 999 private final WorkSource mRunningWifiUids = new WorkSource(); 1000 1001 /** 1002 * The last reported UIDs that were responsible for starting WIFI. 1003 */ 1004 private final WorkSource mLastRunningWifiUids = new WorkSource(); 1005 1006 private final IBatteryStats mBatteryStats; 1007 1008 private BatchedScanSettings mBatchedScanSettings = null; 1009 1010 /** 1011 * Track the worksource/cost of the current settings and track what's been noted 1012 * to the battery stats, so we can mark the end of the previous when changing. 1013 */ 1014 private WorkSource mBatchedScanWorkSource = null; 1015 private int mBatchedScanCsph = 0; 1016 private WorkSource mNotedBatchedScanWorkSource = null; 1017 private int mNotedBatchedScanCsph = 0; 1018 1019 private final String mTcpBufferSizes; 1020 1021 // Used for debug and stats gathering 1022 private static int sScanAlarmIntentCount = 0; 1023 1024 final static int frameworkMinScanIntervalSaneValue = 10000; 1025 1026 public WifiStateMachine(Context context, String wlanInterface, 1027 WifiTrafficPoller trafficPoller) { 1028 super("WifiStateMachine"); 1029 mContext = context; 1030 mSetCountryCode = Settings.Global.getString( 1031 mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE); 1032 mInterfaceName = wlanInterface; 1033 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 1034 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 1035 BatteryStats.SERVICE_NAME)); 1036 1037 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 1038 mNwService = INetworkManagementService.Stub.asInterface(b); 1039 1040 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 1041 PackageManager.FEATURE_WIFI_DIRECT); 1042 1043 mWifiNative = new WifiNative(mInterfaceName); 1044 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 1045 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 1046 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); 1047 mWifiLogger = new WifiLogger(mContext, this); 1048 mWifiMonitor = new WifiMonitor(this, mWifiNative); 1049 mWifiInfo = new WifiInfo(); 1050 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 1051 getHandler()); 1052 mLinkProperties = new LinkProperties(); 1053 1054 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 1055 mWifiP2pServiceImpl = (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1); 1056 1057 IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE); 1058 1059 mNetworkInfo.setIsAvailable(false); 1060 mLastBssid = null; 1061 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 1062 mLastSignalLevel = -1; 1063 1064 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 1065 public void update() { 1066 sendMessage(CMD_UPDATE_LINKPROPERTIES); 1067 } 1068 }); 1069 try { 1070 mNwService.registerObserver(mNetlinkTracker); 1071 } catch (RemoteException e) { 1072 loge("Couldn't register netlink tracker: " + e.toString()); 1073 } 1074 1075 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 1076 mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST); 1077 mBatchedScanIntervalIntent = getPrivateBroadcast(ACTION_REFRESH_BATCHED_SCAN, 0); 1078 1079 // Make sure the interval is not configured less than 10 seconds 1080 int period = mContext.getResources().getInteger( 1081 R.integer.config_wifi_framework_scan_interval); 1082 if (period < frameworkMinScanIntervalSaneValue) { 1083 period = frameworkMinScanIntervalSaneValue; 1084 } 1085 mDefaultFrameworkScanIntervalMs = period; 1086 mDriverStopDelayMs = mContext.getResources().getInteger( 1087 R.integer.config_wifi_driver_stop_delay); 1088 1089 mBackgroundScanSupported = mContext.getResources().getBoolean( 1090 R.bool.config_wifi_background_scan_support); 1091 1092 mPrimaryDeviceType = mContext.getResources().getString( 1093 R.string.config_wifi_p2p_device_type); 1094 1095 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 1096 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 1097 1098 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 1099 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 1100 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 1101 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 1102 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 1103 // TODO - needs to be a bit more dynamic 1104 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 1105 1106 mContext.registerReceiver( 1107 new BroadcastReceiver() { 1108 @Override 1109 public void onReceive(Context context, Intent intent) { 1110 ArrayList<String> available = intent.getStringArrayListExtra( 1111 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 1112 ArrayList<String> active = intent.getStringArrayListExtra( 1113 ConnectivityManager.EXTRA_ACTIVE_TETHER); 1114 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 1115 } 1116 }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 1117 1118 mContext.registerReceiver( 1119 new BroadcastReceiver() { 1120 @Override 1121 public void onReceive(Context context, Intent intent) { 1122 sScanAlarmIntentCount++; // Used for debug only 1123 startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null); 1124 if (VDBG) 1125 loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get()); 1126 } 1127 }, 1128 new IntentFilter(ACTION_START_SCAN)); 1129 1130 IntentFilter filter = new IntentFilter(); 1131 filter.addAction(Intent.ACTION_SCREEN_ON); 1132 filter.addAction(Intent.ACTION_SCREEN_OFF); 1133 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 1134 mContext.registerReceiver( 1135 new BroadcastReceiver() { 1136 @Override 1137 public void onReceive(Context context, Intent intent) { 1138 String action = intent.getAction(); 1139 1140 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1141 sendMessage(CMD_SCREEN_STATE_CHANGED, 1); 1142 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1143 sendMessage(CMD_SCREEN_STATE_CHANGED, 0); 1144 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 1145 startNextBatchedScanAsync(); 1146 } 1147 } 1148 }, filter); 1149 1150 mContext.registerReceiver( 1151 new BroadcastReceiver() { 1152 @Override 1153 public void onReceive(Context context, Intent intent) { 1154 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 1155 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 1156 } 1157 }, 1158 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 1159 1160 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 1161 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 1162 new ContentObserver(getHandler()) { 1163 @Override 1164 public void onChange(boolean selfChange) { 1165 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 1166 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 1167 } 1168 }); 1169 1170 mContext.registerReceiver( 1171 new BroadcastReceiver() { 1172 @Override 1173 public void onReceive(Context context, Intent intent) { 1174 sendMessage(CMD_BOOT_COMPLETED); 1175 } 1176 }, 1177 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 1178 1179 mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE); 1180 1181 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 1182 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 1183 1184 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 1185 mSuspendWakeLock.setReferenceCounted(false); 1186 1187 mTcpBufferSizes = mContext.getResources().getString( 1188 com.android.internal.R.string.config_wifi_tcp_buffers); 1189 1190 addState(mDefaultState); 1191 addState(mInitialState, mDefaultState); 1192 addState(mSupplicantStartingState, mDefaultState); 1193 addState(mSupplicantStartedState, mDefaultState); 1194 addState(mDriverStartingState, mSupplicantStartedState); 1195 addState(mDriverStartedState, mSupplicantStartedState); 1196 addState(mScanModeState, mDriverStartedState); 1197 addState(mConnectModeState, mDriverStartedState); 1198 addState(mL2ConnectedState, mConnectModeState); 1199 addState(mObtainingIpState, mL2ConnectedState); 1200 addState(mVerifyingLinkState, mL2ConnectedState); 1201 addState(mConnectedState, mL2ConnectedState); 1202 addState(mRoamingState, mL2ConnectedState); 1203 addState(mDisconnectingState, mConnectModeState); 1204 addState(mDisconnectedState, mConnectModeState); 1205 addState(mWpsRunningState, mConnectModeState); 1206 addState(mWaitForP2pDisableState, mSupplicantStartedState); 1207 addState(mDriverStoppingState, mSupplicantStartedState); 1208 addState(mDriverStoppedState, mSupplicantStartedState); 1209 addState(mSupplicantStoppingState, mDefaultState); 1210 addState(mSoftApStartingState, mDefaultState); 1211 addState(mSoftApStartedState, mDefaultState); 1212 addState(mTetheringState, mSoftApStartedState); 1213 addState(mTetheredState, mSoftApStartedState); 1214 addState(mUntetheringState, mSoftApStartedState); 1215 1216 setInitialState(mInitialState); 1217 1218 setLogRecSize(ActivityManager.isLowRamDeviceStatic() ? 100 : 3000); 1219 setLogOnlyTransitions(false); 1220 if (VDBG) setDbg(true); 1221 1222 //start the state machine 1223 start(); 1224 1225 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 1226 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1227 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 1228 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1229 } 1230 1231 1232 PendingIntent getPrivateBroadcast(String action, int requestCode) { 1233 Intent intent = new Intent(action, null); 1234 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1235 intent.setPackage(this.getClass().getPackage().getName()); 1236 return PendingIntent.getBroadcast(mContext, requestCode, intent, 0); 1237 } 1238 1239 private int mVerboseLoggingLevel = 0; 1240 1241 int getVerboseLoggingLevel() { 1242 return mVerboseLoggingLevel; 1243 } 1244 1245 void enableVerboseLogging(int verbose) { 1246 mVerboseLoggingLevel = verbose; 1247 if (verbose > 0) { 1248 DBG = true; 1249 VDBG = true; 1250 PDBG = true; 1251 mLogMessages = true; 1252 mWifiNative.setSupplicantLogLevel("DEBUG"); 1253 } else { 1254 DBG = false; 1255 VDBG = false; 1256 PDBG = false; 1257 mLogMessages = false; 1258 mWifiNative.setSupplicantLogLevel("INFO"); 1259 } 1260 mWifiAutoJoinController.enableVerboseLogging(verbose); 1261 mWifiMonitor.enableVerboseLogging(verbose); 1262 mWifiNative.enableVerboseLogging(verbose); 1263 mWifiConfigStore.enableVerboseLogging(verbose); 1264 mSupplicantStateTracker.enableVerboseLogging(verbose); 1265 } 1266 1267 private int mAggressiveHandover = 0; 1268 1269 int getAggressiveHandover() { 1270 return mAggressiveHandover; 1271 } 1272 1273 void enableAggressiveHandover(int enabled) { 1274 mAggressiveHandover = enabled; 1275 } 1276 1277 public void clearANQPCache() { 1278 mWifiConfigStore.clearANQPCache(); 1279 } 1280 1281 public void setAllowScansWithTraffic(int enabled) { 1282 mWifiConfigStore.alwaysEnableScansWhileAssociated.set(enabled); 1283 } 1284 1285 public int getAllowScansWithTraffic() { 1286 return mWifiConfigStore.alwaysEnableScansWhileAssociated.get(); 1287 } 1288 1289 public void setAllowScansWhileAssociated(boolean enabled) { 1290 mWifiConfigStore.enableAutoJoinScanWhenAssociated.set(enabled); 1291 } 1292 1293 public boolean getAllowScansWhileAssociated() { 1294 return mWifiConfigStore.enableAutoJoinScanWhenAssociated.get(); 1295 } 1296 1297 /* 1298 * 1299 * Framework scan control 1300 */ 1301 1302 private boolean mAlarmEnabled = false; 1303 1304 private AtomicInteger mDelayedScanCounter = new AtomicInteger(); 1305 1306 private void setScanAlarm(boolean enabled) { 1307 if (PDBG) { 1308 loge("setScanAlarm " + enabled 1309 + " period " + mDefaultFrameworkScanIntervalMs 1310 + " mBackgroundScanSupported " + mBackgroundScanSupported); 1311 } 1312 if (mBackgroundScanSupported == false) { 1313 // Scan alarm is only used for background scans if they are not 1314 // offloaded to the wifi chipset, hence enable the scan alarm 1315 // gicing us RTC_WAKEUP of backgroundScan is NOT supported 1316 enabled = true; 1317 } 1318 1319 if (enabled == mAlarmEnabled) return; 1320 if (enabled) { 1321 /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */ 1322 /* going to wake up the host processor to look for access points */ 1323 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 1324 System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs, 1325 mScanIntent); 1326 mAlarmEnabled = true; 1327 } else { 1328 mAlarmManager.cancel(mScanIntent); 1329 mAlarmEnabled = false; 1330 } 1331 } 1332 1333 private void cancelDelayedScan() { 1334 mDelayedScanCounter.incrementAndGet(); 1335 loge("cancelDelayedScan -> " + mDelayedScanCounter); 1336 } 1337 1338 private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli, 1339 ScanSettings settings, WorkSource workSource) { 1340 1341 if (counter != mDelayedScanCounter.get()) { 1342 return false; 1343 } 1344 if (restart) 1345 startDelayedScan(milli, settings, workSource); 1346 return true; 1347 } 1348 1349 private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) { 1350 if (milli <= 0) return; 1351 /** 1352 * The cases where the scan alarm should be run are : 1353 * - DisconnectedState && screenOn => used delayed timer 1354 * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO 1355 * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm 1356 * - ConnectedState && screenOn => used delayed timer 1357 */ 1358 1359 mDelayedScanCounter.incrementAndGet(); 1360 if (mScreenOn && 1361 (getCurrentState() == mDisconnectedState 1362 || getCurrentState() == mConnectedState)) { 1363 Bundle bundle = new Bundle(); 1364 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1365 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1366 bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); 1367 sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE, 1368 mDelayedScanCounter.get(), bundle, milli); 1369 if (DBG) loge("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli); 1370 } else if (mBackgroundScanSupported == false 1371 && !mScreenOn && getCurrentState() == mDisconnectedState) { 1372 setScanAlarm(true); 1373 if (DBG) loge("startDelayedScan start scan alarm -> " 1374 + mDelayedScanCounter + " milli " + milli); 1375 } else { 1376 if (DBG) loge("startDelayedScan unhandled -> " 1377 + mDelayedScanCounter + " milli " + milli); 1378 } 1379 } 1380 1381 private boolean setRandomMacOui() { 1382 String oui = mContext.getResources().getString( 1383 R.string.config_wifi_random_mac_oui, GOOGLE_OUI); 1384 String[] ouiParts = oui.split("-"); 1385 byte[] ouiBytes = new byte[3]; 1386 ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF); 1387 ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF); 1388 ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF); 1389 1390 logd("Setting OUI to " + oui); 1391 return mWifiNative.setScanningMacOui(ouiBytes); 1392 } 1393 1394 /** 1395 * ****************************************************** 1396 * Methods exposed for public use 1397 * ****************************************************** 1398 */ 1399 1400 public Messenger getMessenger() { 1401 return new Messenger(getHandler()); 1402 } 1403 1404 public WifiMonitor getWifiMonitor() { 1405 return mWifiMonitor; 1406 } 1407 1408 /** 1409 * TODO: doc 1410 */ 1411 public boolean syncPingSupplicant(AsyncChannel channel) { 1412 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1413 boolean result = (resultMsg.arg1 != FAILURE); 1414 resultMsg.recycle(); 1415 return result; 1416 } 1417 1418 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1419 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1420 List<WifiChannel> list = null; 1421 if (resultMsg.obj != null) { 1422 list = new ArrayList<WifiChannel>(); 1423 String freqs = (String) resultMsg.obj; 1424 String[] lines = freqs.split("\n"); 1425 for (String line : lines) 1426 if (line.contains("MHz")) { 1427 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1428 WifiChannel c = new WifiChannel(); 1429 String[] prop = line.split(" "); 1430 if (prop.length < 5) continue; 1431 try { 1432 c.channelNum = Integer.parseInt(prop[1]); 1433 c.freqMHz = Integer.parseInt(prop[3]); 1434 } catch (NumberFormatException e) { 1435 } 1436 c.isDFS = line.contains("(DFS)"); 1437 list.add(c); 1438 } else if (line.contains("Mode[B] Channels:")) { 1439 // B channels are the same as G channels, skipped 1440 break; 1441 } 1442 } 1443 resultMsg.recycle(); 1444 return (list != null && list.size() > 0) ? list : null; 1445 } 1446 1447 /** 1448 * When settings allowing making use of untrusted networks change, trigger a scan 1449 * so as to kick of autojoin. 1450 */ 1451 public void startScanForUntrustedSettingChange() { 1452 startScan(SET_ALLOW_UNTRUSTED_SOURCE, 0, null, null); 1453 } 1454 1455 /** 1456 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1457 * given to callingUid. 1458 * 1459 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1460 * workSource is specified. 1461 * @param workSource If not null, blame is given to workSource. 1462 * @param settings Scan settings, see {@link ScanSettings}. 1463 */ 1464 public void startScan(int callingUid, int scanCounter, 1465 ScanSettings settings, WorkSource workSource) { 1466 Bundle bundle = new Bundle(); 1467 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1468 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1469 bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); 1470 sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle); 1471 } 1472 1473 /** 1474 * start or stop batched scanning using the given settings 1475 */ 1476 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1477 WorkSource workSource) { 1478 Bundle bundle = new Bundle(); 1479 bundle.putParcelable(BATCHED_SETTING, settings); 1480 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1481 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1482 } 1483 1484 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1485 synchronized (mBatchedScanResults) { 1486 List<BatchedScanResult> batchedScanList = 1487 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1488 for (BatchedScanResult result : mBatchedScanResults) { 1489 batchedScanList.add(new BatchedScanResult(result)); 1490 } 1491 return batchedScanList; 1492 } 1493 } 1494 1495 public void requestBatchedScanPoll() { 1496 sendMessage(CMD_POLL_BATCHED_SCAN); 1497 } 1498 1499 private void startBatchedScan() { 1500 if (mBatchedScanSettings == null) return; 1501 1502 if (mDhcpActive) { 1503 if (DBG) log("not starting Batched Scans due to DHCP"); 1504 return; 1505 } 1506 1507 // first grab any existing data 1508 retrieveBatchedScanData(); 1509 1510 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1511 1512 1513 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1514 1515 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1516 try { 1517 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1518 setNextBatchedAlarm(mExpectedBatchedScans); 1519 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1520 } catch (NumberFormatException e) { 1521 stopBatchedScan(); 1522 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1523 } 1524 } 1525 1526 // called from BroadcastListener 1527 private void startNextBatchedScanAsync() { 1528 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1529 } 1530 1531 private void startNextBatchedScan() { 1532 // first grab any existing data 1533 retrieveBatchedScanData(); 1534 1535 setNextBatchedAlarm(mExpectedBatchedScans); 1536 } 1537 1538 private void handleBatchedScanPollRequest() { 1539 if (DBG) { 1540 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1541 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1542 mBatchedScanSettings); 1543 } 1544 // if there is no appropriate PollTime that's because we either aren't 1545 // batching or we've already set a time for a poll request 1546 if (mBatchedScanMinPollTime == 0) return; 1547 if (mBatchedScanSettings == null) return; 1548 1549 long now = System.currentTimeMillis(); 1550 1551 if (now > mBatchedScanMinPollTime) { 1552 // do the poll and reset our timers 1553 startNextBatchedScan(); 1554 } else { 1555 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1556 mBatchedScanIntervalIntent); 1557 mBatchedScanMinPollTime = 0; 1558 } 1559 } 1560 1561 // return true if new/different 1562 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1563 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1564 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1565 1566 if (DBG) { 1567 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1568 ", worksource=" + responsibleWorkSource); 1569 } 1570 if (settings != null) { 1571 if (settings.equals(mBatchedScanSettings)) return false; 1572 } else { 1573 if (mBatchedScanSettings == null) return false; 1574 } 1575 mBatchedScanSettings = settings; 1576 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1577 mBatchedScanWorkSource = responsibleWorkSource; 1578 mBatchedScanCsph = csph; 1579 return true; 1580 } 1581 1582 private void stopBatchedScan() { 1583 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1584 retrieveBatchedScanData(); 1585 mWifiNative.setBatchedScanSettings(null); 1586 noteBatchedScanStop(); 1587 } 1588 1589 private void setNextBatchedAlarm(int scansExpected) { 1590 1591 if (mBatchedScanSettings == null || scansExpected < 1) return; 1592 1593 mBatchedScanMinPollTime = System.currentTimeMillis() + 1594 mBatchedScanSettings.scanIntervalSec * 1000; 1595 1596 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1597 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1598 } 1599 1600 int secToFull = mBatchedScanSettings.scanIntervalSec; 1601 secToFull *= scansExpected; 1602 1603 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1604 if (debugPeriod > 0) secToFull = debugPeriod; 1605 1606 // set the alarm to do the next poll. We set it a little short as we'd rather 1607 // wake up wearly than miss a scan due to buffer overflow 1608 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1609 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1610 mBatchedScanIntervalIntent); 1611 } 1612 1613 /** 1614 * Start reading new scan data 1615 * Data comes in as: 1616 * "scancount=5\n" 1617 * "nextcount=5\n" 1618 * "apcount=3\n" 1619 * "trunc\n" (optional) 1620 * "bssid=...\n" 1621 * "ssid=...\n" 1622 * "freq=...\n" (in Mhz) 1623 * "level=...\n" 1624 * "dist=...\n" (in cm) 1625 * "distsd=...\n" (standard deviation, in cm) 1626 * "====" 1627 * "bssid=...\n" 1628 * etc 1629 * "====" 1630 * "bssid=...\n" 1631 * etc 1632 * "%%%%" 1633 * "apcount=2\n" 1634 * "bssid=...\n" 1635 * etc 1636 * "%%%% 1637 * etc 1638 * "----" 1639 */ 1640 private final static boolean DEBUG_PARSE = false; 1641 1642 private void retrieveBatchedScanData() { 1643 String rawData = mWifiNative.getBatchedScanResults(); 1644 if (DEBUG_PARSE) log("rawData = " + rawData); 1645 mBatchedScanMinPollTime = 0; 1646 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1647 loge("Unexpected BatchedScanResults :" + rawData); 1648 return; 1649 } 1650 1651 int scanCount = 0; 1652 final String END_OF_BATCHES = "----"; 1653 final String SCANCOUNT = "scancount="; 1654 final String TRUNCATED = "trunc"; 1655 final String AGE = "age="; 1656 final String DIST = "dist="; 1657 final String DISTSD = "distSd="; 1658 1659 String splitData[] = rawData.split("\n"); 1660 int n = 0; 1661 if (splitData[n].startsWith(SCANCOUNT)) { 1662 try { 1663 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1664 } catch (NumberFormatException e) { 1665 loge("scancount parseInt Exception from " + splitData[n]); 1666 } 1667 } else log("scancount not found"); 1668 if (scanCount == 0) { 1669 loge("scanCount==0 - aborting"); 1670 return; 1671 } 1672 1673 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1674 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1675 1676 synchronized (mBatchedScanResults) { 1677 mBatchedScanResults.clear(); 1678 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1679 1680 String bssid = null; 1681 WifiSsid wifiSsid = null; 1682 int level = 0; 1683 int freq = 0; 1684 int dist, distSd; 1685 long tsf = 0; 1686 dist = distSd = ScanResult.UNSPECIFIED; 1687 final long now = SystemClock.elapsedRealtime(); 1688 final int bssidStrLen = BSSID_STR.length(); 1689 1690 while (true) { 1691 while (n < splitData.length) { 1692 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1693 if (splitData[n].equals(END_OF_BATCHES)) { 1694 if (n + 1 != splitData.length) { 1695 loge("didn't consume " + (splitData.length - n)); 1696 } 1697 if (mBatchedScanResults.size() > 0) { 1698 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1699 } 1700 logd("retrieveBatchedScanResults X"); 1701 return; 1702 } 1703 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1704 if (bssid != null) { 1705 batchedScanResult.scanResults.add(new ScanResult( 1706 wifiSsid, bssid, null, 1707 level, freq, tsf, dist, distSd)); 1708 wifiSsid = null; 1709 bssid = null; 1710 level = 0; 1711 freq = 0; 1712 tsf = 0; 1713 dist = distSd = ScanResult.UNSPECIFIED; 1714 } 1715 if (splitData[n].equals(END_STR)) { 1716 if (batchedScanResult.scanResults.size() != 0) { 1717 mBatchedScanResults.add(batchedScanResult); 1718 batchedScanResult = new BatchedScanResult(); 1719 } else { 1720 logd("Found empty batch"); 1721 } 1722 } 1723 } else if (splitData[n].equals(TRUNCATED)) { 1724 batchedScanResult.truncated = true; 1725 } else if (splitData[n].startsWith(BSSID_STR)) { 1726 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1727 splitData[n].length() - bssidStrLen); 1728 } else if (splitData[n].startsWith(FREQ_STR)) { 1729 try { 1730 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1731 } catch (NumberFormatException e) { 1732 loge("Invalid freqency: " + splitData[n]); 1733 freq = 0; 1734 } 1735 } else if (splitData[n].startsWith(AGE)) { 1736 try { 1737 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1738 tsf *= 1000; // convert mS -> uS 1739 } catch (NumberFormatException e) { 1740 loge("Invalid timestamp: " + splitData[n]); 1741 tsf = 0; 1742 } 1743 } else if (splitData[n].startsWith(SSID_STR)) { 1744 wifiSsid = WifiSsid.createFromAsciiEncoded( 1745 splitData[n].substring(SSID_STR.length())); 1746 } else if (splitData[n].startsWith(LEVEL_STR)) { 1747 try { 1748 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1749 if (level > 0) level -= 256; 1750 } catch (NumberFormatException e) { 1751 loge("Invalid level: " + splitData[n]); 1752 level = 0; 1753 } 1754 } else if (splitData[n].startsWith(DIST)) { 1755 try { 1756 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1757 } catch (NumberFormatException e) { 1758 loge("Invalid distance: " + splitData[n]); 1759 dist = ScanResult.UNSPECIFIED; 1760 } 1761 } else if (splitData[n].startsWith(DISTSD)) { 1762 try { 1763 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1764 } catch (NumberFormatException e) { 1765 loge("Invalid distanceSd: " + splitData[n]); 1766 distSd = ScanResult.UNSPECIFIED; 1767 } 1768 } else { 1769 loge("Unable to parse batched scan result line: " + splitData[n]); 1770 } 1771 n++; 1772 } 1773 rawData = mWifiNative.getBatchedScanResults(); 1774 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1775 if (rawData == null) { 1776 loge("Unexpected null BatchedScanResults"); 1777 return; 1778 } 1779 splitData = rawData.split("\n"); 1780 if (splitData.length == 0 || splitData[0].equals("ok")) { 1781 loge("batch scan results just ended!"); 1782 if (mBatchedScanResults.size() > 0) { 1783 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1784 } 1785 return; 1786 } 1787 n = 0; 1788 } 1789 } 1790 } 1791 1792 private long mDisconnectedTimeStamp = 0; 1793 1794 public long getDisconnectedTimeMilli() { 1795 if (getCurrentState() == mDisconnectedState 1796 && mDisconnectedTimeStamp != 0) { 1797 long now_ms = System.currentTimeMillis(); 1798 return now_ms - mDisconnectedTimeStamp; 1799 } 1800 return 0; 1801 } 1802 1803 // Keeping track of scan requests 1804 private long lastStartScanTimeStamp = 0; 1805 private long lastScanDuration = 0; 1806 // Last connect attempt is used to prevent scan requests: 1807 // - for a period of 10 seconds after attempting to connect 1808 private long lastConnectAttempt = 0; 1809 private String lastScanFreqs = null; 1810 1811 // For debugging, keep track of last message status handling 1812 // TODO, find an equivalent mechanism as part of parent class 1813 private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2; 1814 private static int MESSAGE_HANDLING_STATUS_OK = 1; 1815 private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0; 1816 private static int MESSAGE_HANDLING_STATUS_REFUSED = -1; 1817 private static int MESSAGE_HANDLING_STATUS_FAIL = -2; 1818 private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3; 1819 private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4; 1820 private static int MESSAGE_HANDLING_STATUS_DISCARD = -5; 1821 private static int MESSAGE_HANDLING_STATUS_LOOPED = -6; 1822 private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7; 1823 1824 private int messageHandlingStatus = 0; 1825 1826 //TODO: this is used only to track connection attempts, however the link state and packet per 1827 //TODO: second logic should be folded into that 1828 private boolean checkOrDeferScanAllowed(Message msg) { 1829 long now = System.currentTimeMillis(); 1830 if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { 1831 Message dmsg = Message.obtain(msg); 1832 sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttempt)); 1833 return false; 1834 } 1835 return true; 1836 } 1837 1838 private int mOnTime = 0; 1839 private int mTxTime = 0; 1840 private int mRxTime = 0; 1841 private int mOnTimeStartScan = 0; 1842 private int mTxTimeStartScan = 0; 1843 private int mRxTimeStartScan = 0; 1844 private int mOnTimeScan = 0; 1845 private int mTxTimeScan = 0; 1846 private int mRxTimeScan = 0; 1847 private int mOnTimeThisScan = 0; 1848 private int mTxTimeThisScan = 0; 1849 private int mRxTimeThisScan = 0; 1850 1851 private int mOnTimeScreenStateChange = 0; 1852 private int mOnTimeAtLastReport = 0; 1853 private long lastOntimeReportTimeStamp = 0; 1854 private long lastScreenStateChangeTimeStamp = 0; 1855 private int mOnTimeLastReport = 0; 1856 private int mTxTimeLastReport = 0; 1857 private int mRxTimeLastReport = 0; 1858 1859 private long lastLinkLayerStatsUpdate = 0; 1860 1861 String reportOnTime() { 1862 long now = System.currentTimeMillis(); 1863 StringBuilder sb = new StringBuilder(); 1864 // Report stats since last report 1865 int on = mOnTime - mOnTimeLastReport; 1866 mOnTimeLastReport = mOnTime; 1867 int tx = mTxTime - mTxTimeLastReport; 1868 mTxTimeLastReport = mTxTime; 1869 int rx = mRxTime - mRxTimeLastReport; 1870 mRxTimeLastReport = mRxTime; 1871 int period = (int) (now - lastOntimeReportTimeStamp); 1872 lastOntimeReportTimeStamp = now; 1873 sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period)); 1874 // Report stats since Screen State Changed 1875 on = mOnTime - mOnTimeScreenStateChange; 1876 period = (int) (now - lastScreenStateChangeTimeStamp); 1877 sb.append(String.format(" from screen [on:%d period:%d]", on, period)); 1878 return sb.toString(); 1879 } 1880 1881 WifiLinkLayerStats getWifiLinkLayerStats(boolean dbg) { 1882 WifiLinkLayerStats stats = null; 1883 if (mWifiLinkLayerStatsSupported > 0) { 1884 String name = "wlan0"; 1885 stats = mWifiNative.getWifiLinkLayerStats(name); 1886 if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) { 1887 mWifiLinkLayerStatsSupported -= 1; 1888 } else if (stats != null) { 1889 lastLinkLayerStatsUpdate = System.currentTimeMillis(); 1890 mOnTime = stats.on_time; 1891 mTxTime = stats.tx_time; 1892 mRxTime = stats.rx_time; 1893 mRunningBeaconCount = stats.beacon_rx; 1894 if (dbg) { 1895 loge(stats.toString()); 1896 } 1897 } 1898 } 1899 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 1900 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 1901 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 1902 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 1903 } else { 1904 mWifiInfo.updatePacketRates(stats); 1905 } 1906 return stats; 1907 } 1908 1909 void startRadioScanStats() { 1910 WifiLinkLayerStats stats = getWifiLinkLayerStats(false); 1911 if (stats != null) { 1912 mOnTimeStartScan = stats.on_time; 1913 mTxTimeStartScan = stats.tx_time; 1914 mRxTimeStartScan = stats.rx_time; 1915 mOnTime = stats.on_time; 1916 mTxTime = stats.tx_time; 1917 mRxTime = stats.rx_time; 1918 } 1919 } 1920 1921 void closeRadioScanStats() { 1922 WifiLinkLayerStats stats = getWifiLinkLayerStats(false); 1923 if (stats != null) { 1924 mOnTimeThisScan = stats.on_time - mOnTimeStartScan; 1925 mTxTimeThisScan = stats.tx_time - mTxTimeStartScan; 1926 mRxTimeThisScan = stats.rx_time - mRxTimeStartScan; 1927 mOnTimeScan += mOnTimeThisScan; 1928 mTxTimeScan += mTxTimeThisScan; 1929 mRxTimeScan += mRxTimeThisScan; 1930 } 1931 } 1932 1933 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1934 private void noteScanStart(int callingUid, WorkSource workSource) { 1935 long now = System.currentTimeMillis(); 1936 lastStartScanTimeStamp = now; 1937 lastScanDuration = 0; 1938 if (DBG) { 1939 String ts = String.format("[%,d ms]", now); 1940 if (workSource != null) { 1941 loge(ts + " noteScanStart" + workSource.toString() 1942 + " uid " + Integer.toString(callingUid)); 1943 } else { 1944 loge(ts + " noteScanstart no scan source" 1945 + " uid " + Integer.toString(callingUid)); 1946 } 1947 } 1948 startRadioScanStats(); 1949 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE 1950 && callingUid != SCAN_ALARM_SOURCE) 1951 || workSource != null)) { 1952 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1953 try { 1954 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1955 } catch (RemoteException e) { 1956 log(e.toString()); 1957 } 1958 } 1959 } 1960 1961 private void noteScanEnd() { 1962 long now = System.currentTimeMillis(); 1963 if (lastStartScanTimeStamp != 0) { 1964 lastScanDuration = now - lastStartScanTimeStamp; 1965 } 1966 lastStartScanTimeStamp = 0; 1967 if (DBG) { 1968 String ts = String.format("[%,d ms]", now); 1969 if (mScanWorkSource != null) 1970 loge(ts + " noteScanEnd " + mScanWorkSource.toString() 1971 + " onTime=" + mOnTimeThisScan); 1972 else 1973 loge(ts + " noteScanEnd no scan source" 1974 + " onTime=" + mOnTimeThisScan); 1975 } 1976 if (mScanWorkSource != null) { 1977 try { 1978 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1979 } catch (RemoteException e) { 1980 log(e.toString()); 1981 } finally { 1982 mScanWorkSource = null; 1983 } 1984 } 1985 } 1986 1987 private void noteBatchedScanStart() { 1988 if (PDBG) loge("noteBatchedScanstart()"); 1989 // note the end of a previous scan set 1990 if (mNotedBatchedScanWorkSource != null && 1991 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1992 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1993 try { 1994 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1995 } catch (RemoteException e) { 1996 log(e.toString()); 1997 } finally { 1998 mNotedBatchedScanWorkSource = null; 1999 mNotedBatchedScanCsph = 0; 2000 } 2001 } 2002 // note the start of the new 2003 try { 2004 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 2005 mBatchedScanCsph); 2006 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 2007 mNotedBatchedScanCsph = mBatchedScanCsph; 2008 } catch (RemoteException e) { 2009 log(e.toString()); 2010 } 2011 } 2012 2013 private void noteBatchedScanStop() { 2014 if (PDBG) loge("noteBatchedScanstop()"); 2015 2016 if (mNotedBatchedScanWorkSource != null) { 2017 try { 2018 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 2019 } catch (RemoteException e) { 2020 log(e.toString()); 2021 } finally { 2022 mNotedBatchedScanWorkSource = null; 2023 mNotedBatchedScanCsph = 0; 2024 } 2025 } 2026 } 2027 2028 private void handleScanRequest(int type, Message message) { 2029 ScanSettings settings = null; 2030 WorkSource workSource = null; 2031 2032 // unbundle parameters 2033 Bundle bundle = (Bundle) message.obj; 2034 2035 if (bundle != null) { 2036 settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 2037 workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 2038 } 2039 2040 // parse scan settings 2041 String freqs = null; 2042 if (settings != null && settings.channelSet != null) { 2043 StringBuilder sb = new StringBuilder(); 2044 boolean first = true; 2045 for (WifiChannel channel : settings.channelSet) { 2046 if (!first) sb.append(','); 2047 else first = false; 2048 sb.append(channel.freqMHz); 2049 } 2050 freqs = sb.toString(); 2051 } 2052 2053 // call wifi native to start the scan 2054 if (startScanNative(type, freqs)) { 2055 // only count battery consumption if scan request is accepted 2056 noteScanStart(message.arg1, workSource); 2057 // a full scan covers everything, clearing scan request buffer 2058 if (freqs == null) 2059 mBufferedScanMsg.clear(); 2060 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; 2061 if (workSource != null) { 2062 // External worksource was passed along the scan request, 2063 // hence always send a broadcast 2064 mSendScanResultsBroadcast = true; 2065 } 2066 return; 2067 } 2068 2069 // if reach here, scan request is rejected 2070 2071 if (!mIsScanOngoing) { 2072 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 2073 2074 // discard this request and pop up the next one 2075 if (mBufferedScanMsg.size() > 0) { 2076 sendMessage(mBufferedScanMsg.remove()); 2077 } 2078 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 2079 } else if (!mIsFullScanOngoing) { 2080 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 2081 // buffer the scan request to make sure specified channels will be scanned eventually 2082 if (freqs == null) 2083 mBufferedScanMsg.clear(); 2084 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 2085 Message msg = obtainMessage(CMD_START_SCAN, 2086 message.arg1, message.arg2, bundle); 2087 mBufferedScanMsg.add(msg); 2088 } else { 2089 // if too many requests in buffer, combine them into a single full scan 2090 bundle = new Bundle(); 2091 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 2092 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 2093 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle); 2094 mBufferedScanMsg.clear(); 2095 mBufferedScanMsg.add(msg); 2096 } 2097 messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED; 2098 } else { 2099 // mIsScanOngoing and mIsFullScanOngoing 2100 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 2101 } 2102 } 2103 2104 2105 /** 2106 * return true iff scan request is accepted 2107 */ 2108 private boolean startScanNative(int type, String freqs) { 2109 if (mWifiNative.scan(type, freqs)) { 2110 mIsScanOngoing = true; 2111 mIsFullScanOngoing = (freqs == null); 2112 lastScanFreqs = freqs; 2113 return true; 2114 } 2115 return false; 2116 } 2117 2118 /** 2119 * TODO: doc 2120 */ 2121 public void setSupplicantRunning(boolean enable) { 2122 if (enable) { 2123 sendMessage(CMD_START_SUPPLICANT); 2124 } else { 2125 sendMessage(CMD_STOP_SUPPLICANT); 2126 } 2127 } 2128 2129 /** 2130 * TODO: doc 2131 */ 2132 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 2133 if (enable) { 2134 sendMessage(CMD_START_AP, wifiConfig); 2135 } else { 2136 sendMessage(CMD_STOP_AP); 2137 } 2138 } 2139 2140 public void setWifiApConfiguration(WifiConfiguration config) { 2141 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 2142 } 2143 2144 public WifiConfiguration syncGetWifiApConfiguration() { 2145 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 2146 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 2147 resultMsg.recycle(); 2148 return ret; 2149 } 2150 2151 /** 2152 * TODO: doc 2153 */ 2154 public int syncGetWifiState() { 2155 return mWifiState.get(); 2156 } 2157 2158 /** 2159 * TODO: doc 2160 */ 2161 public String syncGetWifiStateByName() { 2162 switch (mWifiState.get()) { 2163 case WIFI_STATE_DISABLING: 2164 return "disabling"; 2165 case WIFI_STATE_DISABLED: 2166 return "disabled"; 2167 case WIFI_STATE_ENABLING: 2168 return "enabling"; 2169 case WIFI_STATE_ENABLED: 2170 return "enabled"; 2171 case WIFI_STATE_UNKNOWN: 2172 return "unknown state"; 2173 default: 2174 return "[invalid state]"; 2175 } 2176 } 2177 2178 /** 2179 * TODO: doc 2180 */ 2181 public int syncGetWifiApState() { 2182 return mWifiApState.get(); 2183 } 2184 2185 /** 2186 * TODO: doc 2187 */ 2188 public String syncGetWifiApStateByName() { 2189 switch (mWifiApState.get()) { 2190 case WIFI_AP_STATE_DISABLING: 2191 return "disabling"; 2192 case WIFI_AP_STATE_DISABLED: 2193 return "disabled"; 2194 case WIFI_AP_STATE_ENABLING: 2195 return "enabling"; 2196 case WIFI_AP_STATE_ENABLED: 2197 return "enabled"; 2198 case WIFI_AP_STATE_FAILED: 2199 return "failed"; 2200 default: 2201 return "[invalid state]"; 2202 } 2203 } 2204 2205 /** 2206 * Get status information for the current connection, if any. 2207 * 2208 * @return a {@link WifiInfo} object containing information about the current connection 2209 */ 2210 public WifiInfo syncRequestConnectionInfo() { 2211 return mWifiInfo; 2212 } 2213 2214 public DhcpResults syncGetDhcpResults() { 2215 synchronized (mDhcpResultsLock) { 2216 return new DhcpResults(mDhcpResults); 2217 } 2218 } 2219 2220 /** 2221 * TODO: doc 2222 */ 2223 public void setDriverStart(boolean enable) { 2224 if (enable) { 2225 sendMessage(CMD_START_DRIVER); 2226 } else { 2227 sendMessage(CMD_STOP_DRIVER); 2228 } 2229 } 2230 2231 /** 2232 * TODO: doc 2233 */ 2234 public void setOperationalMode(int mode) { 2235 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 2236 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 2237 } 2238 2239 /** 2240 * TODO: doc 2241 */ 2242 public List<ScanResult> syncGetScanResultsList() { 2243 synchronized (mScanResultCache) { 2244 List<ScanResult> scanList = new ArrayList<ScanResult>(); 2245 for (ScanDetail result : mScanResults) { 2246 scanList.add(new ScanResult(result.getScanResult())); 2247 } 2248 return scanList; 2249 } 2250 } 2251 2252 public void disableEphemeralNetwork(String SSID) { 2253 if (SSID != null) { 2254 sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID); 2255 } 2256 } 2257 2258 /** 2259 * Get unsynchronized pointer to scan result list 2260 * Can be called only from AutoJoinController which runs in the WifiStateMachine context 2261 */ 2262 public List<ScanDetail> getScanResultsListNoCopyUnsync() { 2263 return mScanResults; 2264 } 2265 2266 /** 2267 * Disconnect from Access Point 2268 */ 2269 public void disconnectCommand() { 2270 sendMessage(CMD_DISCONNECT); 2271 } 2272 2273 public void disconnectCommand(int uid, int reason) { 2274 sendMessage(CMD_DISCONNECT, uid, reason); 2275 } 2276 2277 /** 2278 * Initiate a reconnection to AP 2279 */ 2280 public void reconnectCommand() { 2281 sendMessage(CMD_RECONNECT); 2282 } 2283 2284 /** 2285 * Initiate a re-association to AP 2286 */ 2287 public void reassociateCommand() { 2288 sendMessage(CMD_REASSOCIATE); 2289 } 2290 2291 /** 2292 * Reload networks and then reconnect; helps load correct data for TLS networks 2293 */ 2294 2295 public void reloadTlsNetworksAndReconnect() { 2296 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 2297 } 2298 2299 /** 2300 * Add a network synchronously 2301 * 2302 * @return network id of the new network 2303 */ 2304 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 2305 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 2306 int result = resultMsg.arg1; 2307 resultMsg.recycle(); 2308 return result; 2309 } 2310 2311 /** 2312 * Get configured networks synchronously 2313 * 2314 * @param channel 2315 * @return 2316 */ 2317 2318 public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) { 2319 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid); 2320 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 2321 resultMsg.recycle(); 2322 return result; 2323 } 2324 2325 public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) { 2326 Message resultMsg = channel.sendMessageSynchronously( 2327 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS); 2328 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 2329 resultMsg.recycle(); 2330 return result; 2331 } 2332 2333 public WifiConfiguration syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel) { 2334 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_MATCHING_CONFIG, scanResult); 2335 return (WifiConfiguration) resultMsg.obj; 2336 } 2337 2338 /** 2339 * Get connection statistics synchronously 2340 * 2341 * @param channel 2342 * @return 2343 */ 2344 2345 public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) { 2346 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS); 2347 WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj; 2348 resultMsg.recycle(); 2349 return result; 2350 } 2351 2352 /** 2353 * Get adaptors synchronously 2354 */ 2355 2356 public int syncGetSupportedFeatures(AsyncChannel channel) { 2357 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES); 2358 int supportedFeatureSet = resultMsg.arg1; 2359 resultMsg.recycle(); 2360 return supportedFeatureSet; 2361 } 2362 2363 /** 2364 * Get link layers stats for adapter synchronously 2365 */ 2366 public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) { 2367 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS); 2368 WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj; 2369 resultMsg.recycle(); 2370 return result; 2371 } 2372 2373 /** 2374 * Delete a network 2375 * 2376 * @param networkId id of the network to be removed 2377 */ 2378 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 2379 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 2380 boolean result = (resultMsg.arg1 != FAILURE); 2381 resultMsg.recycle(); 2382 return result; 2383 } 2384 2385 /** 2386 * Enable a network 2387 * 2388 * @param netId network id of the network 2389 * @param disableOthers true, if all other networks have to be disabled 2390 * @return {@code true} if the operation succeeds, {@code false} otherwise 2391 */ 2392 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 2393 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 2394 disableOthers ? 1 : 0); 2395 boolean result = (resultMsg.arg1 != FAILURE); 2396 resultMsg.recycle(); 2397 return result; 2398 } 2399 2400 /** 2401 * Disable a network 2402 * 2403 * @param netId network id of the network 2404 * @return {@code true} if the operation succeeds, {@code false} otherwise 2405 */ 2406 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 2407 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 2408 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 2409 resultMsg.recycle(); 2410 return result; 2411 } 2412 2413 /** 2414 * Retrieves a WPS-NFC configuration token for the specified network 2415 * 2416 * @return a hex string representation of the WPS-NFC configuration token 2417 */ 2418 public String syncGetWpsNfcConfigurationToken(int netId) { 2419 return mWifiNative.getNfcWpsConfigurationToken(netId); 2420 } 2421 2422 void enableBackgroundScan(boolean enable) { 2423 if (enable) { 2424 mWifiConfigStore.enableAllNetworks(); 2425 } 2426 mWifiNative.enableBackgroundScan(enable); 2427 } 2428 2429 /** 2430 * Blacklist a BSSID. This will avoid the AP if there are 2431 * alternate APs to connect 2432 * 2433 * @param bssid BSSID of the network 2434 */ 2435 public void addToBlacklist(String bssid) { 2436 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 2437 } 2438 2439 /** 2440 * Clear the blacklist list 2441 */ 2442 public void clearBlacklist() { 2443 sendMessage(CMD_CLEAR_BLACKLIST); 2444 } 2445 2446 public void enableRssiPolling(boolean enabled) { 2447 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 2448 } 2449 2450 public void enableAllNetworks() { 2451 sendMessage(CMD_ENABLE_ALL_NETWORKS); 2452 } 2453 2454 /** 2455 * Start filtering Multicast v4 packets 2456 */ 2457 public void startFilteringMulticastV4Packets() { 2458 mFilteringMulticastV4Packets.set(true); 2459 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 2460 } 2461 2462 /** 2463 * Stop filtering Multicast v4 packets 2464 */ 2465 public void stopFilteringMulticastV4Packets() { 2466 mFilteringMulticastV4Packets.set(false); 2467 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 2468 } 2469 2470 /** 2471 * Start filtering Multicast v4 packets 2472 */ 2473 public void startFilteringMulticastV6Packets() { 2474 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 2475 } 2476 2477 /** 2478 * Stop filtering Multicast v4 packets 2479 */ 2480 public void stopFilteringMulticastV6Packets() { 2481 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 2482 } 2483 2484 /** 2485 * Set high performance mode of operation. 2486 * Enabling would set active power mode and disable suspend optimizations; 2487 * disabling would set auto power mode and enable suspend optimizations 2488 * 2489 * @param enable true if enable, false otherwise 2490 */ 2491 public void setHighPerfModeEnabled(boolean enable) { 2492 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 2493 } 2494 2495 /** 2496 * Set the country code 2497 * 2498 * @param countryCode following ISO 3166 format 2499 * @param persist {@code true} if the setting should be remembered. 2500 */ 2501 public synchronized void setCountryCode(String countryCode, boolean persist) { 2502 // If it's a good country code, apply after the current 2503 // wifi connection is terminated; ignore resetting of code 2504 // for now (it is unclear what the chipset should do when 2505 // country code is reset) 2506 2507 if (TextUtils.isEmpty(countryCode)) { 2508 log("Ignoring resetting of country code"); 2509 } else { 2510 // if mCountryCodeSequence == 0, it is the first time to set country code, always set 2511 // else only when the new country code is different from the current one to set 2512 int countryCodeSequence = mCountryCodeSequence.get(); 2513 if (countryCodeSequence == 0 || countryCode.equals(mSetCountryCode) == false) { 2514 2515 countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 2516 mSetCountryCode = countryCode; 2517 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, 2518 countryCode); 2519 } 2520 2521 if (persist) { 2522 Settings.Global.putString(mContext.getContentResolver(), 2523 Settings.Global.WIFI_COUNTRY_CODE, 2524 countryCode); 2525 } 2526 } 2527 } 2528 2529 /** 2530 * Get Network object of current wifi network 2531 * @return Network object of current wifi network 2532 */ 2533 public Network getCurrentNetwork() { 2534 if (mNetworkAgent != null) { 2535 return new Network(mNetworkAgent.netId); 2536 } else { 2537 return null; 2538 } 2539 } 2540 2541 /** 2542 * Get the country code 2543 * 2544 * @param countryCode following ISO 3166 format 2545 */ 2546 public String getCountryCode() { 2547 return mSetCountryCode; 2548 } 2549 2550 2551 /** 2552 * Set the operational frequency band 2553 * 2554 * @param band 2555 * @param persist {@code true} if the setting should be remembered. 2556 */ 2557 public void setFrequencyBand(int band, boolean persist) { 2558 if (persist) { 2559 Settings.Global.putInt(mContext.getContentResolver(), 2560 Settings.Global.WIFI_FREQUENCY_BAND, 2561 band); 2562 } 2563 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 2564 } 2565 2566 /** 2567 * Enable TDLS for a specific MAC address 2568 */ 2569 public void enableTdls(String remoteMacAddress, boolean enable) { 2570 int enabler = enable ? 1 : 0; 2571 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 2572 } 2573 2574 /** 2575 * Returns the operational frequency band 2576 */ 2577 public int getFrequencyBand() { 2578 return mFrequencyBand.get(); 2579 } 2580 2581 /** 2582 * Returns the wifi configuration file 2583 */ 2584 public String getConfigFile() { 2585 return mWifiConfigStore.getConfigFile(); 2586 } 2587 2588 /** 2589 * Send a message indicating bluetooth adapter connection state changed 2590 */ 2591 public void sendBluetoothAdapterStateChange(int state) { 2592 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 2593 } 2594 2595 /** 2596 * Send a message indicating a package has been uninstalled. 2597 */ 2598 public void removeAppConfigs(String packageName, int uid) { 2599 // Build partial AppInfo manually - package may not exist in database any more 2600 ApplicationInfo ai = new ApplicationInfo(); 2601 ai.packageName = packageName; 2602 ai.uid = uid; 2603 sendMessage(CMD_REMOVE_APP_CONFIGURATIONS, ai); 2604 } 2605 2606 /** 2607 * Send a message indicating a user has been removed. 2608 */ 2609 public void removeUserConfigs(int userId) { 2610 sendMessage(CMD_REMOVE_USER_CONFIGURATIONS, userId); 2611 } 2612 2613 /** 2614 * Save configuration on supplicant 2615 * 2616 * @return {@code true} if the operation succeeds, {@code false} otherwise 2617 * <p/> 2618 * TODO: deprecate this 2619 */ 2620 public boolean syncSaveConfig(AsyncChannel channel) { 2621 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 2622 boolean result = (resultMsg.arg1 != FAILURE); 2623 resultMsg.recycle(); 2624 return result; 2625 } 2626 2627 public void updateBatteryWorkSource(WorkSource newSource) { 2628 synchronized (mRunningWifiUids) { 2629 try { 2630 if (newSource != null) { 2631 mRunningWifiUids.set(newSource); 2632 } 2633 if (mIsRunning) { 2634 if (mReportedRunning) { 2635 // If the work source has changed since last time, need 2636 // to remove old work from battery stats. 2637 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 2638 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 2639 mRunningWifiUids); 2640 mLastRunningWifiUids.set(mRunningWifiUids); 2641 } 2642 } else { 2643 // Now being started, report it. 2644 mBatteryStats.noteWifiRunning(mRunningWifiUids); 2645 mLastRunningWifiUids.set(mRunningWifiUids); 2646 mReportedRunning = true; 2647 } 2648 } else { 2649 if (mReportedRunning) { 2650 // Last reported we were running, time to stop. 2651 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 2652 mLastRunningWifiUids.clear(); 2653 mReportedRunning = false; 2654 } 2655 } 2656 mWakeLock.setWorkSource(newSource); 2657 } catch (RemoteException ignore) { 2658 } 2659 } 2660 } 2661 2662 @Override 2663 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2664 super.dump(fd, pw, args); 2665 mSupplicantStateTracker.dump(fd, pw, args); 2666 pw.println("mLinkProperties " + mLinkProperties); 2667 pw.println("mWifiInfo " + mWifiInfo); 2668 pw.println("mDhcpResults " + mDhcpResults); 2669 pw.println("mNetworkInfo " + mNetworkInfo); 2670 pw.println("mLastSignalLevel " + mLastSignalLevel); 2671 pw.println("mLastBssid " + mLastBssid); 2672 pw.println("mLastNetworkId " + mLastNetworkId); 2673 pw.println("mOperationalMode " + mOperationalMode); 2674 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 2675 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2676 pw.println("Supplicant status " + mWifiNative.status(true)); 2677 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 2678 pw.println("mSetCountryCode " + mSetCountryCode); 2679 pw.println("mDriverSetCountryCode " + mDriverSetCountryCode); 2680 mNetworkFactory.dump(fd, pw, args); 2681 mUntrustedNetworkFactory.dump(fd, pw, args); 2682 pw.println(); 2683 mWifiConfigStore.dump(fd, pw, args); 2684 } 2685 2686 /** 2687 * ****************************************************** 2688 * Internal private functions 2689 * ****************************************************** 2690 */ 2691 2692 private void logStateAndMessage(Message message, String state) { 2693 messageHandlingStatus = 0; 2694 if (mLogMessages) { 2695 //long now = SystemClock.elapsedRealtimeNanos(); 2696 //String ts = String.format("[%,d us]", now/1000); 2697 2698 loge(" " + state + " " + getLogRecString(message)); 2699 } 2700 } 2701 2702 /** 2703 * helper, prints the milli time since boot wi and w/o suspended time 2704 */ 2705 String printTime() { 2706 StringBuilder sb = new StringBuilder(); 2707 sb.append(" rt=").append(SystemClock.uptimeMillis()); 2708 sb.append("/").append(SystemClock.elapsedRealtime()); 2709 return sb.toString(); 2710 } 2711 2712 /** 2713 * Return the additional string to be logged by LogRec, default 2714 * 2715 * @param msg that was processed 2716 * @return information to be logged as a String 2717 */ 2718 protected String getLogRecString(Message msg) { 2719 WifiConfiguration config; 2720 Long now; 2721 String report; 2722 String key; 2723 StringBuilder sb = new StringBuilder(); 2724 if (mScreenOn) { 2725 sb.append("!"); 2726 } 2727 if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) { 2728 sb.append("(").append(messageHandlingStatus).append(")"); 2729 } 2730 sb.append(smToString(msg)); 2731 if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) { 2732 sb.append(" uid=" + msg.sendingUid); 2733 } 2734 switch (msg.what) { 2735 case CMD_STARTED_PNO_DBG: 2736 sb.append(" "); 2737 sb.append(Integer.toString(msg.arg1)); 2738 sb.append(" "); 2739 sb.append(Integer.toString(msg.arg2)); 2740 if (msg.obj != null) { 2741 sb.append((String)msg.obj); 2742 } 2743 break; 2744 case CMD_PNO_NETWORK_FOUND: 2745 sb.append(" "); 2746 sb.append(Integer.toString(msg.arg1)); 2747 sb.append(" "); 2748 sb.append(Integer.toString(msg.arg2)); 2749 if (msg.obj != null) { 2750 ScanResult[] results = (ScanResult[])msg.obj; 2751 for (int i = 0; i < results.length; i++) { 2752 sb.append(" ").append(results[i].SSID).append(" "); 2753 sb.append(results[i].frequency); 2754 sb.append(" ").append(results[i].level); 2755 } 2756 } 2757 break; 2758 case CMD_START_SCAN: 2759 now = System.currentTimeMillis(); 2760 sb.append(" "); 2761 sb.append(Integer.toString(msg.arg1)); 2762 sb.append(" "); 2763 sb.append(Integer.toString(msg.arg2)); 2764 sb.append(" ic="); 2765 sb.append(Integer.toString(sScanAlarmIntentCount)); 2766 if (msg.obj != null) { 2767 Bundle bundle = (Bundle) msg.obj; 2768 Long request = bundle.getLong(SCAN_REQUEST_TIME, 0); 2769 if (request != 0) { 2770 sb.append(" proc(ms):").append(now - request); 2771 } 2772 } 2773 if (mIsScanOngoing) sb.append(" onGoing"); 2774 if (mIsFullScanOngoing) sb.append(" full"); 2775 if (lastStartScanTimeStamp != 0) { 2776 sb.append(" started:").append(lastStartScanTimeStamp); 2777 sb.append(",").append(now - lastStartScanTimeStamp); 2778 } 2779 if (lastScanDuration != 0) { 2780 sb.append(" dur:").append(lastScanDuration); 2781 } 2782 sb.append(" cnt=").append(mDelayedScanCounter); 2783 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2784 sb.append(" f=").append(mWifiInfo.getFrequency()); 2785 sb.append(" sc=").append(mWifiInfo.score); 2786 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2787 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2788 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2789 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2790 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2791 if (lastScanFreqs != null) { 2792 sb.append(" list=").append(lastScanFreqs); 2793 } else { 2794 sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli); 2795 } 2796 report = reportOnTime(); 2797 if (report != null) { 2798 sb.append(" ").append(report); 2799 } 2800 break; 2801 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2802 sb.append(" "); 2803 sb.append(Integer.toString(msg.arg1)); 2804 sb.append(" "); 2805 sb.append(Integer.toString(msg.arg2)); 2806 sb.append(printTime()); 2807 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2808 if (stateChangeResult != null) { 2809 sb.append(stateChangeResult.toString()); 2810 } 2811 break; 2812 case WifiManager.SAVE_NETWORK: 2813 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 2814 sb.append(" "); 2815 sb.append(Integer.toString(msg.arg1)); 2816 sb.append(" "); 2817 sb.append(Integer.toString(msg.arg2)); 2818 if (lastSavedConfigurationAttempt != null) { 2819 sb.append(" ").append(lastSavedConfigurationAttempt.configKey()); 2820 sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId); 2821 if (lastSavedConfigurationAttempt.hiddenSSID) { 2822 sb.append(" hidden"); 2823 } 2824 if (lastSavedConfigurationAttempt.preSharedKey != null 2825 && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) { 2826 sb.append(" hasPSK"); 2827 } 2828 if (lastSavedConfigurationAttempt.ephemeral) { 2829 sb.append(" ephemeral"); 2830 } 2831 if (lastSavedConfigurationAttempt.selfAdded) { 2832 sb.append(" selfAdded"); 2833 } 2834 sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid); 2835 sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid); 2836 } 2837 break; 2838 case WifiManager.FORGET_NETWORK: 2839 sb.append(" "); 2840 sb.append(Integer.toString(msg.arg1)); 2841 sb.append(" "); 2842 sb.append(Integer.toString(msg.arg2)); 2843 if (lastForgetConfigurationAttempt != null) { 2844 sb.append(" ").append(lastForgetConfigurationAttempt.configKey()); 2845 sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId); 2846 if (lastForgetConfigurationAttempt.hiddenSSID) { 2847 sb.append(" hidden"); 2848 } 2849 if (lastForgetConfigurationAttempt.preSharedKey != null) { 2850 sb.append(" hasPSK"); 2851 } 2852 if (lastForgetConfigurationAttempt.ephemeral) { 2853 sb.append(" ephemeral"); 2854 } 2855 if (lastForgetConfigurationAttempt.selfAdded) { 2856 sb.append(" selfAdded"); 2857 } 2858 sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid); 2859 sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid); 2860 sb.append(" ajst=").append(lastForgetConfigurationAttempt.autoJoinStatus); 2861 } 2862 break; 2863 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2864 sb.append(" "); 2865 sb.append(Integer.toString(msg.arg1)); 2866 sb.append(" "); 2867 sb.append(Integer.toString(msg.arg2)); 2868 String bssid = (String) msg.obj; 2869 if (bssid != null && bssid.length() > 0) { 2870 sb.append(" "); 2871 sb.append(bssid); 2872 } 2873 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); 2874 sb.append(printTime()); 2875 break; 2876 case WifiMonitor.SCAN_RESULTS_EVENT: 2877 sb.append(" "); 2878 sb.append(Integer.toString(msg.arg1)); 2879 sb.append(" "); 2880 sb.append(Integer.toString(msg.arg2)); 2881 if (mScanResults != null) { 2882 sb.append(" found="); 2883 sb.append(mScanResults.size()); 2884 } 2885 sb.append(" known=").append(mNumScanResultsKnown); 2886 sb.append(" got=").append(mNumScanResultsReturned); 2887 if (lastScanDuration != 0) { 2888 sb.append(" dur:").append(lastScanDuration); 2889 } 2890 if (mOnTime != 0) { 2891 sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan); 2892 sb.append(",").append(mOnTime); 2893 } 2894 if (mTxTime != 0) { 2895 sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan); 2896 sb.append(",").append(mTxTime); 2897 } 2898 if (mRxTime != 0) { 2899 sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan); 2900 sb.append(",").append(mRxTime); 2901 } 2902 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 2903 sb.append(String.format(" con=%d", mConnectionRequests)); 2904 key = mWifiConfigStore.getLastSelectedConfiguration(); 2905 if (key != null) { 2906 sb.append(" last=").append(key); 2907 } 2908 break; 2909 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2910 sb.append(" "); 2911 sb.append(Integer.toString(msg.arg1)); 2912 sb.append(" "); 2913 sb.append(Integer.toString(msg.arg2)); 2914 sb.append(" ").append(mLastBssid); 2915 sb.append(" nid=").append(mLastNetworkId); 2916 config = getCurrentWifiConfiguration(); 2917 if (config != null) { 2918 sb.append(" ").append(config.configKey()); 2919 } 2920 sb.append(printTime()); 2921 key = mWifiConfigStore.getLastSelectedConfiguration(); 2922 if (key != null) { 2923 sb.append(" last=").append(key); 2924 } 2925 break; 2926 case CMD_TARGET_BSSID: 2927 case CMD_ASSOCIATED_BSSID: 2928 sb.append(" "); 2929 sb.append(Integer.toString(msg.arg1)); 2930 sb.append(" "); 2931 sb.append(Integer.toString(msg.arg2)); 2932 if (msg.obj != null) { 2933 sb.append(" BSSID=").append((String) msg.obj); 2934 } 2935 if (mTargetRoamBSSID != null) { 2936 sb.append(" Target=").append(mTargetRoamBSSID); 2937 } 2938 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2939 sb.append(printTime()); 2940 break; 2941 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2942 if (msg.obj != null) { 2943 sb.append(" ").append((String) msg.obj); 2944 } 2945 sb.append(" nid=").append(msg.arg1); 2946 sb.append(" reason=").append(msg.arg2); 2947 if (mLastBssid != null) { 2948 sb.append(" lastbssid=").append(mLastBssid); 2949 } 2950 if (mWifiInfo.getFrequency() != -1) { 2951 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2952 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2953 } 2954 if (linkDebouncing) { 2955 sb.append(" debounce"); 2956 } 2957 sb.append(printTime()); 2958 break; 2959 case WifiMonitor.SSID_TEMP_DISABLED: 2960 case WifiMonitor.SSID_REENABLED: 2961 sb.append(" nid=").append(msg.arg1); 2962 if (msg.obj != null) { 2963 sb.append(" ").append((String) msg.obj); 2964 } 2965 config = getCurrentWifiConfiguration(); 2966 if (config != null) { 2967 sb.append(" cur=").append(config.configKey()); 2968 sb.append(" ajst=").append(config.autoJoinStatus); 2969 if (config.selfAdded) { 2970 sb.append(" selfAdded"); 2971 } 2972 if (config.status != 0) { 2973 sb.append(" st=").append(config.status); 2974 sb.append(" rs=").append(config.disableReason); 2975 } 2976 if (config.lastConnected != 0) { 2977 now = System.currentTimeMillis(); 2978 sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)"); 2979 } 2980 if (mLastBssid != null) { 2981 sb.append(" lastbssid=").append(mLastBssid); 2982 } 2983 if (mWifiInfo.getFrequency() != -1) { 2984 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2985 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2986 sb.append(" bssid=").append(mWifiInfo.getBSSID()); 2987 } 2988 } 2989 sb.append(printTime()); 2990 break; 2991 case CMD_RSSI_POLL: 2992 case CMD_UNWANTED_NETWORK: 2993 case WifiManager.RSSI_PKTCNT_FETCH: 2994 sb.append(" "); 2995 sb.append(Integer.toString(msg.arg1)); 2996 sb.append(" "); 2997 sb.append(Integer.toString(msg.arg2)); 2998 if (mWifiInfo.getSSID() != null) 2999 if (mWifiInfo.getSSID() != null) 3000 sb.append(" ").append(mWifiInfo.getSSID()); 3001 if (mWifiInfo.getBSSID() != null) 3002 sb.append(" ").append(mWifiInfo.getBSSID()); 3003 sb.append(" rssi=").append(mWifiInfo.getRssi()); 3004 sb.append(" f=").append(mWifiInfo.getFrequency()); 3005 sb.append(" sc=").append(mWifiInfo.score); 3006 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 3007 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 3008 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 3009 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 3010 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 3011 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 3012 report = reportOnTime(); 3013 if (report != null) { 3014 sb.append(" ").append(report); 3015 } 3016 if (wifiScoringReport != null) { 3017 sb.append(wifiScoringReport); 3018 } 3019 break; 3020 case CMD_AUTO_CONNECT: 3021 case WifiManager.CONNECT_NETWORK: 3022 sb.append(" "); 3023 sb.append(Integer.toString(msg.arg1)); 3024 sb.append(" "); 3025 sb.append(Integer.toString(msg.arg2)); 3026 config = (WifiConfiguration) msg.obj; 3027 if (config != null) { 3028 sb.append(" ").append(config.configKey()); 3029 if (config.visibility != null) { 3030 sb.append(" ").append(config.visibility.toString()); 3031 } 3032 } 3033 if (mTargetRoamBSSID != null) { 3034 sb.append(" ").append(mTargetRoamBSSID); 3035 } 3036 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 3037 sb.append(printTime()); 3038 config = getCurrentWifiConfiguration(); 3039 if (config != null) { 3040 sb.append(config.configKey()); 3041 if (config.visibility != null) { 3042 sb.append(" ").append(config.visibility.toString()); 3043 } 3044 } 3045 break; 3046 case CMD_AUTO_ROAM: 3047 sb.append(" "); 3048 sb.append(Integer.toString(msg.arg1)); 3049 sb.append(" "); 3050 sb.append(Integer.toString(msg.arg2)); 3051 ScanResult result = (ScanResult) msg.obj; 3052 if (result != null) { 3053 now = System.currentTimeMillis(); 3054 sb.append(" bssid=").append(result.BSSID); 3055 sb.append(" rssi=").append(result.level); 3056 sb.append(" freq=").append(result.frequency); 3057 if (result.seen > 0 && result.seen < now) { 3058 sb.append(" seen=").append(now - result.seen); 3059 } else { 3060 // Somehow the timestamp for this scan result is inconsistent 3061 sb.append(" !seen=").append(result.seen); 3062 } 3063 } 3064 if (mTargetRoamBSSID != null) { 3065 sb.append(" ").append(mTargetRoamBSSID); 3066 } 3067 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 3068 sb.append(" fail count=").append(Integer.toString(mRoamFailCount)); 3069 sb.append(printTime()); 3070 break; 3071 case CMD_ADD_OR_UPDATE_NETWORK: 3072 sb.append(" "); 3073 sb.append(Integer.toString(msg.arg1)); 3074 sb.append(" "); 3075 sb.append(Integer.toString(msg.arg2)); 3076 if (msg.obj != null) { 3077 config = (WifiConfiguration) msg.obj; 3078 sb.append(" ").append(config.configKey()); 3079 sb.append(" prio=").append(config.priority); 3080 sb.append(" status=").append(config.status); 3081 if (config.BSSID != null) { 3082 sb.append(" ").append(config.BSSID); 3083 } 3084 WifiConfiguration curConfig = getCurrentWifiConfiguration(); 3085 if (curConfig != null) { 3086 if (curConfig.configKey().equals(config.configKey())) { 3087 sb.append(" is current"); 3088 } else { 3089 sb.append(" current=").append(curConfig.configKey()); 3090 sb.append(" prio=").append(curConfig.priority); 3091 sb.append(" status=").append(curConfig.status); 3092 } 3093 } 3094 } 3095 break; 3096 case WifiManager.DISABLE_NETWORK: 3097 case CMD_ENABLE_NETWORK: 3098 sb.append(" "); 3099 sb.append(Integer.toString(msg.arg1)); 3100 sb.append(" "); 3101 sb.append(Integer.toString(msg.arg2)); 3102 key = mWifiConfigStore.getLastSelectedConfiguration(); 3103 if (key != null) { 3104 sb.append(" last=").append(key); 3105 } 3106 config = mWifiConfigStore.getWifiConfiguration(msg.arg1); 3107 if (config != null && (key == null || !config.configKey().equals(key))) { 3108 sb.append(" target=").append(key); 3109 } 3110 break; 3111 case CMD_GET_CONFIGURED_NETWORKS: 3112 sb.append(" "); 3113 sb.append(Integer.toString(msg.arg1)); 3114 sb.append(" "); 3115 sb.append(Integer.toString(msg.arg2)); 3116 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize()); 3117 break; 3118 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3119 sb.append(" "); 3120 sb.append(Integer.toString(msg.arg1)); 3121 sb.append(" "); 3122 sb.append(Integer.toString(msg.arg2)); 3123 sb.append(" txpkts=").append(mWifiInfo.txSuccess); 3124 sb.append(",").append(mWifiInfo.txBad); 3125 sb.append(",").append(mWifiInfo.txRetries); 3126 break; 3127 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3128 sb.append(" "); 3129 sb.append(Integer.toString(msg.arg1)); 3130 sb.append(" "); 3131 sb.append(Integer.toString(msg.arg2)); 3132 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3133 sb.append(" OK "); 3134 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3135 sb.append(" FAIL "); 3136 } 3137 if (mLinkProperties != null) { 3138 if (mLinkProperties.hasIPv4Address()) { 3139 sb.append(" v4"); 3140 } 3141 if (mLinkProperties.hasGlobalIPv6Address()) { 3142 sb.append(" v6"); 3143 } 3144 if (mLinkProperties.hasIPv4DefaultRoute()) { 3145 sb.append(" v4r"); 3146 } 3147 if (mLinkProperties.hasIPv6DefaultRoute()) { 3148 sb.append(" v6r"); 3149 } 3150 if (mLinkProperties.hasIPv4DnsServer()) { 3151 sb.append(" v4dns"); 3152 } 3153 if (mLinkProperties.hasIPv6DnsServer()) { 3154 sb.append(" v6dns"); 3155 } 3156 } 3157 break; 3158 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 3159 sb.append(" "); 3160 sb.append(Integer.toString(msg.arg1)); 3161 sb.append(" "); 3162 sb.append(Integer.toString(msg.arg2)); 3163 if (msg.obj != null) { 3164 NetworkInfo info = (NetworkInfo) msg.obj; 3165 NetworkInfo.State state = info.getState(); 3166 NetworkInfo.DetailedState detailedState = info.getDetailedState(); 3167 if (state != null) { 3168 sb.append(" st=").append(state); 3169 } 3170 if (detailedState != null) { 3171 sb.append("/").append(detailedState); 3172 } 3173 } 3174 break; 3175 case CMD_IP_CONFIGURATION_LOST: 3176 int count = -1; 3177 WifiConfiguration c = getCurrentWifiConfiguration(); 3178 if (c != null) count = c.numIpConfigFailures; 3179 sb.append(" "); 3180 sb.append(Integer.toString(msg.arg1)); 3181 sb.append(" "); 3182 sb.append(Integer.toString(msg.arg2)); 3183 sb.append(" failures: "); 3184 sb.append(Integer.toString(count)); 3185 sb.append("/"); 3186 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries())); 3187 if (mWifiInfo.getBSSID() != null) { 3188 sb.append(" ").append(mWifiInfo.getBSSID()); 3189 } 3190 if (c != null) { 3191 ScanDetailCache scanDetailCache = 3192 mWifiConfigStore.getScanDetailCache(c); 3193 if (scanDetailCache != null) { 3194 for (ScanDetail sd : scanDetailCache.values()) { 3195 ScanResult r = sd.getScanResult(); 3196 if (r.BSSID.equals(mWifiInfo.getBSSID())) { 3197 sb.append(" ipfail=").append(r.numIpConfigFailures); 3198 sb.append(",st=").append(r.autoJoinStatus); 3199 } 3200 } 3201 } 3202 sb.append(" -> ajst=").append(c.autoJoinStatus); 3203 sb.append(" ").append(c.disableReason); 3204 sb.append(" txpkts=").append(mWifiInfo.txSuccess); 3205 sb.append(",").append(mWifiInfo.txBad); 3206 sb.append(",").append(mWifiInfo.txRetries); 3207 } 3208 sb.append(printTime()); 3209 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 3210 break; 3211 case CMD_UPDATE_LINKPROPERTIES: 3212 sb.append(" "); 3213 sb.append(Integer.toString(msg.arg1)); 3214 sb.append(" "); 3215 sb.append(Integer.toString(msg.arg2)); 3216 if (mLinkProperties != null) { 3217 if (mLinkProperties.hasIPv4Address()) { 3218 sb.append(" v4"); 3219 } 3220 if (mLinkProperties.hasGlobalIPv6Address()) { 3221 sb.append(" v6"); 3222 } 3223 if (mLinkProperties.hasIPv4DefaultRoute()) { 3224 sb.append(" v4r"); 3225 } 3226 if (mLinkProperties.hasIPv6DefaultRoute()) { 3227 sb.append(" v6r"); 3228 } 3229 if (mLinkProperties.hasIPv4DnsServer()) { 3230 sb.append(" v4dns"); 3231 } 3232 if (mLinkProperties.hasIPv6DnsServer()) { 3233 sb.append(" v6dns"); 3234 } 3235 } 3236 break; 3237 case CMD_SET_COUNTRY_CODE: 3238 sb.append(" "); 3239 sb.append(Integer.toString(msg.arg1)); 3240 sb.append(" "); 3241 sb.append(Integer.toString(msg.arg2)); 3242 if (msg.obj != null) { 3243 sb.append(" ").append((String) msg.obj); 3244 } 3245 break; 3246 case CMD_ROAM_WATCHDOG_TIMER: 3247 sb.append(" "); 3248 sb.append(Integer.toString(msg.arg1)); 3249 sb.append(" "); 3250 sb.append(Integer.toString(msg.arg2)); 3251 sb.append(" cur=").append(roamWatchdogCount); 3252 break; 3253 case CMD_DISCONNECTING_WATCHDOG_TIMER: 3254 sb.append(" "); 3255 sb.append(Integer.toString(msg.arg1)); 3256 sb.append(" "); 3257 sb.append(Integer.toString(msg.arg2)); 3258 sb.append(" cur=").append(disconnectingWatchdogCount); 3259 break; 3260 default: 3261 sb.append(" "); 3262 sb.append(Integer.toString(msg.arg1)); 3263 sb.append(" "); 3264 sb.append(Integer.toString(msg.arg2)); 3265 break; 3266 } 3267 3268 return sb.toString(); 3269 } 3270 3271 private void stopPno() { 3272 3273 // Stop PNO scans while we are trying to associate 3274 mWifiScanner.stopBackgroundScan(mWifiScanListener); 3275 3276 // clear the PNO list 3277 if (!WifiNative.setPnoList(null, WifiStateMachine.this)) { 3278 Log.e(TAG, "Failed to stop pno"); 3279 } 3280 3281 } 3282 3283 private boolean startPno() { 3284 if (!mAlwaysOnPnoSupported || (!mWifiConfigStore.enableHalBasedPno.get())) return false; 3285 3286 /* 3287 if (mWifiScannerChannel == null) { 3288 log("startPno: mWifiScannerChannel is null "); 3289 return false; 3290 }*/ 3291 if (mWifiScanner == null) { 3292 log("startPno: mWifiScanner is null "); 3293 return true; 3294 } 3295 3296 List<WifiNative.WifiPnoNetwork> llist 3297 = mWifiAutoJoinController.getPnoList(getCurrentWifiConfiguration()); 3298 if (llist != null) { 3299 log("startPno: got llist size " + llist.size()); 3300 3301 // first program the network we want to look for thru the pno API 3302 WifiNative.WifiPnoNetwork list[] 3303 = (WifiNative.WifiPnoNetwork[]) llist.toArray(new WifiNative.WifiPnoNetwork[0]); 3304 3305 if (!WifiNative.setPnoList(list, WifiStateMachine.this)) { 3306 Log.e(TAG, "Failed to set pno, length = " + list.length); 3307 } 3308 3309 // then send a scan background request so as firmware 3310 // starts looking for our networks 3311 WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings(); 3312 settings.band = WifiScanner.WIFI_BAND_BOTH; 3313 3314 // TODO, fix the scan interval logic 3315 if (mScreenOn) 3316 settings.periodInMs = mDefaultFrameworkScanIntervalMs; 3317 else 3318 settings.periodInMs = mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(); 3319 3320 settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL; 3321 log("startPno: settings BOTH_BANDS, length = " + list.length); 3322 3323 mWifiScanner.startBackgroundScan(settings, mWifiScanListener); 3324// mWifiScannerChannel.sendMessage 3325// (WifiScanner.CMD_START_BACKGROUND_SCAN, settings); 3326 if (DBG) { 3327 StringBuilder sb = new StringBuilder(); 3328 sb.append(" list: "); 3329 for (WifiNative.WifiPnoNetwork net : llist) { 3330 sb.append(" ").append(net.SSID).append(" auth ").append(net.auth); 3331 } 3332 sendMessage(CMD_STARTED_PNO_DBG, 1, 0, sb.toString()); 3333 } 3334 return true; 3335 } 3336 log("startPno: couldnt get PNO list "); 3337 return false; 3338 } 3339 3340 private void handleScreenStateChanged(boolean screenOn, boolean startBackgroundScanIfNeeded) { 3341 mScreenOn = screenOn; 3342 if (PDBG) { 3343 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 3344 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 3345 + " state " + getCurrentState().getName() 3346 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 3347 } 3348 enableRssiPolling(screenOn); 3349 if (screenOn) enableAllNetworks(); 3350 if (mUserWantsSuspendOpt.get()) { 3351 if (screenOn) { 3352 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 3353 } else { 3354 // Allow 2s for suspend optimizations to be set 3355 mSuspendWakeLock.acquire(2000); 3356 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 3357 } 3358 } 3359 mScreenBroadcastReceived.set(true); 3360 3361 getWifiLinkLayerStats(false); 3362 mOnTimeScreenStateChange = mOnTime; 3363 lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate; 3364 mEnableBackgroundScan = false; 3365 cancelDelayedScan(); 3366 3367 if (screenOn) { 3368 setScanAlarm(false); 3369 clearBlacklist(); 3370 3371 fullBandConnectedTimeIntervalMilli = mWifiConfigStore.associatedPartialScanPeriodMilli.get(); 3372 // In either Disconnectedstate or ConnectedState, 3373 // start the scan alarm so as to enable autojoin 3374 if (getCurrentState() == mConnectedState 3375 && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get()) { 3376 if (!startPno()) { 3377 // Scan after 500ms 3378 startDelayedScan(500, null, null); 3379 } 3380 } else if (getCurrentState() == mDisconnectedState) { 3381 if (!startPno()) { 3382 // Scan after 500ms 3383 startDelayedScan(500, null, null); 3384 } 3385 } 3386 } else if (startBackgroundScanIfNeeded) { 3387 // Screen Off and Disconnected and chipset doesn't support scan offload 3388 // => start scan alarm 3389 // Screen Off and Disconnected and chipset does support scan offload 3390 // => will use scan offload (i.e. background scan) 3391 if (!mAlwaysOnPnoSupported) { 3392 if (!mBackgroundScanSupported) { 3393 setScanAlarm(true); 3394 } else { 3395 mEnableBackgroundScan = true; 3396 } 3397 } 3398 } 3399 if (DBG) logd("backgroundScan enabled=" + mEnableBackgroundScan 3400 + " startBackgroundScanIfNeeded:" + startBackgroundScanIfNeeded); 3401 if (startBackgroundScanIfNeeded) { 3402 if (!startPno()) { 3403 // to scan for them in background, we need all networks enabled 3404 enableBackgroundScan(mEnableBackgroundScan); 3405 } 3406 } 3407 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 3408 } 3409 3410 private void checkAndSetConnectivityInstance() { 3411 if (mCm == null) { 3412 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 3413 } 3414 } 3415 3416 private boolean startTethering(ArrayList<String> available) { 3417 3418 boolean wifiAvailable = false; 3419 3420 checkAndSetConnectivityInstance(); 3421 3422 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 3423 3424 for (String intf : available) { 3425 for (String regex : wifiRegexs) { 3426 if (intf.matches(regex)) { 3427 3428 InterfaceConfiguration ifcg = null; 3429 try { 3430 ifcg = mNwService.getInterfaceConfig(intf); 3431 if (ifcg != null) { 3432 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 3433 ifcg.setLinkAddress(new LinkAddress( 3434 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 3435 ifcg.setInterfaceUp(); 3436 3437 mNwService.setInterfaceConfig(intf, ifcg); 3438 } 3439 } catch (Exception e) { 3440 loge("Error configuring interface " + intf + ", :" + e); 3441 return false; 3442 } 3443 3444 if (mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 3445 loge("Error tethering on " + intf); 3446 return false; 3447 } 3448 mTetherInterfaceName = intf; 3449 return true; 3450 } 3451 } 3452 } 3453 // We found no interfaces to tether 3454 return false; 3455 } 3456 3457 private void stopTethering() { 3458 3459 checkAndSetConnectivityInstance(); 3460 3461 /* Clear the interface config to allow dhcp correctly configure new 3462 ip settings */ 3463 InterfaceConfiguration ifcg = null; 3464 try { 3465 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 3466 if (ifcg != null) { 3467 ifcg.setLinkAddress( 3468 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 3469 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 3470 } 3471 } catch (Exception e) { 3472 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 3473 } 3474 3475 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 3476 loge("Untether initiate failed!"); 3477 } 3478 } 3479 3480 private boolean isWifiTethered(ArrayList<String> active) { 3481 3482 checkAndSetConnectivityInstance(); 3483 3484 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 3485 for (String intf : active) { 3486 for (String regex : wifiRegexs) { 3487 if (intf.matches(regex)) { 3488 return true; 3489 } 3490 } 3491 } 3492 // We found no interfaces that are tethered 3493 return false; 3494 } 3495 3496 /** 3497 * Set the country code from the system setting value, if any. 3498 */ 3499 private void setCountryCode() { 3500 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 3501 Settings.Global.WIFI_COUNTRY_CODE); 3502 if (countryCode != null && !countryCode.isEmpty()) { 3503 setCountryCode(countryCode, false); 3504 } else { 3505 //use driver default 3506 } 3507 } 3508 3509 /** 3510 * Set the frequency band from the system setting value, if any. 3511 */ 3512 private void setFrequencyBand() { 3513 int band = Settings.Global.getInt(mContext.getContentResolver(), 3514 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 3515 setFrequencyBand(band, false); 3516 } 3517 3518 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 3519 if (DBG) { 3520 log("setSuspendOptimizationsNative: " + reason + " " + enabled 3521 + " -want " + mUserWantsSuspendOpt.get() 3522 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3523 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 3524 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 3525 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 3526 } 3527 //mWifiNative.setSuspendOptimizations(enabled); 3528 3529 if (enabled) { 3530 mSuspendOptNeedsDisabled &= ~reason; 3531 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 3532 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 3533 if (DBG) { 3534 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 3535 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3536 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 3537 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 3538 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 3539 } 3540 mWifiNative.setSuspendOptimizations(true); 3541 } 3542 } else { 3543 mSuspendOptNeedsDisabled |= reason; 3544 mWifiNative.setSuspendOptimizations(false); 3545 } 3546 } 3547 3548 private void setSuspendOptimizations(int reason, boolean enabled) { 3549 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 3550 if (enabled) { 3551 mSuspendOptNeedsDisabled &= ~reason; 3552 } else { 3553 mSuspendOptNeedsDisabled |= reason; 3554 } 3555 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 3556 } 3557 3558 private void setWifiState(int wifiState) { 3559 final int previousWifiState = mWifiState.get(); 3560 3561 try { 3562 if (wifiState == WIFI_STATE_ENABLED) { 3563 mBatteryStats.noteWifiOn(); 3564 } else if (wifiState == WIFI_STATE_DISABLED) { 3565 mBatteryStats.noteWifiOff(); 3566 } 3567 } catch (RemoteException e) { 3568 loge("Failed to note battery stats in wifi"); 3569 } 3570 3571 mWifiState.set(wifiState); 3572 3573 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 3574 3575 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 3576 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3577 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 3578 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 3579 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3580 } 3581 3582 private void setWifiApState(int wifiApState) { 3583 final int previousWifiApState = mWifiApState.get(); 3584 3585 try { 3586 if (wifiApState == WIFI_AP_STATE_ENABLED) { 3587 mBatteryStats.noteWifiOn(); 3588 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 3589 mBatteryStats.noteWifiOff(); 3590 } 3591 } catch (RemoteException e) { 3592 loge("Failed to note battery stats in wifi"); 3593 } 3594 3595 // Update state 3596 mWifiApState.set(wifiApState); 3597 3598 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 3599 3600 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 3601 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3602 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 3603 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 3604 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3605 } 3606 3607 /* 3608 void ageOutScanResults(int age) { 3609 synchronized(mScanResultCache) { 3610 // Trim mScanResults, which prevent WifiStateMachine to return 3611 // obsolete scan results to queriers 3612 long now = System.CurrentTimeMillis(); 3613 for (int i = 0; i < mScanResults.size(); i++) { 3614 ScanResult result = mScanResults.get(i); 3615 if ((result.seen > now || (now - result.seen) > age)) { 3616 mScanResults.remove(i); 3617 } 3618 } 3619 } 3620 }*/ 3621 3622 private static final String IE_STR = "ie="; 3623 private static final String ID_STR = "id="; 3624 private static final String BSSID_STR = "bssid="; 3625 private static final String FREQ_STR = "freq="; 3626 private static final String LEVEL_STR = "level="; 3627 private static final String TSF_STR = "tsf="; 3628 private static final String FLAGS_STR = "flags="; 3629 private static final String SSID_STR = "ssid="; 3630 private static final String DELIMITER_STR = "===="; 3631 private static final String END_STR = "####"; 3632 3633 int emptyScanResultCount = 0; 3634 3635 // Used for matching BSSID strings, at least one characteer must be a non-zero number 3636 private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]"); 3637 3638 /** 3639 * Format: 3640 * <p/> 3641 * id=1 3642 * bssid=68:7f:76:d7:1a:6e 3643 * freq=2412 3644 * level=-44 3645 * tsf=1344626243700342 3646 * flags=[WPA2-PSK-CCMP][WPS][ESS] 3647 * ssid=zfdy 3648 * ==== 3649 * id=2 3650 * bssid=68:5f:74:d7:1a:6f 3651 * freq=5180 3652 * level=-73 3653 * tsf=1344626243700373 3654 * flags=[WPA2-PSK-CCMP][WPS][ESS] 3655 * ssid=zuby 3656 * ==== 3657 */ 3658 private void setScanResults() { 3659 mNumScanResultsKnown = 0; 3660 mNumScanResultsReturned = 0; 3661 String bssid = ""; 3662 int level = 0; 3663 int freq = 0; 3664 long tsf = 0; 3665 String flags = ""; 3666 WifiSsid wifiSsid = null; 3667 String scanResults; 3668 String tmpResults; 3669 StringBuffer scanResultsBuf = new StringBuffer(); 3670 int sid = 0; 3671 3672 while (true) { 3673 tmpResults = mWifiNative.scanResults(sid); 3674 if (TextUtils.isEmpty(tmpResults)) break; 3675 scanResultsBuf.append(tmpResults); 3676 scanResultsBuf.append("\n"); 3677 String[] lines = tmpResults.split("\n"); 3678 sid = -1; 3679 for (int i = lines.length - 1; i >= 0; i--) { 3680 if (lines[i].startsWith(END_STR)) { 3681 break; 3682 } else if (lines[i].startsWith(ID_STR)) { 3683 try { 3684 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 3685 } catch (NumberFormatException e) { 3686 // Nothing to do 3687 } 3688 break; 3689 } 3690 } 3691 if (sid == -1) break; 3692 } 3693 3694 // Age out scan results, we return all scan results found in the last 12 seconds, 3695 // and NOT all scan results since last scan. 3696 // ageOutScanResults(12000); 3697 3698 scanResults = scanResultsBuf.toString(); 3699 if (TextUtils.isEmpty(scanResults)) { 3700 emptyScanResultCount++; 3701 if (emptyScanResultCount > 10) { 3702 // If we got too many empty scan results, the current scan cache is stale, 3703 // hence clear it. 3704 mScanResults = new ArrayList<>(); 3705 } 3706 return; 3707 } 3708 3709 emptyScanResultCount = 0; 3710 3711 // note that all these splits and substrings keep references to the original 3712 // huge string buffer while the amount we really want is generally pretty small 3713 // so make copies instead (one example b/11087956 wasted 400k of heap here). 3714 synchronized (mScanResultCache) { 3715 mScanResults = new ArrayList<>(); 3716 String[] lines = scanResults.split("\n"); 3717 final int bssidStrLen = BSSID_STR.length(); 3718 final int flagLen = FLAGS_STR.length(); 3719 String infoElements = null; 3720 List<String> anqpLines = null; 3721 3722 for (String line : lines) { 3723 if (line.startsWith(BSSID_STR)) { 3724 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 3725 } else if (line.startsWith(FREQ_STR)) { 3726 try { 3727 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 3728 } catch (NumberFormatException e) { 3729 freq = 0; 3730 } 3731 } else if (line.startsWith(LEVEL_STR)) { 3732 try { 3733 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 3734 /* some implementations avoid negative values by adding 256 3735 * so we need to adjust for that here. 3736 */ 3737 if (level > 0) level -= 256; 3738 } catch (NumberFormatException e) { 3739 level = 0; 3740 } 3741 } else if (line.startsWith(TSF_STR)) { 3742 try { 3743 tsf = Long.parseLong(line.substring(TSF_STR.length())); 3744 } catch (NumberFormatException e) { 3745 tsf = 0; 3746 } 3747 } else if (line.startsWith(FLAGS_STR)) { 3748 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 3749 } else if (line.startsWith(SSID_STR)) { 3750 wifiSsid = WifiSsid.createFromAsciiEncoded( 3751 line.substring(SSID_STR.length())); 3752 } else if (line.startsWith(IE_STR)) { 3753 infoElements = line; 3754 } else if (SupplicantBridge.isAnqpAttribute(line)) { 3755 if (anqpLines == null) { 3756 anqpLines = new ArrayList<>(); 3757 } 3758 anqpLines.add(line); 3759 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 3760 if (bssid != null) { 3761 try { 3762 NetworkDetail networkDetail = 3763 new NetworkDetail(bssid, infoElements, anqpLines, freq); 3764 3765 String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 3766 if (!xssid.equals(networkDetail.getSSID())) { 3767 Log.d("HS2J", "Inconsistency: SSID: '" + xssid + 3768 "' vs '" + networkDetail.getSSID() + "': " + infoElements); 3769 } 3770 3771 if (networkDetail.hasInterworking()) { 3772 Log.d("HS2J", "HSNwk: '" + networkDetail); 3773 } 3774 3775 ScanDetail scanDetail = mScanResultCache.get(networkDetail); 3776 if (scanDetail != null) { 3777 scanDetail.updateResults(networkDetail, level, wifiSsid, xssid, 3778 flags, freq, tsf); 3779 } else { 3780 scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, 3781 flags, level, freq, tsf); 3782 mScanResultCache.put(networkDetail, scanDetail); 3783 } 3784 3785 mNumScanResultsReturned++; // Keep track of how many scan results we got 3786 // as part of this scan's processing 3787 mScanResults.add(scanDetail); 3788 } catch (IllegalArgumentException iae) { 3789 Log.d("HS2J", "Failed to parse information elements: " + iae); 3790 } catch (BufferUnderflowException bue) { 3791 Log.d("HS2J", "Failed to parse information elements: " + bue); 3792 } 3793 } 3794 bssid = null; 3795 level = 0; 3796 freq = 0; 3797 tsf = 0; 3798 flags = ""; 3799 wifiSsid = null; 3800 infoElements = null; 3801 anqpLines = null; 3802 } 3803 } 3804 } 3805 3806 boolean attemptAutoJoin = true; 3807 SupplicantState state = mWifiInfo.getSupplicantState(); 3808 String selection = mWifiConfigStore.getLastSelectedConfiguration(); 3809 if (getCurrentState() == mRoamingState 3810 || getCurrentState() == mObtainingIpState 3811 || getCurrentState() == mScanModeState 3812 || getCurrentState() == mDisconnectingState 3813 || (getCurrentState() == mConnectedState 3814 && !mWifiConfigStore.enableAutoJoinWhenAssociated.get()) 3815 || linkDebouncing 3816 || state == SupplicantState.ASSOCIATING 3817 || state == SupplicantState.AUTHENTICATING 3818 || state == SupplicantState.FOUR_WAY_HANDSHAKE 3819 || state == SupplicantState.GROUP_HANDSHAKE 3820 || (/* keep autojoin enabled if user has manually selected a wifi network, 3821 so as to make sure we reliably remain connected to this network */ 3822 mConnectionRequests == 0 && selection == null)) { 3823 // Dont attempt auto-joining again while we are already attempting to join 3824 // and/or obtaining Ip address 3825 attemptAutoJoin = false; 3826 } 3827 if (DBG) { 3828 if (selection == null) { 3829 selection = "<none>"; 3830 } 3831 loge("wifi setScanResults state" + getCurrentState() 3832 + " sup_state=" + state 3833 + " debouncing=" + linkDebouncing 3834 + " mConnectionRequests=" + mConnectionRequests 3835 + " selection=" + selection); 3836 } 3837 if (attemptAutoJoin) { 3838 messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED; 3839 } 3840 // Loose last selected configuration if we have been disconnected for 5 minutes 3841 if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) { 3842 mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 3843 } 3844 3845 if (mWifiConfigStore.enableAutoJoinWhenAssociated.get()) { 3846 synchronized (mScanResultCache) { 3847 // AutoJoincontroller will directly acces the scan result list and update it with 3848 // ScanResult status 3849 mNumScanResultsKnown = mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin); 3850 } 3851 } 3852 if (linkDebouncing) { 3853 // If debouncing, we dont re-select a SSID or BSSID hence 3854 // there is no need to call the network selection code 3855 // in WifiAutoJoinController, instead, 3856 // just try to reconnect to the same SSID by triggering a roam 3857 sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null); 3858 } 3859 } 3860 3861 /* 3862 * Fetch RSSI, linkspeed, and frequency on current connection 3863 */ 3864 private void fetchRssiLinkSpeedAndFrequencyNative() { 3865 int newRssi = -1; 3866 int newLinkSpeed = -1; 3867 int newFrequency = -1; 3868 3869 String signalPoll = mWifiNative.signalPoll(); 3870 3871 if (signalPoll != null) { 3872 String[] lines = signalPoll.split("\n"); 3873 for (String line : lines) { 3874 String[] prop = line.split("="); 3875 if (prop.length < 2) continue; 3876 try { 3877 if (prop[0].equals("RSSI")) { 3878 newRssi = Integer.parseInt(prop[1]); 3879 } else if (prop[0].equals("LINKSPEED")) { 3880 newLinkSpeed = Integer.parseInt(prop[1]); 3881 } else if (prop[0].equals("FREQUENCY")) { 3882 newFrequency = Integer.parseInt(prop[1]); 3883 } 3884 } catch (NumberFormatException e) { 3885 //Ignore, defaults on rssi and linkspeed are assigned 3886 } 3887 } 3888 } 3889 3890 if (PDBG) { 3891 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 3892 + Integer.toString(newRssi) + " linkspeed=" 3893 + Integer.toString(newLinkSpeed)); 3894 } 3895 3896 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 3897 // screen out invalid values 3898 /* some implementations avoid negative values by adding 256 3899 * so we need to adjust for that here. 3900 */ 3901 if (newRssi > 0) newRssi -= 256; 3902 mWifiInfo.setRssi(newRssi); 3903 /* 3904 * Rather then sending the raw RSSI out every time it 3905 * changes, we precalculate the signal level that would 3906 * be displayed in the status bar, and only send the 3907 * broadcast if that much more coarse-grained number 3908 * changes. This cuts down greatly on the number of 3909 * broadcasts, at the cost of not informing others 3910 * interested in RSSI of all the changes in signal 3911 * level. 3912 */ 3913 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 3914 if (newSignalLevel != mLastSignalLevel) { 3915 sendRssiChangeBroadcast(newRssi); 3916 } 3917 mLastSignalLevel = newSignalLevel; 3918 } else { 3919 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 3920 } 3921 3922 if (newLinkSpeed != -1) { 3923 mWifiInfo.setLinkSpeed(newLinkSpeed); 3924 } 3925 if (newFrequency > 0) { 3926 if (ScanResult.is5GHz(newFrequency)) { 3927 mWifiConnectionStatistics.num5GhzConnected++; 3928 } 3929 if (ScanResult.is24GHz(newFrequency)) { 3930 mWifiConnectionStatistics.num24GhzConnected++; 3931 } 3932 mWifiInfo.setFrequency(newFrequency); 3933 } 3934 mWifiConfigStore.updateConfiguration(mWifiInfo); 3935 } 3936 3937 /** 3938 * Determine if we need to switch network: 3939 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 3940 * - match the uregncy of the switch versus the packet usage at the interface 3941 */ 3942 boolean shouldSwitchNetwork(int networkDelta) { 3943 int delta; 3944 if (networkDelta <= 0) { 3945 return false; 3946 } 3947 delta = networkDelta; 3948 if (mWifiInfo != null) { 3949 if (!mWifiConfigStore.enableAutoJoinWhenAssociated.get() 3950 && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3951 // If AutoJoin while associated is not enabled, 3952 // we should never switch network when already associated 3953 delta = -1000; 3954 } else { 3955 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present 3956 // TODO: at the interface. We should also discriminate between ucast and mcast, 3957 // TODO: since the rxSuccessRate include all the bonjour and Ipv6 3958 // TODO: broadcasts 3959 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 3960 delta -= 999; 3961 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 3962 delta -= 6; 3963 } 3964 loge("WifiStateMachine shouldSwitchNetwork " 3965 + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 3966 + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 3967 + " delta " + networkDelta + " -> " + delta); 3968 } 3969 } else { 3970 loge("WifiStateMachine shouldSwitchNetwork " 3971 + " delta " + networkDelta + " -> " + delta); 3972 } 3973 if (delta > 0) { 3974 return true; 3975 } 3976 return false; 3977 } 3978 3979 // Polling has completed, hence we wont have a score anymore 3980 private void cleanWifiScore() { 3981 mWifiInfo.txBadRate = 0; 3982 mWifiInfo.txSuccessRate = 0; 3983 mWifiInfo.txRetriesRate = 0; 3984 mWifiInfo.rxSuccessRate = 0; 3985 } 3986 3987 int mBadLinkspeedcount = 0; 3988 3989 // For debug, provide information about the last scoring operation 3990 String wifiScoringReport = null; 3991 3992 private void calculateWifiScore(WifiLinkLayerStats stats) { 3993 StringBuilder sb = new StringBuilder(); 3994 3995 int score = 56; // Starting score, temporarily hardcoded in between 50 and 60 3996 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 3997 && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24) 3998 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() 3999 < mWifiConfigStore.badLinkSpeed5); 4000 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 4001 && mWifiInfo.getLinkSpeed() >= mWifiConfigStore.goodLinkSpeed24) 4002 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() 4003 >= mWifiConfigStore.goodLinkSpeed5); 4004 4005 if (isBadLinkspeed) { 4006 if (mBadLinkspeedcount < 6) 4007 mBadLinkspeedcount++; 4008 } else { 4009 if (mBadLinkspeedcount > 0) 4010 mBadLinkspeedcount--; 4011 } 4012 4013 if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")"); 4014 if (isGoodLinkspeed) sb.append(" gl"); 4015 4016 /** 4017 * We want to make sure that we use the 24GHz RSSI thresholds if 4018 * there are 2.4GHz scan results 4019 * otherwise we end up lowering the score based on 5GHz values 4020 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 4021 * We also might unblacklist the configuation based on 2.4GHz 4022 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 4023 */ 4024 boolean use24Thresholds = false; 4025 boolean homeNetworkBoost = false; 4026 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 4027 ScanDetailCache scanDetailCache = 4028 mWifiConfigStore.getScanDetailCache(currentConfiguration); 4029 if (currentConfiguration != null && scanDetailCache != null) { 4030 currentConfiguration.setVisibility(scanDetailCache.getVisibility(12000)); 4031 if (currentConfiguration.visibility != null) { 4032 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 4033 && currentConfiguration.visibility.rssi24 4034 >= (currentConfiguration.visibility.rssi5 - 2)) { 4035 use24Thresholds = true; 4036 } 4037 } 4038 if (scanDetailCache.size() <= 6 4039 && currentConfiguration.allowedKeyManagement.cardinality() == 1 4040 && currentConfiguration.allowedKeyManagement. 4041 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 4042 // A PSK network with less than 6 known BSSIDs 4043 // This is most likely a home network and thus we want to stick to wifi more 4044 homeNetworkBoost = true; 4045 } 4046 } 4047 if (homeNetworkBoost) sb.append(" hn"); 4048 if (use24Thresholds) sb.append(" u24"); 4049 4050 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 4051 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 4052 sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover)); 4053 4054 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 4055 4056 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get()) 4057 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get()); 4058 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get()) 4059 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get()); 4060 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get()) 4061 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get()); 4062 4063 if (isBadRSSI) sb.append(" br"); 4064 if (isLowRSSI) sb.append(" lr"); 4065 if (isHighRSSI) sb.append(" hr"); 4066 4067 int penalizedDueToUserTriggeredDisconnect = 0; // For debug information 4068 if (currentConfiguration != null && 4069 (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) { 4070 if (isBadRSSI) { 4071 currentConfiguration.numTicksAtBadRSSI++; 4072 if (currentConfiguration.numTicksAtBadRSSI > 1000) { 4073 // We remained associated for a compound amount of time while passing 4074 // traffic, hence loose the corresponding user triggered disabled stats 4075 if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) { 4076 currentConfiguration.numUserTriggeredWifiDisableBadRSSI--; 4077 } 4078 if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) { 4079 currentConfiguration.numUserTriggeredWifiDisableLowRSSI--; 4080 } 4081 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4082 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 4083 } 4084 currentConfiguration.numTicksAtBadRSSI = 0; 4085 } 4086 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 4087 (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0 4088 || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0 4089 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) { 4090 score = score - 5; 4091 penalizedDueToUserTriggeredDisconnect = 1; 4092 sb.append(" p1"); 4093 } 4094 } else if (isLowRSSI) { 4095 currentConfiguration.numTicksAtLowRSSI++; 4096 if (currentConfiguration.numTicksAtLowRSSI > 1000) { 4097 // We remained associated for a compound amount of time while passing 4098 // traffic, hence loose the corresponding user triggered disabled stats 4099 if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) { 4100 currentConfiguration.numUserTriggeredWifiDisableLowRSSI--; 4101 } 4102 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4103 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 4104 } 4105 currentConfiguration.numTicksAtLowRSSI = 0; 4106 } 4107 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 4108 (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0 4109 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) { 4110 score = score - 5; 4111 penalizedDueToUserTriggeredDisconnect = 2; 4112 sb.append(" p2"); 4113 } 4114 } else if (!isHighRSSI) { 4115 currentConfiguration.numTicksAtNotHighRSSI++; 4116 if (currentConfiguration.numTicksAtNotHighRSSI > 1000) { 4117 // We remained associated for a compound amount of time while passing 4118 // traffic, hence loose the corresponding user triggered disabled stats 4119 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4120 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 4121 } 4122 currentConfiguration.numTicksAtNotHighRSSI = 0; 4123 } 4124 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 4125 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4126 score = score - 5; 4127 penalizedDueToUserTriggeredDisconnect = 3; 4128 sb.append(" p3"); 4129 } 4130 } 4131 sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI, 4132 currentConfiguration.numTicksAtLowRSSI, 4133 currentConfiguration.numTicksAtNotHighRSSI)); 4134 } 4135 4136 if (PDBG) { 4137 String rssiStatus = ""; 4138 if (isBadRSSI) rssiStatus += " badRSSI "; 4139 else if (isHighRSSI) rssiStatus += " highRSSI "; 4140 else if (isLowRSSI) rssiStatus += " lowRSSI "; 4141 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 4142 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 4143 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 4144 + " score=" + Integer.toString(mWifiInfo.score) 4145 + rssiStatus 4146 + " -> txbadrate=" + String.format("%.2f", mWifiInfo.txBadRate) 4147 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 4148 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 4149 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 4150 + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect); 4151 } 4152 4153 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 4154 && (isBadRSSI || isLowRSSI)) { 4155 // Link is stuck 4156 if (mWifiInfo.linkStuckCount < 5) 4157 mWifiInfo.linkStuckCount += 1; 4158 sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount)); 4159 if (PDBG) loge(" bad link -> stuck count =" 4160 + Integer.toString(mWifiInfo.linkStuckCount)); 4161 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 4162 if (mWifiInfo.linkStuckCount > 0) 4163 mWifiInfo.linkStuckCount -= 1; 4164 sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount)); 4165 if (PDBG) loge(" good link -> stuck count =" 4166 + Integer.toString(mWifiInfo.linkStuckCount)); 4167 } 4168 4169 sb.append(String.format(" [%d", score)); 4170 4171 if (mWifiInfo.linkStuckCount > 1) { 4172 // Once link gets stuck for more than 3 seconds, start reducing the score 4173 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 4174 } 4175 sb.append(String.format(",%d", score)); 4176 4177 if (isBadLinkspeed) { 4178 score -= 4; 4179 if (PDBG) { 4180 loge(" isBadLinkspeed ---> count=" + mBadLinkspeedcount 4181 + " score=" + Integer.toString(score)); 4182 } 4183 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 4184 score += 4; // So as bad rssi alone dont kill us 4185 } 4186 sb.append(String.format(",%d", score)); 4187 4188 if (isBadRSSI) { 4189 if (mWifiInfo.badRssiCount < 7) 4190 mWifiInfo.badRssiCount += 1; 4191 } else if (isLowRSSI) { 4192 mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1 4193 if (mWifiInfo.badRssiCount > 0) { 4194 // Decrement bad Rssi count 4195 mWifiInfo.badRssiCount -= 1; 4196 } 4197 } else { 4198 mWifiInfo.badRssiCount = 0; 4199 mWifiInfo.lowRssiCount = 0; 4200 } 4201 4202 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount; 4203 sb.append(String.format(",%d", score)); 4204 4205 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 4206 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 4207 + " --> score " + Integer.toString(score)); 4208 4209 4210 if (isHighRSSI) { 4211 score += 5; 4212 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 4213 } 4214 sb.append(String.format(",%d]", score)); 4215 4216 sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount)); 4217 4218 //sanitize boundaries 4219 if (score > NetworkAgent.WIFI_BASE_SCORE) 4220 score = NetworkAgent.WIFI_BASE_SCORE; 4221 if (score < 0) 4222 score = 0; 4223 4224 //report score 4225 if (score != mWifiInfo.score) { 4226 if (DBG) { 4227 loge("calculateWifiScore() report new score " + Integer.toString(score)); 4228 } 4229 mWifiInfo.score = score; 4230 if (mNetworkAgent != null) { 4231 mNetworkAgent.sendNetworkScore(score); 4232 } 4233 } 4234 wifiScoringReport = sb.toString(); 4235 } 4236 4237 public double getTxPacketRate() { 4238 if (mWifiInfo != null) { 4239 return mWifiInfo.txSuccessRate; 4240 } 4241 return -1; 4242 } 4243 4244 public double getRxPacketRate() { 4245 if (mWifiInfo != null) { 4246 return mWifiInfo.rxSuccessRate; 4247 } 4248 return -1; 4249 } 4250 4251 /** 4252 * Fetch TX packet counters on current connection 4253 */ 4254 private void fetchPktcntNative(RssiPacketCountInfo info) { 4255 String pktcntPoll = mWifiNative.pktcntPoll(); 4256 4257 if (pktcntPoll != null) { 4258 String[] lines = pktcntPoll.split("\n"); 4259 for (String line : lines) { 4260 String[] prop = line.split("="); 4261 if (prop.length < 2) continue; 4262 try { 4263 if (prop[0].equals("TXGOOD")) { 4264 info.txgood = Integer.parseInt(prop[1]); 4265 } else if (prop[0].equals("TXBAD")) { 4266 info.txbad = Integer.parseInt(prop[1]); 4267 } 4268 } catch (NumberFormatException e) { 4269 // Ignore 4270 } 4271 } 4272 } 4273 } 4274 4275 private boolean clearIPv4Address(String iface) { 4276 try { 4277 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 4278 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 4279 mNwService.setInterfaceConfig(iface, ifcg); 4280 return true; 4281 } catch (RemoteException e) { 4282 return false; 4283 } 4284 } 4285 4286 private boolean isProvisioned(LinkProperties lp) { 4287 return lp.isProvisioned() || 4288 (mWifiConfigStore.isUsingStaticIp(mLastNetworkId) && lp.hasIPv4Address()); 4289 } 4290 4291 /** 4292 * Updates mLinkProperties by merging information from various sources. 4293 * <p/> 4294 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 4295 * netlink, static configuration, ...). When one of these sources of information has updated 4296 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 4297 * information that came from other sources. Instead, when one of those sources has new 4298 * information, we update the object that tracks the information from that source and then 4299 * call this method to apply the change to mLinkProperties. 4300 * <p/> 4301 * The information in mLinkProperties is currently obtained as follows: 4302 * - Interface name: set in the constructor. 4303 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 4304 * - IPv4 routes, DNS servers, and domains: DHCP. 4305 * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker. 4306 * - HTTP proxy: the wifi config store. 4307 */ 4308 private void updateLinkProperties(int reason) { 4309 LinkProperties newLp = new LinkProperties(); 4310 4311 // Interface name, proxy, and TCP buffer sizes are locally configured. 4312 newLp.setInterfaceName(mInterfaceName); 4313 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 4314 if (!TextUtils.isEmpty(mTcpBufferSizes)) { 4315 newLp.setTcpBufferSizes(mTcpBufferSizes); 4316 } 4317 4318 // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink. 4319 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 4320 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 4321 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 4322 newLp.addRoute(route); 4323 } 4324 for (InetAddress dns : netlinkLinkProperties.getDnsServers()) { 4325 newLp.addDnsServer(dns); 4326 } 4327 4328 // IPv4 routes, DNS servers and domains come from mDhcpResults. 4329 synchronized (mDhcpResultsLock) { 4330 // Even when we're using static configuration, we don't need to look at the config 4331 // store, because static IP configuration also populates mDhcpResults. 4332 if ((mDhcpResults != null)) { 4333 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) { 4334 newLp.addRoute(route); 4335 } 4336 for (InetAddress dns : mDhcpResults.dnsServers) { 4337 newLp.addDnsServer(dns); 4338 } 4339 newLp.setDomains(mDhcpResults.domains); 4340 } 4341 } 4342 4343 final boolean linkChanged = !newLp.equals(mLinkProperties); 4344 final boolean wasProvisioned = isProvisioned(mLinkProperties); 4345 final boolean isProvisioned = isProvisioned(newLp); 4346 final boolean lostIPv4Provisioning = 4347 mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address(); 4348 final DetailedState detailedState = getNetworkDetailedState(); 4349 4350 if (linkChanged) { 4351 if (DBG) { 4352 log("Link configuration changed for netId: " + mLastNetworkId 4353 + " old: " + mLinkProperties + " new: " + newLp); 4354 } 4355 mLinkProperties = newLp; 4356 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 4357 } 4358 4359 if (DBG) { 4360 StringBuilder sb = new StringBuilder(); 4361 sb.append("updateLinkProperties nid: " + mLastNetworkId); 4362 sb.append(" state: " + detailedState); 4363 sb.append(" reason: " + smToString(reason)); 4364 4365 if (mLinkProperties != null) { 4366 if (mLinkProperties.hasIPv4Address()) { 4367 sb.append(" v4"); 4368 } 4369 if (mLinkProperties.hasGlobalIPv6Address()) { 4370 sb.append(" v6"); 4371 } 4372 if (mLinkProperties.hasIPv4DefaultRoute()) { 4373 sb.append(" v4r"); 4374 } 4375 if (mLinkProperties.hasIPv6DefaultRoute()) { 4376 sb.append(" v6r"); 4377 } 4378 if (mLinkProperties.hasIPv4DnsServer()) { 4379 sb.append(" v4dns"); 4380 } 4381 if (mLinkProperties.hasIPv6DnsServer()) { 4382 sb.append(" v6dns"); 4383 } 4384 if (isProvisioned) { 4385 sb.append(" isprov"); 4386 } 4387 } 4388 loge(sb.toString()); 4389 } 4390 4391 // If we just configured or lost IP configuration, do the needful. 4392 // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost() 4393 // here because those should only be called if we're attempting to connect or already 4394 // connected, whereas updateLinkProperties can be called at any time. 4395 switch (reason) { 4396 case DhcpStateMachine.DHCP_SUCCESS: 4397 case CMD_STATIC_IP_SUCCESS: 4398 // IPv4 provisioning succeded. Advance to connected state. 4399 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4400 if (!isProvisioned) { 4401 // Can never happen unless DHCP reports success but isProvisioned thinks the 4402 // resulting configuration is invalid (e.g., no IPv4 address, or the state in 4403 // mLinkProperties is out of sync with reality, or there's a bug in this code). 4404 // TODO: disconnect here instead. If our configuration is not usable, there's no 4405 // point in staying connected, and if mLinkProperties is out of sync with 4406 // reality, that will cause problems in the future. 4407 loge("IPv4 config succeeded, but not provisioned"); 4408 } 4409 break; 4410 4411 case DhcpStateMachine.DHCP_FAILURE: 4412 // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it, 4413 // give up and disconnect. 4414 // If we're already provisioned (e.g., IPv6-only network), stay connected. 4415 if (!isProvisioned || lostIPv4Provisioning) { 4416 sendMessage(CMD_IP_CONFIGURATION_LOST); 4417 } else { 4418 // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). 4419 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4420 4421 // To be sure we don't get stuck with a non-working network if all we had is 4422 // IPv4, remove the IPv4 address from the interface (since we're using DHCP, 4423 // and DHCP failed). If we had an IPv4 address before, the deletion of the 4424 // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was 4425 // necessary for provisioning, its deletion will cause us to disconnect. 4426 // 4427 // This shouldn't be needed, because on an IPv4-only network a DHCP failure will 4428 // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will 4429 // not return true if we're using DHCP and don't have an IPv4 default route. So 4430 // for now it's only here for extra redundancy. However, it will increase 4431 // robustness if we move to getting IPv4 routes from netlink as well. 4432 loge("DHCP failure: provisioned, clearing IPv4 address."); 4433 if (!clearIPv4Address(mInterfaceName)) { 4434 sendMessage(CMD_IP_CONFIGURATION_LOST); 4435 } 4436 } 4437 break; 4438 4439 case CMD_STATIC_IP_FAILURE: 4440 // Static configuration was invalid, or an error occurred in applying it. Give up. 4441 sendMessage(CMD_IP_CONFIGURATION_LOST); 4442 break; 4443 4444 case CMD_UPDATE_LINKPROPERTIES: 4445 // IP addresses, DNS servers, etc. changed. Act accordingly. 4446 if (wasProvisioned && !isProvisioned) { 4447 // We no longer have a usable network configuration. Disconnect. 4448 sendMessage(CMD_IP_CONFIGURATION_LOST); 4449 } else if (!wasProvisioned && isProvisioned) { 4450 // We have a usable IPv6-only config. Advance to connected state. 4451 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4452 } 4453 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) { 4454 // If anything has changed and we're already connected, send out a notification. 4455 sendLinkConfigurationChangedBroadcast(); 4456 } 4457 break; 4458 } 4459 } 4460 4461 /** 4462 * Clears all our link properties. 4463 */ 4464 private void clearLinkProperties() { 4465 // Clear the link properties obtained from DHCP and netlink. 4466 synchronized (mDhcpResultsLock) { 4467 if (mDhcpResults != null) { 4468 mDhcpResults.clear(); 4469 } 4470 } 4471 mNetlinkTracker.clearLinkProperties(); 4472 4473 // Now clear the merged link properties. 4474 mLinkProperties.clear(); 4475 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 4476 } 4477 4478 /** 4479 * try to update default route MAC address. 4480 */ 4481 private String updateDefaultRouteMacAddress(int timeout) { 4482 String address = null; 4483 for (RouteInfo route : mLinkProperties.getRoutes()) { 4484 if (route.isDefaultRoute() && route.hasGateway()) { 4485 InetAddress gateway = route.getGateway(); 4486 if (gateway instanceof Inet4Address) { 4487 if (PDBG) { 4488 loge("updateDefaultRouteMacAddress found Ipv4 default :" 4489 + gateway.getHostAddress()); 4490 } 4491 address = macAddressFromRoute(gateway.getHostAddress()); 4492 /* The gateway's MAC address is known */ 4493 if ((address == null) && (timeout > 0)) { 4494 boolean reachable = false; 4495 try { 4496 reachable = gateway.isReachable(timeout); 4497 } catch (Exception e) { 4498 loge("updateDefaultRouteMacAddress exception reaching :" 4499 + gateway.getHostAddress()); 4500 4501 } finally { 4502 if (reachable == true) { 4503 4504 address = macAddressFromRoute(gateway.getHostAddress()); 4505 if (PDBG) { 4506 loge("updateDefaultRouteMacAddress reachable (tried again) :" 4507 + gateway.getHostAddress() + " found " + address); 4508 } 4509 } 4510 } 4511 } 4512 if (address != null) { 4513 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 4514 } 4515 } 4516 } 4517 } 4518 return address; 4519 } 4520 4521 private void sendScanResultsAvailableBroadcast() { 4522 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 4523 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4524 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4525 } 4526 4527 private void sendRssiChangeBroadcast(final int newRssi) { 4528 try { 4529 mBatteryStats.noteWifiRssiChanged(newRssi); 4530 } catch (RemoteException e) { 4531 // Won't happen. 4532 } 4533 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 4534 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4535 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 4536 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4537 } 4538 4539 private void sendNetworkStateChangeBroadcast(String bssid) { 4540 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 4541 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4542 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 4543 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 4544 if (bssid != null) 4545 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 4546 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 4547 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 4548 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 4549 } 4550 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4551 } 4552 4553 private void sendLinkConfigurationChangedBroadcast() { 4554 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 4555 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4556 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 4557 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4558 } 4559 4560 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 4561 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 4562 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4563 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 4564 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4565 } 4566 4567 /** 4568 * Record the detailed state of a network. 4569 * 4570 * @param state the new {@code DetailedState} 4571 */ 4572 private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) { 4573 boolean hidden = false; 4574 4575 if (linkDebouncing || isRoaming()) { 4576 // There is generally a confusion in the system about colluding 4577 // WiFi Layer 2 state (as reported by supplicant) and the Network state 4578 // which leads to multiple confusion. 4579 // 4580 // If link is de-bouncing or roaming, we already have an IP address 4581 // as well we were connected and are doing L2 cycles of 4582 // reconnecting or renewing IP address to check that we still have it 4583 // This L2 link flapping should ne be reflected into the Network state 4584 // which is the state of the WiFi Network visible to Layer 3 and applications 4585 // Note that once debouncing and roaming are completed, we will 4586 // set the Network state to where it should be, or leave it as unchanged 4587 // 4588 hidden = true; 4589 } 4590 if (DBG) { 4591 log("setDetailed state, old =" 4592 + mNetworkInfo.getDetailedState() + " and new state=" + state 4593 + " hidden=" + hidden); 4594 } 4595 if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null) { 4596 // Always indicate that SSID has changed 4597 if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) { 4598 if (DBG) { 4599 log("setDetailed state send new extra info" + mWifiInfo.getSSID()); 4600 } 4601 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID()); 4602 sendNetworkStateChangeBroadcast(null); 4603 } 4604 } 4605 if (hidden == true) { 4606 return false; 4607 } 4608 4609 if (state != mNetworkInfo.getDetailedState()) { 4610 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 4611 if (mNetworkAgent != null) { 4612 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4613 } 4614 sendNetworkStateChangeBroadcast(null); 4615 return true; 4616 } 4617 return false; 4618 } 4619 4620 private DetailedState getNetworkDetailedState() { 4621 return mNetworkInfo.getDetailedState(); 4622 } 4623 4624 private SupplicantState handleSupplicantStateChange(Message message) { 4625 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4626 SupplicantState state = stateChangeResult.state; 4627 // Supplicant state change 4628 // [31-13] Reserved for future use 4629 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 4630 // 50023 supplicant_state_changed (custom|1|5) 4631 mWifiInfo.setSupplicantState(state); 4632 // Network id is only valid when we start connecting 4633 if (SupplicantState.isConnecting(state)) { 4634 mWifiInfo.setNetworkId(stateChangeResult.networkId); 4635 } else { 4636 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 4637 } 4638 4639 mWifiInfo.setBSSID(stateChangeResult.BSSID); 4640 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 4641 4642 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 4643 4644 return state; 4645 } 4646 4647 /** 4648 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 4649 * using the interface, stopping DHCP & disabling interface 4650 */ 4651 private void handleNetworkDisconnect() { 4652 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 4653 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 4654 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 4655 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 4656 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 4657 4658 4659 clearCurrentConfigBSSID("handleNetworkDisconnect"); 4660 4661 stopDhcp(); 4662 4663 try { 4664 mNwService.clearInterfaceAddresses(mInterfaceName); 4665 mNwService.disableIpv6(mInterfaceName); 4666 } catch (Exception e) { 4667 loge("Failed to clear addresses or disable ipv6" + e); 4668 } 4669 4670 /* Reset data structures */ 4671 mBadLinkspeedcount = 0; 4672 mWifiInfo.reset(); 4673 linkDebouncing = false; 4674 /* Reset roaming parameters */ 4675 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 4676 4677 /** 4678 * fullBandConnectedTimeIntervalMilli: 4679 * - start scans at mWifiConfigStore.associatedPartialScanPeriodMilli seconds interval 4680 * - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli 4681 * Initialize to sane value = 20 seconds 4682 */ 4683 fullBandConnectedTimeIntervalMilli = 20 * 1000; 4684 4685 setNetworkDetailedState(DetailedState.DISCONNECTED); 4686 if (mNetworkAgent != null) { 4687 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4688 mNetworkAgent = null; 4689 } 4690 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 4691 4692 /* Clear network properties */ 4693 clearLinkProperties(); 4694 4695 /* Cend event to CM & network change broadcast */ 4696 sendNetworkStateChangeBroadcast(mLastBssid); 4697 4698 /* Cancel auto roam requests */ 4699 autoRoamSetBSSID(mLastNetworkId, "any"); 4700 4701 mLastBssid = null; 4702 registerDisconnected(); 4703 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 4704 } 4705 4706 private void handleSupplicantConnectionLoss() { 4707 /* Socket connection can be lost when we do a graceful shutdown 4708 * or when the driver is hung. Ensure supplicant is stopped here. 4709 */ 4710 mWifiMonitor.killSupplicant(mP2pSupported); 4711 mWifiNative.closeSupplicantConnection(); 4712 sendSupplicantConnectionChangedBroadcast(false); 4713 setWifiState(WIFI_STATE_DISABLED); 4714 } 4715 4716 void handlePreDhcpSetup() { 4717 mDhcpActive = true; 4718 if (!mBluetoothConnectionActive) { 4719 /* 4720 * There are problems setting the Wi-Fi driver's power 4721 * mode to active when bluetooth coexistence mode is 4722 * enabled or sense. 4723 * <p> 4724 * We set Wi-Fi to active mode when 4725 * obtaining an IP address because we've found 4726 * compatibility issues with some routers with low power 4727 * mode. 4728 * <p> 4729 * In order for this active power mode to properly be set, 4730 * we disable coexistence mode until we're done with 4731 * obtaining an IP address. One exception is if we 4732 * are currently connected to a headset, since disabling 4733 * coexistence would interrupt that connection. 4734 */ 4735 // Disable the coexistence mode 4736 mWifiNative.setBluetoothCoexistenceMode( 4737 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 4738 } 4739 4740 // Disable power save and suspend optimizations during DHCP 4741 // Note: The order here is important for now. Brcm driver changes 4742 // power settings when we control suspend mode optimizations. 4743 // TODO: Remove this comment when the driver is fixed. 4744 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 4745 mWifiNative.setPowerSave(false); 4746 4747 // stopBatchedScan(); 4748 WifiNative.pauseScan(); 4749 4750 // Update link layer stats 4751 getWifiLinkLayerStats(false); 4752 4753 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 4754 Message msg = new Message(); 4755 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 4756 msg.arg1 = WifiP2pServiceImpl.ENABLED; 4757 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 4758 msg.obj = mDhcpStateMachine; 4759 mWifiP2pChannel.sendMessage(msg); 4760 } 4761 4762 4763 private boolean useLegacyDhcpClient() { 4764 return Settings.Global.getInt( 4765 mContext.getContentResolver(), 4766 Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1; 4767 } 4768 4769 private void maybeInitDhcpStateMachine() { 4770 if (mDhcpStateMachine == null) { 4771 if (useLegacyDhcpClient()) { 4772 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 4773 mContext, WifiStateMachine.this, mInterfaceName); 4774 } else { 4775 mDhcpStateMachine = DhcpClient.makeDhcpStateMachine( 4776 mContext, WifiStateMachine.this, mInterfaceName); 4777 } 4778 } 4779 } 4780 4781 void startDhcp() { 4782 maybeInitDhcpStateMachine(); 4783 mDhcpStateMachine.registerForPreDhcpNotification(); 4784 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 4785 } 4786 4787 void renewDhcp() { 4788 maybeInitDhcpStateMachine(); 4789 mDhcpStateMachine.registerForPreDhcpNotification(); 4790 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 4791 } 4792 4793 void stopDhcp() { 4794 if (mDhcpStateMachine != null) { 4795 /* In case we were in middle of DHCP operation restore back powermode */ 4796 handlePostDhcpSetup(); 4797 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 4798 } 4799 } 4800 4801 void handlePostDhcpSetup() { 4802 /* Restore power save and suspend optimizations */ 4803 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 4804 mWifiNative.setPowerSave(true); 4805 4806 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 4807 4808 // Set the coexistence mode back to its default value 4809 mWifiNative.setBluetoothCoexistenceMode( 4810 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 4811 4812 mDhcpActive = false; 4813 4814 // startBatchedScan(); 4815 WifiNative.restartScan(); 4816 } 4817 4818 void connectScanningService() { 4819 4820 if (mWifiScanner == null) 4821 mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE); 4822 4823 } 4824 4825 private void handleIPv4Success(DhcpResults dhcpResults, int reason) { 4826 4827 if (PDBG) { 4828 loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() + ">"); 4829 loge("link address " + dhcpResults.ipAddress); 4830 } 4831 4832 synchronized (mDhcpResultsLock) { 4833 mDhcpResults = dhcpResults; 4834 } 4835 4836 Inet4Address addr = (Inet4Address) dhcpResults.ipAddress.getAddress(); 4837 if (isRoaming()) { 4838 if (addr instanceof Inet4Address) { 4839 int previousAddress = mWifiInfo.getIpAddress(); 4840 int newAddress = NetworkUtils.inetAddressToInt(addr); 4841 if (previousAddress != newAddress) { 4842 loge("handleIPv4Success, roaming and address changed" + 4843 mWifiInfo + " got: " + addr); 4844 } else { 4845 4846 } 4847 } else { 4848 loge("handleIPv4Success, roaming and didnt get an IPv4 address" + 4849 addr.toString()); 4850 } 4851 } 4852 mWifiInfo.setInetAddress(addr); 4853 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 4854 updateLinkProperties(reason); 4855 } 4856 4857 private void handleSuccessfulIpConfiguration() { 4858 mLastSignalLevel = -1; // Force update of signal strength 4859 WifiConfiguration c = getCurrentWifiConfiguration(); 4860 if (c != null) { 4861 // Reset IP failure tracking 4862 c.numConnectionFailures = 0; 4863 4864 // Tell the framework whether the newly connected network is trusted or untrusted. 4865 updateCapabilities(c); 4866 } 4867 if (c != null) { 4868 ScanResult result = getCurrentScanResult(); 4869 if (result == null) { 4870 loge("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" + 4871 c.configKey()); 4872 } else { 4873 // Clear the per BSSID failure count 4874 result.numIpConfigFailures = 0; 4875 // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry 4876 // any BSSID, even though it may already have a non zero ip failure count, 4877 // this will typically happen if the user walks away and come back to his arrea 4878 // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted 4879 // in supplicant for a couple of hours or a day 4880 mWifiNative.clearBlacklist(); 4881 } 4882 } 4883 } 4884 4885 private void handleIPv4Failure(int reason) { 4886 synchronized(mDhcpResultsLock) { 4887 if (mDhcpResults != null) { 4888 mDhcpResults.clear(); 4889 } 4890 } 4891 if (PDBG) { 4892 loge("wifistatemachine handleIPv4Failure"); 4893 } 4894 updateLinkProperties(reason); 4895 } 4896 4897 private void handleIpConfigurationLost() { 4898 mWifiInfo.setInetAddress(null); 4899 mWifiInfo.setMeteredHint(false); 4900 4901 mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false, 4902 "DHCP FAILURE", mWifiInfo.getBSSID()); 4903 4904 /* DHCP times out after about 30 seconds, we do a 4905 * disconnect thru supplicant, we will let autojoin retry connecting to the network 4906 */ 4907 mWifiNative.disconnect(); 4908 } 4909 4910 private int convertFrequencyToChannelNumber(int frequency) { 4911 if (frequency >= 2412 && frequency <= 2484) { 4912 return (frequency -2412) / 5 + 1; 4913 } else if (frequency >= 5170 && frequency <=5825) { 4914 //DFS is included 4915 return (frequency -5170) / 5 + 34; 4916 } else { 4917 return 0; 4918 } 4919 } 4920 4921 private int chooseApChannel(int apBand) { 4922 int apChannel; 4923 int[] channel; 4924 4925 if (apBand == 0) { 4926 //for 2.4GHz, we only set the AP at channel 1,6,11 4927 apChannel = 5 * mRandom.nextInt(3) + 1; 4928 } else { 4929 //5G without DFS 4930 channel = mWifiNative.getChannelsForBand(2); 4931 if (channel != null && channel.length > 0) { 4932 apChannel = channel[mRandom.nextInt(channel.length)]; 4933 apChannel = convertFrequencyToChannelNumber(apChannel); 4934 } else { 4935 Log.e(TAG, "SoftAp do not get available channel list"); 4936 apChannel = 0; 4937 } 4938 } 4939 4940 if(DBG) { 4941 Log.d(TAG, "SoftAp set on channel " + apChannel); 4942 } 4943 4944 return apChannel; 4945 } 4946 4947 4948 /* Current design is to not set the config on a running hostapd but instead 4949 * stop and start tethering when user changes config on a running access point 4950 * 4951 * TODO: Add control channel setup through hostapd that allows changing config 4952 * on a running daemon 4953 */ 4954 private void startSoftApWithConfig(final WifiConfiguration configuration) { 4955 // set channel 4956 final WifiConfiguration config = new WifiConfiguration(configuration); 4957 4958 if (DBG) { 4959 Log.d(TAG, "SoftAp config channel is: " + config.apChannel); 4960 } 4961 //set country code through HAL Here 4962 if (mSetCountryCode != null) { 4963 if(!mWifiNative.setCountryCodeHal(mSetCountryCode.toUpperCase(Locale.ROOT))) { 4964 if (config.apBand != 0) { 4965 Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz"); 4966 //countrycode is mandatory for 5GHz 4967 sendMessage(CMD_START_AP_FAILURE); 4968 return; 4969 } 4970 } 4971 } else { 4972 if (config.apBand != 0) { 4973 //countrycode is mandatory for 5GHz 4974 Log.e(TAG, "Can not setup softAp on 5GHz without country code!"); 4975 sendMessage(CMD_START_AP_FAILURE); 4976 return; 4977 } 4978 } 4979 4980 if (config.apChannel == 0) { 4981 config.apChannel = chooseApChannel(config.apBand); 4982 if (config.apChannel == 0) { 4983 //fail to get available channel 4984 sendMessage(CMD_START_AP_FAILURE); 4985 return; 4986 } 4987 } 4988 //turn off interface 4989 if (!mWifiNative.toggleInterface(0)) { 4990 sendMessage(CMD_START_AP_FAILURE); 4991 return; 4992 } 4993 // Start hostapd on a separate thread 4994 new Thread(new Runnable() { 4995 public void run() { 4996 try { 4997 mNwService.startAccessPoint(config, mInterfaceName); 4998 } catch (Exception e) { 4999 loge("Exception in softap start " + e); 5000 try { 5001 mNwService.stopAccessPoint(mInterfaceName); 5002 mNwService.startAccessPoint(config, mInterfaceName); 5003 } catch (Exception e1) { 5004 loge("Exception in softap re-start " + e1); 5005 sendMessage(CMD_START_AP_FAILURE); 5006 return; 5007 } 5008 } 5009 if (DBG) log("Soft AP start successful"); 5010 sendMessage(CMD_START_AP_SUCCESS); 5011 } 5012 }).start(); 5013 } 5014 5015 /* 5016 * Read a MAC address in /proc/arp/table, used by WifistateMachine 5017 * so as to record MAC address of default gateway. 5018 **/ 5019 private String macAddressFromRoute(String ipAddress) { 5020 String macAddress = null; 5021 BufferedReader reader = null; 5022 try { 5023 reader = new BufferedReader(new FileReader("/proc/net/arp")); 5024 5025 // Skip over the line bearing colum titles 5026 String line = reader.readLine(); 5027 5028 while ((line = reader.readLine()) != null) { 5029 String[] tokens = line.split("[ ]+"); 5030 if (tokens.length < 6) { 5031 continue; 5032 } 5033 5034 // ARP column format is 5035 // Address HWType HWAddress Flags Mask IFace 5036 String ip = tokens[0]; 5037 String mac = tokens[3]; 5038 5039 if (ipAddress.equals(ip)) { 5040 macAddress = mac; 5041 break; 5042 } 5043 } 5044 5045 if (macAddress == null) { 5046 loge("Did not find remoteAddress {" + ipAddress + "} in " + 5047 "/proc/net/arp"); 5048 } 5049 5050 } catch (FileNotFoundException e) { 5051 loge("Could not open /proc/net/arp to lookup mac address"); 5052 } catch (IOException e) { 5053 loge("Could not read /proc/net/arp to lookup mac address"); 5054 } finally { 5055 try { 5056 if (reader != null) { 5057 reader.close(); 5058 } 5059 } catch (IOException e) { 5060 // Do nothing 5061 } 5062 } 5063 return macAddress; 5064 5065 } 5066 5067 private class WifiNetworkFactory extends NetworkFactory { 5068 public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { 5069 super(l, c, TAG, f); 5070 } 5071 5072 @Override 5073 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 5074 ++mConnectionRequests; 5075 } 5076 5077 @Override 5078 protected void releaseNetworkFor(NetworkRequest networkRequest) { 5079 --mConnectionRequests; 5080 } 5081 5082 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5083 pw.println("mConnectionRequests " + mConnectionRequests); 5084 } 5085 5086 } 5087 5088 private class UntrustedWifiNetworkFactory extends NetworkFactory { 5089 private int mUntrustedReqCount; 5090 5091 public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) { 5092 super(l, c, tag, f); 5093 } 5094 5095 @Override 5096 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 5097 if (!networkRequest.networkCapabilities.hasCapability( 5098 NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { 5099 if (++mUntrustedReqCount == 1) { 5100 mWifiAutoJoinController.setAllowUntrustedConnections(true); 5101 } 5102 } 5103 } 5104 5105 @Override 5106 protected void releaseNetworkFor(NetworkRequest networkRequest) { 5107 if (!networkRequest.networkCapabilities.hasCapability( 5108 NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { 5109 if (--mUntrustedReqCount == 0) { 5110 mWifiAutoJoinController.setAllowUntrustedConnections(false); 5111 } 5112 } 5113 } 5114 5115 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5116 pw.println("mUntrustedReqCount " + mUntrustedReqCount); 5117 } 5118 } 5119 5120 void maybeRegisterNetworkFactory() { 5121 if (mNetworkFactory == null) { 5122 checkAndSetConnectivityInstance(); 5123 if (mCm != null) { 5124 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, 5125 NETWORKTYPE, mNetworkCapabilitiesFilter); 5126 mNetworkFactory.setScoreFilter(60); 5127 mNetworkFactory.register(); 5128 5129 // We can't filter untrusted network in the capabilities filter because a trusted 5130 // network would still satisfy a request that accepts untrusted ones. 5131 mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(), 5132 mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter); 5133 mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE); 5134 mUntrustedNetworkFactory.register(); 5135 } 5136 } 5137 } 5138 5139 /******************************************************** 5140 * HSM states 5141 *******************************************************/ 5142 5143 class DefaultState extends State { 5144 @Override 5145 public boolean processMessage(Message message) { 5146 logStateAndMessage(message, getClass().getSimpleName()); 5147 5148 switch (message.what) { 5149 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 5150 AsyncChannel ac = (AsyncChannel) message.obj; 5151 if (ac == mWifiP2pChannel) { 5152 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 5153 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 5154 } else { 5155 loge("WifiP2pService connection failure, error=" + message.arg1); 5156 } 5157 } else { 5158 loge("got HALF_CONNECTED for unknown channel"); 5159 } 5160 break; 5161 } 5162 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 5163 AsyncChannel ac = (AsyncChannel) message.obj; 5164 if (ac == mWifiP2pChannel) { 5165 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 5166 //TODO: Re-establish connection to state machine after a delay 5167 // mWifiP2pChannel.connect(mContext, getHandler(), 5168 // mWifiP2pManager.getMessenger()); 5169 } 5170 break; 5171 } 5172 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 5173 mBluetoothConnectionActive = (message.arg1 != 5174 BluetoothAdapter.STATE_DISCONNECTED); 5175 break; 5176 /* Synchronous call returns */ 5177 case CMD_PING_SUPPLICANT: 5178 case CMD_ENABLE_NETWORK: 5179 case CMD_ADD_OR_UPDATE_NETWORK: 5180 case CMD_REMOVE_NETWORK: 5181 case CMD_SAVE_CONFIG: 5182 replyToMessage(message, message.what, FAILURE); 5183 break; 5184 case CMD_GET_CAPABILITY_FREQ: 5185 replyToMessage(message, message.what, null); 5186 break; 5187 case CMD_GET_CONFIGURED_NETWORKS: 5188 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 5189 break; 5190 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 5191 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 5192 break; 5193 case CMD_ENABLE_RSSI_POLL: 5194 mEnableRssiPolling = (message.arg1 == 1); 5195 break; 5196 case CMD_SET_HIGH_PERF_MODE: 5197 if (message.arg1 == 1) { 5198 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 5199 } else { 5200 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 5201 } 5202 break; 5203 case CMD_BOOT_COMPLETED: 5204 maybeRegisterNetworkFactory(); 5205 break; 5206 case CMD_SET_BATCHED_SCAN: 5207 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 5208 break; 5209 case CMD_POLL_BATCHED_SCAN: 5210 handleBatchedScanPollRequest(); 5211 break; 5212 case CMD_START_NEXT_BATCHED_SCAN: 5213 startNextBatchedScan(); 5214 break; 5215 case CMD_SCREEN_STATE_CHANGED: 5216 handleScreenStateChanged(message.arg1 != 0, 5217 /* startBackgroundScanIfNeeded = */ false); 5218 break; 5219 /* Discard */ 5220 case CMD_START_SCAN: 5221 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5222 break; 5223 case CMD_START_SUPPLICANT: 5224 case CMD_STOP_SUPPLICANT: 5225 case CMD_STOP_SUPPLICANT_FAILED: 5226 case CMD_START_DRIVER: 5227 case CMD_STOP_DRIVER: 5228 case CMD_DELAYED_STOP_DRIVER: 5229 case CMD_DRIVER_START_TIMED_OUT: 5230 case CMD_START_AP: 5231 case CMD_START_AP_SUCCESS: 5232 case CMD_START_AP_FAILURE: 5233 case CMD_STOP_AP: 5234 case CMD_TETHER_STATE_CHANGE: 5235 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5236 case CMD_DISCONNECT: 5237 case CMD_RECONNECT: 5238 case CMD_REASSOCIATE: 5239 case CMD_RELOAD_TLS_AND_RECONNECT: 5240 case WifiMonitor.SUP_CONNECTION_EVENT: 5241 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5242 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5243 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5244 case WifiMonitor.SCAN_RESULTS_EVENT: 5245 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5246 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5247 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5248 case WifiMonitor.WPS_OVERLAP_EVENT: 5249 case CMD_BLACKLIST_NETWORK: 5250 case CMD_CLEAR_BLACKLIST: 5251 case CMD_SET_OPERATIONAL_MODE: 5252 case CMD_SET_COUNTRY_CODE: 5253 case CMD_SET_FREQUENCY_BAND: 5254 case CMD_RSSI_POLL: 5255 case CMD_ENABLE_ALL_NETWORKS: 5256 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 5257 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 5258 /* Handled by WifiApConfigStore */ 5259 case CMD_SET_AP_CONFIG: 5260 case CMD_SET_AP_CONFIG_COMPLETED: 5261 case CMD_REQUEST_AP_CONFIG: 5262 case CMD_RESPONSE_AP_CONFIG: 5263 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5264 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 5265 case CMD_NO_NETWORKS_PERIODIC_SCAN: 5266 case CMD_DISABLE_P2P_RSP: 5267 case WifiMonitor.SUP_REQUEST_IDENTITY: 5268 case CMD_TEST_NETWORK_DISCONNECT: 5269 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 5270 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 5271 case CMD_TARGET_BSSID: 5272 case CMD_AUTO_CONNECT: 5273 case CMD_AUTO_ROAM: 5274 case CMD_AUTO_SAVE_NETWORK: 5275 case CMD_ASSOCIATED_BSSID: 5276 case CMD_UNWANTED_NETWORK: 5277 case CMD_DISCONNECTING_WATCHDOG_TIMER: 5278 case CMD_ROAM_WATCHDOG_TIMER: 5279 case CMD_DISABLE_EPHEMERAL_NETWORK: 5280 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5281 break; 5282 case DhcpStateMachine.CMD_ON_QUIT: 5283 mDhcpStateMachine = null; 5284 break; 5285 case CMD_SET_SUSPEND_OPT_ENABLED: 5286 if (message.arg1 == 1) { 5287 mSuspendWakeLock.release(); 5288 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 5289 } else { 5290 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 5291 } 5292 break; 5293 case WifiMonitor.DRIVER_HUNG_EVENT: 5294 setSupplicantRunning(false); 5295 setSupplicantRunning(true); 5296 break; 5297 case WifiManager.CONNECT_NETWORK: 5298 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5299 WifiManager.BUSY); 5300 break; 5301 case WifiManager.FORGET_NETWORK: 5302 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 5303 WifiManager.BUSY); 5304 break; 5305 case WifiManager.SAVE_NETWORK: 5306 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 5307 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5308 WifiManager.BUSY); 5309 break; 5310 case WifiManager.START_WPS: 5311 replyToMessage(message, WifiManager.WPS_FAILED, 5312 WifiManager.BUSY); 5313 break; 5314 case WifiManager.CANCEL_WPS: 5315 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 5316 WifiManager.BUSY); 5317 break; 5318 case WifiManager.DISABLE_NETWORK: 5319 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 5320 WifiManager.BUSY); 5321 break; 5322 case WifiManager.RSSI_PKTCNT_FETCH: 5323 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 5324 WifiManager.BUSY); 5325 break; 5326 case CMD_GET_SUPPORTED_FEATURES: 5327 if (WifiNative.startHal()) { 5328 int featureSet = WifiNative.getSupportedFeatureSet(); 5329 replyToMessage(message, message.what, featureSet); 5330 } else { 5331 replyToMessage(message, message.what, 0); 5332 } 5333 break; 5334 case CMD_GET_LINK_LAYER_STATS: 5335 // Not supported hence reply with error message 5336 replyToMessage(message, message.what, null); 5337 break; 5338 case CMD_GET_MATCHING_CONFIG: 5339 replyToMessage(message, message.what); 5340 break; 5341 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 5342 NetworkInfo info = (NetworkInfo) message.obj; 5343 mP2pConnected.set(info.isConnected()); 5344 break; 5345 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5346 mTemporarilyDisconnectWifi = (message.arg1 == 1); 5347 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 5348 break; 5349 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 5350 case CMD_UPDATE_LINKPROPERTIES: 5351 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 5352 break; 5353 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5354 case CMD_IP_CONFIGURATION_LOST: 5355 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5356 break; 5357 case CMD_GET_CONNECTION_STATISTICS: 5358 replyToMessage(message, message.what, mWifiConnectionStatistics); 5359 break; 5360 case CMD_REMOVE_APP_CONFIGURATIONS: 5361 deferMessage(message); 5362 break; 5363 case CMD_REMOVE_USER_CONFIGURATIONS: 5364 deferMessage(message); 5365 break; 5366 default: 5367 loge("Error! unhandled message" + message); 5368 break; 5369 } 5370 return HANDLED; 5371 } 5372 } 5373 5374 class InitialState extends State { 5375 @Override 5376 public void enter() { 5377 mWifiNative.unloadDriver(); 5378 5379 if (mWifiP2pChannel == null) { 5380 mWifiP2pChannel = new AsyncChannel(); 5381 mWifiP2pChannel.connect(mContext, getHandler(), 5382 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 5383 } 5384 5385 if (mWifiApConfigChannel == null) { 5386 mWifiApConfigChannel = new AsyncChannel(); 5387 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 5388 mContext, getHandler()); 5389 wifiApConfigStore.loadApConfiguration(); 5390 mWifiApConfigChannel.connectSync(mContext, getHandler(), 5391 wifiApConfigStore.getMessenger()); 5392 } 5393 } 5394 @Override 5395 public boolean processMessage(Message message) { 5396 logStateAndMessage(message, getClass().getSimpleName()); 5397 switch (message.what) { 5398 case CMD_START_SUPPLICANT: 5399 if (mWifiNative.loadDriver()) { 5400 try { 5401 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 5402 } catch (Exception e) { 5403 loge("Failed to reload STA firmware " + e); 5404 // Continue 5405 } 5406 5407 try { 5408 // A runtime crash can leave the interface up and 5409 // IP addresses configured, and this affects 5410 // connectivity when supplicant starts up. 5411 // Ensure interface is down and we have no IP 5412 // addresses before a supplicant start. 5413 mNwService.setInterfaceDown(mInterfaceName); 5414 mNwService.clearInterfaceAddresses(mInterfaceName); 5415 5416 // Set privacy extensions 5417 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 5418 5419 // IPv6 is enabled only as long as access point is connected since: 5420 // - IPv6 addresses and routes stick around after disconnection 5421 // - kernel is unaware when connected and fails to start IPv6 negotiation 5422 // - kernel can start autoconfiguration when 802.1x is not complete 5423 mNwService.disableIpv6(mInterfaceName); 5424 } catch (RemoteException re) { 5425 loge("Unable to change interface settings: " + re); 5426 } catch (IllegalStateException ie) { 5427 loge("Unable to change interface settings: " + ie); 5428 } 5429 5430 /* Stop a running supplicant after a runtime restart 5431 * Avoids issues with drivers that do not handle interface down 5432 * on a running supplicant properly. 5433 */ 5434 mWifiMonitor.killSupplicant(mP2pSupported); 5435 if(mWifiNative.startSupplicant(mP2pSupported)) { 5436 setWifiState(WIFI_STATE_ENABLING); 5437 if (DBG) log("Supplicant start successful"); 5438 mWifiMonitor.startMonitoring(); 5439 transitionTo(mSupplicantStartingState); 5440 } else { 5441 loge("Failed to start supplicant!"); 5442 } 5443 } else { 5444 loge("Failed to load driver"); 5445 } 5446 break; 5447 case CMD_START_AP: 5448 if (mWifiNative.loadDriver()) { 5449 setWifiApState(WIFI_AP_STATE_ENABLING); 5450 transitionTo(mSoftApStartingState); 5451 } else { 5452 loge("Failed to load driver for softap"); 5453 } 5454 break; 5455 default: 5456 return NOT_HANDLED; 5457 } 5458 return HANDLED; 5459 } 5460 } 5461 5462 class SupplicantStartingState extends State { 5463 private void initializeWpsDetails() { 5464 String detail; 5465 detail = SystemProperties.get("ro.product.name", ""); 5466 if (!mWifiNative.setDeviceName(detail)) { 5467 loge("Failed to set device name " + detail); 5468 } 5469 detail = SystemProperties.get("ro.product.manufacturer", ""); 5470 if (!mWifiNative.setManufacturer(detail)) { 5471 loge("Failed to set manufacturer " + detail); 5472 } 5473 detail = SystemProperties.get("ro.product.model", ""); 5474 if (!mWifiNative.setModelName(detail)) { 5475 loge("Failed to set model name " + detail); 5476 } 5477 detail = SystemProperties.get("ro.product.model", ""); 5478 if (!mWifiNative.setModelNumber(detail)) { 5479 loge("Failed to set model number " + detail); 5480 } 5481 detail = SystemProperties.get("ro.serialno", ""); 5482 if (!mWifiNative.setSerialNumber(detail)) { 5483 loge("Failed to set serial number " + detail); 5484 } 5485 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 5486 loge("Failed to set WPS config methods"); 5487 } 5488 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 5489 loge("Failed to set primary device type " + mPrimaryDeviceType); 5490 } 5491 } 5492 5493 @Override 5494 public boolean processMessage(Message message) { 5495 logStateAndMessage(message, getClass().getSimpleName()); 5496 5497 switch(message.what) { 5498 case WifiMonitor.SUP_CONNECTION_EVENT: 5499 if (DBG) log("Supplicant connection established"); 5500 setWifiState(WIFI_STATE_ENABLED); 5501 mSupplicantRestartCount = 0; 5502 /* Reset the supplicant state to indicate the supplicant 5503 * state is not known at this time */ 5504 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5505 /* Initialize data structures */ 5506 mLastBssid = null; 5507 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 5508 mLastSignalLevel = -1; 5509 5510 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 5511 mWifiNative.enableSaveConfig(); 5512 mWifiConfigStore.loadAndEnableAllNetworks(); 5513 if (mWifiConfigStore.enableVerboseLogging.get() > 0) { 5514 enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get()); 5515 } 5516 if (mWifiConfigStore.associatedPartialScanPeriodMilli.get() < 0) { 5517 mWifiConfigStore.associatedPartialScanPeriodMilli.set(0); 5518 } 5519 initializeWpsDetails(); 5520 5521 sendSupplicantConnectionChangedBroadcast(true); 5522 transitionTo(mDriverStartedState); 5523 break; 5524 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5525 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 5526 loge("Failed to setup control channel, restart supplicant"); 5527 mWifiMonitor.killSupplicant(mP2pSupported); 5528 transitionTo(mInitialState); 5529 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 5530 } else { 5531 loge("Failed " + mSupplicantRestartCount + 5532 " times to start supplicant, unload driver"); 5533 mSupplicantRestartCount = 0; 5534 setWifiState(WIFI_STATE_UNKNOWN); 5535 transitionTo(mInitialState); 5536 } 5537 break; 5538 case CMD_START_SUPPLICANT: 5539 case CMD_STOP_SUPPLICANT: 5540 case CMD_START_AP: 5541 case CMD_STOP_AP: 5542 case CMD_START_DRIVER: 5543 case CMD_STOP_DRIVER: 5544 case CMD_SET_OPERATIONAL_MODE: 5545 case CMD_SET_COUNTRY_CODE: 5546 case CMD_SET_FREQUENCY_BAND: 5547 case CMD_START_PACKET_FILTERING: 5548 case CMD_STOP_PACKET_FILTERING: 5549 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5550 deferMessage(message); 5551 break; 5552 default: 5553 return NOT_HANDLED; 5554 } 5555 return HANDLED; 5556 } 5557 } 5558 5559 class SupplicantStartedState extends State { 5560 @Override 5561 public void enter() { 5562 /* Wifi is available as long as we have a connection to supplicant */ 5563 mNetworkInfo.setIsAvailable(true); 5564 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 5565 5566 int defaultInterval = mContext.getResources().getInteger( 5567 R.integer.config_wifi_supplicant_scan_interval); 5568 5569 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 5570 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 5571 defaultInterval); 5572 5573 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 5574 mWifiNative.setExternalSim(true); 5575 5576 /* turn on use of DFS channels */ 5577 WifiNative.setDfsFlag(true); 5578 5579 /* set country code */ 5580 setCountryCode(); 5581 5582 setRandomMacOui(); 5583 mWifiNative.enableAutoConnect(false); 5584 } 5585 5586 @Override 5587 public boolean processMessage(Message message) { 5588 logStateAndMessage(message, getClass().getSimpleName()); 5589 5590 switch(message.what) { 5591 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 5592 if (mP2pSupported) { 5593 transitionTo(mWaitForP2pDisableState); 5594 } else { 5595 transitionTo(mSupplicantStoppingState); 5596 } 5597 break; 5598 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 5599 loge("Connection lost, restart supplicant"); 5600 handleSupplicantConnectionLoss(); 5601 handleNetworkDisconnect(); 5602 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5603 if (mP2pSupported) { 5604 transitionTo(mWaitForP2pDisableState); 5605 } else { 5606 transitionTo(mInitialState); 5607 } 5608 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 5609 break; 5610 case WifiMonitor.SCAN_RESULTS_EVENT: 5611 maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered 5612 closeRadioScanStats(); 5613 noteScanEnd(); 5614 setScanResults(); 5615 if (mIsFullScanOngoing || mSendScanResultsBroadcast) { 5616 /* Just updated results from full scan, let apps know about this */ 5617 sendScanResultsAvailableBroadcast(); 5618 } 5619 mSendScanResultsBroadcast = false; 5620 mIsScanOngoing = false; 5621 mIsFullScanOngoing = false; 5622 if (mBufferedScanMsg.size() > 0) 5623 sendMessage(mBufferedScanMsg.remove()); 5624 break; 5625 case CMD_PING_SUPPLICANT: 5626 boolean ok = mWifiNative.ping(); 5627 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 5628 break; 5629 case CMD_GET_CAPABILITY_FREQ: 5630 String freqs = mWifiNative.getFreqCapability(); 5631 replyToMessage(message, message.what, freqs); 5632 break; 5633 case CMD_START_AP: 5634 /* Cannot start soft AP while in client mode */ 5635 loge("Failed to start soft AP with a running supplicant"); 5636 setWifiApState(WIFI_AP_STATE_FAILED); 5637 break; 5638 case CMD_SET_OPERATIONAL_MODE: 5639 mOperationalMode = message.arg1; 5640 mWifiConfigStore. 5641 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 5642 break; 5643 case CMD_TARGET_BSSID: 5644 // Trying to associate to this BSSID 5645 if (message.obj != null) { 5646 mTargetRoamBSSID = (String) message.obj; 5647 } 5648 break; 5649 case CMD_GET_LINK_LAYER_STATS: 5650 WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG); 5651 if (stats == null) { 5652 // When firmware doesnt support link layer stats, return an empty object 5653 stats = new WifiLinkLayerStats(); 5654 } 5655 replyToMessage(message, message.what, stats); 5656 break; 5657 case CMD_SET_COUNTRY_CODE: 5658 String country = (String) message.obj; 5659 5660 final boolean persist = (message.arg2 == 1); 5661 final int sequence = message.arg1; 5662 5663 if (sequence != mCountryCodeSequence.get()) { 5664 if (DBG) log("set country code ignored due to sequnce num"); 5665 break; 5666 } 5667 if (DBG) log("set country code " + country); 5668 country = country.toUpperCase(Locale.ROOT); 5669 5670 if (mDriverSetCountryCode == null || !mDriverSetCountryCode.equals(country)) { 5671 if (mWifiNative.setCountryCode(country)) { 5672 mDriverSetCountryCode = country; 5673 } else { 5674 loge("Failed to set country code " + country); 5675 } 5676 } 5677 5678 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 5679 break; 5680 default: 5681 return NOT_HANDLED; 5682 } 5683 return HANDLED; 5684 } 5685 5686 @Override 5687 public void exit() { 5688 mNetworkInfo.setIsAvailable(false); 5689 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 5690 } 5691 } 5692 5693 class SupplicantStoppingState extends State { 5694 @Override 5695 public void enter() { 5696 /* Send any reset commands to supplicant before shutting it down */ 5697 handleNetworkDisconnect(); 5698 if (mDhcpStateMachine != null) { 5699 mDhcpStateMachine.doQuit(); 5700 } 5701 5702 String suppState = System.getProperty("init.svc.wpa_supplicant"); 5703 if (suppState == null) suppState = "unknown"; 5704 String p2pSuppState = System.getProperty("init.svc.p2p_supplicant"); 5705 if (p2pSuppState == null) p2pSuppState = "unknown"; 5706 5707 loge("SupplicantStoppingState: stopSupplicant " 5708 + " init.svc.wpa_supplicant=" + suppState 5709 + " init.svc.p2p_supplicant=" + p2pSuppState); 5710 mWifiMonitor.stopSupplicant(); 5711 5712 /* Send ourselves a delayed message to indicate failure after a wait time */ 5713 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 5714 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 5715 setWifiState(WIFI_STATE_DISABLING); 5716 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5717 } 5718 @Override 5719 public boolean processMessage(Message message) { 5720 logStateAndMessage(message, getClass().getSimpleName()); 5721 5722 switch(message.what) { 5723 case WifiMonitor.SUP_CONNECTION_EVENT: 5724 loge("Supplicant connection received while stopping"); 5725 break; 5726 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5727 if (DBG) log("Supplicant connection lost"); 5728 handleSupplicantConnectionLoss(); 5729 transitionTo(mInitialState); 5730 break; 5731 case CMD_STOP_SUPPLICANT_FAILED: 5732 if (message.arg1 == mSupplicantStopFailureToken) { 5733 loge("Timed out on a supplicant stop, kill and proceed"); 5734 handleSupplicantConnectionLoss(); 5735 transitionTo(mInitialState); 5736 } 5737 break; 5738 case CMD_START_SUPPLICANT: 5739 case CMD_STOP_SUPPLICANT: 5740 case CMD_START_AP: 5741 case CMD_STOP_AP: 5742 case CMD_START_DRIVER: 5743 case CMD_STOP_DRIVER: 5744 case CMD_SET_OPERATIONAL_MODE: 5745 case CMD_SET_COUNTRY_CODE: 5746 case CMD_SET_FREQUENCY_BAND: 5747 case CMD_START_PACKET_FILTERING: 5748 case CMD_STOP_PACKET_FILTERING: 5749 deferMessage(message); 5750 break; 5751 default: 5752 return NOT_HANDLED; 5753 } 5754 return HANDLED; 5755 } 5756 } 5757 5758 class DriverStartingState extends State { 5759 private int mTries; 5760 @Override 5761 public void enter() { 5762 mTries = 1; 5763 /* Send ourselves a delayed message to start driver a second time */ 5764 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 5765 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 5766 } 5767 @Override 5768 public boolean processMessage(Message message) { 5769 logStateAndMessage(message, getClass().getSimpleName()); 5770 5771 switch(message.what) { 5772 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5773 SupplicantState state = handleSupplicantStateChange(message); 5774 /* If suplicant is exiting out of INTERFACE_DISABLED state into 5775 * a state that indicates driver has started, it is ready to 5776 * receive driver commands 5777 */ 5778 if (SupplicantState.isDriverActive(state)) { 5779 transitionTo(mDriverStartedState); 5780 } 5781 break; 5782 case CMD_DRIVER_START_TIMED_OUT: 5783 if (message.arg1 == mDriverStartToken) { 5784 if (mTries >= 2) { 5785 loge("Failed to start driver after " + mTries); 5786 transitionTo(mDriverStoppedState); 5787 } else { 5788 loge("Driver start failed, retrying"); 5789 mWakeLock.acquire(); 5790 mWifiNative.startDriver(); 5791 mWakeLock.release(); 5792 5793 ++mTries; 5794 /* Send ourselves a delayed message to start driver again */ 5795 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 5796 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 5797 } 5798 } 5799 break; 5800 /* Queue driver commands & connection events */ 5801 case CMD_START_DRIVER: 5802 case CMD_STOP_DRIVER: 5803 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5804 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5805 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5806 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5807 case WifiMonitor.WPS_OVERLAP_EVENT: 5808 case CMD_SET_COUNTRY_CODE: 5809 case CMD_SET_FREQUENCY_BAND: 5810 case CMD_START_PACKET_FILTERING: 5811 case CMD_STOP_PACKET_FILTERING: 5812 case CMD_START_SCAN: 5813 case CMD_DISCONNECT: 5814 case CMD_REASSOCIATE: 5815 case CMD_RECONNECT: 5816 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5817 deferMessage(message); 5818 break; 5819 case WifiMonitor.SCAN_RESULTS_EVENT: 5820 // Loose scan results obtained in Driver Starting state, they can only confuse 5821 // the state machine 5822 break; 5823 default: 5824 return NOT_HANDLED; 5825 } 5826 return HANDLED; 5827 } 5828 } 5829 5830 class DriverStartedState extends State { 5831 @Override 5832 public void enter() { 5833 5834 if (PDBG) { 5835 loge("DriverStartedState enter"); 5836 } 5837 mIsRunning = true; 5838 mInDelayedStop = false; 5839 mDelayedStopCounter++; 5840 updateBatteryWorkSource(null); 5841 /** 5842 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 5843 * When this mode is on, some of the low-level scan parameters used by the 5844 * driver are changed to reduce interference with bluetooth 5845 */ 5846 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 5847 /* set frequency band of operation */ 5848 setFrequencyBand(); 5849 /* initialize network state */ 5850 setNetworkDetailedState(DetailedState.DISCONNECTED); 5851 5852 /* Remove any filtering on Multicast v6 at start */ 5853 mWifiNative.stopFilteringMulticastV6Packets(); 5854 5855 /* Reset Multicast v4 filtering state */ 5856 if (mFilteringMulticastV4Packets.get()) { 5857 mWifiNative.startFilteringMulticastV4Packets(); 5858 } else { 5859 mWifiNative.stopFilteringMulticastV4Packets(); 5860 } 5861 5862 mDhcpActive = false; 5863 5864 startBatchedScan(); 5865 5866 if (mOperationalMode != CONNECT_MODE) { 5867 mWifiNative.disconnect(); 5868 mWifiConfigStore.disableAllNetworks(); 5869 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 5870 setWifiState(WIFI_STATE_DISABLED); 5871 } 5872 transitionTo(mScanModeState); 5873 } else { 5874 5875 // Status pulls in the current supplicant state and network connection state 5876 // events over the monitor connection. This helps framework sync up with 5877 // current supplicant state 5878 // TODO: actually check th supplicant status string and make sure the supplicant 5879 // is in disconnecte4d state. 5880 mWifiNative.status(); 5881 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin 5882 transitionTo(mDisconnectedState); 5883 } 5884 5885 // We may have missed screen update at boot 5886 if (mScreenBroadcastReceived.get() == false) { 5887 PowerManager powerManager = (PowerManager)mContext.getSystemService( 5888 Context.POWER_SERVICE); 5889 handleScreenStateChanged(powerManager.isScreenOn(), 5890 /* startBackgroundScanIfNeeded = */ false); 5891 } else { 5892 // Set the right suspend mode settings 5893 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 5894 && mUserWantsSuspendOpt.get()); 5895 } 5896 mWifiNative.setPowerSave(true); 5897 5898 if (mP2pSupported) { 5899 if (mOperationalMode == CONNECT_MODE) { 5900 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 5901 } else { 5902 // P2P statemachine starts in disabled state, and is not enabled until 5903 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 5904 // keep it disabled. 5905 } 5906 } 5907 5908 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 5909 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 5910 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 5911 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 5912 5913 if (WifiNative.startHal()) { 5914 mHalFeatureSet = WifiNative.getSupportedFeatureSet(); 5915 if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO) 5916 == WifiManager.WIFI_FEATURE_HAL_EPNO) { 5917 mAlwaysOnPnoSupported = true; 5918 } 5919 } 5920 5921 if (PDBG) { 5922 loge("Driverstarted State enter done, epno=" + mAlwaysOnPnoSupported 5923 + " feature=" + mHalFeatureSet); 5924 } 5925 } 5926 5927 @Override 5928 public boolean processMessage(Message message) { 5929 logStateAndMessage(message, getClass().getSimpleName()); 5930 5931 switch(message.what) { 5932 case CMD_START_SCAN: 5933 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5934 break; 5935 case CMD_SET_BATCHED_SCAN: 5936 if (recordBatchedScanSettings(message.arg1, message.arg2, 5937 (Bundle) message.obj)) { 5938 if (mBatchedScanSettings != null) { 5939 startBatchedScan(); 5940 } else { 5941 stopBatchedScan(); 5942 } 5943 } 5944 break; 5945 case CMD_SET_FREQUENCY_BAND: 5946 int band = message.arg1; 5947 if (DBG) log("set frequency band " + band); 5948 if (mWifiNative.setBand(band)) { 5949 5950 if (PDBG) loge("did set frequency band " + band); 5951 5952 mFrequencyBand.set(band); 5953 // Flush old data - like scan results 5954 mWifiNative.bssFlush(); 5955 // Fetch the latest scan results when frequency band is set 5956 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 5957 5958 if (PDBG) loge("done set frequency band " + band); 5959 5960 } else { 5961 loge("Failed to set frequency band " + band); 5962 } 5963 break; 5964 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 5965 mBluetoothConnectionActive = (message.arg1 != 5966 BluetoothAdapter.STATE_DISCONNECTED); 5967 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 5968 break; 5969 case CMD_STOP_DRIVER: 5970 int mode = message.arg1; 5971 5972 /* Already doing a delayed stop */ 5973 if (mInDelayedStop) { 5974 if (DBG) log("Already in delayed stop"); 5975 break; 5976 } 5977 /* disconnect right now, but leave the driver running for a bit */ 5978 mWifiConfigStore.disableAllNetworks(); 5979 5980 mInDelayedStop = true; 5981 mDelayedStopCounter++; 5982 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 5983 5984 /* send regular delayed shut down */ 5985 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 5986 driverStopIntent.setPackage(this.getClass().getPackage().getName()); 5987 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 5988 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 5989 DRIVER_STOP_REQUEST, driverStopIntent, 5990 PendingIntent.FLAG_UPDATE_CURRENT); 5991 5992 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 5993 + mDriverStopDelayMs, mDriverStopIntent); 5994 break; 5995 case CMD_START_DRIVER: 5996 if (mInDelayedStop) { 5997 mInDelayedStop = false; 5998 mDelayedStopCounter++; 5999 mAlarmManager.cancel(mDriverStopIntent); 6000 if (DBG) log("Delayed stop ignored due to start"); 6001 if (mOperationalMode == CONNECT_MODE) { 6002 mWifiConfigStore.enableAllNetworks(); 6003 } 6004 } 6005 break; 6006 case CMD_DELAYED_STOP_DRIVER: 6007 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 6008 if (message.arg1 != mDelayedStopCounter) break; 6009 if (getCurrentState() != mDisconnectedState) { 6010 mWifiNative.disconnect(); 6011 handleNetworkDisconnect(); 6012 } 6013 mWakeLock.acquire(); 6014 mWifiNative.stopDriver(); 6015 mWakeLock.release(); 6016 if (mP2pSupported) { 6017 transitionTo(mWaitForP2pDisableState); 6018 } else { 6019 transitionTo(mDriverStoppingState); 6020 } 6021 break; 6022 case CMD_START_PACKET_FILTERING: 6023 if (message.arg1 == MULTICAST_V6) { 6024 mWifiNative.startFilteringMulticastV6Packets(); 6025 } else if (message.arg1 == MULTICAST_V4) { 6026 mWifiNative.startFilteringMulticastV4Packets(); 6027 } else { 6028 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 6029 } 6030 break; 6031 case CMD_STOP_PACKET_FILTERING: 6032 if (message.arg1 == MULTICAST_V6) { 6033 mWifiNative.stopFilteringMulticastV6Packets(); 6034 } else if (message.arg1 == MULTICAST_V4) { 6035 mWifiNative.stopFilteringMulticastV4Packets(); 6036 } else { 6037 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 6038 } 6039 break; 6040 case CMD_SET_SUSPEND_OPT_ENABLED: 6041 if (message.arg1 == 1) { 6042 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 6043 mSuspendWakeLock.release(); 6044 } else { 6045 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 6046 } 6047 break; 6048 case CMD_SET_HIGH_PERF_MODE: 6049 if (message.arg1 == 1) { 6050 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 6051 } else { 6052 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 6053 } 6054 break; 6055 case CMD_ENABLE_TDLS: 6056 if (message.obj != null) { 6057 String remoteAddress = (String) message.obj; 6058 boolean enable = (message.arg1 == 1); 6059 mWifiNative.startTdls(remoteAddress, enable); 6060 } 6061 break; 6062 case WifiMonitor.ANQP_DONE_EVENT: 6063 Log.d("HS2J", String.format("WFSM: ANQP for %016x %s", 6064 (Long)message.obj, message.arg1 != 0 ? "success" : "fail")); 6065 mWifiConfigStore.notifyANQPDone((Long) message.obj, message.arg1 != 0); 6066 break; 6067 default: 6068 return NOT_HANDLED; 6069 } 6070 return HANDLED; 6071 } 6072 @Override 6073 public void exit() { 6074 mIsRunning = false; 6075 updateBatteryWorkSource(null); 6076 mScanResults = new ArrayList<>(); 6077 6078 stopBatchedScan(); 6079 6080 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 6081 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 6082 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 6083 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 6084 noteScanEnd(); // wrap up any pending request. 6085 mBufferedScanMsg.clear(); 6086 } 6087 } 6088 6089 class WaitForP2pDisableState extends State { 6090 private State mTransitionToState; 6091 @Override 6092 public void enter() { 6093 switch (getCurrentMessage().what) { 6094 case WifiMonitor.SUP_DISCONNECTION_EVENT: 6095 mTransitionToState = mInitialState; 6096 break; 6097 case CMD_DELAYED_STOP_DRIVER: 6098 mTransitionToState = mDriverStoppingState; 6099 break; 6100 case CMD_STOP_SUPPLICANT: 6101 mTransitionToState = mSupplicantStoppingState; 6102 break; 6103 default: 6104 mTransitionToState = mDriverStoppingState; 6105 break; 6106 } 6107 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 6108 } 6109 @Override 6110 public boolean processMessage(Message message) { 6111 logStateAndMessage(message, getClass().getSimpleName()); 6112 6113 switch(message.what) { 6114 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 6115 transitionTo(mTransitionToState); 6116 break; 6117 /* Defer wifi start/shut and driver commands */ 6118 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6119 case CMD_START_SUPPLICANT: 6120 case CMD_STOP_SUPPLICANT: 6121 case CMD_START_AP: 6122 case CMD_STOP_AP: 6123 case CMD_START_DRIVER: 6124 case CMD_STOP_DRIVER: 6125 case CMD_SET_OPERATIONAL_MODE: 6126 case CMD_SET_COUNTRY_CODE: 6127 case CMD_SET_FREQUENCY_BAND: 6128 case CMD_START_PACKET_FILTERING: 6129 case CMD_STOP_PACKET_FILTERING: 6130 case CMD_START_SCAN: 6131 case CMD_DISCONNECT: 6132 case CMD_REASSOCIATE: 6133 case CMD_RECONNECT: 6134 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 6135 deferMessage(message); 6136 break; 6137 default: 6138 return NOT_HANDLED; 6139 } 6140 return HANDLED; 6141 } 6142 } 6143 6144 class DriverStoppingState extends State { 6145 @Override 6146 public boolean processMessage(Message message) { 6147 logStateAndMessage(message, getClass().getSimpleName()); 6148 6149 switch(message.what) { 6150 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6151 SupplicantState state = handleSupplicantStateChange(message); 6152 if (state == SupplicantState.INTERFACE_DISABLED) { 6153 transitionTo(mDriverStoppedState); 6154 } 6155 break; 6156 /* Queue driver commands */ 6157 case CMD_START_DRIVER: 6158 case CMD_STOP_DRIVER: 6159 case CMD_SET_COUNTRY_CODE: 6160 case CMD_SET_FREQUENCY_BAND: 6161 case CMD_START_PACKET_FILTERING: 6162 case CMD_STOP_PACKET_FILTERING: 6163 case CMD_START_SCAN: 6164 case CMD_DISCONNECT: 6165 case CMD_REASSOCIATE: 6166 case CMD_RECONNECT: 6167 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 6168 deferMessage(message); 6169 break; 6170 default: 6171 return NOT_HANDLED; 6172 } 6173 return HANDLED; 6174 } 6175 } 6176 6177 class DriverStoppedState extends State { 6178 @Override 6179 public boolean processMessage(Message message) { 6180 logStateAndMessage(message, getClass().getSimpleName()); 6181 switch (message.what) { 6182 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6183 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6184 SupplicantState state = stateChangeResult.state; 6185 // A WEXT bug means that we can be back to driver started state 6186 // unexpectedly 6187 if (SupplicantState.isDriverActive(state)) { 6188 transitionTo(mDriverStartedState); 6189 } 6190 break; 6191 case CMD_START_DRIVER: 6192 mWakeLock.acquire(); 6193 mWifiNative.startDriver(); 6194 mWakeLock.release(); 6195 transitionTo(mDriverStartingState); 6196 break; 6197 default: 6198 return NOT_HANDLED; 6199 } 6200 return HANDLED; 6201 } 6202 } 6203 6204 class ScanModeState extends State { 6205 private int mLastOperationMode; 6206 @Override 6207 public void enter() { 6208 mLastOperationMode = mOperationalMode; 6209 } 6210 @Override 6211 public boolean processMessage(Message message) { 6212 logStateAndMessage(message, getClass().getSimpleName()); 6213 6214 switch(message.what) { 6215 case CMD_SET_OPERATIONAL_MODE: 6216 if (message.arg1 == CONNECT_MODE) { 6217 6218 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 6219 setWifiState(WIFI_STATE_ENABLED); 6220 // Load and re-enable networks when going back to enabled state 6221 // This is essential for networks to show up after restore 6222 mWifiConfigStore.loadAndEnableAllNetworks(); 6223 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 6224 } else { 6225 mWifiConfigStore.enableAllNetworks(); 6226 } 6227 6228 // Try autojoining with recent network already present in the cache 6229 // If none are found then trigger a scan which will trigger autojoin 6230 // upon reception of scan results event 6231 if (!mWifiAutoJoinController.attemptAutoJoin()) { 6232 startScan(ENABLE_WIFI, 0, null, null); 6233 } 6234 6235 // Loose last selection choice since user toggled WiFi 6236 mWifiConfigStore. 6237 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 6238 6239 mOperationalMode = CONNECT_MODE; 6240 transitionTo(mDisconnectedState); 6241 } else { 6242 // Nothing to do 6243 return HANDLED; 6244 } 6245 break; 6246 // Handle scan. All the connection related commands are 6247 // handled only in ConnectModeState 6248 case CMD_START_SCAN: 6249 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 6250 break; 6251 default: 6252 return NOT_HANDLED; 6253 } 6254 return HANDLED; 6255 } 6256 } 6257 6258 6259 String smToString(Message message) { 6260 return smToString(message.what); 6261 } 6262 6263 String smToString(int what) { 6264 String s = "unknown"; 6265 switch (what) { 6266 case WifiMonitor.DRIVER_HUNG_EVENT: 6267 s = "DRIVER_HUNG_EVENT"; 6268 break; 6269 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 6270 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED"; 6271 break; 6272 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 6273 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED"; 6274 break; 6275 case CMD_SET_FREQUENCY_BAND: 6276 s = "CMD_SET_FREQUENCY_BAND"; 6277 break; 6278 case CMD_DELAYED_NETWORK_DISCONNECT: 6279 s = "CMD_DELAYED_NETWORK_DISCONNECT"; 6280 break; 6281 case CMD_TEST_NETWORK_DISCONNECT: 6282 s = "CMD_TEST_NETWORK_DISCONNECT"; 6283 break; 6284 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 6285 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER"; 6286 break; 6287 case CMD_DISABLE_EPHEMERAL_NETWORK: 6288 s = "CMD_DISABLE_EPHEMERAL_NETWORK"; 6289 break; 6290 case CMD_START_DRIVER: 6291 s = "CMD_START_DRIVER"; 6292 break; 6293 case CMD_STOP_DRIVER: 6294 s = "CMD_STOP_DRIVER"; 6295 break; 6296 case CMD_STOP_SUPPLICANT: 6297 s = "CMD_STOP_SUPPLICANT"; 6298 break; 6299 case CMD_STOP_SUPPLICANT_FAILED: 6300 s = "CMD_STOP_SUPPLICANT_FAILED"; 6301 break; 6302 case CMD_START_SUPPLICANT: 6303 s = "CMD_START_SUPPLICANT"; 6304 break; 6305 case CMD_REQUEST_AP_CONFIG: 6306 s = "CMD_REQUEST_AP_CONFIG"; 6307 break; 6308 case CMD_RESPONSE_AP_CONFIG: 6309 s = "CMD_RESPONSE_AP_CONFIG"; 6310 break; 6311 case CMD_TETHER_STATE_CHANGE: 6312 s = "CMD_TETHER_STATE_CHANGE"; 6313 break; 6314 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6315 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT"; 6316 break; 6317 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 6318 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE"; 6319 break; 6320 case CMD_ADD_OR_UPDATE_NETWORK: 6321 s = "CMD_ADD_OR_UPDATE_NETWORK"; 6322 break; 6323 case CMD_REMOVE_NETWORK: 6324 s = "CMD_REMOVE_NETWORK"; 6325 break; 6326 case CMD_ENABLE_NETWORK: 6327 s = "CMD_ENABLE_NETWORK"; 6328 break; 6329 case CMD_ENABLE_ALL_NETWORKS: 6330 s = "CMD_ENABLE_ALL_NETWORKS"; 6331 break; 6332 case CMD_AUTO_CONNECT: 6333 s = "CMD_AUTO_CONNECT"; 6334 break; 6335 case CMD_AUTO_ROAM: 6336 s = "CMD_AUTO_ROAM"; 6337 break; 6338 case CMD_AUTO_SAVE_NETWORK: 6339 s = "CMD_AUTO_SAVE_NETWORK"; 6340 break; 6341 case CMD_BOOT_COMPLETED: 6342 s = "CMD_BOOT_COMPLETED"; 6343 break; 6344 case DhcpStateMachine.CMD_START_DHCP: 6345 s = "CMD_START_DHCP"; 6346 break; 6347 case DhcpStateMachine.CMD_STOP_DHCP: 6348 s = "CMD_STOP_DHCP"; 6349 break; 6350 case DhcpStateMachine.CMD_RENEW_DHCP: 6351 s = "CMD_RENEW_DHCP"; 6352 break; 6353 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 6354 s = "CMD_PRE_DHCP_ACTION"; 6355 break; 6356 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 6357 s = "CMD_POST_DHCP_ACTION"; 6358 break; 6359 case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE: 6360 s = "CMD_PRE_DHCP_ACTION_COMPLETE"; 6361 break; 6362 case DhcpStateMachine.CMD_ON_QUIT: 6363 s = "CMD_ON_QUIT"; 6364 break; 6365 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 6366 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST"; 6367 break; 6368 case WifiManager.DISABLE_NETWORK: 6369 s = "WifiManager.DISABLE_NETWORK"; 6370 break; 6371 case CMD_BLACKLIST_NETWORK: 6372 s = "CMD_BLACKLIST_NETWORK"; 6373 break; 6374 case CMD_CLEAR_BLACKLIST: 6375 s = "CMD_CLEAR_BLACKLIST"; 6376 break; 6377 case CMD_SAVE_CONFIG: 6378 s = "CMD_SAVE_CONFIG"; 6379 break; 6380 case CMD_GET_CONFIGURED_NETWORKS: 6381 s = "CMD_GET_CONFIGURED_NETWORKS"; 6382 break; 6383 case CMD_GET_SUPPORTED_FEATURES: 6384 s = "CMD_GET_SUPPORTED_FEATURES"; 6385 break; 6386 case CMD_UNWANTED_NETWORK: 6387 s = "CMD_UNWANTED_NETWORK"; 6388 break; 6389 case CMD_NETWORK_STATUS: 6390 s = "CMD_NETWORK_STATUS"; 6391 break; 6392 case CMD_GET_LINK_LAYER_STATS: 6393 s = "CMD_GET_LINK_LAYER_STATS"; 6394 break; 6395 case CMD_GET_MATCHING_CONFIG: 6396 s = "CMD_GET_MATCHING_CONFIG"; 6397 break; 6398 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 6399 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS"; 6400 break; 6401 case CMD_DISCONNECT: 6402 s = "CMD_DISCONNECT"; 6403 break; 6404 case CMD_RECONNECT: 6405 s = "CMD_RECONNECT"; 6406 break; 6407 case CMD_REASSOCIATE: 6408 s = "CMD_REASSOCIATE"; 6409 break; 6410 case CMD_GET_CONNECTION_STATISTICS: 6411 s = "CMD_GET_CONNECTION_STATISTICS"; 6412 break; 6413 case CMD_SET_HIGH_PERF_MODE: 6414 s = "CMD_SET_HIGH_PERF_MODE"; 6415 break; 6416 case CMD_SET_COUNTRY_CODE: 6417 s = "CMD_SET_COUNTRY_CODE"; 6418 break; 6419 case CMD_ENABLE_RSSI_POLL: 6420 s = "CMD_ENABLE_RSSI_POLL"; 6421 break; 6422 case CMD_RSSI_POLL: 6423 s = "CMD_RSSI_POLL"; 6424 break; 6425 case CMD_START_PACKET_FILTERING: 6426 s = "CMD_START_PACKET_FILTERING"; 6427 break; 6428 case CMD_STOP_PACKET_FILTERING: 6429 s = "CMD_STOP_PACKET_FILTERING"; 6430 break; 6431 case CMD_SET_SUSPEND_OPT_ENABLED: 6432 s = "CMD_SET_SUSPEND_OPT_ENABLED"; 6433 break; 6434 case CMD_NO_NETWORKS_PERIODIC_SCAN: 6435 s = "CMD_NO_NETWORKS_PERIODIC_SCAN"; 6436 break; 6437 case CMD_SET_BATCHED_SCAN: 6438 s = "CMD_SET_BATCHED_SCAN"; 6439 break; 6440 case CMD_START_NEXT_BATCHED_SCAN: 6441 s = "CMD_START_NEXT_BATCHED_SCAN"; 6442 break; 6443 case CMD_POLL_BATCHED_SCAN: 6444 s = "CMD_POLL_BATCHED_SCAN"; 6445 break; 6446 case CMD_UPDATE_LINKPROPERTIES: 6447 s = "CMD_UPDATE_LINKPROPERTIES"; 6448 break; 6449 case CMD_RELOAD_TLS_AND_RECONNECT: 6450 s = "CMD_RELOAD_TLS_AND_RECONNECT"; 6451 break; 6452 case WifiManager.CONNECT_NETWORK: 6453 s = "CONNECT_NETWORK"; 6454 break; 6455 case WifiManager.SAVE_NETWORK: 6456 s = "SAVE_NETWORK"; 6457 break; 6458 case WifiManager.FORGET_NETWORK: 6459 s = "FORGET_NETWORK"; 6460 break; 6461 case WifiMonitor.SUP_CONNECTION_EVENT: 6462 s = "SUP_CONNECTION_EVENT"; 6463 break; 6464 case WifiMonitor.SUP_DISCONNECTION_EVENT: 6465 s = "SUP_DISCONNECTION_EVENT"; 6466 break; 6467 case WifiMonitor.SCAN_RESULTS_EVENT: 6468 s = "SCAN_RESULTS_EVENT"; 6469 break; 6470 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6471 s = "SUPPLICANT_STATE_CHANGE_EVENT"; 6472 break; 6473 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6474 s = "AUTHENTICATION_FAILURE_EVENT"; 6475 break; 6476 case WifiMonitor.SSID_TEMP_DISABLED: 6477 s = "SSID_TEMP_DISABLED"; 6478 break; 6479 case WifiMonitor.SSID_REENABLED: 6480 s = "SSID_REENABLED"; 6481 break; 6482 case WifiMonitor.WPS_SUCCESS_EVENT: 6483 s = "WPS_SUCCESS_EVENT"; 6484 break; 6485 case WifiMonitor.WPS_FAIL_EVENT: 6486 s = "WPS_FAIL_EVENT"; 6487 break; 6488 case WifiMonitor.SUP_REQUEST_IDENTITY: 6489 s = "SUP_REQUEST_IDENTITY"; 6490 break; 6491 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6492 s = "NETWORK_CONNECTION_EVENT"; 6493 break; 6494 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6495 s = "NETWORK_DISCONNECTION_EVENT"; 6496 break; 6497 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6498 s = "ASSOCIATION_REJECTION_EVENT"; 6499 break; 6500 case CMD_SET_OPERATIONAL_MODE: 6501 s = "CMD_SET_OPERATIONAL_MODE"; 6502 break; 6503 case CMD_START_SCAN: 6504 s = "CMD_START_SCAN"; 6505 break; 6506 case CMD_DISABLE_P2P_RSP: 6507 s = "CMD_DISABLE_P2P_RSP"; 6508 break; 6509 case CMD_DISABLE_P2P_REQ: 6510 s = "CMD_DISABLE_P2P_REQ"; 6511 break; 6512 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 6513 s = "GOOD_LINK_DETECTED"; 6514 break; 6515 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6516 s = "POOR_LINK_DETECTED"; 6517 break; 6518 case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT: 6519 s = "GROUP_CREATING_TIMED_OUT"; 6520 break; 6521 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 6522 s = "P2P_CONNECTION_CHANGED"; 6523 break; 6524 case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE: 6525 s = "P2P.DISCONNECT_WIFI_RESPONSE"; 6526 break; 6527 case WifiP2pServiceImpl.SET_MIRACAST_MODE: 6528 s = "P2P.SET_MIRACAST_MODE"; 6529 break; 6530 case WifiP2pServiceImpl.BLOCK_DISCOVERY: 6531 s = "P2P.BLOCK_DISCOVERY"; 6532 break; 6533 case WifiP2pServiceImpl.SET_COUNTRY_CODE: 6534 s = "P2P.SET_COUNTRY_CODE"; 6535 break; 6536 case WifiManager.CANCEL_WPS: 6537 s = "CANCEL_WPS"; 6538 break; 6539 case WifiManager.CANCEL_WPS_FAILED: 6540 s = "CANCEL_WPS_FAILED"; 6541 break; 6542 case WifiManager.CANCEL_WPS_SUCCEDED: 6543 s = "CANCEL_WPS_SUCCEDED"; 6544 break; 6545 case WifiManager.START_WPS: 6546 s = "START_WPS"; 6547 break; 6548 case WifiManager.START_WPS_SUCCEEDED: 6549 s = "START_WPS_SUCCEEDED"; 6550 break; 6551 case WifiManager.WPS_FAILED: 6552 s = "WPS_FAILED"; 6553 break; 6554 case WifiManager.WPS_COMPLETED: 6555 s = "WPS_COMPLETED"; 6556 break; 6557 case WifiManager.RSSI_PKTCNT_FETCH: 6558 s = "RSSI_PKTCNT_FETCH"; 6559 break; 6560 case CMD_IP_CONFIGURATION_LOST: 6561 s = "CMD_IP_CONFIGURATION_LOST"; 6562 break; 6563 case CMD_IP_CONFIGURATION_SUCCESSFUL: 6564 s = "CMD_IP_CONFIGURATION_SUCCESSFUL"; 6565 break; 6566 case CMD_STATIC_IP_SUCCESS: 6567 s = "CMD_STATIC_IP_SUCCESSFUL"; 6568 break; 6569 case CMD_STATIC_IP_FAILURE: 6570 s = "CMD_STATIC_IP_FAILURE"; 6571 break; 6572 case DhcpStateMachine.DHCP_SUCCESS: 6573 s = "DHCP_SUCCESS"; 6574 break; 6575 case DhcpStateMachine.DHCP_FAILURE: 6576 s = "DHCP_FAILURE"; 6577 break; 6578 case CMD_TARGET_BSSID: 6579 s = "CMD_TARGET_BSSID"; 6580 break; 6581 case CMD_ASSOCIATED_BSSID: 6582 s = "CMD_ASSOCIATED_BSSID"; 6583 break; 6584 case CMD_REMOVE_APP_CONFIGURATIONS: 6585 s = "CMD_REMOVE_APP_CONFIGURATIONS"; 6586 break; 6587 case CMD_REMOVE_USER_CONFIGURATIONS: 6588 s = "CMD_REMOVE_USER_CONFIGURATIONS"; 6589 break; 6590 case CMD_ROAM_WATCHDOG_TIMER: 6591 s = "CMD_ROAM_WATCHDOG_TIMER"; 6592 break; 6593 case CMD_SCREEN_STATE_CHANGED: 6594 s = "CMD_SCREEN_STATE_CHANGED"; 6595 break; 6596 case CMD_DISCONNECTING_WATCHDOG_TIMER: 6597 s = "CMD_DISCONNECTING_WATCHDOG_TIMER"; 6598 break; 6599 case CMD_START_PNO: 6600 s = "CMD_START_PNO"; 6601 break; 6602 case CMD_STARTED_PNO_DBG: 6603 s = "CMD_STARTED_PNO_DBG"; 6604 break; 6605 case CMD_PNO_NETWORK_FOUND: 6606 s = "CMD_PNO_NETWORK_FOUND"; 6607 break; 6608 default: 6609 s = "what:" + Integer.toString(what); 6610 break; 6611 } 6612 return s; 6613 } 6614 6615 void registerConnected() { 6616 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 6617 long now_ms = System.currentTimeMillis(); 6618 // We are switching away from this configuration, 6619 // hence record the time we were connected last 6620 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6621 if (config != null) { 6622 config.lastConnected = System.currentTimeMillis(); 6623 config.autoJoinBailedDueToLowRssi = false; 6624 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 6625 config.numConnectionFailures = 0; 6626 config.numIpConfigFailures = 0; 6627 config.numAuthFailures = 0; 6628 config.numAssociation++; 6629 } 6630 mBadLinkspeedcount = 0; 6631 } 6632 } 6633 6634 void registerDisconnected() { 6635 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 6636 long now_ms = System.currentTimeMillis(); 6637 // We are switching away from this configuration, 6638 // hence record the time we were connected last 6639 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6640 if (config != null) { 6641 config.lastDisconnected = System.currentTimeMillis(); 6642 if (config.ephemeral) { 6643 // Remove ephemeral WifiConfigurations from file 6644 mWifiConfigStore.forgetNetwork(mLastNetworkId); 6645 } 6646 } 6647 } 6648 } 6649 6650 void noteWifiDisabledWhileAssociated() { 6651 // We got disabled by user while we were associated, make note of it 6652 int rssi = mWifiInfo.getRssi(); 6653 WifiConfiguration config = getCurrentWifiConfiguration(); 6654 if (getCurrentState() == mConnectedState 6655 && rssi != WifiInfo.INVALID_RSSI 6656 && config != null) { 6657 boolean is24GHz = mWifiInfo.is24GHz(); 6658 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get()) 6659 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get()); 6660 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get()) 6661 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get()); 6662 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get()) 6663 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get()); 6664 if (isBadRSSI) { 6665 // Take note that we got disabled while RSSI was Bad 6666 config.numUserTriggeredWifiDisableLowRSSI++; 6667 } else if (isLowRSSI) { 6668 // Take note that we got disabled while RSSI was Low 6669 config.numUserTriggeredWifiDisableBadRSSI++; 6670 } else if (!isHighRSSI) { 6671 // Take note that we got disabled while RSSI was Not high 6672 config.numUserTriggeredWifiDisableNotHighRSSI++; 6673 } 6674 } 6675 } 6676 6677 WifiConfiguration getCurrentWifiConfiguration() { 6678 if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 6679 return null; 6680 } 6681 return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6682 } 6683 6684 ScanResult getCurrentScanResult() { 6685 WifiConfiguration config = getCurrentWifiConfiguration(); 6686 if (config == null) { 6687 return null; 6688 } 6689 String BSSID = mWifiInfo.getBSSID(); 6690 if (BSSID == null) { 6691 BSSID = mTargetRoamBSSID; 6692 } 6693 ScanDetailCache scanDetailCache = 6694 mWifiConfigStore.getScanDetailCache(config); 6695 6696 if (scanDetailCache == null) { 6697 return null; 6698 } 6699 6700 return scanDetailCache.get(BSSID); 6701 } 6702 6703 String getCurrentBSSID() { 6704 if (linkDebouncing) { 6705 return null; 6706 } 6707 return mLastBssid; 6708 } 6709 6710 class ConnectModeState extends State { 6711 @Override 6712 public boolean processMessage(Message message) { 6713 WifiConfiguration config; 6714 int netId; 6715 boolean ok; 6716 boolean didDisconnect; 6717 String bssid; 6718 String ssid; 6719 NetworkUpdateResult result; 6720 logStateAndMessage(message, getClass().getSimpleName()); 6721 6722 connectScanningService(); 6723 6724 switch (message.what) { 6725 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6726 didBlackListBSSID = false; 6727 bssid = (String) message.obj; 6728 if (bssid == null || TextUtils.isEmpty(bssid)) { 6729 // If BSSID is null, use the target roam BSSID 6730 bssid = mTargetRoamBSSID; 6731 } 6732 if (bssid != null) { 6733 // If we have a BSSID, tell configStore to black list it 6734 synchronized(mScanResultCache) { 6735 didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList 6736 (mLastNetworkId, bssid, false); 6737 } 6738 } 6739 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 6740 break; 6741 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6742 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 6743 break; 6744 case WifiMonitor.SSID_TEMP_DISABLED: 6745 case WifiMonitor.SSID_REENABLED: 6746 String substr = (String) message.obj; 6747 String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ? 6748 "temp-disabled" : "re-enabled"; 6749 loge("ConnectModeState SSID state=" + en + " nid=" 6750 + Integer.toString(message.arg1) + " [" + substr + "]"); 6751 synchronized(mScanResultCache) { 6752 mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what == 6753 WifiMonitor.SSID_REENABLED, substr, mWifiInfo.getBSSID()); 6754 } 6755 break; 6756 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6757 SupplicantState state = handleSupplicantStateChange(message); 6758 // A driver/firmware hang can now put the interface in a down state. 6759 // We detect the interface going down and recover from it 6760 if (!SupplicantState.isDriverActive(state)) { 6761 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 6762 handleNetworkDisconnect(); 6763 } 6764 log("Detected an interface down, restart driver"); 6765 transitionTo(mDriverStoppedState); 6766 sendMessage(CMD_START_DRIVER); 6767 break; 6768 } 6769 6770 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 6771 // when authentication times out after a successful connection, 6772 // we can figure this from the supplicant state. If supplicant 6773 // state is DISCONNECTED, but the mNetworkInfo says we are not 6774 // disconnected, we need to handle a disconnection 6775 if (!linkDebouncing && state == SupplicantState.DISCONNECTED && 6776 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 6777 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 6778 handleNetworkDisconnect(); 6779 transitionTo(mDisconnectedState); 6780 } 6781 break; 6782 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 6783 if (message.arg1 == 1) { 6784 mWifiNative.disconnect(); 6785 mTemporarilyDisconnectWifi = true; 6786 } else { 6787 mWifiNative.reconnect(); 6788 mTemporarilyDisconnectWifi = false; 6789 } 6790 break; 6791 case CMD_ADD_OR_UPDATE_NETWORK: 6792 config = (WifiConfiguration) message.obj; 6793 6794 if (!recordUidIfAuthorized(config, message.sendingUid)) { 6795 loge("Not authorized to update network " 6796 + " config=" + config.SSID 6797 + " cnid=" + config.networkId 6798 + " uid=" + message.sendingUid); 6799 replyToMessage(message, message.what, FAILURE); 6800 break; 6801 } 6802 6803 int res = mWifiConfigStore.addOrUpdateNetwork(config, message.sendingUid); 6804 if (res < 0) { 6805 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6806 } else { 6807 WifiConfiguration curConfig = getCurrentWifiConfiguration(); 6808 if (curConfig != null && config != null) { 6809 if (curConfig.priority < config.priority 6810 && config.status == WifiConfiguration.Status.ENABLED) { 6811 // Interpret this as a connect attempt 6812 // Set the last selected configuration so as to allow the system to 6813 // stick the last user choice without persisting the choice 6814 mWifiConfigStore.setLastSelectedConfiguration(res); 6815 mWifiConfigStore.updateLastConnectUid(config, message.sendingUid); 6816 mWifiConfigStore.writeKnownNetworkHistory(false); 6817 6818 // Remember time of last connection attempt 6819 lastConnectAttempt = System.currentTimeMillis(); 6820 6821 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6822 6823 // As a courtesy to the caller, trigger a scan now 6824 startScan(ADD_OR_UPDATE_SOURCE, 0, null, null); 6825 } 6826 } 6827 } 6828 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res); 6829 break; 6830 case CMD_REMOVE_NETWORK: 6831 netId = message.arg1; 6832 if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId)) { 6833 loge("Not authorized to remove network " 6834 + " cnid=" + netId 6835 + " uid=" + message.sendingUid); 6836 replyToMessage(message, message.what, FAILURE); 6837 break; 6838 } 6839 6840 ok = mWifiConfigStore.removeNetwork(message.arg1); 6841 if (!ok) { 6842 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6843 } 6844 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 6845 break; 6846 case CMD_ENABLE_NETWORK: 6847 boolean others = message.arg2 == 1; 6848 // Tell autojoin the user did try to select to that network 6849 // However, do NOT persist the choice by bumping the priority of the network 6850 if (others) { 6851 mWifiAutoJoinController. 6852 updateConfigurationHistory(message.arg1, true, false); 6853 // Set the last selected configuration so as to allow the system to 6854 // stick the last user choice without persisting the choice 6855 mWifiConfigStore.setLastSelectedConfiguration(message.arg1); 6856 6857 // Remember time of last connection attempt 6858 lastConnectAttempt = System.currentTimeMillis(); 6859 6860 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6861 } 6862 // Cancel auto roam requests 6863 autoRoamSetBSSID(message.arg1, "any"); 6864 6865 int uid = message.sendingUid; 6866 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1, uid); 6867 if (!ok) { 6868 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6869 } 6870 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 6871 break; 6872 case CMD_ENABLE_ALL_NETWORKS: 6873 long time = android.os.SystemClock.elapsedRealtime(); 6874 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 6875 mWifiConfigStore.enableAllNetworks(); 6876 mLastEnableAllNetworksTime = time; 6877 } 6878 break; 6879 case WifiManager.DISABLE_NETWORK: 6880 if (mWifiConfigStore.disableNetwork(message.arg1, 6881 WifiConfiguration.DISABLED_BY_WIFI_MANAGER) == true) { 6882 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 6883 } else { 6884 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6885 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 6886 WifiManager.ERROR); 6887 } 6888 break; 6889 case CMD_DISABLE_EPHEMERAL_NETWORK: 6890 config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj); 6891 if (config != null) { 6892 if (config.networkId == mLastNetworkId) { 6893 // Disconnect and let autojoin reselect a new network 6894 sendMessage(CMD_DISCONNECT); 6895 } 6896 } 6897 break; 6898 case CMD_BLACKLIST_NETWORK: 6899 mWifiNative.addToBlacklist((String) message.obj); 6900 break; 6901 case CMD_CLEAR_BLACKLIST: 6902 mWifiNative.clearBlacklist(); 6903 break; 6904 case CMD_SAVE_CONFIG: 6905 ok = mWifiConfigStore.saveConfig(); 6906 6907 if (DBG) loge("wifistatemachine did save config " + ok); 6908 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 6909 6910 // Inform the backup manager about a data change 6911 IBackupManager ibm = IBackupManager.Stub.asInterface( 6912 ServiceManager.getService(Context.BACKUP_SERVICE)); 6913 if (ibm != null) { 6914 try { 6915 ibm.dataChanged("com.android.providers.settings"); 6916 } catch (Exception e) { 6917 // Try again later 6918 } 6919 } 6920 break; 6921 case CMD_GET_CONFIGURED_NETWORKS: 6922 replyToMessage(message, message.what, 6923 mWifiConfigStore.getConfiguredNetworks()); 6924 break; 6925 case WifiMonitor.SUP_REQUEST_IDENTITY: 6926 int networkId = message.arg2; 6927 boolean identitySent = false; 6928 int eapMethod = WifiEnterpriseConfig.Eap.NONE; 6929 6930 if (targetWificonfiguration != null 6931 && targetWificonfiguration.enterpriseConfig != null) { 6932 eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod(); 6933 } 6934 6935 // For SIM & AKA/AKA' EAP method Only, get identity from ICC 6936 if (targetWificonfiguration != null 6937 && targetWificonfiguration.networkId == networkId 6938 && targetWificonfiguration.allowedKeyManagement 6939 .get(WifiConfiguration.KeyMgmt.IEEE8021X) 6940 && (eapMethod == WifiEnterpriseConfig.Eap.SIM 6941 || eapMethod == WifiEnterpriseConfig.Eap.AKA 6942 || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) { 6943 TelephonyManager tm = (TelephonyManager) 6944 mContext.getSystemService(Context.TELEPHONY_SERVICE); 6945 if (tm != null) { 6946 String imsi = tm.getSubscriberId(); 6947 String mccMnc = ""; 6948 6949 if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) 6950 mccMnc = tm.getSimOperator(); 6951 6952 String identity = buildIdentity(eapMethod, imsi, mccMnc); 6953 6954 if (!identity.isEmpty()) { 6955 mWifiNative.simIdentityResponse(networkId, identity); 6956 identitySent = true; 6957 } 6958 } 6959 } 6960 if (!identitySent) { 6961 // Supplicant lacks credentials to connect to that network, hence black list 6962 ssid = (String) message.obj; 6963 if (targetWificonfiguration != null && ssid != null 6964 && targetWificonfiguration.SSID != null 6965 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) { 6966 mWifiConfigStore.handleSSIDStateChange( 6967 targetWificonfiguration.networkId, false, 6968 "AUTH_FAILED no identity", null); 6969 } 6970 // Disconnect now, as we don't have any way to fullfill 6971 // the supplicant request. 6972 mWifiConfigStore.setLastSelectedConfiguration( 6973 WifiConfiguration.INVALID_NETWORK_ID); 6974 mWifiNative.disconnect(); 6975 } 6976 break; 6977 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 6978 logd("Received SUP_REQUEST_SIM_AUTH"); 6979 SimAuthRequestData requestData = (SimAuthRequestData) message.obj; 6980 if (requestData != null) { 6981 if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) { 6982 handleGsmAuthRequest(requestData); 6983 } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA 6984 || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) { 6985 handle3GAuthRequest(requestData); 6986 } 6987 } else { 6988 loge("Invalid sim auth request"); 6989 } 6990 break; 6991 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 6992 replyToMessage(message, message.what, 6993 mWifiConfigStore.getPrivilegedConfiguredNetworks()); 6994 break; 6995 case CMD_GET_MATCHING_CONFIG: 6996 replyToMessage(message, message.what, 6997 mWifiConfigStore.getMatchingConfig((ScanResult)message.obj)); 6998 break; 6999 /* Do a redundant disconnect without transition */ 7000 case CMD_DISCONNECT: 7001 mWifiConfigStore.setLastSelectedConfiguration 7002 (WifiConfiguration.INVALID_NETWORK_ID); 7003 mWifiNative.disconnect(); 7004 break; 7005 case CMD_RECONNECT: 7006 mWifiAutoJoinController.attemptAutoJoin(); 7007 break; 7008 case CMD_REASSOCIATE: 7009 lastConnectAttempt = System.currentTimeMillis(); 7010 mWifiNative.reassociate(); 7011 break; 7012 case CMD_RELOAD_TLS_AND_RECONNECT: 7013 if (mWifiConfigStore.needsUnlockedKeyStore()) { 7014 logd("Reconnecting to give a chance to un-connected TLS networks"); 7015 mWifiNative.disconnect(); 7016 lastConnectAttempt = System.currentTimeMillis(); 7017 mWifiNative.reconnect(); 7018 } 7019 break; 7020 case CMD_AUTO_ROAM: 7021 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7022 return HANDLED; 7023 case CMD_AUTO_CONNECT: 7024 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 7025 * associated status to the STATUS command but somehow-someplace still thinks 7026 * it is associated and thus will ignore select/reconnect command with 7027 * following message: 7028 * "Already associated with the selected network - do nothing" 7029 * 7030 * Hence, sends a disconnect to supplicant first. 7031 */ 7032 didDisconnect = false; 7033 if (getCurrentState() != mDisconnectedState) { 7034 /** Supplicant will ignore the reconnect if we are currently associated, 7035 * hence trigger a disconnect 7036 */ 7037 didDisconnect = true; 7038 mWifiNative.disconnect(); 7039 } 7040 7041 /* connect command coming from auto-join */ 7042 config = (WifiConfiguration) message.obj; 7043 netId = message.arg1; 7044 int roam = message.arg2; 7045 loge("CMD_AUTO_CONNECT sup state " 7046 + mSupplicantStateTracker.getSupplicantStateName() 7047 + " my state " + getCurrentState().getName() 7048 + " nid=" + Integer.toString(netId) 7049 + " roam=" + Integer.toString(roam)); 7050 if (config == null) { 7051 loge("AUTO_CONNECT and no config, bail out..."); 7052 break; 7053 } 7054 7055 /* Make sure we cancel any previous roam request */ 7056 autoRoamSetBSSID(netId, config.BSSID); 7057 7058 /* Save the network config */ 7059 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 7060 + " nid=" + Integer.toString(netId)); 7061 result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID); 7062 netId = result.getNetworkId(); 7063 loge("CMD_AUTO_CONNECT did save config -> " 7064 + " nid=" + Integer.toString(netId)); 7065 7066 if (deferForUserInput(message, netId, false)) { 7067 break; 7068 } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved == 7069 WifiConfiguration.USER_BANNED) { 7070 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7071 WifiManager.NOT_AUTHORIZED); 7072 break; 7073 } 7074 7075 // Make sure the network is enabled, since supplicant will not reenable it 7076 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 7077 7078 // If we're autojoining a network that the user or an app explicitly selected, 7079 // keep track of the UID that selected it. 7080 int lastConnectUid = mWifiConfigStore.isLastSelectedConfiguration(config) ? 7081 config.lastConnectUid : WifiConfiguration.UNKNOWN_UID; 7082 7083 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false, 7084 lastConnectUid) && mWifiNative.reconnect()) { 7085 lastConnectAttempt = System.currentTimeMillis(); 7086 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 7087 config = mWifiConfigStore.getWifiConfiguration(netId); 7088 if (config != null 7089 && !mWifiConfigStore.isLastSelectedConfiguration(config)) { 7090 // If we autojoined a different config than the user selected one, 7091 // it means we could not see the last user selection, 7092 // or that the last user selection was faulty and ended up blacklisted 7093 // for some reason (in which case the user is notified with an error 7094 // message in the Wifi picker), and thus we managed to auto-join away 7095 // from the selected config. -> in that case we need to forget 7096 // the selection because we don't want to abruptly switch back to it. 7097 // 7098 // Note that the user selection is also forgotten after a period of time 7099 // during which the device has been disconnected. 7100 // The default value is 30 minutes : see the code path at bottom of 7101 // setScanResults() function. 7102 mWifiConfigStore. 7103 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 7104 } 7105 mAutoRoaming = roam; 7106 if (isRoaming() || linkDebouncing) { 7107 transitionTo(mRoamingState); 7108 } else if (didDisconnect) { 7109 transitionTo(mDisconnectingState); 7110 } else { 7111 /* Already in disconnected state, nothing to change */ 7112 } 7113 } else { 7114 loge("Failed to connect config: " + config + " netId: " + netId); 7115 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7116 WifiManager.ERROR); 7117 break; 7118 } 7119 break; 7120 case CMD_REMOVE_APP_CONFIGURATIONS: 7121 mWifiConfigStore.removeNetworksForApp((ApplicationInfo) message.obj); 7122 break; 7123 case CMD_REMOVE_USER_CONFIGURATIONS: 7124 mWifiConfigStore.removeNetworksForUser(message.arg1); 7125 break; 7126 case WifiManager.CONNECT_NETWORK: 7127 /** 7128 * The connect message can contain a network id passed as arg1 on message or 7129 * or a config passed as obj on message. 7130 * For a new network, a config is passed to create and connect. 7131 * For an existing network, a network id is passed 7132 */ 7133 netId = message.arg1; 7134 config = (WifiConfiguration) message.obj; 7135 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 7136 boolean updatedExisting = false; 7137 7138 /* Save the network config */ 7139 if (config != null) { 7140 if (!recordUidIfAuthorized(config, message.sendingUid)) { 7141 loge("Not authorized to update network " 7142 + " config=" + config.SSID 7143 + " cnid=" + config.networkId 7144 + " uid=" + message.sendingUid); 7145 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7146 WifiManager.NOT_AUTHORIZED); 7147 break; 7148 } 7149 7150 String configKey = config.configKey(true /* allowCached */); 7151 WifiConfiguration savedConfig = 7152 mWifiConfigStore.getWifiConfiguration(configKey); 7153 if (savedConfig != null) { 7154 // There is an existing config with this netId, but it wasn't exposed 7155 // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore# 7156 // getConfiguredNetworks). Remove those bits and update the config. 7157 config = savedConfig; 7158 loge("CONNECT_NETWORK updating existing config with id=" + 7159 config.networkId + " configKey=" + configKey); 7160 config.ephemeral = false; 7161 config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED; 7162 updatedExisting = true; 7163 } 7164 7165 result = mWifiConfigStore.saveNetwork(config, message.sendingUid); 7166 netId = result.getNetworkId(); 7167 } 7168 config = mWifiConfigStore.getWifiConfiguration(netId); 7169 7170 if (config == null) { 7171 loge("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " " 7172 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 7173 + getCurrentState().getName()); 7174 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7175 WifiManager.ERROR); 7176 break; 7177 } else { 7178 String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : ""; 7179 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 7180 + " config=" + config.SSID 7181 + " cnid=" + config.networkId 7182 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 7183 + " my state " + getCurrentState().getName() 7184 + " uid = " + message.sendingUid 7185 + wasSkipped); 7186 } 7187 7188 autoRoamSetBSSID(netId, "any"); 7189 7190 if (message.sendingUid == Process.WIFI_UID 7191 || message.sendingUid == Process.SYSTEM_UID) { 7192 // As a sanity measure, clear the BSSID in the supplicant network block. 7193 // If system or Wifi Settings want to connect, they will not 7194 // specify the BSSID. 7195 // If an app however had added a BSSID to this configuration, and the BSSID 7196 // was wrong, Then we would forever fail to connect until that BSSID 7197 // is cleaned up. 7198 clearConfigBSSID(config, "CONNECT_NETWORK"); 7199 } 7200 7201 if (deferForUserInput(message, netId, true)) { 7202 break; 7203 } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved == 7204 WifiConfiguration.USER_BANNED) { 7205 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7206 WifiManager.NOT_AUTHORIZED); 7207 break; 7208 } 7209 7210 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 7211 7212 /* Tell autojoin the user did try to connect to that network if from settings */ 7213 boolean persist = 7214 mWifiConfigStore.checkConfigOverridePermission(message.sendingUid); 7215 mWifiAutoJoinController.updateConfigurationHistory(netId, true, persist); 7216 7217 mWifiConfigStore.setLastSelectedConfiguration(netId); 7218 7219 didDisconnect = false; 7220 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID 7221 && mLastNetworkId != netId) { 7222 /** Supplicant will ignore the reconnect if we are currently associated, 7223 * hence trigger a disconnect 7224 */ 7225 didDisconnect = true; 7226 mWifiNative.disconnect(); 7227 } 7228 7229 // Make sure the network is enabled, since supplicant will not reenable it 7230 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 7231 7232 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true, 7233 message.sendingUid) && mWifiNative.reconnect()) { 7234 lastConnectAttempt = System.currentTimeMillis(); 7235 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 7236 7237 /* The state tracker handles enabling networks upon completion/failure */ 7238 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 7239 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 7240 if (didDisconnect) { 7241 /* Expect a disconnection from the old connection */ 7242 transitionTo(mDisconnectingState); 7243 } else if (updatedExisting && getCurrentState() == mConnectedState && 7244 getCurrentWifiConfiguration().networkId == netId) { 7245 // Update the current set of network capabilities, but stay in the 7246 // current state. 7247 updateCapabilities(config); 7248 } else { 7249 /** 7250 * Directly go to disconnected state where we 7251 * process the connection events from supplicant 7252 **/ 7253 transitionTo(mDisconnectedState); 7254 } 7255 } else { 7256 loge("Failed to connect config: " + config + " netId: " + netId); 7257 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7258 WifiManager.ERROR); 7259 break; 7260 } 7261 break; 7262 case WifiManager.SAVE_NETWORK: 7263 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 7264 // Fall thru 7265 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 7266 lastSavedConfigurationAttempt = null; // Used for debug 7267 config = (WifiConfiguration) message.obj; 7268 if (config == null) { 7269 loge("ERROR: SAVE_NETWORK with null configuration" 7270 + mSupplicantStateTracker.getSupplicantStateName() 7271 + " my state " + getCurrentState().getName()); 7272 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 7273 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7274 WifiManager.ERROR); 7275 break; 7276 } 7277 lastSavedConfigurationAttempt = new WifiConfiguration(config); 7278 int nid = config.networkId; 7279 loge("SAVE_NETWORK id=" + Integer.toString(nid) 7280 + " config=" + config.SSID 7281 + " nid=" + config.networkId 7282 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 7283 + " my state " + getCurrentState().getName()); 7284 7285 // Only record the uid if this is user initiated 7286 boolean checkUid = (message.what == WifiManager.SAVE_NETWORK); 7287 if (checkUid && !recordUidIfAuthorized(config, message.sendingUid)) { 7288 loge("Not authorized to update network " 7289 + " config=" + config.SSID 7290 + " cnid=" + config.networkId 7291 + " uid=" + message.sendingUid); 7292 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7293 WifiManager.NOT_AUTHORIZED); 7294 break; 7295 } 7296 7297 result = mWifiConfigStore.saveNetwork(config, WifiConfiguration.UNKNOWN_UID); 7298 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 7299 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 7300 if (result.hasIpChanged()) { 7301 // The currently connection configuration was changed 7302 // We switched from DHCP to static or from static to DHCP, or the 7303 // static IP address has changed. 7304 log("Reconfiguring IP on connection"); 7305 // TODO: clear addresses and disable IPv6 7306 // to simplify obtainingIpState. 7307 transitionTo(mObtainingIpState); 7308 } 7309 if (result.hasProxyChanged()) { 7310 log("Reconfiguring proxy on connection"); 7311 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 7312 } 7313 } 7314 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 7315 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config); 7316 7317 if (VDBG) { 7318 loge("Success save network nid=" 7319 + Integer.toString(result.getNetworkId())); 7320 } 7321 7322 synchronized(mScanResultCache) { 7323 /** 7324 * If the command comes from WifiManager, then 7325 * tell autojoin the user did try to modify and save that network, 7326 * and interpret the SAVE_NETWORK as a request to connect 7327 */ 7328 boolean user = message.what == WifiManager.SAVE_NETWORK; 7329 7330 // Did this connect come from settings 7331 boolean persistConnect = 7332 mWifiConfigStore.checkConfigOverridePermission(message.sendingUid); 7333 7334 if (user) { 7335 mWifiConfigStore.updateLastConnectUid(config, message.sendingUid); 7336 mWifiConfigStore.writeKnownNetworkHistory(false); 7337 } 7338 7339 mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() 7340 , user, persistConnect); 7341 mWifiAutoJoinController.attemptAutoJoin(); 7342 } 7343 } else { 7344 loge("Failed to save network"); 7345 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 7346 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7347 WifiManager.ERROR); 7348 } 7349 break; 7350 case WifiManager.FORGET_NETWORK: 7351 // Debug only, remember last configuration that was forgotten 7352 WifiConfiguration toRemove 7353 = mWifiConfigStore.getWifiConfiguration(message.arg1); 7354 if (toRemove == null) { 7355 lastForgetConfigurationAttempt = null; 7356 } else { 7357 lastForgetConfigurationAttempt = new WifiConfiguration(toRemove); 7358 } 7359 // check that the caller owns this network 7360 netId = message.arg1; 7361 7362 if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId)) { 7363 loge("Not authorized to forget network " 7364 + " cnid=" + netId 7365 + " uid=" + message.sendingUid); 7366 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 7367 WifiManager.NOT_AUTHORIZED); 7368 break; 7369 } 7370 7371 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 7372 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 7373 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT, 7374 (WifiConfiguration) message.obj); 7375 } else { 7376 loge("Failed to forget network"); 7377 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 7378 WifiManager.ERROR); 7379 } 7380 break; 7381 case WifiManager.START_WPS: 7382 WpsInfo wpsInfo = (WpsInfo) message.obj; 7383 WpsResult wpsResult; 7384 switch (wpsInfo.setup) { 7385 case WpsInfo.PBC: 7386 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 7387 break; 7388 case WpsInfo.KEYPAD: 7389 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 7390 break; 7391 case WpsInfo.DISPLAY: 7392 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 7393 break; 7394 default: 7395 wpsResult = new WpsResult(Status.FAILURE); 7396 loge("Invalid setup for WPS"); 7397 break; 7398 } 7399 mWifiConfigStore.setLastSelectedConfiguration 7400 (WifiConfiguration.INVALID_NETWORK_ID); 7401 if (wpsResult.status == Status.SUCCESS) { 7402 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 7403 transitionTo(mWpsRunningState); 7404 } else { 7405 loge("Failed to start WPS with config " + wpsInfo.toString()); 7406 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 7407 } 7408 break; 7409 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7410 if (DBG) log("Network connection established"); 7411 mLastNetworkId = message.arg1; 7412 mLastBssid = (String) message.obj; 7413 7414 mWifiInfo.setBSSID(mLastBssid); 7415 mWifiInfo.setNetworkId(mLastNetworkId); 7416 7417 sendNetworkStateChangeBroadcast(mLastBssid); 7418 transitionTo(mObtainingIpState); 7419 break; 7420 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 7421 // Calling handleNetworkDisconnect here is redundant because we might already 7422 // have called it when leaving L2ConnectedState to go to disconnecting state 7423 // or thru other path 7424 // We should normally check the mWifiInfo or mLastNetworkId so as to check 7425 // if they are valid, and only in this case call handleNEtworkDisconnect, 7426 // TODO: this should be fixed for a L MR release 7427 // The side effect of calling handleNetworkDisconnect twice is that a bunch of 7428 // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode 7429 // at the chip etc... 7430 if (DBG) log("ConnectModeState: Network connection lost "); 7431 handleNetworkDisconnect(); 7432 transitionTo(mDisconnectedState); 7433 break; 7434 case CMD_START_PNO: 7435 // Restart Pno if required, reevaluating the list of networks 7436 startPno(); 7437 break; 7438 case CMD_PNO_NETWORK_FOUND: 7439 processPnoNetworkFound((ScanResult[])message.obj); 7440 break; 7441 default: 7442 return NOT_HANDLED; 7443 } 7444 return HANDLED; 7445 } 7446 } 7447 7448 private void updateCapabilities(WifiConfiguration config) { 7449 if (config.ephemeral) { 7450 mNetworkCapabilities.removeCapability( 7451 NetworkCapabilities.NET_CAPABILITY_TRUSTED); 7452 } else { 7453 mNetworkCapabilities.addCapability( 7454 NetworkCapabilities.NET_CAPABILITY_TRUSTED); 7455 } 7456 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 7457 } 7458 7459 private class WifiNetworkAgent extends NetworkAgent { 7460 public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, 7461 NetworkCapabilities nc, LinkProperties lp, int score) { 7462 super(l, c, TAG, ni, nc, lp, score); 7463 } 7464 protected void unwanted() { 7465 // Ignore if we're not the current networkAgent. 7466 if (this != mNetworkAgent) return; 7467 if (DBG) log("WifiNetworkAgent -> Wifi unwanted score " 7468 + Integer.toString(mWifiInfo.score)); 7469 unwantedNetwork(network_status_unwanted_disconnect); 7470 } 7471 7472 @Override 7473 protected void networkStatus(int status) { 7474 if (this != mNetworkAgent) return; 7475 if (status == NetworkAgent.INVALID_NETWORK) { 7476 if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score=" 7477 + Integer.toString(mWifiInfo.score)); 7478 unwantedNetwork(network_status_unwanted_disable_autojoin); 7479 } else if (status == NetworkAgent.VALID_NETWORK) { 7480 if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= " 7481 + Integer.toString(mWifiInfo.score)); 7482 doNetworkStatus(status); 7483 } 7484 } 7485 7486 @Override 7487 protected void saveAcceptUnvalidated(boolean accept) { 7488 if (this != mNetworkAgent) return; 7489 WifiStateMachine.this.sendMessage(CMD_ACCEPT_UNVALIDATED, accept ? 1 : 0); 7490 } 7491 } 7492 7493 void unwantedNetwork(int reason) { 7494 sendMessage(CMD_UNWANTED_NETWORK, reason); 7495 } 7496 7497 void doNetworkStatus(int status) { 7498 sendMessage(CMD_NETWORK_STATUS, status); 7499 } 7500 7501 // rfc4186 & rfc4187: 7502 // create Permanent Identity base on IMSI, 7503 // identity = usernam@realm 7504 // with username = prefix | IMSI 7505 // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003) 7506 private String buildIdentity(int eapMethod, String imsi, String mccMnc) { 7507 String mcc; 7508 String mnc; 7509 String prefix; 7510 7511 if (imsi == null || imsi.isEmpty()) 7512 return ""; 7513 7514 if (eapMethod == WifiEnterpriseConfig.Eap.SIM) 7515 prefix = "1"; 7516 else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) 7517 prefix = "0"; 7518 else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME) 7519 prefix = "6"; 7520 else // not a valide EapMethod 7521 return ""; 7522 7523 /* extract mcc & mnc from mccMnc */ 7524 if (mccMnc != null && !mccMnc.isEmpty()) { 7525 mcc = mccMnc.substring(0, 3); 7526 mnc = mccMnc.substring(3); 7527 if (mnc.length() == 2) 7528 mnc = "0" + mnc; 7529 } else { 7530 // extract mcc & mnc from IMSI, assume mnc size is 3 7531 mcc = imsi.substring(0, 3); 7532 mnc = imsi.substring(3, 6); 7533 } 7534 7535 return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org"; 7536 } 7537 7538 boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) { 7539 if (config == null) 7540 return false; 7541 7542 // We are still seeing a fairly high power consumption triggered by autojoin scans 7543 // Hence do partial scans only for PSK configuration that are roamable since the 7544 // primary purpose of the partial scans is roaming. 7545 // Full badn scans with exponential backoff for the purpose or extended roaming and 7546 // network switching are performed unconditionally. 7547 ScanDetailCache scanDetailCache = 7548 mWifiConfigStore.getScanDetailCache(config); 7549 if (scanDetailCache == null 7550 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 7551 || scanDetailCache.size() > 6) { 7552 //return true but to not trigger the scan 7553 return true; 7554 } 7555 HashSet<Integer> channels = mWifiConfigStore.makeChannelList(config, 7556 ONE_HOUR_MILLI, restrictChannelList); 7557 if (channels != null && channels.size() != 0) { 7558 StringBuilder freqs = new StringBuilder(); 7559 boolean first = true; 7560 for (Integer channel : channels) { 7561 if (!first) 7562 freqs.append(","); 7563 freqs.append(channel.toString()); 7564 first = false; 7565 } 7566 //if (DBG) { 7567 loge("WifiStateMachine starting scan for " + config.configKey() + " with " + freqs); 7568 //} 7569 // Call wifi native to start the scan 7570 if (startScanNative( 7571 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, 7572 freqs.toString())) { 7573 // Only count battery consumption if scan request is accepted 7574 noteScanStart(SCAN_ALARM_SOURCE, null); 7575 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; 7576 } else { 7577 // used for debug only, mark scan as failed 7578 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; 7579 } 7580 return true; 7581 } else { 7582 if (DBG) loge("WifiStateMachine no channels for " + config.configKey()); 7583 return false; 7584 } 7585 } 7586 7587 void clearCurrentConfigBSSID(String dbg) { 7588 // Clear the bssid in the current config's network block 7589 WifiConfiguration config = getCurrentWifiConfiguration(); 7590 if (config == null) 7591 return; 7592 clearConfigBSSID(config, dbg); 7593 } 7594 void clearConfigBSSID(WifiConfiguration config, String dbg) { 7595 if (config == null) 7596 return; 7597 if (DBG) { 7598 loge(dbg + " " + mTargetRoamBSSID + " config " + config.configKey() 7599 + " config.bssid " + config.BSSID); 7600 } 7601 config.autoJoinBSSID = "any"; 7602 config.BSSID = "any"; 7603 if (DBG) { 7604 loge(dbg + " " + config.SSID 7605 + " nid=" + Integer.toString(config.networkId)); 7606 } 7607 mWifiConfigStore.saveWifiConfigBSSID(config); 7608 } 7609 7610 class L2ConnectedState extends State { 7611 @Override 7612 public void enter() { 7613 mRssiPollToken++; 7614 if (mEnableRssiPolling) { 7615 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 7616 } 7617 if (mNetworkAgent != null) { 7618 loge("Have NetworkAgent when entering L2Connected"); 7619 setNetworkDetailedState(DetailedState.DISCONNECTED); 7620 } 7621 setNetworkDetailedState(DetailedState.CONNECTING); 7622 7623 if (!TextUtils.isEmpty(mTcpBufferSizes)) { 7624 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes); 7625 } 7626 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 7627 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 7628 mLinkProperties, 60); 7629 7630 // We must clear the config BSSID, as the wifi chipset may decide to roam 7631 // from this point on and having the BSSID specified in the network block would 7632 // cause the roam to faile and the device to disconnect 7633 clearCurrentConfigBSSID("L2ConnectedState"); 7634 } 7635 7636 @Override 7637 public void exit() { 7638 // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState 7639 // Bug: 15347363 7640 // For paranoia's sake, call handleNetworkDisconnect 7641 // only if BSSID is null or last networkId 7642 // is not invalid. 7643 if (DBG) { 7644 StringBuilder sb = new StringBuilder(); 7645 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId)); 7646 if (mLastBssid !=null) { 7647 sb.append(" ").append(mLastBssid); 7648 } 7649 } 7650 if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 7651 handleNetworkDisconnect(); 7652 } 7653 } 7654 7655 @Override 7656 public boolean processMessage(Message message) { 7657 logStateAndMessage(message, getClass().getSimpleName()); 7658 7659 switch (message.what) { 7660 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 7661 handlePreDhcpSetup(); 7662 break; 7663 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 7664 handlePostDhcpSetup(); 7665 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 7666 if (DBG) log("WifiStateMachine DHCP successful"); 7667 handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS); 7668 // We advance to mVerifyingLinkState because handleIPv4Success will call 7669 // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL. 7670 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 7671 if (DBG) { 7672 int count = -1; 7673 WifiConfiguration config = getCurrentWifiConfiguration(); 7674 if (config != null) { 7675 count = config.numConnectionFailures; 7676 } 7677 log("WifiStateMachine DHCP failure count=" + count); 7678 } 7679 handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); 7680 // As above, we transition to mDisconnectingState via updateLinkProperties. 7681 } 7682 break; 7683 case CMD_IP_CONFIGURATION_SUCCESSFUL: 7684 handleSuccessfulIpConfiguration(); 7685 sendConnectedState(); 7686 transitionTo(mConnectedState); 7687 break; 7688 case CMD_IP_CONFIGURATION_LOST: 7689 // Get Link layer stats so as we get fresh tx packet counters 7690 getWifiLinkLayerStats(true); 7691 handleIpConfigurationLost(); 7692 transitionTo(mDisconnectingState); 7693 break; 7694 case CMD_DISCONNECT: 7695 mWifiNative.disconnect(); 7696 transitionTo(mDisconnectingState); 7697 break; 7698 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 7699 if (message.arg1 == 1) { 7700 mWifiNative.disconnect(); 7701 mTemporarilyDisconnectWifi = true; 7702 transitionTo(mDisconnectingState); 7703 } 7704 break; 7705 case CMD_SET_OPERATIONAL_MODE: 7706 if (message.arg1 != CONNECT_MODE) { 7707 sendMessage(CMD_DISCONNECT); 7708 deferMessage(message); 7709 if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 7710 noteWifiDisabledWhileAssociated(); 7711 } 7712 } 7713 mWifiConfigStore. 7714 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 7715 break; 7716 case CMD_SET_COUNTRY_CODE: 7717 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7718 deferMessage(message); 7719 break; 7720 case CMD_START_SCAN: 7721 //if (DBG) { 7722 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 7723 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 7724 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 7725 + " targetRoamBSSID=" + mTargetRoamBSSID 7726 + " RSSI=" + mWifiInfo.getRssi()); 7727 //} 7728 if (message.arg1 == SCAN_ALARM_SOURCE) { 7729 // Check if the CMD_START_SCAN message is obsolete (and thus if it should 7730 // not be processed) and restart the scan if needed 7731 boolean shouldScan = 7732 mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get(); 7733 if (!checkAndRestartDelayedScan(message.arg2, 7734 shouldScan, 7735 mWifiConfigStore.associatedPartialScanPeriodMilli.get(), null, null)) { 7736 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; 7737 loge("WifiStateMachine L2Connected CMD_START_SCAN source " 7738 + message.arg1 7739 + " " + message.arg2 + ", " + mDelayedScanCounter 7740 + " -> obsolete"); 7741 return HANDLED; 7742 } 7743 if (mP2pConnected.get()) { 7744 loge("WifiStateMachine L2Connected CMD_START_SCAN source " 7745 + message.arg1 7746 + " " + message.arg2 + ", " + mDelayedScanCounter 7747 + " ignore because P2P is connected"); 7748 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7749 return HANDLED; 7750 } 7751 boolean tryFullBandScan = false; 7752 boolean restrictChannelList = false; 7753 long now_ms = System.currentTimeMillis(); 7754 if (DBG) { 7755 loge("WifiStateMachine CMD_START_SCAN with age=" 7756 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 7757 + " interval=" + fullBandConnectedTimeIntervalMilli 7758 + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli); 7759 } 7760 if (mWifiInfo != null) { 7761 if (mWifiConfigStore.enableFullBandScanWhenAssociated.get() && 7762 (now_ms - lastFullBandConnectedTimeMilli) 7763 > fullBandConnectedTimeIntervalMilli) { 7764 if (DBG) { 7765 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 7766 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 7767 + " interval=" + fullBandConnectedTimeIntervalMilli 7768 + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli); 7769 } 7770 tryFullBandScan = true; 7771 } 7772 7773 if (mWifiInfo.txSuccessRate > 7774 mWifiConfigStore.maxTxPacketForFullScans 7775 || mWifiInfo.rxSuccessRate > 7776 mWifiConfigStore.maxRxPacketForFullScans) { 7777 // Too much traffic at the interface, hence no full band scan 7778 if (DBG) { 7779 loge("WifiStateMachine CMD_START_SCAN " + 7780 "prevent full band scan due to pkt rate"); 7781 } 7782 tryFullBandScan = false; 7783 } 7784 7785 if (mWifiInfo.txSuccessRate > 7786 mWifiConfigStore.maxTxPacketForPartialScans 7787 || mWifiInfo.rxSuccessRate > 7788 mWifiConfigStore.maxRxPacketForPartialScans) { 7789 // Don't scan if lots of packets are being sent 7790 restrictChannelList = true; 7791 if (mWifiConfigStore.alwaysEnableScansWhileAssociated.get() == 0) { 7792 if (DBG) { 7793 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 7794 + " ...and ignore scans" 7795 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 7796 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 7797 } 7798 messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; 7799 return HANDLED; 7800 } 7801 } 7802 } 7803 7804 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 7805 if (DBG) { 7806 loge("WifiStateMachine CMD_START_SCAN full=" + 7807 tryFullBandScan); 7808 } 7809 if (currentConfiguration != null) { 7810 if (fullBandConnectedTimeIntervalMilli 7811 < mWifiConfigStore.associatedPartialScanPeriodMilli.get()) { 7812 // Sanity 7813 fullBandConnectedTimeIntervalMilli 7814 = mWifiConfigStore.associatedPartialScanPeriodMilli.get(); 7815 } 7816 if (tryFullBandScan) { 7817 lastFullBandConnectedTimeMilli = now_ms; 7818 if (fullBandConnectedTimeIntervalMilli 7819 < mWifiConfigStore.associatedFullScanMaxIntervalMilli) { 7820 // Increase the interval 7821 fullBandConnectedTimeIntervalMilli 7822 = fullBandConnectedTimeIntervalMilli 7823 * mWifiConfigStore.associatedFullScanBackoff.get() / 8; 7824 7825 if (DBG) { 7826 loge("WifiStateMachine CMD_START_SCAN bump interval =" 7827 + fullBandConnectedTimeIntervalMilli); 7828 } 7829 } 7830 handleScanRequest( 7831 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 7832 } else { 7833 if (!startScanForConfiguration( 7834 currentConfiguration, restrictChannelList)) { 7835 if (DBG) { 7836 loge("WifiStateMachine starting scan, " + 7837 " did not find channels -> full"); 7838 } 7839 lastFullBandConnectedTimeMilli = now_ms; 7840 if (fullBandConnectedTimeIntervalMilli 7841 < mWifiConfigStore.associatedFullScanMaxIntervalMilli) { 7842 // Increase the interval 7843 fullBandConnectedTimeIntervalMilli 7844 = fullBandConnectedTimeIntervalMilli 7845 * mWifiConfigStore.associatedFullScanBackoff.get() / 8; 7846 7847 if (DBG) { 7848 loge("WifiStateMachine CMD_START_SCAN bump interval =" 7849 + fullBandConnectedTimeIntervalMilli); 7850 } 7851 } 7852 handleScanRequest( 7853 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 7854 } 7855 } 7856 7857 } else { 7858 loge("CMD_START_SCAN : connected mode and no configuration"); 7859 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; 7860 } 7861 } else { 7862 // Not scan alarm source 7863 return NOT_HANDLED; 7864 } 7865 break; 7866 /* Ignore connection to same network */ 7867 case WifiManager.CONNECT_NETWORK: 7868 int netId = message.arg1; 7869 if (mWifiInfo.getNetworkId() == netId) { 7870 break; 7871 } 7872 return NOT_HANDLED; 7873 /* Ignore */ 7874 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7875 break; 7876 case CMD_RSSI_POLL: 7877 if (message.arg1 == mRssiPollToken) { 7878 if (mWifiConfigStore.enableChipWakeUpWhenAssociated.get()) { 7879 if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported); 7880 WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG); 7881 if (stats != null) { 7882 // Sanity check the results provided by driver 7883 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI 7884 && (stats.rssi_mgmt == 0 7885 || stats.beacon_rx == 0)) { 7886 stats = null; 7887 } 7888 } 7889 // Get Info and continue polling 7890 fetchRssiLinkSpeedAndFrequencyNative(); 7891 calculateWifiScore(stats); 7892 } 7893 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 7894 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 7895 7896 if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi()); 7897 } else { 7898 // Polling has completed 7899 } 7900 break; 7901 case CMD_ENABLE_RSSI_POLL: 7902 if (mWifiConfigStore.enableRssiPollWhenAssociated.get()) { 7903 mEnableRssiPolling = (message.arg1 == 1); 7904 } else { 7905 mEnableRssiPolling = false; 7906 } 7907 mRssiPollToken++; 7908 if (mEnableRssiPolling) { 7909 // First poll 7910 fetchRssiLinkSpeedAndFrequencyNative(); 7911 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 7912 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 7913 } else { 7914 cleanWifiScore(); 7915 } 7916 break; 7917 case WifiManager.RSSI_PKTCNT_FETCH: 7918 RssiPacketCountInfo info = new RssiPacketCountInfo(); 7919 fetchRssiLinkSpeedAndFrequencyNative(); 7920 info.rssi = mWifiInfo.getRssi(); 7921 fetchPktcntNative(info); 7922 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 7923 break; 7924 case CMD_DELAYED_NETWORK_DISCONNECT: 7925 if (!linkDebouncing && mWifiConfigStore.enableLinkDebouncing) { 7926 7927 // Ignore if we are not debouncing 7928 loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore " 7929 + message.arg1); 7930 return HANDLED; 7931 } else { 7932 loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect " 7933 + message.arg1); 7934 7935 linkDebouncing = false; 7936 // If we are still debouncing while this message comes, 7937 // it means we were not able to reconnect within the alloted time 7938 // = LINK_FLAPPING_DEBOUNCE_MSEC 7939 // and thus, trigger a real disconnect 7940 handleNetworkDisconnect(); 7941 transitionTo(mDisconnectedState); 7942 } 7943 break; 7944 case CMD_ASSOCIATED_BSSID: 7945 if ((String) message.obj == null) { 7946 loge("Associated command w/o BSSID"); 7947 break; 7948 } 7949 mLastBssid = (String) message.obj; 7950 if (mLastBssid != null 7951 && (mWifiInfo.getBSSID() == null 7952 || !mLastBssid.equals(mWifiInfo.getBSSID()))) { 7953 mWifiInfo.setBSSID((String) message.obj); 7954 sendNetworkStateChangeBroadcast(mLastBssid); 7955 } 7956 break; 7957 default: 7958 return NOT_HANDLED; 7959 } 7960 7961 return HANDLED; 7962 } 7963 } 7964 7965 class ObtainingIpState extends State { 7966 @Override 7967 public void enter() { 7968 if (DBG) { 7969 String key = ""; 7970 if (getCurrentWifiConfiguration() != null) { 7971 key = getCurrentWifiConfiguration().configKey(); 7972 } 7973 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 7974 + " " + key + " " 7975 + " roam=" + mAutoRoaming 7976 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId) 7977 + " watchdog= " + obtainingIpWatchdogCount); 7978 } 7979 7980 // Reset link Debouncing, indicating we have successfully re-connected to the AP 7981 // We might still be roaming 7982 linkDebouncing = false; 7983 7984 // Send event to CM & network change broadcast 7985 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 7986 7987 // We must clear the config BSSID, as the wifi chipset may decide to roam 7988 // from this point on and having the BSSID specified in the network block would 7989 // cause the roam to faile and the device to disconnect 7990 clearCurrentConfigBSSID("ObtainingIpAddress"); 7991 7992 try { 7993 mNwService.enableIpv6(mInterfaceName); 7994 } catch (RemoteException re) { 7995 loge("Failed to enable IPv6: " + re); 7996 } catch (IllegalStateException e) { 7997 loge("Failed to enable IPv6: " + e); 7998 } 7999 8000 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 8001 if (isRoaming()) { 8002 renewDhcp(); 8003 } else { 8004 // Remove any IP address on the interface in case we're switching from static 8005 // IP configuration to DHCP. This is safe because if we get here when not 8006 // roaming, we don't have a usable address. 8007 clearIPv4Address(mInterfaceName); 8008 startDhcp(); 8009 } 8010 obtainingIpWatchdogCount++; 8011 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); 8012 // Get Link layer stats so as we get fresh tx packet counters 8013 getWifiLinkLayerStats(true); 8014 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, 8015 obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); 8016 } else { 8017 // stop any running dhcp before assigning static IP 8018 stopDhcp(); 8019 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration( 8020 mLastNetworkId); 8021 if (config.ipAddress == null) { 8022 loge("Static IP lacks address"); 8023 sendMessage(CMD_STATIC_IP_FAILURE); 8024 } else { 8025 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 8026 ifcg.setLinkAddress(config.ipAddress); 8027 ifcg.setInterfaceUp(); 8028 try { 8029 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 8030 if (DBG) log("Static IP configuration succeeded"); 8031 DhcpResults dhcpResults = new DhcpResults(config); 8032 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 8033 } catch (RemoteException re) { 8034 loge("Static IP configuration failed: " + re); 8035 sendMessage(CMD_STATIC_IP_FAILURE); 8036 } catch (IllegalStateException e) { 8037 loge("Static IP configuration failed: " + e); 8038 sendMessage(CMD_STATIC_IP_FAILURE); 8039 } 8040 } 8041 } 8042 } 8043 @Override 8044 public boolean processMessage(Message message) { 8045 logStateAndMessage(message, getClass().getSimpleName()); 8046 8047 switch(message.what) { 8048 case CMD_STATIC_IP_SUCCESS: 8049 handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 8050 break; 8051 case CMD_STATIC_IP_FAILURE: 8052 handleIPv4Failure(CMD_STATIC_IP_FAILURE); 8053 break; 8054 case CMD_AUTO_CONNECT: 8055 case CMD_AUTO_ROAM: 8056 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8057 break; 8058 case WifiManager.SAVE_NETWORK: 8059 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 8060 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 8061 deferMessage(message); 8062 break; 8063 /* Defer any power mode changes since we must keep active power mode at DHCP */ 8064 case CMD_SET_HIGH_PERF_MODE: 8065 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 8066 deferMessage(message); 8067 break; 8068 /* Defer scan request since we should not switch to other channels at DHCP */ 8069 case CMD_START_SCAN: 8070 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 8071 deferMessage(message); 8072 break; 8073 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 8074 if (message.arg1 == obtainingIpWatchdogCount) { 8075 loge("ObtainingIpAddress: Watchdog Triggered, count=" 8076 + obtainingIpWatchdogCount); 8077 handleIpConfigurationLost(); 8078 transitionTo(mDisconnectingState); 8079 break; 8080 } 8081 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8082 break; 8083 default: 8084 return NOT_HANDLED; 8085 } 8086 return HANDLED; 8087 } 8088 } 8089 8090 class VerifyingLinkState extends State { 8091 @Override 8092 public void enter() { 8093 log(getName() + " enter"); 8094 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 8095 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 8096 sendNetworkStateChangeBroadcast(mLastBssid); 8097 // End roaming 8098 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8099 } 8100 @Override 8101 public boolean processMessage(Message message) { 8102 logStateAndMessage(message, getClass().getSimpleName()); 8103 8104 switch (message.what) { 8105 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 8106 // Stay here 8107 log(getName() + " POOR_LINK_DETECTED: no transition"); 8108 break; 8109 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 8110 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 8111 8112 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 8113 sendConnectedState(); 8114 transitionTo(mConnectedState); 8115 break; 8116 default: 8117 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 8118 return NOT_HANDLED; 8119 } 8120 return HANDLED; 8121 } 8122 } 8123 8124 private void sendConnectedState() { 8125 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 8126 // existing behaviour. The captive portal check really happens after we 8127 // transition into DetailedState.CONNECTED. 8128 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 8129 mWifiConfigStore.updateStatus(mLastNetworkId, 8130 DetailedState.CAPTIVE_PORTAL_CHECK); 8131 sendNetworkStateChangeBroadcast(mLastBssid); 8132 8133 // If this network was explicitly selected by the user, evaluate whether to call 8134 // explicitlySelected() so the system can treat it appropriately. 8135 WifiConfiguration config = getCurrentWifiConfiguration(); 8136 if (mWifiConfigStore.isLastSelectedConfiguration(config)) { 8137 boolean prompt = mWifiConfigStore.checkConfigOverridePermission(config.lastConnectUid); 8138 if (DBG) { 8139 log("Network selected by UID " + config.lastConnectUid + " prompt=" + prompt); 8140 } 8141 if (prompt) { 8142 // Selected by the user via Settings or QuickSettings. If this network has Internet 8143 // access, switch to it. Otherwise, switch to it only if the user confirms that they 8144 // really want to switch, or has already confirmed and selected "Don't ask again". 8145 if (DBG) { 8146 log("explictlySelected acceptUnvalidated=" + config.noInternetAccessExpected); 8147 } 8148 mNetworkAgent.explicitlySelected(config.noInternetAccessExpected); 8149 } 8150 } 8151 8152 setNetworkDetailedState(DetailedState.CONNECTED); 8153 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 8154 sendNetworkStateChangeBroadcast(mLastBssid); 8155 } 8156 8157 class RoamingState extends State { 8158 boolean mAssociated; 8159 @Override 8160 public void enter() { 8161 if (DBG) { 8162 log("RoamingState Enter" 8163 + " mScreenOn=" + mScreenOn ); 8164 } 8165 setScanAlarm(false); 8166 8167 // Make sure we disconnect if roaming fails 8168 roamWatchdogCount++; 8169 loge("Start Roam Watchdog " + roamWatchdogCount); 8170 sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER, 8171 roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC); 8172 mAssociated = false; 8173 } 8174 @Override 8175 public boolean processMessage(Message message) { 8176 logStateAndMessage(message, getClass().getSimpleName()); 8177 WifiConfiguration config; 8178 switch (message.what) { 8179 case CMD_IP_CONFIGURATION_LOST: 8180 config = getCurrentWifiConfiguration(); 8181 if (config != null) { 8182 mWifiConfigStore.noteRoamingFailure(config, 8183 WifiConfiguration.ROAMING_FAILURE_IP_CONFIG); 8184 } 8185 return NOT_HANDLED; 8186 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 8187 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 8188 return HANDLED; 8189 case CMD_UNWANTED_NETWORK: 8190 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 8191 return HANDLED; 8192 case CMD_SET_OPERATIONAL_MODE: 8193 if (message.arg1 != CONNECT_MODE) { 8194 deferMessage(message); 8195 } 8196 break; 8197 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8198 /** 8199 * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT 8200 * before NETWORK_DISCONNECTION_EVENT 8201 * And there is an associated BSSID corresponding to our target BSSID, then 8202 * we have missed the network disconnection, transition to mDisconnectedState 8203 * and handle the rest of the events there. 8204 */ 8205 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 8206 if (stateChangeResult.state == SupplicantState.DISCONNECTED 8207 || stateChangeResult.state == SupplicantState.INACTIVE 8208 || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) { 8209 if (DBG) { 8210 log("STATE_CHANGE_EVENT in roaming state " 8211 + stateChangeResult.toString() ); 8212 } 8213 if (stateChangeResult.BSSID != null 8214 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) { 8215 handleNetworkDisconnect(); 8216 transitionTo(mDisconnectedState); 8217 } 8218 } 8219 if (stateChangeResult.state == SupplicantState.ASSOCIATED) { 8220 // We completed the layer2 roaming part 8221 mAssociated = true; 8222 if (stateChangeResult.BSSID != null) { 8223 mTargetRoamBSSID = (String) stateChangeResult.BSSID; 8224 } 8225 } 8226 break; 8227 case CMD_ROAM_WATCHDOG_TIMER: 8228 if (roamWatchdogCount == message.arg1) { 8229 if (DBG) log("roaming watchdog! -> disconnect"); 8230 mRoamFailCount++; 8231 handleNetworkDisconnect(); 8232 mWifiNative.disconnect(); 8233 transitionTo(mDisconnectedState); 8234 } 8235 break; 8236 case WifiMonitor.NETWORK_CONNECTION_EVENT: 8237 if (mAssociated) { 8238 if (DBG) log("roaming and Network connection established"); 8239 mLastNetworkId = message.arg1; 8240 mLastBssid = (String) message.obj; 8241 mWifiInfo.setBSSID(mLastBssid); 8242 mWifiInfo.setNetworkId(mLastNetworkId); 8243 mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true); 8244 sendNetworkStateChangeBroadcast(mLastBssid); 8245 transitionTo(mObtainingIpState); 8246 } else { 8247 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8248 } 8249 break; 8250 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8251 // Throw away but only if it corresponds to the network we're roaming to 8252 String bssid = (String)message.obj; 8253 if (true) { 8254 String target = ""; 8255 if (mTargetRoamBSSID != null) target = mTargetRoamBSSID; 8256 log("NETWORK_DISCONNECTION_EVENT in roaming state" 8257 + " BSSID=" + bssid 8258 + " target=" + target); 8259 } 8260 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 8261 handleNetworkDisconnect(); 8262 transitionTo(mDisconnectedState); 8263 } 8264 break; 8265 case WifiMonitor.SSID_TEMP_DISABLED: 8266 // Auth error while roaming 8267 loge("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId) 8268 + " id=" + Integer.toString(message.arg1) 8269 + " isRoaming=" + isRoaming() 8270 + " roam=" + Integer.toString(mAutoRoaming)); 8271 if (message.arg1 == mLastNetworkId) { 8272 config = getCurrentWifiConfiguration(); 8273 if (config != null) { 8274 mWifiConfigStore.noteRoamingFailure(config, 8275 WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE); 8276 } 8277 handleNetworkDisconnect(); 8278 transitionTo(mDisconnectingState); 8279 } 8280 return NOT_HANDLED; 8281 case CMD_START_SCAN: 8282 deferMessage(message); 8283 break; 8284 default: 8285 return NOT_HANDLED; 8286 } 8287 return HANDLED; 8288 } 8289 8290 @Override 8291 public void exit() { 8292 loge("WifiStateMachine: Leaving Roaming state"); 8293 } 8294 } 8295 8296 class ConnectedState extends State { 8297 @Override 8298 public void enter() { 8299 String address; 8300 updateDefaultRouteMacAddress(1000); 8301 if (DBG) { 8302 log("ConnectedState Enter " 8303 + " mScreenOn=" + mScreenOn 8304 + " scanperiod=" 8305 + Integer.toString(mWifiConfigStore.associatedPartialScanPeriodMilli.get()) ); 8306 } 8307 if (mScreenOn 8308 && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get()) { 8309 if (mAlwaysOnPnoSupported) { 8310 startPno(); 8311 } else { 8312 // restart scan alarm 8313 startDelayedScan(mWifiConfigStore.associatedPartialScanPeriodMilli.get(), 8314 null, null); 8315 } 8316 } 8317 registerConnected(); 8318 lastConnectAttempt = 0; 8319 targetWificonfiguration = null; 8320 // Paranoia 8321 linkDebouncing = false; 8322 8323 // Not roaming anymore 8324 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8325 8326 if (testNetworkDisconnect) { 8327 testNetworkDisconnectCounter++; 8328 loge("ConnectedState Enter start disconnect test " + 8329 testNetworkDisconnectCounter); 8330 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT, 8331 testNetworkDisconnectCounter, 0), 15000); 8332 } 8333 8334 // Reenable all networks, allow for hidden networks to be scanned 8335 mWifiConfigStore.enableAllNetworks(); 8336 8337 mLastDriverRoamAttempt = 0; 8338 } 8339 @Override 8340 public boolean processMessage(Message message) { 8341 WifiConfiguration config = null; 8342 logStateAndMessage(message, getClass().getSimpleName()); 8343 8344 switch (message.what) { 8345 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 8346 if (DBG) log("Watchdog reports poor link"); 8347 transitionTo(mVerifyingLinkState); 8348 break; 8349 case CMD_UNWANTED_NETWORK: 8350 if (message.arg1 == network_status_unwanted_disconnect) { 8351 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 8352 mWifiNative.disconnect(); 8353 transitionTo(mDisconnectingState); 8354 } else if (message.arg1 == network_status_unwanted_disable_autojoin) { 8355 config = getCurrentWifiConfiguration(); 8356 if (config != null) { 8357 // Disable autojoin 8358 config.numNoInternetAccessReports += 1; 8359 } 8360 } 8361 return HANDLED; 8362 case CMD_NETWORK_STATUS: 8363 if (message.arg1 == NetworkAgent.VALID_NETWORK) { 8364 config = getCurrentWifiConfiguration(); 8365 if (config != null) { 8366 // re-enable autojoin 8367 config.numNoInternetAccessReports = 0; 8368 config.validatedInternetAccess = true; 8369 } 8370 } 8371 return HANDLED; 8372 case CMD_ACCEPT_UNVALIDATED: 8373 boolean accept = (message.arg1 != 0); 8374 config = getCurrentWifiConfiguration(); 8375 if (config != null) { 8376 config.noInternetAccessExpected = accept; 8377 } 8378 return HANDLED; 8379 case CMD_TEST_NETWORK_DISCONNECT: 8380 // Force a disconnect 8381 if (message.arg1 == testNetworkDisconnectCounter) { 8382 mWifiNative.disconnect(); 8383 } 8384 break; 8385 case CMD_ASSOCIATED_BSSID: 8386 // ASSOCIATING to a new BSSID while already connected, indicates 8387 // that driver is roaming 8388 mLastDriverRoamAttempt = System.currentTimeMillis(); 8389 String toBSSID = (String)message.obj; 8390 if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) { 8391 mWifiConfigStore.driverRoamedFrom(mWifiInfo); 8392 } 8393 return NOT_HANDLED; 8394 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8395 long lastRoam = 0; 8396 if (mLastDriverRoamAttempt != 0) { 8397 // Calculate time since last driver roam attempt 8398 lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt; 8399 mLastDriverRoamAttempt = 0; 8400 } 8401 config = getCurrentWifiConfiguration(); 8402 if (mScreenOn 8403 && !linkDebouncing 8404 && config != null 8405 && config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED 8406 && !mWifiConfigStore.isLastSelectedConfiguration(config) 8407 && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */ 8408 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */) 8409 && ((ScanResult.is24GHz(mWifiInfo.getFrequency()) 8410 && mWifiInfo.getRssi() > 8411 WifiConfiguration.BAD_RSSI_24) 8412 || (ScanResult.is5GHz(mWifiInfo.getFrequency()) 8413 && mWifiInfo.getRssi() > 8414 WifiConfiguration.BAD_RSSI_5))) { 8415 // Start de-bouncing the L2 disconnection: 8416 // this L2 disconnection might be spurious. 8417 // Hence we allow 7 seconds for the state machine to try 8418 // to reconnect, go thru the 8419 // roaming cycle and enter Obtaining IP address 8420 // before signalling the disconnect to ConnectivityService and L3 8421 startScanForConfiguration(getCurrentWifiConfiguration(), false); 8422 linkDebouncing = true; 8423 8424 sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT, 8425 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC); 8426 if (DBG) { 8427 log("NETWORK_DISCONNECTION_EVENT in connected state" 8428 + " BSSID=" + mWifiInfo.getBSSID() 8429 + " RSSI=" + mWifiInfo.getRssi() 8430 + " freq=" + mWifiInfo.getFrequency() 8431 + " reason=" + message.arg2 8432 + " -> debounce"); 8433 } 8434 return HANDLED; 8435 } else { 8436 if (DBG) { 8437 int ajst = -1; 8438 if (config != null) ajst = config.autoJoinStatus; 8439 log("NETWORK_DISCONNECTION_EVENT in connected state" 8440 + " BSSID=" + mWifiInfo.getBSSID() 8441 + " RSSI=" + mWifiInfo.getRssi() 8442 + " freq=" + mWifiInfo.getFrequency() 8443 + " was debouncing=" + linkDebouncing 8444 + " reason=" + message.arg2 8445 + " ajst=" + ajst); 8446 } 8447 } 8448 break; 8449 case CMD_AUTO_ROAM: 8450 // Clear the driver roam indication since we are attempting a framerwork roam 8451 mLastDriverRoamAttempt = 0; 8452 8453 /* Connect command coming from auto-join */ 8454 ScanResult candidate = (ScanResult)message.obj; 8455 String bssid = "any"; 8456 if (candidate != null && candidate.is5GHz()) { 8457 // Only lock BSSID for 5GHz networks 8458 bssid = candidate.BSSID; 8459 } 8460 int netId = mLastNetworkId; 8461 config = getCurrentWifiConfiguration(); 8462 8463 8464 if (config == null) { 8465 loge("AUTO_ROAM and no config, bail out..."); 8466 break; 8467 } 8468 8469 loge("CMD_AUTO_ROAM sup state " 8470 + mSupplicantStateTracker.getSupplicantStateName() 8471 + " my state " + getCurrentState().getName() 8472 + " nid=" + Integer.toString(netId) 8473 + " config " + config.configKey() 8474 + " roam=" + Integer.toString(message.arg2) 8475 + " to " + bssid 8476 + " targetRoamBSSID " + mTargetRoamBSSID); 8477 8478 /* Save the BSSID so as to lock it @ firmware */ 8479 if (!autoRoamSetBSSID(config, bssid) && !linkDebouncing) { 8480 loge("AUTO_ROAM nothing to do"); 8481 // Same BSSID, nothing to do 8482 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8483 break; 8484 }; 8485 8486 // Make sure the network is enabled, since supplicant will not reenable it 8487 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 8488 8489 if (deferForUserInput(message, netId, false)) { 8490 break; 8491 } else if (mWifiConfigStore.getWifiConfiguration(netId).userApproved == 8492 WifiConfiguration.USER_BANNED) { 8493 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 8494 WifiManager.NOT_AUTHORIZED); 8495 break; 8496 } 8497 8498 boolean ret = false; 8499 if (mLastNetworkId != netId) { 8500 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false, 8501 WifiConfiguration.UNKNOWN_UID) && mWifiNative.reconnect()) { 8502 ret = true; 8503 } 8504 } else { 8505 ret = mWifiNative.reassociate(); 8506 } 8507 if (ret) { 8508 lastConnectAttempt = System.currentTimeMillis(); 8509 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 8510 8511 // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 8512 mAutoRoaming = message.arg2; 8513 transitionTo(mRoamingState); 8514 8515 } else { 8516 loge("Failed to connect config: " + config + " netId: " + netId); 8517 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 8518 WifiManager.ERROR); 8519 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 8520 break; 8521 } 8522 break; 8523 default: 8524 return NOT_HANDLED; 8525 } 8526 return HANDLED; 8527 } 8528 8529 @Override 8530 public void exit() { 8531 loge("WifiStateMachine: Leaving Connected state"); 8532 setScanAlarm(false); 8533 mLastDriverRoamAttempt = 0; 8534 } 8535 } 8536 8537 class DisconnectingState extends State { 8538 8539 @Override 8540 public void enter() { 8541 8542 if (PDBG) { 8543 loge(" Enter DisconnectingState State scan interval " 8544 + mWifiConfigStore.wifiDisconnectedScanIntervalMs 8545 + " mEnableBackgroundScan= " + mEnableBackgroundScan 8546 + " screenOn=" + mScreenOn); 8547 } 8548 8549 // Make sure we disconnect: we enter this state prior connecting to a new 8550 // network, waiting for either a DISCONECT event or a SUPPLICANT_STATE_CHANGE 8551 // event which in this case will be indicating that supplicant started to associate. 8552 // In some cases supplicant doesn't ignore the connect requests (it might not 8553 // find the target SSID in its cache), 8554 // Therefore we end up stuck that state, hence the need for the watchdog. 8555 disconnectingWatchdogCount++; 8556 loge("Start Disconnecting Watchdog " + disconnectingWatchdogCount); 8557 sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER, 8558 disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC); 8559 } 8560 8561 @Override 8562 public boolean processMessage(Message message) { 8563 logStateAndMessage(message, getClass().getSimpleName()); 8564 switch (message.what) { 8565 case CMD_SET_OPERATIONAL_MODE: 8566 if (message.arg1 != CONNECT_MODE) { 8567 deferMessage(message); 8568 } 8569 break; 8570 case CMD_START_SCAN: 8571 deferMessage(message); 8572 return HANDLED; 8573 case CMD_DISCONNECTING_WATCHDOG_TIMER: 8574 if (disconnectingWatchdogCount == message.arg1) { 8575 if (DBG) log("disconnecting watchdog! -> disconnect"); 8576 handleNetworkDisconnect(); 8577 transitionTo(mDisconnectedState); 8578 } 8579 break; 8580 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8581 /** 8582 * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 8583 * we have missed the network disconnection, transition to mDisconnectedState 8584 * and handle the rest of the events there 8585 */ 8586 deferMessage(message); 8587 handleNetworkDisconnect(); 8588 transitionTo(mDisconnectedState); 8589 break; 8590 default: 8591 return NOT_HANDLED; 8592 } 8593 return HANDLED; 8594 } 8595 } 8596 8597 class DisconnectedState extends State { 8598 @Override 8599 public void enter() { 8600 // We dont scan frequently if this is a temporary disconnect 8601 // due to p2p 8602 if (mTemporarilyDisconnectWifi) { 8603 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 8604 return; 8605 } 8606 8607 if (PDBG) { 8608 loge(" Enter disconnected State scan interval " 8609 + mWifiConfigStore.wifiDisconnectedScanIntervalMs.get() 8610 + " mEnableBackgroundScan= " + mEnableBackgroundScan 8611 + " screenOn=" + mScreenOn); 8612 } 8613 8614 /** clear the roaming state, if we were roaming, we failed */ 8615 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8616 8617 if (!startPno()) { 8618 if (mScreenOn) { 8619 /** 8620 * screen lit and => delayed timer 8621 */ 8622 startDelayedScan(mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(), 8623 null, null); 8624 } else { 8625 /** 8626 * screen dark and PNO supported => scan alarm disabled 8627 */ 8628 if (mEnableBackgroundScan) { 8629 /* If a regular scan result is pending, do not initiate background 8630 * scan until the scan results are returned. This is needed because 8631 * initiating a background scan will cancel the regular scan and 8632 * scan results will not be returned until background scanning is 8633 * cleared 8634 */ 8635 if (!mIsScanOngoing) { 8636 enableBackgroundScan(true); 8637 } 8638 } else { 8639 setScanAlarm(true); 8640 } 8641 } 8642 } 8643 8644 /** 8645 * If we have no networks saved, the supplicant stops doing the periodic scan. 8646 * The scans are useful to notify the user of the presence of an open network. 8647 * Note that these are not wake up scans. 8648 */ 8649 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8650 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8651 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8652 } 8653 8654 mDisconnectedTimeStamp = System.currentTimeMillis(); 8655 8656 } 8657 @Override 8658 public boolean processMessage(Message message) { 8659 boolean ret = HANDLED; 8660 8661 logStateAndMessage(message, getClass().getSimpleName()); 8662 8663 switch (message.what) { 8664 case CMD_NO_NETWORKS_PERIODIC_SCAN: 8665 if (mP2pConnected.get()) break; 8666 if (message.arg1 == mPeriodicScanToken && 8667 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8668 startScan(UNKNOWN_SCAN_SOURCE, -1, null, null); 8669 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8670 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8671 } 8672 break; 8673 case WifiManager.FORGET_NETWORK: 8674 case CMD_REMOVE_NETWORK: 8675 case CMD_REMOVE_APP_CONFIGURATIONS: 8676 case CMD_REMOVE_USER_CONFIGURATIONS: 8677 // Set up a delayed message here. After the forget/remove is handled 8678 // the handled delayed message will determine if there is a need to 8679 // scan and continue 8680 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8681 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8682 ret = NOT_HANDLED; 8683 break; 8684 case CMD_SET_OPERATIONAL_MODE: 8685 if (message.arg1 != CONNECT_MODE) { 8686 mOperationalMode = message.arg1; 8687 8688 mWifiConfigStore.disableAllNetworks(); 8689 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 8690 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 8691 setWifiState(WIFI_STATE_DISABLED); 8692 } 8693 transitionTo(mScanModeState); 8694 } 8695 mWifiConfigStore. 8696 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 8697 break; 8698 /* Ignore network disconnect */ 8699 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8700 break; 8701 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8702 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 8703 if (DBG) { 8704 loge("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state + 8705 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state) 8706 + " debouncing=" + linkDebouncing); 8707 } 8708 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 8709 /* ConnectModeState does the rest of the handling */ 8710 ret = NOT_HANDLED; 8711 break; 8712 case CMD_START_SCAN: 8713 if (!checkOrDeferScanAllowed(message)) { 8714 // The scan request was rescheduled 8715 messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; 8716 return HANDLED; 8717 } 8718 /* Disable background scan temporarily during a regular scan */ 8719 if (mEnableBackgroundScan) { 8720 enableBackgroundScan(false); 8721 } 8722 if (message.arg1 == SCAN_ALARM_SOURCE) { 8723 // Check if the CMD_START_SCAN message is obsolete (and thus if it should 8724 // not be processed) and restart the scan 8725 int period = mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(); 8726 if (mP2pConnected.get()) { 8727 period = (int)Settings.Global.getLong(mContext.getContentResolver(), 8728 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 8729 period); 8730 } 8731 if (!checkAndRestartDelayedScan(message.arg2, 8732 true, period, null, null)) { 8733 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; 8734 loge("WifiStateMachine Disconnected CMD_START_SCAN source " 8735 + message.arg1 8736 + " " + message.arg2 + ", " + mDelayedScanCounter 8737 + " -> obsolete"); 8738 return HANDLED; 8739 } 8740 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 8741 ret = HANDLED; 8742 } else { 8743 ret = NOT_HANDLED; 8744 } 8745 break; 8746 case WifiMonitor.SCAN_RESULTS_EVENT: 8747 /* Re-enable background scan when a pending scan result is received */ 8748 if (mEnableBackgroundScan && mIsScanOngoing) { 8749 enableBackgroundScan(true); 8750 } 8751 /* Handled in parent state */ 8752 ret = NOT_HANDLED; 8753 break; 8754 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 8755 NetworkInfo info = (NetworkInfo) message.obj; 8756 mP2pConnected.set(info.isConnected()); 8757 if (mP2pConnected.get()) { 8758 int defaultInterval = mContext.getResources().getInteger( 8759 R.integer.config_wifi_scan_interval_p2p_connected); 8760 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 8761 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 8762 defaultInterval); 8763 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 8764 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8765 if (DBG) log("Turn on scanning after p2p disconnected"); 8766 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8767 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8768 } else { 8769 // If P2P is not connected and there are saved networks, then restart 8770 // scanning at the normal period. This is necessary because scanning might 8771 // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS 8772 // was set to zero. 8773 if (!startPno()) { 8774 startDelayedScan(mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(), 8775 null, null); 8776 } 8777 } 8778 break; 8779 case CMD_RECONNECT: 8780 case CMD_REASSOCIATE: 8781 if (mTemporarilyDisconnectWifi) { 8782 // Drop a third party reconnect/reassociate if STA is 8783 // temporarily disconnected for p2p 8784 break; 8785 } else { 8786 // ConnectModeState handles it 8787 ret = NOT_HANDLED; 8788 } 8789 break; 8790 case CMD_SCREEN_STATE_CHANGED: 8791 handleScreenStateChanged(message.arg1 != 0, 8792 /* startBackgroundScanIfNeeded = */ true); 8793 break; 8794 default: 8795 ret = NOT_HANDLED; 8796 } 8797 return ret; 8798 } 8799 8800 @Override 8801 public void exit() { 8802 /* No need for a background scan upon exit from a disconnected state */ 8803 if (mEnableBackgroundScan) { 8804 enableBackgroundScan(false); 8805 } 8806 setScanAlarm(false); 8807 } 8808 } 8809 8810 class WpsRunningState extends State { 8811 // Tracks the source to provide a reply 8812 private Message mSourceMessage; 8813 @Override 8814 public void enter() { 8815 mSourceMessage = Message.obtain(getCurrentMessage()); 8816 } 8817 @Override 8818 public boolean processMessage(Message message) { 8819 logStateAndMessage(message, getClass().getSimpleName()); 8820 8821 switch (message.what) { 8822 case WifiMonitor.WPS_SUCCESS_EVENT: 8823 // Ignore intermediate success, wait for full connection 8824 break; 8825 case WifiMonitor.NETWORK_CONNECTION_EVENT: 8826 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 8827 mSourceMessage.recycle(); 8828 mSourceMessage = null; 8829 deferMessage(message); 8830 transitionTo(mDisconnectedState); 8831 break; 8832 case WifiMonitor.WPS_OVERLAP_EVENT: 8833 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 8834 WifiManager.WPS_OVERLAP_ERROR); 8835 mSourceMessage.recycle(); 8836 mSourceMessage = null; 8837 transitionTo(mDisconnectedState); 8838 break; 8839 case WifiMonitor.WPS_FAIL_EVENT: 8840 // Arg1 has the reason for the failure 8841 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 8842 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 8843 mSourceMessage.recycle(); 8844 mSourceMessage = null; 8845 transitionTo(mDisconnectedState); 8846 } else { 8847 if (DBG) log("Ignore unspecified fail event during WPS connection"); 8848 } 8849 break; 8850 case WifiMonitor.WPS_TIMEOUT_EVENT: 8851 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 8852 WifiManager.WPS_TIMED_OUT); 8853 mSourceMessage.recycle(); 8854 mSourceMessage = null; 8855 transitionTo(mDisconnectedState); 8856 break; 8857 case WifiManager.START_WPS: 8858 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 8859 break; 8860 case WifiManager.CANCEL_WPS: 8861 if (mWifiNative.cancelWps()) { 8862 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 8863 } else { 8864 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 8865 } 8866 transitionTo(mDisconnectedState); 8867 break; 8868 /** 8869 * Defer all commands that can cause connections to a different network 8870 * or put the state machine out of connect mode 8871 */ 8872 case CMD_STOP_DRIVER: 8873 case CMD_SET_OPERATIONAL_MODE: 8874 case WifiManager.CONNECT_NETWORK: 8875 case CMD_ENABLE_NETWORK: 8876 case CMD_RECONNECT: 8877 case CMD_REASSOCIATE: 8878 case CMD_ENABLE_ALL_NETWORKS: 8879 deferMessage(message); 8880 break; 8881 case CMD_AUTO_CONNECT: 8882 case CMD_AUTO_ROAM: 8883 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8884 return HANDLED; 8885 case CMD_START_SCAN: 8886 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8887 return HANDLED; 8888 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8889 if (DBG) log("Network connection lost"); 8890 handleNetworkDisconnect(); 8891 break; 8892 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 8893 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 8894 break; 8895 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 8896 // Disregard auth failure events during WPS connection. The 8897 // EAP sequence is retried several times, and there might be 8898 // failures (especially for wps pin). We will get a WPS_XXX 8899 // event at the end of the sequence anyway. 8900 if (DBG) log("Ignore auth failure during WPS connection"); 8901 break; 8902 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8903 // Throw away supplicant state changes when WPS is running. 8904 // We will start getting supplicant state changes once we get 8905 // a WPS success or failure 8906 break; 8907 default: 8908 return NOT_HANDLED; 8909 } 8910 return HANDLED; 8911 } 8912 8913 @Override 8914 public void exit() { 8915 mWifiConfigStore.enableAllNetworks(); 8916 mWifiConfigStore.loadConfiguredNetworks(); 8917 } 8918 } 8919 8920 class SoftApStartingState extends State { 8921 @Override 8922 public void enter() { 8923 final Message message = getCurrentMessage(); 8924 if (message.what == CMD_START_AP) { 8925 final WifiConfiguration config = (WifiConfiguration) message.obj; 8926 8927 if (config == null) { 8928 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 8929 } else { 8930 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 8931 startSoftApWithConfig(config); 8932 } 8933 } else { 8934 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 8935 } 8936 } 8937 @Override 8938 public boolean processMessage(Message message) { 8939 logStateAndMessage(message, getClass().getSimpleName()); 8940 8941 switch(message.what) { 8942 case CMD_START_SUPPLICANT: 8943 case CMD_STOP_SUPPLICANT: 8944 case CMD_START_AP: 8945 case CMD_STOP_AP: 8946 case CMD_START_DRIVER: 8947 case CMD_STOP_DRIVER: 8948 case CMD_SET_OPERATIONAL_MODE: 8949 case CMD_SET_COUNTRY_CODE: 8950 case CMD_SET_FREQUENCY_BAND: 8951 case CMD_START_PACKET_FILTERING: 8952 case CMD_STOP_PACKET_FILTERING: 8953 case CMD_TETHER_STATE_CHANGE: 8954 deferMessage(message); 8955 break; 8956 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 8957 WifiConfiguration config = (WifiConfiguration) message.obj; 8958 if (config != null) { 8959 startSoftApWithConfig(config); 8960 } else { 8961 loge("Softap config is null!"); 8962 sendMessage(CMD_START_AP_FAILURE); 8963 } 8964 break; 8965 case CMD_START_AP_SUCCESS: 8966 setWifiApState(WIFI_AP_STATE_ENABLED); 8967 transitionTo(mSoftApStartedState); 8968 break; 8969 case CMD_START_AP_FAILURE: 8970 setWifiApState(WIFI_AP_STATE_FAILED); 8971 transitionTo(mInitialState); 8972 break; 8973 default: 8974 return NOT_HANDLED; 8975 } 8976 return HANDLED; 8977 } 8978 } 8979 8980 class SoftApStartedState extends State { 8981 @Override 8982 public boolean processMessage(Message message) { 8983 logStateAndMessage(message, getClass().getSimpleName()); 8984 8985 switch(message.what) { 8986 case CMD_STOP_AP: 8987 if (DBG) log("Stopping Soft AP"); 8988 /* We have not tethered at this point, so we just shutdown soft Ap */ 8989 try { 8990 mNwService.stopAccessPoint(mInterfaceName); 8991 } catch(Exception e) { 8992 loge("Exception in stopAccessPoint()"); 8993 } 8994 setWifiApState(WIFI_AP_STATE_DISABLED); 8995 transitionTo(mInitialState); 8996 break; 8997 case CMD_START_AP: 8998 // Ignore a start on a running access point 8999 break; 9000 // Fail client mode operation when soft AP is enabled 9001 case CMD_START_SUPPLICANT: 9002 loge("Cannot start supplicant with a running soft AP"); 9003 setWifiState(WIFI_STATE_UNKNOWN); 9004 break; 9005 case CMD_TETHER_STATE_CHANGE: 9006 TetherStateChange stateChange = (TetherStateChange) message.obj; 9007 if (startTethering(stateChange.available)) { 9008 transitionTo(mTetheringState); 9009 } 9010 break; 9011 default: 9012 return NOT_HANDLED; 9013 } 9014 return HANDLED; 9015 } 9016 } 9017 9018 class TetheringState extends State { 9019 @Override 9020 public void enter() { 9021 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 9022 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 9023 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 9024 } 9025 @Override 9026 public boolean processMessage(Message message) { 9027 logStateAndMessage(message, getClass().getSimpleName()); 9028 9029 switch(message.what) { 9030 case CMD_TETHER_STATE_CHANGE: 9031 TetherStateChange stateChange = (TetherStateChange) message.obj; 9032 if (isWifiTethered(stateChange.active)) { 9033 transitionTo(mTetheredState); 9034 } 9035 return HANDLED; 9036 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 9037 if (message.arg1 == mTetherToken) { 9038 loge("Failed to get tether update, shutdown soft access point"); 9039 transitionTo(mSoftApStartedState); 9040 // Needs to be first thing handled 9041 sendMessageAtFrontOfQueue(CMD_STOP_AP); 9042 } 9043 break; 9044 case CMD_START_SUPPLICANT: 9045 case CMD_STOP_SUPPLICANT: 9046 case CMD_START_AP: 9047 case CMD_STOP_AP: 9048 case CMD_START_DRIVER: 9049 case CMD_STOP_DRIVER: 9050 case CMD_SET_OPERATIONAL_MODE: 9051 case CMD_SET_COUNTRY_CODE: 9052 case CMD_SET_FREQUENCY_BAND: 9053 case CMD_START_PACKET_FILTERING: 9054 case CMD_STOP_PACKET_FILTERING: 9055 deferMessage(message); 9056 break; 9057 default: 9058 return NOT_HANDLED; 9059 } 9060 return HANDLED; 9061 } 9062 } 9063 9064 class TetheredState extends State { 9065 @Override 9066 public boolean processMessage(Message message) { 9067 logStateAndMessage(message, getClass().getSimpleName()); 9068 9069 switch(message.what) { 9070 case CMD_TETHER_STATE_CHANGE: 9071 TetherStateChange stateChange = (TetherStateChange) message.obj; 9072 if (!isWifiTethered(stateChange.active)) { 9073 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 9074 setHostApRunning(null, false); 9075 setHostApRunning(null, true); 9076 } 9077 return HANDLED; 9078 case CMD_STOP_AP: 9079 if (DBG) log("Untethering before stopping AP"); 9080 setWifiApState(WIFI_AP_STATE_DISABLING); 9081 stopTethering(); 9082 transitionTo(mUntetheringState); 9083 // More work to do after untethering 9084 deferMessage(message); 9085 break; 9086 default: 9087 return NOT_HANDLED; 9088 } 9089 return HANDLED; 9090 } 9091 } 9092 9093 class UntetheringState extends State { 9094 @Override 9095 public void enter() { 9096 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 9097 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 9098 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 9099 9100 } 9101 @Override 9102 public boolean processMessage(Message message) { 9103 logStateAndMessage(message, getClass().getSimpleName()); 9104 9105 switch(message.what) { 9106 case CMD_TETHER_STATE_CHANGE: 9107 TetherStateChange stateChange = (TetherStateChange) message.obj; 9108 9109 /* Wait till wifi is untethered */ 9110 if (isWifiTethered(stateChange.active)) break; 9111 9112 transitionTo(mSoftApStartedState); 9113 break; 9114 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 9115 if (message.arg1 == mTetherToken) { 9116 loge("Failed to get tether update, force stop access point"); 9117 transitionTo(mSoftApStartedState); 9118 } 9119 break; 9120 case CMD_START_SUPPLICANT: 9121 case CMD_STOP_SUPPLICANT: 9122 case CMD_START_AP: 9123 case CMD_STOP_AP: 9124 case CMD_START_DRIVER: 9125 case CMD_STOP_DRIVER: 9126 case CMD_SET_OPERATIONAL_MODE: 9127 case CMD_SET_COUNTRY_CODE: 9128 case CMD_SET_FREQUENCY_BAND: 9129 case CMD_START_PACKET_FILTERING: 9130 case CMD_STOP_PACKET_FILTERING: 9131 deferMessage(message); 9132 break; 9133 default: 9134 return NOT_HANDLED; 9135 } 9136 return HANDLED; 9137 } 9138 } 9139 9140 /** 9141 * State machine initiated requests can have replyTo set to null indicating 9142 * there are no recepients, we ignore those reply actions. 9143 */ 9144 private void replyToMessage(Message msg, int what) { 9145 if (msg.replyTo == null) return; 9146 Message dstMsg = obtainMessageWithWhatAndArg2(msg, what); 9147 mReplyChannel.replyToMessage(msg, dstMsg); 9148 } 9149 9150 private void replyToMessage(Message msg, int what, int arg1) { 9151 if (msg.replyTo == null) return; 9152 Message dstMsg = obtainMessageWithWhatAndArg2(msg, what); 9153 dstMsg.arg1 = arg1; 9154 mReplyChannel.replyToMessage(msg, dstMsg); 9155 } 9156 9157 private void replyToMessage(Message msg, int what, Object obj) { 9158 if (msg.replyTo == null) return; 9159 Message dstMsg = obtainMessageWithWhatAndArg2(msg, what); 9160 dstMsg.obj = obj; 9161 mReplyChannel.replyToMessage(msg, dstMsg); 9162 } 9163 9164 /** 9165 * arg2 on the source message has a unique id that needs to be retained in replies 9166 * to match the request 9167 * <p>see WifiManager for details 9168 */ 9169 private Message obtainMessageWithWhatAndArg2(Message srcMsg, int what) { 9170 Message msg = Message.obtain(); 9171 msg.what = what; 9172 msg.arg2 = srcMsg.arg2; 9173 return msg; 9174 } 9175 9176 /** 9177 * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT 9178 * @param msg Must have a WifiConfiguration obj to succeed 9179 */ 9180 private void broadcastWifiCredentialChanged(int wifiCredentialEventType, 9181 WifiConfiguration config) { 9182 if (config != null && config.preSharedKey != null) { 9183 Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION); 9184 intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID); 9185 intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE, 9186 wifiCredentialEventType); 9187 mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT, 9188 android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE); 9189 } 9190 } 9191 9192 private static int parseHex(char ch) { 9193 if ('0' <= ch && ch <= '9') { 9194 return ch - '0'; 9195 } else if ('a' <= ch && ch <= 'f') { 9196 return ch - 'a' + 10; 9197 } else if ('A' <= ch && ch <= 'F') { 9198 return ch - 'A' + 10; 9199 } else { 9200 throw new NumberFormatException("" + ch + " is not a valid hex digit"); 9201 } 9202 } 9203 9204 private byte[] parseHex(String hex) { 9205 /* This only works for good input; don't throw bad data at it */ 9206 if (hex == null) { 9207 return new byte[0]; 9208 } 9209 9210 if (hex.length() % 2 != 0) { 9211 throw new NumberFormatException(hex + " is not a valid hex string"); 9212 } 9213 9214 byte[] result = new byte[(hex.length())/2 + 1]; 9215 result[0] = (byte) ((hex.length())/2); 9216 for (int i = 0, j = 1; i < hex.length(); i += 2, j++) { 9217 int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1)); 9218 byte b = (byte) (val & 0xFF); 9219 result[j] = b; 9220 } 9221 9222 return result; 9223 } 9224 9225 private static String makeHex(byte[] bytes) { 9226 StringBuilder sb = new StringBuilder(); 9227 for (byte b : bytes) { 9228 sb.append(String.format("%02x", b)); 9229 } 9230 return sb.toString(); 9231 } 9232 9233 private static String makeHex(byte[] bytes, int from, int len) { 9234 StringBuilder sb = new StringBuilder(); 9235 for (int i = 0; i < len; i++) { 9236 sb.append(String.format("%02x", bytes[from+i])); 9237 } 9238 return sb.toString(); 9239 } 9240 9241 private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) { 9242 9243 int len = array1.length + array2.length + array3.length; 9244 9245 if (array1.length != 0) { 9246 len++; /* add another byte for size */ 9247 } 9248 9249 if (array2.length != 0) { 9250 len++; /* add another byte for size */ 9251 } 9252 9253 if (array3.length != 0) { 9254 len++; /* add another byte for size */ 9255 } 9256 9257 byte[] result = new byte[len]; 9258 9259 int index = 0; 9260 if (array1.length != 0) { 9261 result[index] = (byte) (array1.length & 0xFF); 9262 index++; 9263 for (byte b : array1) { 9264 result[index] = b; 9265 index++; 9266 } 9267 } 9268 9269 if (array2.length != 0) { 9270 result[index] = (byte) (array2.length & 0xFF); 9271 index++; 9272 for (byte b : array2) { 9273 result[index] = b; 9274 index++; 9275 } 9276 } 9277 9278 if (array3.length != 0) { 9279 result[index] = (byte) (array3.length & 0xFF); 9280 index++; 9281 for (byte b : array3) { 9282 result[index] = b; 9283 index++; 9284 } 9285 } 9286 return result; 9287 } 9288 9289 private static byte[] concatHex(byte[] array1, byte[] array2) { 9290 9291 int len = array1.length + array2.length; 9292 9293 byte[] result = new byte[len]; 9294 9295 int index = 0; 9296 if (array1.length != 0) { 9297 for (byte b : array1) { 9298 result[index] = b; 9299 index++; 9300 } 9301 } 9302 9303 if (array2.length != 0) { 9304 for (byte b : array2) { 9305 result[index] = b; 9306 index++; 9307 } 9308 } 9309 9310 return result; 9311 } 9312 9313 void handleGsmAuthRequest(SimAuthRequestData requestData) { 9314 if (targetWificonfiguration == null 9315 || targetWificonfiguration.networkId == requestData.networkId) { 9316 logd("id matches targetWifiConfiguration"); 9317 } else { 9318 logd("id does not match targetWifiConfiguration"); 9319 return; 9320 } 9321 9322 TelephonyManager tm = (TelephonyManager) 9323 mContext.getSystemService(Context.TELEPHONY_SERVICE); 9324 9325 if (tm != null) { 9326 StringBuilder sb = new StringBuilder(); 9327 for (String challenge : requestData.data) { 9328 9329 if (challenge == null || challenge.isEmpty()) 9330 continue; 9331 logd("RAND = " + challenge); 9332 9333 byte[] rand = null; 9334 try { 9335 rand = parseHex(challenge); 9336 } catch (NumberFormatException e) { 9337 loge("malformed challenge"); 9338 continue; 9339 } 9340 9341 String base64Challenge = android.util.Base64.encodeToString( 9342 rand, android.util.Base64.NO_WRAP); 9343 /* 9344 * First, try with appType = 2 => USIM according to 9345 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx 9346 */ 9347 int appType = 2; 9348 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9349 if (tmResponse == null) { 9350 /* Then, in case of failure, issue may be due to sim type, retry as a simple sim 9351 * appType = 1 => SIM 9352 */ 9353 appType = 1; 9354 tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9355 } 9356 logv("Raw Response - " + tmResponse); 9357 9358 if (tmResponse != null && tmResponse.length() > 4) { 9359 byte[] result = android.util.Base64.decode(tmResponse, 9360 android.util.Base64.DEFAULT); 9361 logv("Hex Response -" + makeHex(result)); 9362 int sres_len = result[0]; 9363 String sres = makeHex(result, 1, sres_len); 9364 int kc_offset = 1+sres_len; 9365 int kc_len = result[kc_offset]; 9366 String kc = makeHex(result, 1+kc_offset, kc_len); 9367 sb.append(":" + kc + ":" + sres); 9368 logv("kc:" + kc + " sres:" + sres); 9369 } else { 9370 loge("bad response - " + tmResponse); 9371 } 9372 } 9373 9374 String response = sb.toString(); 9375 logv("Supplicant Response -" + response); 9376 mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response); 9377 } else { 9378 loge("could not get telephony manager"); 9379 } 9380 } 9381 9382 void handle3GAuthRequest(SimAuthRequestData requestData) { 9383 StringBuilder sb = new StringBuilder(); 9384 byte[] rand = null; 9385 byte[] authn = null; 9386 String res_type = "UMTS-AUTH"; 9387 9388 if (targetWificonfiguration == null 9389 || targetWificonfiguration.networkId == requestData.networkId) { 9390 logd("id matches targetWifiConfiguration"); 9391 } else { 9392 logd("id does not match targetWifiConfiguration"); 9393 return; 9394 } 9395 if (requestData.data.length == 2) { 9396 try { 9397 rand = parseHex(requestData.data[0]); 9398 authn = parseHex(requestData.data[1]); 9399 } catch (NumberFormatException e) { 9400 loge("malformed challenge"); 9401 } 9402 } else { 9403 loge("malformed challenge"); 9404 } 9405 9406 String tmResponse = ""; 9407 if (rand != null && authn != null) { 9408 String base64Challenge = android.util.Base64.encodeToString( 9409 concatHex(rand,authn), android.util.Base64.NO_WRAP); 9410 9411 TelephonyManager tm = (TelephonyManager) 9412 mContext.getSystemService(Context.TELEPHONY_SERVICE); 9413 if (tm != null) { 9414 int appType = 2; // 2 => USIM 9415 tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9416 logv("Raw Response - " + tmResponse); 9417 } else { 9418 loge("could not get telephony manager"); 9419 } 9420 } 9421 9422 if (tmResponse != null && tmResponse.length() > 4) { 9423 byte[] result = android.util.Base64.decode(tmResponse, 9424 android.util.Base64.DEFAULT); 9425 loge("Hex Response - " + makeHex(result)); 9426 byte tag = result[0]; 9427 if (tag == (byte) 0xdb) { 9428 logv("successful 3G authentication "); 9429 int res_len = result[1]; 9430 String res = makeHex(result, 2, res_len); 9431 int ck_len = result[res_len + 2]; 9432 String ck = makeHex(result, res_len + 3, ck_len); 9433 int ik_len = result[res_len + ck_len + 3]; 9434 String ik = makeHex(result, res_len + ck_len + 4, ik_len); 9435 sb.append(":" + ik + ":" + ck + ":" + res); 9436 logv("ik:" + ik + "ck:" + ck + " res:" + res); 9437 } else if (tag == (byte) 0xdc) { 9438 loge("synchronisation failure"); 9439 int auts_len = result[1]; 9440 String auts = makeHex(result, 2, auts_len); 9441 res_type = "UMTS-AUTS"; 9442 sb.append(":" + auts); 9443 logv("auts:" + auts); 9444 } else { 9445 loge("bad response - unknown tag = " + tag); 9446 return; 9447 } 9448 } else { 9449 loge("bad response - " + tmResponse); 9450 return; 9451 } 9452 9453 String response = sb.toString(); 9454 logv("Supplicant Response -" + response); 9455 mWifiNative.simAuthResponse(requestData.networkId, res_type, response); 9456 } 9457} 9458