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