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