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