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