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