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