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