1 /* 2 * Copyright (C) 2016 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 17 package com.android.server.wifi; 18 19 import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; 20 import android.net.NetworkAgent; 21 import android.net.wifi.ScanResult; 22 import android.net.wifi.SupplicantState; 23 import android.net.wifi.WifiConfiguration; 24 import android.net.wifi.WifiInfo; 25 import android.net.wifi.WifiManager; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.os.Message; 29 import android.util.Base64; 30 import android.util.Log; 31 import android.util.SparseIntArray; 32 33 import com.android.server.wifi.hotspot2.NetworkDetail; 34 import com.android.server.wifi.nano.WifiMetricsProto; 35 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent; 36 import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo; 37 import com.android.server.wifi.util.InformationElementUtil; 38 import com.android.server.wifi.util.ScanResultUtil; 39 40 import java.io.FileDescriptor; 41 import java.io.PrintWriter; 42 import java.util.ArrayList; 43 import java.util.BitSet; 44 import java.util.Calendar; 45 import java.util.LinkedList; 46 import java.util.List; 47 48 /** 49 * Provides storage for wireless connectivity metrics, as they are generated. 50 * Metrics logged by this class include: 51 * Aggregated connection stats (num of connections, num of failures, ...) 52 * Discrete connection event stats (time, duration, failure codes, ...) 53 * Router details (technology type, authentication type, ...) 54 * Scan stats 55 */ 56 public class WifiMetrics { 57 private static final String TAG = "WifiMetrics"; 58 private static final boolean DBG = false; 59 /** 60 * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL 61 */ 62 private static final int MAX_RSSI_POLL = 0; 63 private static final int MIN_RSSI_POLL = -127; 64 public static final int MAX_RSSI_DELTA = 127; 65 public static final int MIN_RSSI_DELTA = -127; 66 /** Maximum time period between ScanResult and RSSI poll to generate rssi delta datapoint */ 67 public static final long TIMEOUT_RSSI_DELTA_MILLIS = 3000; 68 private static final int MIN_WIFI_SCORE = 0; 69 private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE; 70 private final Object mLock = new Object(); 71 private static final int MAX_CONNECTION_EVENTS = 256; 72 private Clock mClock; 73 private boolean mScreenOn; 74 private int mWifiState; 75 private Handler mHandler; 76 /** 77 * Metrics are stored within an instance of the WifiLog proto during runtime, 78 * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during 79 * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced 80 * together at dump-time 81 */ 82 private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog(); 83 /** 84 * Session information that gets logged for every Wifi connection attempt. 85 */ 86 private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>(); 87 /** 88 * The latest started (but un-ended) connection attempt 89 */ 90 private ConnectionEvent mCurrentConnectionEvent; 91 /** 92 * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode 93 */ 94 private final SparseIntArray mScanReturnEntries = new SparseIntArray(); 95 /** 96 * Mapping of system state to the counts of scans requested in that wifi state * screenOn 97 * combination. Indexed by WifiLog.WifiState * (1 + screenOn) 98 */ 99 private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray(); 100 /** Mapping of RSSI values to counts. */ 101 private final SparseIntArray mRssiPollCounts = new SparseIntArray(); 102 /** Mapping of RSSI scan-poll delta values to counts. */ 103 private final SparseIntArray mRssiDeltaCounts = new SparseIntArray(); 104 /** RSSI of the scan result for the last connection event*/ 105 private int mScanResultRssi = 0; 106 /** Boot-relative timestamp when the last candidate scanresult was received, used to calculate 107 RSSI deltas. -1 designates no candidate scanResult being tracked */ 108 private long mScanResultRssiTimestampMillis = -1; 109 /** Mapping of alert reason to the respective alert count. */ 110 private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray(); 111 /** 112 * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data 113 * capture for for this WifiMetricsProto 114 */ 115 private long mRecordStartTimeSec; 116 /** Mapping of Wifi Scores to counts */ 117 private final SparseIntArray mWifiScoreCounts = new SparseIntArray(); 118 /** Mapping of SoftApManager start SoftAp return codes to counts */ 119 private final SparseIntArray mSoftApManagerReturnCodeCounts = new SparseIntArray(); 120 class RouterFingerPrint { 121 private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto; 122 RouterFingerPrint() { 123 mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint(); 124 } 125 126 public String toString() { 127 StringBuilder sb = new StringBuilder(); 128 synchronized (mLock) { 129 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType); 130 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo); 131 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim); 132 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication); 133 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden); 134 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology); 135 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6); 136 } 137 return sb.toString(); 138 } 139 public void updateFromWifiConfiguration(WifiConfiguration config) { 140 synchronized (mLock) { 141 if (config != null) { 142 // Is this a hidden network 143 mRouterFingerPrintProto.hidden = config.hiddenSSID; 144 // Config may not have a valid dtimInterval set yet, in which case dtim will be zero 145 // (These are only populated from beacon frame scan results, which are returned as 146 // scan results from the chip far less frequently than Probe-responses) 147 if (config.dtimInterval > 0) { 148 mRouterFingerPrintProto.dtim = config.dtimInterval; 149 } 150 mCurrentConnectionEvent.mConfigSsid = config.SSID; 151 // Get AuthType information from config (We do this again from ScanResult after 152 // associating with BSSID) 153 if (config.allowedKeyManagement != null 154 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) { 155 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 156 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; 157 } else if (config.isEnterprise()) { 158 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 159 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; 160 } else { 161 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 162 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 163 } 164 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 165 .passpoint = config.isPasspoint(); 166 // If there's a ScanResult candidate associated with this config already, get it and 167 // log (more accurate) metrics from it 168 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); 169 if (candidate != null) { 170 updateMetricsFromScanResult(candidate); 171 } 172 } 173 } 174 } 175 } 176 177 /** 178 * Log event, tracking the start time, end time and result of a wireless connection attempt. 179 */ 180 class ConnectionEvent { 181 WifiMetricsProto.ConnectionEvent mConnectionEvent; 182 //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field 183 //covering more than just l2 failures. see b/27652362 184 /** 185 * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot 186 * more failures than just l2 though, since the proto does not have a place to log 187 * framework failures) 188 */ 189 // Failure is unknown 190 public static final int FAILURE_UNKNOWN = 0; 191 // NONE 192 public static final int FAILURE_NONE = 1; 193 // ASSOCIATION_REJECTION_EVENT 194 public static final int FAILURE_ASSOCIATION_REJECTION = 2; 195 // AUTHENTICATION_FAILURE_EVENT 196 public static final int FAILURE_AUTHENTICATION_FAILURE = 3; 197 // SSID_TEMP_DISABLED (Also Auth failure) 198 public static final int FAILURE_SSID_TEMP_DISABLED = 4; 199 // reconnect() or reassociate() call to WifiNative failed 200 public static final int FAILURE_CONNECT_NETWORK_FAILED = 5; 201 // NETWORK_DISCONNECTION_EVENT 202 public static final int FAILURE_NETWORK_DISCONNECTION = 6; 203 // NEW_CONNECTION_ATTEMPT before previous finished 204 public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7; 205 // New connection attempt to the same network & bssid 206 public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8; 207 // Roam Watchdog timer triggered (Roaming timed out) 208 public static final int FAILURE_ROAM_TIMEOUT = 9; 209 // DHCP failure 210 public static final int FAILURE_DHCP = 10; 211 212 RouterFingerPrint mRouterFingerPrint; 213 private long mRealStartTime; 214 private long mRealEndTime; 215 private String mConfigSsid; 216 private String mConfigBssid; 217 private int mWifiState; 218 private boolean mScreenOn; 219 220 private ConnectionEvent() { 221 mConnectionEvent = new WifiMetricsProto.ConnectionEvent(); 222 mRealEndTime = 0; 223 mRealStartTime = 0; 224 mRouterFingerPrint = new RouterFingerPrint(); 225 mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto; 226 mConfigSsid = "<NULL>"; 227 mConfigBssid = "<NULL>"; 228 mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN; 229 mScreenOn = false; 230 } 231 232 public String toString() { 233 StringBuilder sb = new StringBuilder(); 234 sb.append("startTime="); 235 Calendar c = Calendar.getInstance(); 236 synchronized (mLock) { 237 c.setTimeInMillis(mConnectionEvent.startTimeMillis); 238 sb.append(mConnectionEvent.startTimeMillis == 0 ? " <null>" : 239 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 240 sb.append(", SSID="); 241 sb.append(mConfigSsid); 242 sb.append(", BSSID="); 243 sb.append(mConfigBssid); 244 sb.append(", durationMillis="); 245 sb.append(mConnectionEvent.durationTakenToConnectMillis); 246 sb.append(", roamType="); 247 switch(mConnectionEvent.roamType) { 248 case 1: 249 sb.append("ROAM_NONE"); 250 break; 251 case 2: 252 sb.append("ROAM_DBDC"); 253 break; 254 case 3: 255 sb.append("ROAM_ENTERPRISE"); 256 break; 257 case 4: 258 sb.append("ROAM_USER_SELECTED"); 259 break; 260 case 5: 261 sb.append("ROAM_UNRELATED"); 262 break; 263 default: 264 sb.append("ROAM_UNKNOWN"); 265 } 266 sb.append(", connectionResult="); 267 sb.append(mConnectionEvent.connectionResult); 268 sb.append(", level2FailureCode="); 269 switch(mConnectionEvent.level2FailureCode) { 270 case FAILURE_NONE: 271 sb.append("NONE"); 272 break; 273 case FAILURE_ASSOCIATION_REJECTION: 274 sb.append("ASSOCIATION_REJECTION"); 275 break; 276 case FAILURE_AUTHENTICATION_FAILURE: 277 sb.append("AUTHENTICATION_FAILURE"); 278 break; 279 case FAILURE_SSID_TEMP_DISABLED: 280 sb.append("SSID_TEMP_DISABLED"); 281 break; 282 case FAILURE_CONNECT_NETWORK_FAILED: 283 sb.append("CONNECT_NETWORK_FAILED"); 284 break; 285 case FAILURE_NETWORK_DISCONNECTION: 286 sb.append("NETWORK_DISCONNECTION"); 287 break; 288 case FAILURE_NEW_CONNECTION_ATTEMPT: 289 sb.append("NEW_CONNECTION_ATTEMPT"); 290 break; 291 case FAILURE_REDUNDANT_CONNECTION_ATTEMPT: 292 sb.append("REDUNDANT_CONNECTION_ATTEMPT"); 293 break; 294 case FAILURE_ROAM_TIMEOUT: 295 sb.append("ROAM_TIMEOUT"); 296 break; 297 case FAILURE_DHCP: 298 sb.append("DHCP"); 299 default: 300 sb.append("UNKNOWN"); 301 break; 302 } 303 sb.append(", connectivityLevelFailureCode="); 304 switch(mConnectionEvent.connectivityLevelFailureCode) { 305 case WifiMetricsProto.ConnectionEvent.HLF_NONE: 306 sb.append("NONE"); 307 break; 308 case WifiMetricsProto.ConnectionEvent.HLF_DHCP: 309 sb.append("DHCP"); 310 break; 311 case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET: 312 sb.append("NO_INTERNET"); 313 break; 314 case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED: 315 sb.append("UNWANTED"); 316 break; 317 default: 318 sb.append("UNKNOWN"); 319 break; 320 } 321 sb.append(", signalStrength="); 322 sb.append(mConnectionEvent.signalStrength); 323 sb.append(", wifiState="); 324 switch(mWifiState) { 325 case WifiMetricsProto.WifiLog.WIFI_DISABLED: 326 sb.append("WIFI_DISABLED"); 327 break; 328 case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED: 329 sb.append("WIFI_DISCONNECTED"); 330 break; 331 case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED: 332 sb.append("WIFI_ASSOCIATED"); 333 break; 334 default: 335 sb.append("WIFI_UNKNOWN"); 336 break; 337 } 338 sb.append(", screenOn="); 339 sb.append(mScreenOn); 340 sb.append(". mRouterFingerprint: "); 341 sb.append(mRouterFingerPrint.toString()); 342 } 343 return sb.toString(); 344 } 345 } 346 347 public WifiMetrics(Clock clock, Looper looper) { 348 mClock = clock; 349 mCurrentConnectionEvent = null; 350 mScreenOn = true; 351 mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED; 352 mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000; 353 354 mHandler = new Handler(looper) { 355 public void handleMessage(Message msg) { 356 synchronized (mLock) { 357 processMessage(msg); 358 } 359 } 360 }; 361 } 362 363 // Values used for indexing SystemStateEntries 364 private static final int SCREEN_ON = 1; 365 private static final int SCREEN_OFF = 0; 366 367 /** 368 * Create a new connection event. Call when wifi attempts to make a new network connection 369 * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity 370 * failure code. 371 * Gathers and sets the RouterFingerPrint data as well 372 * 373 * @param config WifiConfiguration of the config used for the current connection attempt 374 * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X 375 */ 376 public void startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType) { 377 synchronized (mLock) { 378 // Check if this is overlapping another current connection event 379 if (mCurrentConnectionEvent != null) { 380 //Is this new Connection Event the same as the current one 381 if (mCurrentConnectionEvent.mConfigSsid != null 382 && mCurrentConnectionEvent.mConfigBssid != null 383 && config != null 384 && mCurrentConnectionEvent.mConfigSsid.equals(config.SSID) 385 && (mCurrentConnectionEvent.mConfigBssid.equals("any") 386 || mCurrentConnectionEvent.mConfigBssid.equals(targetBSSID))) { 387 mCurrentConnectionEvent.mConfigBssid = targetBSSID; 388 // End Connection Event due to new connection attempt to the same network 389 endConnectionEvent(ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT, 390 WifiMetricsProto.ConnectionEvent.HLF_NONE); 391 } else { 392 // End Connection Event due to new connection attempt to different network 393 endConnectionEvent(ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT, 394 WifiMetricsProto.ConnectionEvent.HLF_NONE); 395 } 396 } 397 //If past maximum connection events, start removing the oldest 398 while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) { 399 mConnectionEventList.remove(0); 400 } 401 mCurrentConnectionEvent = new ConnectionEvent(); 402 mCurrentConnectionEvent.mConnectionEvent.startTimeMillis = 403 mClock.getWallClockMillis(); 404 mCurrentConnectionEvent.mConfigBssid = targetBSSID; 405 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; 406 mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config); 407 mCurrentConnectionEvent.mConfigBssid = "any"; 408 mCurrentConnectionEvent.mRealStartTime = mClock.getElapsedSinceBootMillis(); 409 mCurrentConnectionEvent.mWifiState = mWifiState; 410 mCurrentConnectionEvent.mScreenOn = mScreenOn; 411 mConnectionEventList.add(mCurrentConnectionEvent); 412 mScanResultRssiTimestampMillis = -1; 413 if (config != null) { 414 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); 415 if (candidate != null) { 416 // Cache the RSSI of the candidate, as the connection event level is updated 417 // from other sources (polls, bssid_associations) and delta requires the 418 // scanResult rssi 419 mScanResultRssi = candidate.level; 420 mScanResultRssiTimestampMillis = mClock.getElapsedSinceBootMillis(); 421 } 422 } 423 } 424 } 425 426 /** 427 * set the RoamType of the current ConnectionEvent (if any) 428 */ 429 public void setConnectionEventRoamType(int roamType) { 430 synchronized (mLock) { 431 if (mCurrentConnectionEvent != null) { 432 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; 433 } 434 } 435 } 436 437 /** 438 * Set AP related metrics from ScanDetail 439 */ 440 public void setConnectionScanDetail(ScanDetail scanDetail) { 441 synchronized (mLock) { 442 if (mCurrentConnectionEvent != null && scanDetail != null) { 443 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 444 ScanResult scanResult = scanDetail.getScanResult(); 445 //Ensure that we have a networkDetail, and that it corresponds to the currently 446 //tracked connection attempt 447 if (networkDetail != null && scanResult != null 448 && mCurrentConnectionEvent.mConfigSsid != null 449 && mCurrentConnectionEvent.mConfigSsid 450 .equals("\"" + networkDetail.getSSID() + "\"")) { 451 updateMetricsFromNetworkDetail(networkDetail); 452 updateMetricsFromScanResult(scanResult); 453 } 454 } 455 } 456 } 457 458 /** 459 * End a Connection event record. Call when wifi connection attempt succeeds or fails. 460 * If a Connection event has not been started and is active when .end is called, a new one is 461 * created with zero duration. 462 * 463 * @param level2FailureCode Level 2 failure code returned by supplicant 464 * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X 465 */ 466 public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) { 467 synchronized (mLock) { 468 if (mCurrentConnectionEvent != null) { 469 boolean result = (level2FailureCode == 1) 470 && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE); 471 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0; 472 mCurrentConnectionEvent.mRealEndTime = mClock.getElapsedSinceBootMillis(); 473 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int) 474 (mCurrentConnectionEvent.mRealEndTime 475 - mCurrentConnectionEvent.mRealStartTime); 476 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode; 477 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode = 478 connectivityFailureCode; 479 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here 480 mCurrentConnectionEvent = null; 481 if (!result) { 482 mScanResultRssiTimestampMillis = -1; 483 } 484 } 485 } 486 } 487 488 /** 489 * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail 490 */ 491 private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) { 492 int dtimInterval = networkDetail.getDtimInterval(); 493 if (dtimInterval > 0) { 494 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim = 495 dtimInterval; 496 } 497 int connectionWifiMode; 498 switch (networkDetail.getWifiMode()) { 499 case InformationElementUtil.WifiMode.MODE_UNDEFINED: 500 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN; 501 break; 502 case InformationElementUtil.WifiMode.MODE_11A: 503 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A; 504 break; 505 case InformationElementUtil.WifiMode.MODE_11B: 506 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B; 507 break; 508 case InformationElementUtil.WifiMode.MODE_11G: 509 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G; 510 break; 511 case InformationElementUtil.WifiMode.MODE_11N: 512 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N; 513 break; 514 case InformationElementUtil.WifiMode.MODE_11AC : 515 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC; 516 break; 517 default: 518 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER; 519 break; 520 } 521 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 522 .routerTechnology = connectionWifiMode; 523 } 524 525 /** 526 * Set ConnectionEvent RSSI and authentication type from ScanResult 527 */ 528 private void updateMetricsFromScanResult(ScanResult scanResult) { 529 mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level; 530 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 531 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; 532 mCurrentConnectionEvent.mConfigBssid = scanResult.BSSID; 533 if (scanResult.capabilities != null) { 534 if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) { 535 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 536 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 537 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) { 538 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 539 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 540 } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) { 541 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 542 WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; 543 } 544 } 545 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo = 546 scanResult.frequency; 547 } 548 549 void setIsLocationEnabled(boolean enabled) { 550 synchronized (mLock) { 551 mWifiLogProto.isLocationEnabled = enabled; 552 } 553 } 554 555 void setIsScanningAlwaysEnabled(boolean enabled) { 556 synchronized (mLock) { 557 mWifiLogProto.isScanningAlwaysEnabled = enabled; 558 } 559 } 560 561 /** 562 * Increment Non Empty Scan Results count 563 */ 564 public void incrementNonEmptyScanResultCount() { 565 if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount"); 566 synchronized (mLock) { 567 mWifiLogProto.numNonEmptyScanResults++; 568 } 569 } 570 571 /** 572 * Increment Empty Scan Results count 573 */ 574 public void incrementEmptyScanResultCount() { 575 if (DBG) Log.v(TAG, "incrementEmptyScanResultCount"); 576 synchronized (mLock) { 577 mWifiLogProto.numEmptyScanResults++; 578 } 579 } 580 581 /** 582 * Increment background scan count 583 */ 584 public void incrementBackgroundScanCount() { 585 if (DBG) Log.v(TAG, "incrementBackgroundScanCount"); 586 synchronized (mLock) { 587 mWifiLogProto.numBackgroundScans++; 588 } 589 } 590 591 /** 592 * Get Background scan count 593 */ 594 public int getBackgroundScanCount() { 595 synchronized (mLock) { 596 return mWifiLogProto.numBackgroundScans; 597 } 598 } 599 600 /** 601 * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry 602 */ 603 public void incrementOneshotScanCount() { 604 synchronized (mLock) { 605 mWifiLogProto.numOneshotScans++; 606 } 607 incrementWifiSystemScanStateCount(mWifiState, mScreenOn); 608 } 609 610 /** 611 * Get oneshot scan count 612 */ 613 public int getOneshotScanCount() { 614 synchronized (mLock) { 615 return mWifiLogProto.numOneshotScans; 616 } 617 } 618 619 private String returnCodeToString(int scanReturnCode) { 620 switch(scanReturnCode){ 621 case WifiMetricsProto.WifiLog.SCAN_UNKNOWN: 622 return "SCAN_UNKNOWN"; 623 case WifiMetricsProto.WifiLog.SCAN_SUCCESS: 624 return "SCAN_SUCCESS"; 625 case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED: 626 return "SCAN_FAILURE_INTERRUPTED"; 627 case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION: 628 return "SCAN_FAILURE_INVALID_CONFIGURATION"; 629 case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED: 630 return "FAILURE_WIFI_DISABLED"; 631 default: 632 return "<UNKNOWN>"; 633 } 634 } 635 636 /** 637 * Increment count of scan return code occurrence 638 * 639 * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X 640 */ 641 public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) { 642 synchronized (mLock) { 643 if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode)); 644 int entry = mScanReturnEntries.get(scanReturnCode); 645 entry += countToAdd; 646 mScanReturnEntries.put(scanReturnCode, entry); 647 } 648 } 649 /** 650 * Get the count of this scanReturnCode 651 * @param scanReturnCode that we are getting the count for 652 */ 653 public int getScanReturnEntry(int scanReturnCode) { 654 synchronized (mLock) { 655 return mScanReturnEntries.get(scanReturnCode); 656 } 657 } 658 659 private String wifiSystemStateToString(int state) { 660 switch(state){ 661 case WifiMetricsProto.WifiLog.WIFI_UNKNOWN: 662 return "WIFI_UNKNOWN"; 663 case WifiMetricsProto.WifiLog.WIFI_DISABLED: 664 return "WIFI_DISABLED"; 665 case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED: 666 return "WIFI_DISCONNECTED"; 667 case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED: 668 return "WIFI_ASSOCIATED"; 669 default: 670 return "default"; 671 } 672 } 673 674 /** 675 * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off 676 * 677 * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X 678 * @param screenOn Is the screen on 679 */ 680 public void incrementWifiSystemScanStateCount(int state, boolean screenOn) { 681 synchronized (mLock) { 682 if (DBG) { 683 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state) 684 + " " + screenOn); 685 } 686 int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF); 687 int entry = mWifiSystemStateEntries.get(index); 688 entry++; 689 mWifiSystemStateEntries.put(index, entry); 690 } 691 } 692 693 /** 694 * Get the count of this system State Entry 695 */ 696 public int getSystemStateCount(int state, boolean screenOn) { 697 synchronized (mLock) { 698 int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF); 699 return mWifiSystemStateEntries.get(index); 700 } 701 } 702 703 /** 704 * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack 705 */ 706 public void incrementNumLastResortWatchdogTriggers() { 707 synchronized (mLock) { 708 mWifiLogProto.numLastResortWatchdogTriggers++; 709 } 710 } 711 /** 712 * @param count number of networks over bad association threshold when watchdog triggered 713 */ 714 public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) { 715 synchronized (mLock) { 716 mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count; 717 } 718 } 719 /** 720 * @param count number of networks over bad authentication threshold when watchdog triggered 721 */ 722 public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) { 723 synchronized (mLock) { 724 mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count; 725 } 726 } 727 /** 728 * @param count number of networks over bad dhcp threshold when watchdog triggered 729 */ 730 public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) { 731 synchronized (mLock) { 732 mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count; 733 } 734 } 735 /** 736 * @param count number of networks over bad other threshold when watchdog triggered 737 */ 738 public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) { 739 synchronized (mLock) { 740 mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count; 741 } 742 } 743 /** 744 * @param count number of networks seen when watchdog triggered 745 */ 746 public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) { 747 synchronized (mLock) { 748 mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count; 749 } 750 } 751 /** 752 * Increment count of triggers with atleast one bad association network 753 */ 754 public void incrementNumLastResortWatchdogTriggersWithBadAssociation() { 755 synchronized (mLock) { 756 mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++; 757 } 758 } 759 /** 760 * Increment count of triggers with atleast one bad authentication network 761 */ 762 public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() { 763 synchronized (mLock) { 764 mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++; 765 } 766 } 767 /** 768 * Increment count of triggers with atleast one bad dhcp network 769 */ 770 public void incrementNumLastResortWatchdogTriggersWithBadDhcp() { 771 synchronized (mLock) { 772 mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++; 773 } 774 } 775 /** 776 * Increment count of triggers with atleast one bad other network 777 */ 778 public void incrementNumLastResortWatchdogTriggersWithBadOther() { 779 synchronized (mLock) { 780 mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++; 781 } 782 } 783 784 /** 785 * Increment number of times connectivity watchdog confirmed pno is working 786 */ 787 public void incrementNumConnectivityWatchdogPnoGood() { 788 synchronized (mLock) { 789 mWifiLogProto.numConnectivityWatchdogPnoGood++; 790 } 791 } 792 /** 793 * Increment number of times connectivity watchdog found pno not working 794 */ 795 public void incrementNumConnectivityWatchdogPnoBad() { 796 synchronized (mLock) { 797 mWifiLogProto.numConnectivityWatchdogPnoBad++; 798 } 799 } 800 /** 801 * Increment number of times connectivity watchdog confirmed background scan is working 802 */ 803 public void incrementNumConnectivityWatchdogBackgroundGood() { 804 synchronized (mLock) { 805 mWifiLogProto.numConnectivityWatchdogBackgroundGood++; 806 } 807 } 808 /** 809 * Increment number of times connectivity watchdog found background scan not working 810 */ 811 public void incrementNumConnectivityWatchdogBackgroundBad() { 812 synchronized (mLock) { 813 mWifiLogProto.numConnectivityWatchdogBackgroundBad++; 814 } 815 } 816 817 /** 818 * Increment various poll related metrics, and cache performance data for StaEvent logging 819 */ 820 public void handlePollResult(WifiInfo wifiInfo) { 821 mLastPollRssi = wifiInfo.getRssi(); 822 mLastPollLinkSpeed = wifiInfo.getLinkSpeed(); 823 mLastPollFreq = wifiInfo.getFrequency(); 824 incrementRssiPollRssiCount(mLastPollRssi); 825 } 826 827 /** 828 * Increment occurence count of RSSI level from RSSI poll. 829 * Ignores rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL] 830 */ 831 public void incrementRssiPollRssiCount(int rssi) { 832 if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) { 833 return; 834 } 835 synchronized (mLock) { 836 int count = mRssiPollCounts.get(rssi); 837 mRssiPollCounts.put(rssi, count + 1); 838 maybeIncrementRssiDeltaCount(rssi - mScanResultRssi); 839 } 840 } 841 842 /** 843 * Increment occurence count of difference between scan result RSSI and the first RSSI poll. 844 * Ignores rssi values outside the bounds of [MIN_RSSI_DELTA, MAX_RSSI_DELTA] 845 * mLock must be held when calling this method. 846 */ 847 private void maybeIncrementRssiDeltaCount(int rssi) { 848 // Check if this RSSI poll is close enough to a scan result RSSI to log a delta value 849 if (mScanResultRssiTimestampMillis >= 0) { 850 long timeDelta = mClock.getElapsedSinceBootMillis() - mScanResultRssiTimestampMillis; 851 if (timeDelta <= TIMEOUT_RSSI_DELTA_MILLIS) { 852 if (rssi >= MIN_RSSI_DELTA && rssi <= MAX_RSSI_DELTA) { 853 int count = mRssiDeltaCounts.get(rssi); 854 mRssiDeltaCounts.put(rssi, count + 1); 855 } 856 } 857 mScanResultRssiTimestampMillis = -1; 858 } 859 } 860 861 /** 862 * Increment count of Watchdog successes. 863 */ 864 public void incrementNumLastResortWatchdogSuccesses() { 865 synchronized (mLock) { 866 mWifiLogProto.numLastResortWatchdogSuccesses++; 867 } 868 } 869 870 /** 871 * Increments the count of alerts by alert reason. 872 * 873 * @param reason The cause of the alert. The reason values are driver-specific. 874 */ 875 public void incrementAlertReasonCount(int reason) { 876 if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX 877 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) { 878 reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED; 879 } 880 synchronized (mLock) { 881 int alertCount = mWifiAlertReasonCounts.get(reason); 882 mWifiAlertReasonCounts.put(reason, alertCount + 1); 883 } 884 } 885 886 /** 887 * Counts all the different types of networks seen in a set of scan results 888 */ 889 public void countScanResults(List<ScanDetail> scanDetails) { 890 if (scanDetails == null) { 891 return; 892 } 893 int totalResults = 0; 894 int openNetworks = 0; 895 int personalNetworks = 0; 896 int enterpriseNetworks = 0; 897 int hiddenNetworks = 0; 898 int hotspot2r1Networks = 0; 899 int hotspot2r2Networks = 0; 900 for (ScanDetail scanDetail : scanDetails) { 901 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 902 ScanResult scanResult = scanDetail.getScanResult(); 903 totalResults++; 904 if (networkDetail != null) { 905 if (networkDetail.isHiddenBeaconFrame()) { 906 hiddenNetworks++; 907 } 908 if (networkDetail.getHSRelease() != null) { 909 if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) { 910 hotspot2r1Networks++; 911 } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) { 912 hotspot2r2Networks++; 913 } 914 } 915 } 916 if (scanResult != null && scanResult.capabilities != null) { 917 if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) { 918 enterpriseNetworks++; 919 } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult) 920 || ScanResultUtil.isScanResultForWepNetwork(scanResult)) { 921 personalNetworks++; 922 } else { 923 openNetworks++; 924 } 925 } 926 } 927 synchronized (mLock) { 928 mWifiLogProto.numTotalScanResults += totalResults; 929 mWifiLogProto.numOpenNetworkScanResults += openNetworks; 930 mWifiLogProto.numPersonalNetworkScanResults += personalNetworks; 931 mWifiLogProto.numEnterpriseNetworkScanResults += enterpriseNetworks; 932 mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks; 933 mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks; 934 mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks; 935 mWifiLogProto.numScans++; 936 } 937 } 938 939 /** 940 * Increments occurence of a particular wifi score calculated 941 * in WifiScoreReport by current connected network. Scores are bounded 942 * within [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray 943 */ 944 public void incrementWifiScoreCount(int score) { 945 if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) { 946 return; 947 } 948 synchronized (mLock) { 949 int count = mWifiScoreCounts.get(score); 950 mWifiScoreCounts.put(score, count + 1); 951 } 952 } 953 954 /** 955 * Increments occurence of the results from attempting to start SoftAp. 956 * Maps the |result| and WifiManager |failureCode| constant to proto defined SoftApStartResult 957 * codes. 958 */ 959 public void incrementSoftApStartResult(boolean result, int failureCode) { 960 synchronized (mLock) { 961 if (result) { 962 int count = mSoftApManagerReturnCodeCounts.get( 963 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY); 964 mSoftApManagerReturnCodeCounts.put( 965 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY, 966 count + 1); 967 return; 968 } 969 970 // now increment failure modes - if not explicitly handled, dump into the general 971 // error bucket. 972 if (failureCode == WifiManager.SAP_START_FAILURE_NO_CHANNEL) { 973 int count = mSoftApManagerReturnCodeCounts.get( 974 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL); 975 mSoftApManagerReturnCodeCounts.put( 976 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL, 977 count + 1); 978 } else { 979 // failure mode not tracked at this time... count as a general error for now. 980 int count = mSoftApManagerReturnCodeCounts.get( 981 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR); 982 mSoftApManagerReturnCodeCounts.put( 983 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR, 984 count + 1); 985 } 986 } 987 } 988 989 /** 990 * Increment number of times the HAL crashed. 991 */ 992 public void incrementNumHalCrashes() { 993 synchronized (mLock) { 994 mWifiLogProto.numHalCrashes++; 995 } 996 } 997 998 /** 999 * Increment number of times the Wificond crashed. 1000 */ 1001 public void incrementNumWificondCrashes() { 1002 synchronized (mLock) { 1003 mWifiLogProto.numWificondCrashes++; 1004 } 1005 } 1006 1007 /** 1008 * Increment number of times the wifi on failed due to an error in HAL. 1009 */ 1010 public void incrementNumWifiOnFailureDueToHal() { 1011 synchronized (mLock) { 1012 mWifiLogProto.numWifiOnFailureDueToHal++; 1013 } 1014 } 1015 1016 /** 1017 * Increment number of times the wifi on failed due to an error in wificond. 1018 */ 1019 public void incrementNumWifiOnFailureDueToWificond() { 1020 synchronized (mLock) { 1021 mWifiLogProto.numWifiOnFailureDueToWificond++; 1022 } 1023 } 1024 1025 1026 public static final String PROTO_DUMP_ARG = "wifiMetricsProto"; 1027 public static final String CLEAN_DUMP_ARG = "clean"; 1028 1029 /** 1030 * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager 1031 * at this time. 1032 * 1033 * @param fd unused 1034 * @param pw PrintWriter for writing dump to 1035 * @param args unused 1036 */ 1037 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1038 synchronized (mLock) { 1039 if (args != null && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) { 1040 // Dump serialized WifiLog proto 1041 consolidateProto(true); 1042 for (ConnectionEvent event : mConnectionEventList) { 1043 if (mCurrentConnectionEvent != event) { 1044 //indicate that automatic bug report has been taken for all valid 1045 //connection events 1046 event.mConnectionEvent.automaticBugReportTaken = true; 1047 } 1048 } 1049 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto); 1050 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT); 1051 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) { 1052 // Output metrics proto bytes (base64) and nothing else 1053 pw.print(metricsProtoDump); 1054 } else { 1055 // Tag the start and end of the metrics proto bytes 1056 pw.println("WifiMetrics:"); 1057 pw.println(metricsProtoDump); 1058 pw.println("EndWifiMetrics"); 1059 } 1060 clear(); 1061 } else { 1062 pw.println("WifiMetrics:"); 1063 pw.println("mConnectionEvents:"); 1064 for (ConnectionEvent event : mConnectionEventList) { 1065 String eventLine = event.toString(); 1066 if (event == mCurrentConnectionEvent) { 1067 eventLine += "CURRENTLY OPEN EVENT"; 1068 } 1069 pw.println(eventLine); 1070 } 1071 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks); 1072 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks); 1073 pw.println("mWifiLogProto.numPersonalNetworks=" 1074 + mWifiLogProto.numPersonalNetworks); 1075 pw.println("mWifiLogProto.numEnterpriseNetworks=" 1076 + mWifiLogProto.numEnterpriseNetworks); 1077 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks); 1078 pw.println("mWifiLogProto.numPasspointNetworks=" 1079 + mWifiLogProto.numPasspointNetworks); 1080 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled); 1081 pw.println("mWifiLogProto.isScanningAlwaysEnabled=" 1082 + mWifiLogProto.isScanningAlwaysEnabled); 1083 pw.println("mWifiLogProto.numNetworksAddedByUser=" 1084 + mWifiLogProto.numNetworksAddedByUser); 1085 pw.println("mWifiLogProto.numNetworksAddedByApps=" 1086 + mWifiLogProto.numNetworksAddedByApps); 1087 pw.println("mWifiLogProto.numNonEmptyScanResults=" 1088 + mWifiLogProto.numNonEmptyScanResults); 1089 pw.println("mWifiLogProto.numEmptyScanResults=" 1090 + mWifiLogProto.numEmptyScanResults); 1091 pw.println("mWifiLogProto.numOneshotScans=" 1092 + mWifiLogProto.numOneshotScans); 1093 pw.println("mWifiLogProto.numBackgroundScans=" 1094 + mWifiLogProto.numBackgroundScans); 1095 1096 pw.println("mScanReturnEntries:"); 1097 pw.println(" SCAN_UNKNOWN: " + getScanReturnEntry( 1098 WifiMetricsProto.WifiLog.SCAN_UNKNOWN)); 1099 pw.println(" SCAN_SUCCESS: " + getScanReturnEntry( 1100 WifiMetricsProto.WifiLog.SCAN_SUCCESS)); 1101 pw.println(" SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry( 1102 WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED)); 1103 pw.println(" SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry( 1104 WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION)); 1105 pw.println(" FAILURE_WIFI_DISABLED: " + getScanReturnEntry( 1106 WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED)); 1107 1108 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>"); 1109 pw.println(" WIFI_UNKNOWN ON: " 1110 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true)); 1111 pw.println(" WIFI_DISABLED ON: " 1112 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true)); 1113 pw.println(" WIFI_DISCONNECTED ON: " 1114 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true)); 1115 pw.println(" WIFI_ASSOCIATED ON: " 1116 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true)); 1117 pw.println(" WIFI_UNKNOWN OFF: " 1118 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false)); 1119 pw.println(" WIFI_DISABLED OFF: " 1120 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false)); 1121 pw.println(" WIFI_DISCONNECTED OFF: " 1122 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false)); 1123 pw.println(" WIFI_ASSOCIATED OFF: " 1124 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false)); 1125 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood=" 1126 + mWifiLogProto.numConnectivityWatchdogPnoGood); 1127 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad=" 1128 + mWifiLogProto.numConnectivityWatchdogPnoBad); 1129 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood=" 1130 + mWifiLogProto.numConnectivityWatchdogBackgroundGood); 1131 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad=" 1132 + mWifiLogProto.numConnectivityWatchdogBackgroundBad); 1133 pw.println("mWifiLogProto.numLastResortWatchdogTriggers=" 1134 + mWifiLogProto.numLastResortWatchdogTriggers); 1135 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal=" 1136 + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal); 1137 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal=" 1138 + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal); 1139 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal=" 1140 + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal); 1141 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal=" 1142 + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal); 1143 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal=" 1144 + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal); 1145 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation=" 1146 + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation); 1147 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication=" 1148 + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication); 1149 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp=" 1150 + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp); 1151 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther=" 1152 + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther); 1153 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses=" 1154 + mWifiLogProto.numLastResortWatchdogSuccesses); 1155 pw.println("mWifiLogProto.recordDurationSec=" 1156 + ((mClock.getElapsedSinceBootMillis() / 1000) - mRecordStartTimeSec)); 1157 pw.println("mWifiLogProto.rssiPollRssiCount: Printing counts for [" + MIN_RSSI_POLL 1158 + ", " + MAX_RSSI_POLL + "]"); 1159 StringBuilder sb = new StringBuilder(); 1160 for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) { 1161 sb.append(mRssiPollCounts.get(i) + " "); 1162 } 1163 pw.println(" " + sb.toString()); 1164 pw.println("mWifiLogProto.rssiPollDeltaCount: Printing counts for [" 1165 + MIN_RSSI_DELTA + ", " + MAX_RSSI_DELTA + "]"); 1166 sb.setLength(0); 1167 for (int i = MIN_RSSI_DELTA; i <= MAX_RSSI_DELTA; i++) { 1168 sb.append(mRssiDeltaCounts.get(i) + " "); 1169 } 1170 pw.println(" " + sb.toString()); 1171 pw.print("mWifiLogProto.alertReasonCounts="); 1172 sb.setLength(0); 1173 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN; 1174 i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) { 1175 int count = mWifiAlertReasonCounts.get(i); 1176 if (count > 0) { 1177 sb.append("(" + i + "," + count + "),"); 1178 } 1179 } 1180 if (sb.length() > 1) { 1181 sb.setLength(sb.length() - 1); // strip trailing comma 1182 pw.println(sb.toString()); 1183 } else { 1184 pw.println("()"); 1185 } 1186 pw.println("mWifiLogProto.numTotalScanResults=" 1187 + mWifiLogProto.numTotalScanResults); 1188 pw.println("mWifiLogProto.numOpenNetworkScanResults=" 1189 + mWifiLogProto.numOpenNetworkScanResults); 1190 pw.println("mWifiLogProto.numPersonalNetworkScanResults=" 1191 + mWifiLogProto.numPersonalNetworkScanResults); 1192 pw.println("mWifiLogProto.numEnterpriseNetworkScanResults=" 1193 + mWifiLogProto.numEnterpriseNetworkScanResults); 1194 pw.println("mWifiLogProto.numHiddenNetworkScanResults=" 1195 + mWifiLogProto.numHiddenNetworkScanResults); 1196 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults=" 1197 + mWifiLogProto.numHotspot2R1NetworkScanResults); 1198 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults=" 1199 + mWifiLogProto.numHotspot2R2NetworkScanResults); 1200 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans); 1201 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", " 1202 + MAX_WIFI_SCORE + "]"); 1203 for (int i = 0; i <= MAX_WIFI_SCORE; i++) { 1204 pw.print(mWifiScoreCounts.get(i) + " "); 1205 } 1206 pw.println(); // add a line after wifi scores 1207 pw.println("mWifiLogProto.SoftApManagerReturnCodeCounts:"); 1208 pw.println(" SUCCESS: " + mSoftApManagerReturnCodeCounts.get( 1209 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY)); 1210 pw.println(" FAILED_GENERAL_ERROR: " + mSoftApManagerReturnCodeCounts.get( 1211 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR)); 1212 pw.println(" FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get( 1213 WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL)); 1214 pw.print("\n"); 1215 pw.println("mWifiLogProto.numHalCrashes=" 1216 + mWifiLogProto.numHalCrashes); 1217 pw.println("mWifiLogProto.numWificondCrashes=" 1218 + mWifiLogProto.numWificondCrashes); 1219 pw.println("mWifiLogProto.numWifiOnFailureDueToHal=" 1220 + mWifiLogProto.numWifiOnFailureDueToHal); 1221 pw.println("mWifiLogProto.numWifiOnFailureDueToWificond=" 1222 + mWifiLogProto.numWifiOnFailureDueToWificond); 1223 pw.println("StaEventList:"); 1224 for (StaEvent event : mStaEventList) { 1225 pw.println(staEventToString(event)); 1226 } 1227 } 1228 } 1229 } 1230 1231 1232 /** 1233 * Update various counts of saved network types 1234 * @param networks List of WifiConfigurations representing all saved networks, must not be null 1235 */ 1236 public void updateSavedNetworks(List<WifiConfiguration> networks) { 1237 synchronized (mLock) { 1238 mWifiLogProto.numSavedNetworks = networks.size(); 1239 mWifiLogProto.numOpenNetworks = 0; 1240 mWifiLogProto.numPersonalNetworks = 0; 1241 mWifiLogProto.numEnterpriseNetworks = 0; 1242 mWifiLogProto.numNetworksAddedByUser = 0; 1243 mWifiLogProto.numNetworksAddedByApps = 0; 1244 mWifiLogProto.numHiddenNetworks = 0; 1245 mWifiLogProto.numPasspointNetworks = 0; 1246 for (WifiConfiguration config : networks) { 1247 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) { 1248 mWifiLogProto.numOpenNetworks++; 1249 } else if (config.isEnterprise()) { 1250 mWifiLogProto.numEnterpriseNetworks++; 1251 } else { 1252 mWifiLogProto.numPersonalNetworks++; 1253 } 1254 if (config.selfAdded) { 1255 mWifiLogProto.numNetworksAddedByUser++; 1256 } else { 1257 mWifiLogProto.numNetworksAddedByApps++; 1258 } 1259 if (config.hiddenSSID) { 1260 mWifiLogProto.numHiddenNetworks++; 1261 } 1262 if (config.isPasspoint()) { 1263 mWifiLogProto.numPasspointNetworks++; 1264 } 1265 } 1266 } 1267 } 1268 1269 /** 1270 * append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their 1271 * respective lists within mWifiLogProto 1272 * 1273 * @param incremental Only include ConnectionEvents created since last automatic bug report 1274 */ 1275 private void consolidateProto(boolean incremental) { 1276 List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>(); 1277 List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>(); 1278 List<WifiMetricsProto.RssiPollCount> rssiDeltas = new ArrayList<>(); 1279 List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>(); 1280 List<WifiMetricsProto.WifiScoreCount> scores = new ArrayList<>(); 1281 synchronized (mLock) { 1282 for (ConnectionEvent event : mConnectionEventList) { 1283 // If this is not incremental, dump full ConnectionEvent list 1284 // Else Dump all un-dumped events except for the current one 1285 if (!incremental || ((mCurrentConnectionEvent != event) 1286 && !event.mConnectionEvent.automaticBugReportTaken)) { 1287 //Get all ConnectionEvents that haven not been dumped as a proto, also exclude 1288 //the current active un-ended connection event 1289 events.add(event.mConnectionEvent); 1290 if (incremental) { 1291 event.mConnectionEvent.automaticBugReportTaken = true; 1292 } 1293 } 1294 } 1295 if (events.size() > 0) { 1296 mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent); 1297 } 1298 1299 //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list 1300 mWifiLogProto.scanReturnEntries = 1301 new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()]; 1302 for (int i = 0; i < mScanReturnEntries.size(); i++) { 1303 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry(); 1304 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i); 1305 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i); 1306 } 1307 1308 // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list 1309 // This one is slightly more complex, as the Sparse are indexed with: 1310 // key: wifiState * 2 + isScreenOn, value: wifiStateCount 1311 mWifiLogProto.wifiSystemStateEntries = 1312 new WifiMetricsProto.WifiLog 1313 .WifiSystemStateEntry[mWifiSystemStateEntries.size()]; 1314 for (int i = 0; i < mWifiSystemStateEntries.size(); i++) { 1315 mWifiLogProto.wifiSystemStateEntries[i] = 1316 new WifiMetricsProto.WifiLog.WifiSystemStateEntry(); 1317 mWifiLogProto.wifiSystemStateEntries[i].wifiState = 1318 mWifiSystemStateEntries.keyAt(i) / 2; 1319 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount = 1320 mWifiSystemStateEntries.valueAt(i); 1321 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn = 1322 (mWifiSystemStateEntries.keyAt(i) % 2) > 0; 1323 } 1324 mWifiLogProto.recordDurationSec = (int) ((mClock.getElapsedSinceBootMillis() / 1000) 1325 - mRecordStartTimeSec); 1326 1327 /** 1328 * Convert the SparseIntArray of RSSI poll rssi's and counts to the proto's repeated 1329 * IntKeyVal array. 1330 */ 1331 for (int i = 0; i < mRssiPollCounts.size(); i++) { 1332 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount(); 1333 keyVal.rssi = mRssiPollCounts.keyAt(i); 1334 keyVal.count = mRssiPollCounts.valueAt(i); 1335 rssis.add(keyVal); 1336 } 1337 mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount); 1338 1339 /** 1340 * Convert the SparseIntArray of RSSI delta rssi's and counts to the proto's repeated 1341 * IntKeyVal array. 1342 */ 1343 for (int i = 0; i < mRssiDeltaCounts.size(); i++) { 1344 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount(); 1345 keyVal.rssi = mRssiDeltaCounts.keyAt(i); 1346 keyVal.count = mRssiDeltaCounts.valueAt(i); 1347 rssiDeltas.add(keyVal); 1348 } 1349 mWifiLogProto.rssiPollDeltaCount = rssiDeltas.toArray(mWifiLogProto.rssiPollDeltaCount); 1350 1351 /** 1352 * Convert the SparseIntArray of alert reasons and counts to the proto's repeated 1353 * IntKeyVal array. 1354 */ 1355 for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) { 1356 WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount(); 1357 keyVal.reason = mWifiAlertReasonCounts.keyAt(i); 1358 keyVal.count = mWifiAlertReasonCounts.valueAt(i); 1359 alertReasons.add(keyVal); 1360 } 1361 mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount); 1362 1363 /** 1364 * Convert the SparseIntArray of Wifi Score and counts to proto's repeated 1365 * IntKeyVal array. 1366 */ 1367 for (int score = 0; score < mWifiScoreCounts.size(); score++) { 1368 WifiMetricsProto.WifiScoreCount keyVal = new WifiMetricsProto.WifiScoreCount(); 1369 keyVal.score = mWifiScoreCounts.keyAt(score); 1370 keyVal.count = mWifiScoreCounts.valueAt(score); 1371 scores.add(keyVal); 1372 } 1373 mWifiLogProto.wifiScoreCount = scores.toArray(mWifiLogProto.wifiScoreCount); 1374 1375 /** 1376 * Convert the SparseIntArray of SoftAp Return codes and counts to proto's repeated 1377 * IntKeyVal array. 1378 */ 1379 int codeCounts = mSoftApManagerReturnCodeCounts.size(); 1380 mWifiLogProto.softApReturnCode = new WifiMetricsProto.SoftApReturnCodeCount[codeCounts]; 1381 for (int sapCode = 0; sapCode < codeCounts; sapCode++) { 1382 mWifiLogProto.softApReturnCode[sapCode] = 1383 new WifiMetricsProto.SoftApReturnCodeCount(); 1384 mWifiLogProto.softApReturnCode[sapCode].startResult = 1385 mSoftApManagerReturnCodeCounts.keyAt(sapCode); 1386 mWifiLogProto.softApReturnCode[sapCode].count = 1387 mSoftApManagerReturnCodeCounts.valueAt(sapCode); 1388 } 1389 1390 mWifiLogProto.staEventList = mStaEventList.toArray(mWifiLogProto.staEventList); 1391 } 1392 } 1393 1394 /** 1395 * Clear all WifiMetrics, except for currentConnectionEvent. 1396 */ 1397 private void clear() { 1398 synchronized (mLock) { 1399 mConnectionEventList.clear(); 1400 if (mCurrentConnectionEvent != null) { 1401 mConnectionEventList.add(mCurrentConnectionEvent); 1402 } 1403 mScanReturnEntries.clear(); 1404 mWifiSystemStateEntries.clear(); 1405 mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000; 1406 mRssiPollCounts.clear(); 1407 mRssiDeltaCounts.clear(); 1408 mWifiAlertReasonCounts.clear(); 1409 mWifiScoreCounts.clear(); 1410 mWifiLogProto.clear(); 1411 mScanResultRssiTimestampMillis = -1; 1412 mSoftApManagerReturnCodeCounts.clear(); 1413 mStaEventList.clear(); 1414 } 1415 } 1416 1417 /** 1418 * Set screen state (On/Off) 1419 */ 1420 public void setScreenState(boolean screenOn) { 1421 synchronized (mLock) { 1422 mScreenOn = screenOn; 1423 } 1424 } 1425 1426 /** 1427 * Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED) 1428 */ 1429 public void setWifiState(int wifiState) { 1430 synchronized (mLock) { 1431 mWifiState = wifiState; 1432 } 1433 } 1434 1435 /** 1436 * Message handler for interesting WifiMonitor messages. Generates StaEvents 1437 */ 1438 private void processMessage(Message msg) { 1439 StaEvent event = new StaEvent(); 1440 boolean logEvent = true; 1441 switch (msg.what) { 1442 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 1443 event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT; 1444 event.associationTimedOut = msg.arg1 > 0 ? true : false; 1445 event.status = msg.arg2; 1446 break; 1447 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 1448 event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT; 1449 switch (msg.arg2) { 1450 case WifiManager.ERROR_AUTH_FAILURE_NONE: 1451 event.authFailureReason = StaEvent.AUTH_FAILURE_NONE; 1452 break; 1453 case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT: 1454 event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT; 1455 break; 1456 case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD: 1457 event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD; 1458 break; 1459 case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE: 1460 event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE; 1461 break; 1462 default: 1463 break; 1464 } 1465 break; 1466 case WifiMonitor.NETWORK_CONNECTION_EVENT: 1467 event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT; 1468 break; 1469 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 1470 event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT; 1471 event.reason = msg.arg2; 1472 event.localGen = msg.arg1 == 0 ? false : true; 1473 break; 1474 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 1475 logEvent = false; 1476 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 1477 mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state); 1478 break; 1479 case WifiStateMachine.CMD_ASSOCIATED_BSSID: 1480 event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID; 1481 break; 1482 case WifiStateMachine.CMD_TARGET_BSSID: 1483 event.type = StaEvent.TYPE_CMD_TARGET_BSSID; 1484 break; 1485 default: 1486 return; 1487 } 1488 if (logEvent) { 1489 addStaEvent(event); 1490 } 1491 } 1492 /** 1493 * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant 1494 * generated event types, which are logged through 'sendMessage' 1495 * @param type StaEvent.EventType describing the event 1496 */ 1497 public void logStaEvent(int type) { 1498 logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, null); 1499 } 1500 /** 1501 * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant 1502 * generated event types, which are logged through 'sendMessage' 1503 * @param type StaEvent.EventType describing the event 1504 * @param config WifiConfiguration for a framework initiated connection attempt 1505 */ 1506 public void logStaEvent(int type, WifiConfiguration config) { 1507 logStaEvent(type, StaEvent.DISCONNECT_UNKNOWN, config); 1508 } 1509 /** 1510 * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant 1511 * generated event types, which are logged through 'sendMessage' 1512 * @param type StaEvent.EventType describing the event 1513 * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework 1514 * initiated a FRAMEWORK_DISCONNECT 1515 */ 1516 public void logStaEvent(int type, int frameworkDisconnectReason) { 1517 logStaEvent(type, frameworkDisconnectReason, null); 1518 } 1519 /** 1520 * Log a StaEvent from WifiStateMachine. The StaEvent must not be one of the supplicant 1521 * generated event types, which are logged through 'sendMessage' 1522 * @param type StaEvent.EventType describing the event 1523 * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework 1524 * initiated a FRAMEWORK_DISCONNECT 1525 * @param config WifiConfiguration for a framework initiated connection attempt 1526 */ 1527 public void logStaEvent(int type, int frameworkDisconnectReason, WifiConfiguration config) { 1528 switch (type) { 1529 case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL: 1530 case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST: 1531 case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST: 1532 case StaEvent.TYPE_CMD_START_CONNECT: 1533 case StaEvent.TYPE_CMD_START_ROAM: 1534 case StaEvent.TYPE_CONNECT_NETWORK: 1535 case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK: 1536 case StaEvent.TYPE_FRAMEWORK_DISCONNECT: 1537 break; 1538 default: 1539 Log.e(TAG, "Unknown StaEvent:" + type); 1540 return; 1541 } 1542 StaEvent event = new StaEvent(); 1543 event.type = type; 1544 if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) { 1545 event.frameworkDisconnectReason = frameworkDisconnectReason; 1546 } 1547 event.configInfo = createConfigInfo(config); 1548 addStaEvent(event); 1549 } 1550 1551 private void addStaEvent(StaEvent staEvent) { 1552 staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis(); 1553 staEvent.lastRssi = mLastPollRssi; 1554 staEvent.lastFreq = mLastPollFreq; 1555 staEvent.lastLinkSpeed = mLastPollLinkSpeed; 1556 staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask; 1557 mSupplicantStateChangeBitmask = 0; 1558 mLastPollRssi = -127; 1559 mLastPollFreq = -1; 1560 mLastPollLinkSpeed = -1; 1561 mStaEventList.add(staEvent); 1562 // Prune StaEventList if it gets too long 1563 if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove(); 1564 } 1565 1566 private ConfigInfo createConfigInfo(WifiConfiguration config) { 1567 if (config == null) return null; 1568 ConfigInfo info = new ConfigInfo(); 1569 info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement); 1570 info.allowedProtocols = bitSetToInt(config.allowedProtocols); 1571 info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms); 1572 info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers); 1573 info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers); 1574 info.hiddenSsid = config.hiddenSSID; 1575 info.isPasspoint = config.isPasspoint(); 1576 info.isEphemeral = config.isEphemeral(); 1577 info.hasEverConnected = config.getNetworkSelectionStatus().getHasEverConnected(); 1578 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); 1579 if (candidate != null) { 1580 info.scanRssi = candidate.level; 1581 info.scanFreq = candidate.frequency; 1582 } 1583 return info; 1584 } 1585 1586 public Handler getHandler() { 1587 return mHandler; 1588 } 1589 1590 // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask 1591 // and attach it to the next event which is generated. 1592 private int mSupplicantStateChangeBitmask = 0; 1593 1594 /** 1595 * Converts a SupplicantState value to a single bit, with position defined by 1596 * {@code StaEvent.SupplicantState} 1597 */ 1598 public static int supplicantStateToBit(SupplicantState state) { 1599 switch(state) { 1600 case DISCONNECTED: 1601 return 1 << StaEvent.STATE_DISCONNECTED; 1602 case INTERFACE_DISABLED: 1603 return 1 << StaEvent.STATE_INTERFACE_DISABLED; 1604 case INACTIVE: 1605 return 1 << StaEvent.STATE_INACTIVE; 1606 case SCANNING: 1607 return 1 << StaEvent.STATE_SCANNING; 1608 case AUTHENTICATING: 1609 return 1 << StaEvent.STATE_AUTHENTICATING; 1610 case ASSOCIATING: 1611 return 1 << StaEvent.STATE_ASSOCIATING; 1612 case ASSOCIATED: 1613 return 1 << StaEvent.STATE_ASSOCIATED; 1614 case FOUR_WAY_HANDSHAKE: 1615 return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE; 1616 case GROUP_HANDSHAKE: 1617 return 1 << StaEvent.STATE_GROUP_HANDSHAKE; 1618 case COMPLETED: 1619 return 1 << StaEvent.STATE_COMPLETED; 1620 case DORMANT: 1621 return 1 << StaEvent.STATE_DORMANT; 1622 case UNINITIALIZED: 1623 return 1 << StaEvent.STATE_UNINITIALIZED; 1624 case INVALID: 1625 return 1 << StaEvent.STATE_INVALID; 1626 default: 1627 Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal()); 1628 return 0; 1629 } 1630 } 1631 1632 private static String supplicantStateChangesBitmaskToString(int mask) { 1633 StringBuilder sb = new StringBuilder(); 1634 sb.append("SUPPLICANT_STATE_CHANGE_EVENTS: {"); 1635 if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED"); 1636 if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED"); 1637 if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE"); 1638 if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING"); 1639 if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING"); 1640 if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING"); 1641 if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED"); 1642 if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE"); 1643 if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE"); 1644 if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED"); 1645 if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT"); 1646 if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED"); 1647 if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID"); 1648 sb.append("}"); 1649 return sb.toString(); 1650 } 1651 1652 /** 1653 * Returns a human readable string from a Sta Event. Only adds information relevant to the event 1654 * type. 1655 */ 1656 public static String staEventToString(StaEvent event) { 1657 if (event == null) return "<NULL>"; 1658 StringBuilder sb = new StringBuilder(); 1659 Long time = event.startTimeMillis; 1660 sb.append(String.format("%9d ", time.longValue())).append(" "); 1661 switch (event.type) { 1662 case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT: 1663 sb.append("ASSOCIATION_REJECTION_EVENT:") 1664 .append(" timedOut=").append(event.associationTimedOut) 1665 .append(" status=").append(event.status).append(":") 1666 .append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status)); 1667 break; 1668 case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT: 1669 sb.append("AUTHENTICATION_FAILURE_EVENT: reason=").append(event.authFailureReason) 1670 .append(":").append(authFailureReasonToString(event.authFailureReason)); 1671 break; 1672 case StaEvent.TYPE_NETWORK_CONNECTION_EVENT: 1673 sb.append("NETWORK_CONNECTION_EVENT:"); 1674 break; 1675 case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT: 1676 sb.append("NETWORK_DISCONNECTION_EVENT:") 1677 .append(" local_gen=").append(event.localGen) 1678 .append(" reason=").append(event.reason).append(":") 1679 .append(ISupplicantStaIfaceCallback.ReasonCode.toString( 1680 (event.reason >= 0 ? event.reason : -1 * event.reason))); 1681 break; 1682 case StaEvent.TYPE_CMD_ASSOCIATED_BSSID: 1683 sb.append("CMD_ASSOCIATED_BSSID:"); 1684 break; 1685 case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL: 1686 sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL:"); 1687 break; 1688 case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST: 1689 sb.append("CMD_IP_CONFIGURATION_LOST:"); 1690 break; 1691 case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST: 1692 sb.append("CMD_IP_REACHABILITY_LOST:"); 1693 break; 1694 case StaEvent.TYPE_CMD_TARGET_BSSID: 1695 sb.append("CMD_TARGET_BSSID:"); 1696 break; 1697 case StaEvent.TYPE_CMD_START_CONNECT: 1698 sb.append("CMD_START_CONNECT:"); 1699 break; 1700 case StaEvent.TYPE_CMD_START_ROAM: 1701 sb.append("CMD_START_ROAM:"); 1702 break; 1703 case StaEvent.TYPE_CONNECT_NETWORK: 1704 sb.append("CONNECT_NETWORK:"); 1705 break; 1706 case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK: 1707 sb.append("NETWORK_AGENT_VALID_NETWORK:"); 1708 break; 1709 case StaEvent.TYPE_FRAMEWORK_DISCONNECT: 1710 sb.append("FRAMEWORK_DISCONNECT:") 1711 .append(" reason=") 1712 .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason)); 1713 break; 1714 default: 1715 sb.append("UNKNOWN " + event.type + ":"); 1716 break; 1717 } 1718 if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi); 1719 if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq); 1720 if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed); 1721 if (event.supplicantStateChangesBitmask != 0) { 1722 sb.append("\n ").append(supplicantStateChangesBitmaskToString( 1723 event.supplicantStateChangesBitmask)); 1724 } 1725 if (event.configInfo != null) { 1726 sb.append("\n ").append(configInfoToString(event.configInfo)); 1727 } 1728 1729 return sb.toString(); 1730 } 1731 1732 private static String authFailureReasonToString(int authFailureReason) { 1733 switch (authFailureReason) { 1734 case StaEvent.AUTH_FAILURE_NONE: 1735 return "ERROR_AUTH_FAILURE_NONE"; 1736 case StaEvent.AUTH_FAILURE_TIMEOUT: 1737 return "ERROR_AUTH_FAILURE_TIMEOUT"; 1738 case StaEvent.AUTH_FAILURE_WRONG_PSWD: 1739 return "ERROR_AUTH_FAILURE_WRONG_PSWD"; 1740 case StaEvent.AUTH_FAILURE_EAP_FAILURE: 1741 return "ERROR_AUTH_FAILURE_EAP_FAILURE"; 1742 default: 1743 return ""; 1744 } 1745 } 1746 1747 private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) { 1748 switch (frameworkDisconnectReason) { 1749 case StaEvent.DISCONNECT_API: 1750 return "DISCONNECT_API"; 1751 case StaEvent.DISCONNECT_GENERIC: 1752 return "DISCONNECT_GENERIC"; 1753 case StaEvent.DISCONNECT_UNWANTED: 1754 return "DISCONNECT_UNWANTED"; 1755 case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER: 1756 return "DISCONNECT_ROAM_WATCHDOG_TIMER"; 1757 case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST: 1758 return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST"; 1759 case StaEvent.DISCONNECT_RESET_SIM_NETWORKS: 1760 return "DISCONNECT_RESET_SIM_NETWORKS"; 1761 default: 1762 return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason; 1763 } 1764 } 1765 1766 private static String configInfoToString(ConfigInfo info) { 1767 StringBuilder sb = new StringBuilder(); 1768 sb.append("ConfigInfo:") 1769 .append(" allowed_key_management=").append(info.allowedKeyManagement) 1770 .append(" allowed_protocols=").append(info.allowedProtocols) 1771 .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms) 1772 .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers) 1773 .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers) 1774 .append(" hidden_ssid=").append(info.hiddenSsid) 1775 .append(" is_passpoint=").append(info.isPasspoint) 1776 .append(" is_ephemeral=").append(info.isEphemeral) 1777 .append(" has_ever_connected=").append(info.hasEverConnected) 1778 .append(" scan_rssi=").append(info.scanRssi) 1779 .append(" scan_freq=").append(info.scanFreq); 1780 return sb.toString(); 1781 } 1782 1783 public static final int MAX_STA_EVENTS = 512; 1784 private LinkedList<StaEvent> mStaEventList = new LinkedList<StaEvent>(); 1785 private int mLastPollRssi = -127; 1786 private int mLastPollLinkSpeed = -1; 1787 private int mLastPollFreq = -1; 1788 1789 /** 1790 * Converts the first 31 bits of a BitSet to a little endian int 1791 */ 1792 private static int bitSetToInt(BitSet bits) { 1793 int value = 0; 1794 int nBits = bits.length() < 31 ? bits.length() : 31; 1795 for (int i = 0; i < nBits; i++) { 1796 value += bits.get(i) ? (1 << i) : 0; 1797 } 1798 return value; 1799 } 1800 } 1801