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.net.NetworkAgent; 20 import android.net.wifi.ScanResult; 21 import android.net.wifi.WifiConfiguration; 22 import android.util.Base64; 23 import android.util.Log; 24 import android.util.SparseIntArray; 25 26 import com.android.server.wifi.hotspot2.NetworkDetail; 27 import com.android.server.wifi.util.InformationElementUtil; 28 29 import java.io.FileDescriptor; 30 import java.io.PrintWriter; 31 import java.util.ArrayList; 32 import java.util.Calendar; 33 import java.util.List; 34 35 /** 36 * Provides storage for wireless connectivity metrics, as they are generated. 37 * Metrics logged by this class include: 38 * Aggregated connection stats (num of connections, num of failures, ...) 39 * Discrete connection event stats (time, duration, failure codes, ...) 40 * Router details (technology type, authentication type, ...) 41 * Scan stats 42 */ 43 public class WifiMetrics { 44 private static final String TAG = "WifiMetrics"; 45 private static final boolean DBG = false; 46 /** 47 * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL 48 */ 49 private static final int MAX_RSSI_POLL = 0; 50 private static final int MIN_RSSI_POLL = -127; 51 private static final int MIN_WIFI_SCORE = 0; 52 private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE; 53 private final Object mLock = new Object(); 54 private static final int MAX_CONNECTION_EVENTS = 256; 55 private Clock mClock; 56 private boolean mScreenOn; 57 private int mWifiState; 58 /** 59 * Metrics are stored within an instance of the WifiLog proto during runtime, 60 * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during 61 * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced 62 * together at dump-time 63 */ 64 private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog(); 65 /** 66 * Session information that gets logged for every Wifi connection attempt. 67 */ 68 private final List<ConnectionEvent> mConnectionEventList = new ArrayList<>(); 69 /** 70 * The latest started (but un-ended) connection attempt 71 */ 72 private ConnectionEvent mCurrentConnectionEvent; 73 /** 74 * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode 75 */ 76 private final SparseIntArray mScanReturnEntries = new SparseIntArray(); 77 /** 78 * Mapping of system state to the counts of scans requested in that wifi state * screenOn 79 * combination. Indexed by WifiLog.WifiState * (1 + screenOn) 80 */ 81 private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray(); 82 /** Mapping of RSSI values to counts. */ 83 private final SparseIntArray mRssiPollCounts = new SparseIntArray(); 84 /** Mapping of alert reason to the respective alert count. */ 85 private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray(); 86 /** 87 * Records the elapsedRealtime (in seconds) that represents the beginning of data 88 * capture for for this WifiMetricsProto 89 */ 90 private long mRecordStartTimeSec; 91 /** Mapping of Wifi Scores to counts */ 92 private final SparseIntArray mWifiScoreCounts = new SparseIntArray(); 93 class RouterFingerPrint { 94 private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto; 95 RouterFingerPrint() { 96 mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint(); 97 } 98 99 public String toString() { 100 StringBuilder sb = new StringBuilder(); 101 synchronized (mLock) { 102 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType); 103 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo); 104 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim); 105 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication); 106 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden); 107 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology); 108 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6); 109 } 110 return sb.toString(); 111 } 112 public void updateFromWifiConfiguration(WifiConfiguration config) { 113 synchronized (mLock) { 114 if (config != null) { 115 // Is this a hidden network 116 mRouterFingerPrintProto.hidden = config.hiddenSSID; 117 // Config may not have a valid dtimInterval set yet, in which case dtim will be zero 118 // (These are only populated from beacon frame scan results, which are returned as 119 // scan results from the chip far less frequently than Probe-responses) 120 if (config.dtimInterval > 0) { 121 mRouterFingerPrintProto.dtim = config.dtimInterval; 122 } 123 mCurrentConnectionEvent.mConfigSsid = config.SSID; 124 // Get AuthType information from config (We do this again from ScanResult after 125 // associating with BSSID) 126 if (config.allowedKeyManagement != null 127 && config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) { 128 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 129 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; 130 } else if (config.isEnterprise()) { 131 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 132 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; 133 } else { 134 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 135 .authentication = WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 136 } 137 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 138 .passpoint = config.isPasspoint(); 139 // If there's a ScanResult candidate associated with this config already, get it and 140 // log (more accurate) metrics from it 141 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); 142 if (candidate != null) { 143 updateMetricsFromScanResult(candidate); 144 } 145 } 146 } 147 } 148 } 149 150 /** 151 * Log event, tracking the start time, end time and result of a wireless connection attempt. 152 */ 153 class ConnectionEvent { 154 WifiMetricsProto.ConnectionEvent mConnectionEvent; 155 //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field 156 //covering more than just l2 failures. see b/27652362 157 /** 158 * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot 159 * more failures than just l2 though, since the proto does not have a place to log 160 * framework failures) 161 */ 162 // Failure is unknown 163 public static final int FAILURE_UNKNOWN = 0; 164 // NONE 165 public static final int FAILURE_NONE = 1; 166 // ASSOCIATION_REJECTION_EVENT 167 public static final int FAILURE_ASSOCIATION_REJECTION = 2; 168 // AUTHENTICATION_FAILURE_EVENT 169 public static final int FAILURE_AUTHENTICATION_FAILURE = 3; 170 // SSID_TEMP_DISABLED (Also Auth failure) 171 public static final int FAILURE_SSID_TEMP_DISABLED = 4; 172 // reconnect() or reassociate() call to WifiNative failed 173 public static final int FAILURE_CONNECT_NETWORK_FAILED = 5; 174 // NETWORK_DISCONNECTION_EVENT 175 public static final int FAILURE_NETWORK_DISCONNECTION = 6; 176 // NEW_CONNECTION_ATTEMPT before previous finished 177 public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7; 178 // New connection attempt to the same network & bssid 179 public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8; 180 // Roam Watchdog timer triggered (Roaming timed out) 181 public static final int FAILURE_ROAM_TIMEOUT = 9; 182 // DHCP failure 183 public static final int FAILURE_DHCP = 10; 184 185 RouterFingerPrint mRouterFingerPrint; 186 private long mRealStartTime; 187 private long mRealEndTime; 188 private String mConfigSsid; 189 private String mConfigBssid; 190 private int mWifiState; 191 private boolean mScreenOn; 192 193 private ConnectionEvent() { 194 mConnectionEvent = new WifiMetricsProto.ConnectionEvent(); 195 mRealEndTime = 0; 196 mRealStartTime = 0; 197 mRouterFingerPrint = new RouterFingerPrint(); 198 mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto; 199 mConfigSsid = "<NULL>"; 200 mConfigBssid = "<NULL>"; 201 mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN; 202 mScreenOn = false; 203 } 204 205 public String toString() { 206 StringBuilder sb = new StringBuilder(); 207 sb.append("startTime="); 208 Calendar c = Calendar.getInstance(); 209 synchronized (mLock) { 210 c.setTimeInMillis(mConnectionEvent.startTimeMillis); 211 sb.append(mConnectionEvent.startTimeMillis == 0 ? " <null>" : 212 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 213 sb.append(", SSID="); 214 sb.append(mConfigSsid); 215 sb.append(", BSSID="); 216 sb.append(mConfigBssid); 217 sb.append(", durationMillis="); 218 sb.append(mConnectionEvent.durationTakenToConnectMillis); 219 sb.append(", roamType="); 220 switch(mConnectionEvent.roamType) { 221 case 1: 222 sb.append("ROAM_NONE"); 223 break; 224 case 2: 225 sb.append("ROAM_DBDC"); 226 break; 227 case 3: 228 sb.append("ROAM_ENTERPRISE"); 229 break; 230 case 4: 231 sb.append("ROAM_USER_SELECTED"); 232 break; 233 case 5: 234 sb.append("ROAM_UNRELATED"); 235 break; 236 default: 237 sb.append("ROAM_UNKNOWN"); 238 } 239 sb.append(", connectionResult="); 240 sb.append(mConnectionEvent.connectionResult); 241 sb.append(", level2FailureCode="); 242 switch(mConnectionEvent.level2FailureCode) { 243 case FAILURE_NONE: 244 sb.append("NONE"); 245 break; 246 case FAILURE_ASSOCIATION_REJECTION: 247 sb.append("ASSOCIATION_REJECTION"); 248 break; 249 case FAILURE_AUTHENTICATION_FAILURE: 250 sb.append("AUTHENTICATION_FAILURE"); 251 break; 252 case FAILURE_SSID_TEMP_DISABLED: 253 sb.append("SSID_TEMP_DISABLED"); 254 break; 255 case FAILURE_CONNECT_NETWORK_FAILED: 256 sb.append("CONNECT_NETWORK_FAILED"); 257 break; 258 case FAILURE_NETWORK_DISCONNECTION: 259 sb.append("NETWORK_DISCONNECTION"); 260 break; 261 case FAILURE_NEW_CONNECTION_ATTEMPT: 262 sb.append("NEW_CONNECTION_ATTEMPT"); 263 break; 264 case FAILURE_REDUNDANT_CONNECTION_ATTEMPT: 265 sb.append("REDUNDANT_CONNECTION_ATTEMPT"); 266 break; 267 case FAILURE_ROAM_TIMEOUT: 268 sb.append("ROAM_TIMEOUT"); 269 break; 270 case FAILURE_DHCP: 271 sb.append("DHCP"); 272 default: 273 sb.append("UNKNOWN"); 274 break; 275 } 276 sb.append(", connectivityLevelFailureCode="); 277 switch(mConnectionEvent.connectivityLevelFailureCode) { 278 case WifiMetricsProto.ConnectionEvent.HLF_NONE: 279 sb.append("NONE"); 280 break; 281 case WifiMetricsProto.ConnectionEvent.HLF_DHCP: 282 sb.append("DHCP"); 283 break; 284 case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET: 285 sb.append("NO_INTERNET"); 286 break; 287 case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED: 288 sb.append("UNWANTED"); 289 break; 290 default: 291 sb.append("UNKNOWN"); 292 break; 293 } 294 sb.append(", signalStrength="); 295 sb.append(mConnectionEvent.signalStrength); 296 sb.append(", wifiState="); 297 switch(mWifiState) { 298 case WifiMetricsProto.WifiLog.WIFI_DISABLED: 299 sb.append("WIFI_DISABLED"); 300 break; 301 case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED: 302 sb.append("WIFI_DISCONNECTED"); 303 break; 304 case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED: 305 sb.append("WIFI_ASSOCIATED"); 306 break; 307 default: 308 sb.append("WIFI_UNKNOWN"); 309 break; 310 } 311 sb.append(", screenOn="); 312 sb.append(mScreenOn); 313 sb.append(". mRouterFingerprint: "); 314 sb.append(mRouterFingerPrint.toString()); 315 } 316 return sb.toString(); 317 } 318 } 319 320 public WifiMetrics(Clock clock) { 321 mClock = clock; 322 mCurrentConnectionEvent = null; 323 mScreenOn = true; 324 mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED; 325 mRecordStartTimeSec = mClock.elapsedRealtime() / 1000; 326 } 327 328 // Values used for indexing SystemStateEntries 329 private static final int SCREEN_ON = 1; 330 private static final int SCREEN_OFF = 0; 331 332 /** 333 * Create a new connection event. Call when wifi attempts to make a new network connection 334 * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity 335 * failure code. 336 * Gathers and sets the RouterFingerPrint data as well 337 * 338 * @param config WifiConfiguration of the config used for the current connection attempt 339 * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X 340 */ 341 public void startConnectionEvent(WifiConfiguration config, String targetBSSID, int roamType) { 342 synchronized (mLock) { 343 // Check if this is overlapping another current connection event 344 if (mCurrentConnectionEvent != null) { 345 //Is this new Connection Event the same as the current one 346 if (mCurrentConnectionEvent.mConfigSsid != null 347 && mCurrentConnectionEvent.mConfigBssid != null 348 && config != null 349 && mCurrentConnectionEvent.mConfigSsid.equals(config.SSID) 350 && (mCurrentConnectionEvent.mConfigBssid.equals("any") 351 || mCurrentConnectionEvent.mConfigBssid.equals(targetBSSID))) { 352 mCurrentConnectionEvent.mConfigBssid = targetBSSID; 353 // End Connection Event due to new connection attempt to the same network 354 endConnectionEvent(ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT, 355 WifiMetricsProto.ConnectionEvent.HLF_NONE); 356 } else { 357 // End Connection Event due to new connection attempt to different network 358 endConnectionEvent(ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT, 359 WifiMetricsProto.ConnectionEvent.HLF_NONE); 360 } 361 } 362 //If past maximum connection events, start removing the oldest 363 while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) { 364 mConnectionEventList.remove(0); 365 } 366 mCurrentConnectionEvent = new ConnectionEvent(); 367 mCurrentConnectionEvent.mConnectionEvent.startTimeMillis = 368 mClock.currentTimeMillis(); 369 mCurrentConnectionEvent.mConfigBssid = targetBSSID; 370 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; 371 mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config); 372 mCurrentConnectionEvent.mConfigBssid = "any"; 373 mCurrentConnectionEvent.mRealStartTime = mClock.elapsedRealtime(); 374 mCurrentConnectionEvent.mWifiState = mWifiState; 375 mCurrentConnectionEvent.mScreenOn = mScreenOn; 376 mConnectionEventList.add(mCurrentConnectionEvent); 377 } 378 } 379 380 /** 381 * set the RoamType of the current ConnectionEvent (if any) 382 */ 383 public void setConnectionEventRoamType(int roamType) { 384 synchronized (mLock) { 385 if (mCurrentConnectionEvent != null) { 386 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; 387 } 388 } 389 } 390 391 /** 392 * Set AP related metrics from ScanDetail 393 */ 394 public void setConnectionScanDetail(ScanDetail scanDetail) { 395 synchronized (mLock) { 396 if (mCurrentConnectionEvent != null && scanDetail != null) { 397 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 398 ScanResult scanResult = scanDetail.getScanResult(); 399 //Ensure that we have a networkDetail, and that it corresponds to the currently 400 //tracked connection attempt 401 if (networkDetail != null && scanResult != null 402 && mCurrentConnectionEvent.mConfigSsid != null 403 && mCurrentConnectionEvent.mConfigSsid 404 .equals("\"" + networkDetail.getSSID() + "\"")) { 405 updateMetricsFromNetworkDetail(networkDetail); 406 updateMetricsFromScanResult(scanResult); 407 } 408 } 409 } 410 } 411 412 /** 413 * End a Connection event record. Call when wifi connection attempt succeeds or fails. 414 * If a Connection event has not been started and is active when .end is called, a new one is 415 * created with zero duration. 416 * 417 * @param level2FailureCode Level 2 failure code returned by supplicant 418 * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X 419 */ 420 public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) { 421 synchronized (mLock) { 422 if (mCurrentConnectionEvent != null) { 423 boolean result = (level2FailureCode == 1) 424 && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE); 425 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0; 426 mCurrentConnectionEvent.mRealEndTime = mClock.elapsedRealtime(); 427 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int) 428 (mCurrentConnectionEvent.mRealEndTime 429 - mCurrentConnectionEvent.mRealStartTime); 430 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode; 431 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode = 432 connectivityFailureCode; 433 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here 434 mCurrentConnectionEvent = null; 435 } 436 } 437 } 438 439 /** 440 * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail 441 */ 442 private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) { 443 int dtimInterval = networkDetail.getDtimInterval(); 444 if (dtimInterval > 0) { 445 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim = 446 dtimInterval; 447 } 448 int connectionWifiMode; 449 switch (networkDetail.getWifiMode()) { 450 case InformationElementUtil.WifiMode.MODE_UNDEFINED: 451 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN; 452 break; 453 case InformationElementUtil.WifiMode.MODE_11A: 454 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A; 455 break; 456 case InformationElementUtil.WifiMode.MODE_11B: 457 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B; 458 break; 459 case InformationElementUtil.WifiMode.MODE_11G: 460 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G; 461 break; 462 case InformationElementUtil.WifiMode.MODE_11N: 463 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N; 464 break; 465 case InformationElementUtil.WifiMode.MODE_11AC : 466 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC; 467 break; 468 default: 469 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER; 470 break; 471 } 472 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 473 .routerTechnology = connectionWifiMode; 474 } 475 476 /** 477 * Set ConnectionEvent RSSI and authentication type from ScanResult 478 */ 479 private void updateMetricsFromScanResult(ScanResult scanResult) { 480 mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level; 481 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 482 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; 483 mCurrentConnectionEvent.mConfigBssid = scanResult.BSSID; 484 if (scanResult.capabilities != null) { 485 if (scanResult.capabilities.contains("WEP")) { 486 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 487 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 488 } else if (scanResult.capabilities.contains("PSK")) { 489 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 490 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 491 } else if (scanResult.capabilities.contains("EAP")) { 492 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 493 WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; 494 } 495 } 496 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo = 497 scanResult.frequency; 498 } 499 500 void setNumSavedNetworks(int num) { 501 synchronized (mLock) { 502 mWifiLogProto.numSavedNetworks = num; 503 } 504 } 505 506 void setNumOpenNetworks(int num) { 507 synchronized (mLock) { 508 mWifiLogProto.numOpenNetworks = num; 509 } 510 } 511 512 void setNumPersonalNetworks(int num) { 513 synchronized (mLock) { 514 mWifiLogProto.numPersonalNetworks = num; 515 } 516 } 517 518 void setNumEnterpriseNetworks(int num) { 519 synchronized (mLock) { 520 mWifiLogProto.numEnterpriseNetworks = num; 521 } 522 } 523 524 void setNumHiddenNetworks(int num) { 525 synchronized (mLock) { 526 mWifiLogProto.numHiddenNetworks = num; 527 } 528 } 529 530 void setNumPasspointNetworks(int num) { 531 synchronized (mLock) { 532 mWifiLogProto.numPasspointNetworks = num; 533 } 534 } 535 536 void setNumNetworksAddedByUser(int num) { 537 synchronized (mLock) { 538 mWifiLogProto.numNetworksAddedByUser = num; 539 } 540 } 541 542 void setNumNetworksAddedByApps(int num) { 543 synchronized (mLock) { 544 mWifiLogProto.numNetworksAddedByApps = num; 545 } 546 } 547 548 void setIsLocationEnabled(boolean enabled) { 549 synchronized (mLock) { 550 mWifiLogProto.isLocationEnabled = enabled; 551 } 552 } 553 554 void setIsScanningAlwaysEnabled(boolean enabled) { 555 synchronized (mLock) { 556 mWifiLogProto.isScanningAlwaysEnabled = enabled; 557 } 558 } 559 560 /** 561 * Increment Non Empty Scan Results count 562 */ 563 public void incrementNonEmptyScanResultCount() { 564 if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount"); 565 synchronized (mLock) { 566 mWifiLogProto.numNonEmptyScanResults++; 567 } 568 } 569 570 /** 571 * Increment Empty Scan Results count 572 */ 573 public void incrementEmptyScanResultCount() { 574 if (DBG) Log.v(TAG, "incrementEmptyScanResultCount"); 575 synchronized (mLock) { 576 mWifiLogProto.numEmptyScanResults++; 577 } 578 } 579 580 /** 581 * Increment background scan count 582 */ 583 public void incrementBackgroundScanCount() { 584 if (DBG) Log.v(TAG, "incrementBackgroundScanCount"); 585 synchronized (mLock) { 586 mWifiLogProto.numBackgroundScans++; 587 } 588 } 589 590 /** 591 * Get Background scan count 592 */ 593 public int getBackgroundScanCount() { 594 synchronized (mLock) { 595 return mWifiLogProto.numBackgroundScans; 596 } 597 } 598 599 /** 600 * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry 601 */ 602 public void incrementOneshotScanCount() { 603 synchronized (mLock) { 604 mWifiLogProto.numOneshotScans++; 605 } 606 incrementWifiSystemScanStateCount(mWifiState, mScreenOn); 607 } 608 609 /** 610 * Get oneshot scan count 611 */ 612 public int getOneshotScanCount() { 613 synchronized (mLock) { 614 return mWifiLogProto.numOneshotScans; 615 } 616 } 617 618 private String returnCodeToString(int scanReturnCode) { 619 switch(scanReturnCode){ 620 case WifiMetricsProto.WifiLog.SCAN_UNKNOWN: 621 return "SCAN_UNKNOWN"; 622 case WifiMetricsProto.WifiLog.SCAN_SUCCESS: 623 return "SCAN_SUCCESS"; 624 case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED: 625 return "SCAN_FAILURE_INTERRUPTED"; 626 case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION: 627 return "SCAN_FAILURE_INVALID_CONFIGURATION"; 628 case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED: 629 return "FAILURE_WIFI_DISABLED"; 630 default: 631 return "<UNKNOWN>"; 632 } 633 } 634 635 /** 636 * Increment count of scan return code occurrence 637 * 638 * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X 639 */ 640 public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) { 641 synchronized (mLock) { 642 if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode)); 643 int entry = mScanReturnEntries.get(scanReturnCode); 644 entry += countToAdd; 645 mScanReturnEntries.put(scanReturnCode, entry); 646 } 647 } 648 /** 649 * Get the count of this scanReturnCode 650 * @param scanReturnCode that we are getting the count for 651 */ 652 public int getScanReturnEntry(int scanReturnCode) { 653 synchronized (mLock) { 654 return mScanReturnEntries.get(scanReturnCode); 655 } 656 } 657 658 private String wifiSystemStateToString(int state) { 659 switch(state){ 660 case WifiMetricsProto.WifiLog.WIFI_UNKNOWN: 661 return "WIFI_UNKNOWN"; 662 case WifiMetricsProto.WifiLog.WIFI_DISABLED: 663 return "WIFI_DISABLED"; 664 case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED: 665 return "WIFI_DISCONNECTED"; 666 case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED: 667 return "WIFI_ASSOCIATED"; 668 default: 669 return "default"; 670 } 671 } 672 673 /** 674 * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off 675 * 676 * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X 677 * @param screenOn Is the screen on 678 */ 679 public void incrementWifiSystemScanStateCount(int state, boolean screenOn) { 680 synchronized (mLock) { 681 if (DBG) { 682 Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state) 683 + " " + screenOn); 684 } 685 int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF); 686 int entry = mWifiSystemStateEntries.get(index); 687 entry++; 688 mWifiSystemStateEntries.put(index, entry); 689 } 690 } 691 692 /** 693 * Get the count of this system State Entry 694 */ 695 public int getSystemStateCount(int state, boolean screenOn) { 696 synchronized (mLock) { 697 int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF); 698 return mWifiSystemStateEntries.get(index); 699 } 700 } 701 702 /** 703 * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack 704 */ 705 public void incrementNumLastResortWatchdogTriggers() { 706 synchronized (mLock) { 707 mWifiLogProto.numLastResortWatchdogTriggers++; 708 } 709 } 710 /** 711 * @param count number of networks over bad association threshold when watchdog triggered 712 */ 713 public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) { 714 synchronized (mLock) { 715 mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count; 716 } 717 } 718 /** 719 * @param count number of networks over bad authentication threshold when watchdog triggered 720 */ 721 public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) { 722 synchronized (mLock) { 723 mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count; 724 } 725 } 726 /** 727 * @param count number of networks over bad dhcp threshold when watchdog triggered 728 */ 729 public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) { 730 synchronized (mLock) { 731 mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count; 732 } 733 } 734 /** 735 * @param count number of networks over bad other threshold when watchdog triggered 736 */ 737 public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) { 738 synchronized (mLock) { 739 mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count; 740 } 741 } 742 /** 743 * @param count number of networks seen when watchdog triggered 744 */ 745 public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) { 746 synchronized (mLock) { 747 mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count; 748 } 749 } 750 /** 751 * Increment count of triggers with atleast one bad association network 752 */ 753 public void incrementNumLastResortWatchdogTriggersWithBadAssociation() { 754 synchronized (mLock) { 755 mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++; 756 } 757 } 758 /** 759 * Increment count of triggers with atleast one bad authentication network 760 */ 761 public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() { 762 synchronized (mLock) { 763 mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++; 764 } 765 } 766 /** 767 * Increment count of triggers with atleast one bad dhcp network 768 */ 769 public void incrementNumLastResortWatchdogTriggersWithBadDhcp() { 770 synchronized (mLock) { 771 mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++; 772 } 773 } 774 /** 775 * Increment count of triggers with atleast one bad other network 776 */ 777 public void incrementNumLastResortWatchdogTriggersWithBadOther() { 778 synchronized (mLock) { 779 mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++; 780 } 781 } 782 783 /** 784 * Increment number of times connectivity watchdog confirmed pno is working 785 */ 786 public void incrementNumConnectivityWatchdogPnoGood() { 787 synchronized (mLock) { 788 mWifiLogProto.numConnectivityWatchdogPnoGood++; 789 } 790 } 791 /** 792 * Increment number of times connectivity watchdog found pno not working 793 */ 794 public void incrementNumConnectivityWatchdogPnoBad() { 795 synchronized (mLock) { 796 mWifiLogProto.numConnectivityWatchdogPnoBad++; 797 } 798 } 799 /** 800 * Increment number of times connectivity watchdog confirmed background scan is working 801 */ 802 public void incrementNumConnectivityWatchdogBackgroundGood() { 803 synchronized (mLock) { 804 mWifiLogProto.numConnectivityWatchdogBackgroundGood++; 805 } 806 } 807 /** 808 * Increment number of times connectivity watchdog found background scan not working 809 */ 810 public void incrementNumConnectivityWatchdogBackgroundBad() { 811 synchronized (mLock) { 812 mWifiLogProto.numConnectivityWatchdogBackgroundBad++; 813 } 814 } 815 816 /** 817 * Increment occurence count of RSSI level from RSSI poll. 818 * Ignores rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL] 819 */ 820 public void incrementRssiPollRssiCount(int rssi) { 821 if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) { 822 return; 823 } 824 synchronized (mLock) { 825 int count = mRssiPollCounts.get(rssi); 826 mRssiPollCounts.put(rssi, count + 1); 827 } 828 } 829 830 /** 831 * Increment count of Watchdog successes. 832 */ 833 public void incrementNumLastResortWatchdogSuccesses() { 834 synchronized (mLock) { 835 mWifiLogProto.numLastResortWatchdogSuccesses++; 836 } 837 } 838 839 /** 840 * Increments the count of alerts by alert reason. 841 * 842 * @param reason The cause of the alert. The reason values are driver-specific. 843 */ 844 public void incrementAlertReasonCount(int reason) { 845 if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX 846 || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) { 847 reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED; 848 } 849 synchronized (mLock) { 850 int alertCount = mWifiAlertReasonCounts.get(reason); 851 mWifiAlertReasonCounts.put(reason, alertCount + 1); 852 } 853 } 854 855 /** 856 * Counts all the different types of networks seen in a set of scan results 857 */ 858 public void countScanResults(List<ScanDetail> scanDetails) { 859 if (scanDetails == null) { 860 return; 861 } 862 int totalResults = 0; 863 int openNetworks = 0; 864 int personalNetworks = 0; 865 int enterpriseNetworks = 0; 866 int hiddenNetworks = 0; 867 int hotspot2r1Networks = 0; 868 int hotspot2r2Networks = 0; 869 for (ScanDetail scanDetail : scanDetails) { 870 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 871 ScanResult scanResult = scanDetail.getScanResult(); 872 totalResults++; 873 if (networkDetail != null) { 874 if (networkDetail.isHiddenBeaconFrame()) { 875 hiddenNetworks++; 876 } 877 if (networkDetail.getHSRelease() != null) { 878 if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) { 879 hotspot2r1Networks++; 880 } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) { 881 hotspot2r2Networks++; 882 } 883 } 884 } 885 if (scanResult != null && scanResult.capabilities != null) { 886 if (scanResult.capabilities.contains("EAP")) { 887 enterpriseNetworks++; 888 } else if (scanResult.capabilities.contains("PSK") 889 || scanResult.capabilities.contains("WEP")) { 890 personalNetworks++; 891 } else { 892 openNetworks++; 893 } 894 } 895 } 896 synchronized (mLock) { 897 mWifiLogProto.numTotalScanResults += totalResults; 898 mWifiLogProto.numOpenNetworkScanResults += openNetworks; 899 mWifiLogProto.numPersonalNetworkScanResults += personalNetworks; 900 mWifiLogProto.numEnterpriseNetworkScanResults += enterpriseNetworks; 901 mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks; 902 mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks; 903 mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks; 904 mWifiLogProto.numScans++; 905 } 906 } 907 908 /** 909 * Increments occurence of a particular wifi score calculated 910 * in WifiScoreReport by current connected network. Scores are bounded 911 * within [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray 912 */ 913 public void incrementWifiScoreCount(int score) { 914 if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) { 915 return; 916 } 917 synchronized (mLock) { 918 int count = mWifiScoreCounts.get(score); 919 mWifiScoreCounts.put(score, count + 1); 920 } 921 } 922 923 public static final String PROTO_DUMP_ARG = "wifiMetricsProto"; 924 public static final String CLEAN_DUMP_ARG = "clean"; 925 926 /** 927 * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager 928 * at this time. 929 * 930 * @param fd unused 931 * @param pw PrintWriter for writing dump to 932 * @param args unused 933 */ 934 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 935 synchronized (mLock) { 936 if (args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) { 937 // Dump serialized WifiLog proto 938 consolidateProto(true); 939 for (ConnectionEvent event : mConnectionEventList) { 940 if (mCurrentConnectionEvent != event) { 941 //indicate that automatic bug report has been taken for all valid 942 //connection events 943 event.mConnectionEvent.automaticBugReportTaken = true; 944 } 945 } 946 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto); 947 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT); 948 if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) { 949 // Output metrics proto bytes (base64) and nothing else 950 pw.print(metricsProtoDump); 951 } else { 952 // Tag the start and end of the metrics proto bytes 953 pw.println("WifiMetrics:"); 954 pw.println(metricsProtoDump); 955 pw.println("EndWifiMetrics"); 956 } 957 clear(); 958 } else { 959 pw.println("WifiMetrics:"); 960 pw.println("mConnectionEvents:"); 961 for (ConnectionEvent event : mConnectionEventList) { 962 String eventLine = event.toString(); 963 if (event == mCurrentConnectionEvent) { 964 eventLine += "CURRENTLY OPEN EVENT"; 965 } 966 pw.println(eventLine); 967 } 968 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks); 969 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks); 970 pw.println("mWifiLogProto.numPersonalNetworks=" 971 + mWifiLogProto.numPersonalNetworks); 972 pw.println("mWifiLogProto.numEnterpriseNetworks=" 973 + mWifiLogProto.numEnterpriseNetworks); 974 pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks); 975 pw.println("mWifiLogProto.numPasspointNetworks=" 976 + mWifiLogProto.numPasspointNetworks); 977 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled); 978 pw.println("mWifiLogProto.isScanningAlwaysEnabled=" 979 + mWifiLogProto.isScanningAlwaysEnabled); 980 pw.println("mWifiLogProto.numNetworksAddedByUser=" 981 + mWifiLogProto.numNetworksAddedByUser); 982 pw.println("mWifiLogProto.numNetworksAddedByApps=" 983 + mWifiLogProto.numNetworksAddedByApps); 984 pw.println("mWifiLogProto.numNonEmptyScanResults=" 985 + mWifiLogProto.numNonEmptyScanResults); 986 pw.println("mWifiLogProto.numEmptyScanResults=" 987 + mWifiLogProto.numEmptyScanResults); 988 pw.println("mWifiLogProto.numOneshotScans=" 989 + mWifiLogProto.numOneshotScans); 990 pw.println("mWifiLogProto.numBackgroundScans=" 991 + mWifiLogProto.numBackgroundScans); 992 993 pw.println("mScanReturnEntries:"); 994 pw.println(" SCAN_UNKNOWN: " + getScanReturnEntry( 995 WifiMetricsProto.WifiLog.SCAN_UNKNOWN)); 996 pw.println(" SCAN_SUCCESS: " + getScanReturnEntry( 997 WifiMetricsProto.WifiLog.SCAN_SUCCESS)); 998 pw.println(" SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry( 999 WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED)); 1000 pw.println(" SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry( 1001 WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION)); 1002 pw.println(" FAILURE_WIFI_DISABLED: " + getScanReturnEntry( 1003 WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED)); 1004 1005 pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>"); 1006 pw.println(" WIFI_UNKNOWN ON: " 1007 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true)); 1008 pw.println(" WIFI_DISABLED ON: " 1009 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true)); 1010 pw.println(" WIFI_DISCONNECTED ON: " 1011 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true)); 1012 pw.println(" WIFI_ASSOCIATED ON: " 1013 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true)); 1014 pw.println(" WIFI_UNKNOWN OFF: " 1015 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false)); 1016 pw.println(" WIFI_DISABLED OFF: " 1017 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false)); 1018 pw.println(" WIFI_DISCONNECTED OFF: " 1019 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false)); 1020 pw.println(" WIFI_ASSOCIATED OFF: " 1021 + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false)); 1022 pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood=" 1023 + mWifiLogProto.numConnectivityWatchdogPnoGood); 1024 pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad=" 1025 + mWifiLogProto.numConnectivityWatchdogPnoBad); 1026 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood=" 1027 + mWifiLogProto.numConnectivityWatchdogBackgroundGood); 1028 pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad=" 1029 + mWifiLogProto.numConnectivityWatchdogBackgroundBad); 1030 pw.println("mWifiLogProto.numLastResortWatchdogTriggers=" 1031 + mWifiLogProto.numLastResortWatchdogTriggers); 1032 pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal=" 1033 + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal); 1034 pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal=" 1035 + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal); 1036 pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal=" 1037 + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal); 1038 pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal=" 1039 + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal); 1040 pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal=" 1041 + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal); 1042 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation=" 1043 + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation); 1044 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication=" 1045 + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication); 1046 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp=" 1047 + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp); 1048 pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther=" 1049 + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther); 1050 pw.println("mWifiLogProto.numLastResortWatchdogSuccesses=" 1051 + mWifiLogProto.numLastResortWatchdogSuccesses); 1052 pw.println("mWifiLogProto.recordDurationSec=" 1053 + ((mClock.elapsedRealtime() / 1000) - mRecordStartTimeSec)); 1054 pw.println("mWifiLogProto.rssiPollRssiCount: Printing counts for [" + MIN_RSSI_POLL 1055 + ", " + MAX_RSSI_POLL + "]"); 1056 StringBuilder sb = new StringBuilder(); 1057 for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) { 1058 sb.append(mRssiPollCounts.get(i) + " "); 1059 } 1060 pw.println(" " + sb.toString()); 1061 pw.print("mWifiLogProto.alertReasonCounts="); 1062 sb.setLength(0); 1063 for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN; 1064 i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) { 1065 int count = mWifiAlertReasonCounts.get(i); 1066 if (count > 0) { 1067 sb.append("(" + i + "," + count + "),"); 1068 } 1069 } 1070 if (sb.length() > 1) { 1071 sb.setLength(sb.length() - 1); // strip trailing comma 1072 pw.println(sb.toString()); 1073 } else { 1074 pw.println("()"); 1075 } 1076 pw.println("mWifiLogProto.numTotalScanResults=" 1077 + mWifiLogProto.numTotalScanResults); 1078 pw.println("mWifiLogProto.numOpenNetworkScanResults=" 1079 + mWifiLogProto.numOpenNetworkScanResults); 1080 pw.println("mWifiLogProto.numPersonalNetworkScanResults=" 1081 + mWifiLogProto.numPersonalNetworkScanResults); 1082 pw.println("mWifiLogProto.numEnterpriseNetworkScanResults=" 1083 + mWifiLogProto.numEnterpriseNetworkScanResults); 1084 pw.println("mWifiLogProto.numHiddenNetworkScanResults=" 1085 + mWifiLogProto.numHiddenNetworkScanResults); 1086 pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults=" 1087 + mWifiLogProto.numHotspot2R1NetworkScanResults); 1088 pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults=" 1089 + mWifiLogProto.numHotspot2R2NetworkScanResults); 1090 pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans); 1091 pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", " 1092 + MAX_WIFI_SCORE + "]"); 1093 for (int i = 0; i <= MAX_WIFI_SCORE; i++) { 1094 pw.print(mWifiScoreCounts.get(i) + " "); 1095 } 1096 pw.print("\n"); 1097 } 1098 } 1099 } 1100 1101 /** 1102 * append the separate ConnectionEvent, SystemStateEntry and ScanReturnCode collections to their 1103 * respective lists within mWifiLogProto 1104 * 1105 * @param incremental Only include ConnectionEvents created since last automatic bug report 1106 */ 1107 private void consolidateProto(boolean incremental) { 1108 List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>(); 1109 List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>(); 1110 List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>(); 1111 List<WifiMetricsProto.WifiScoreCount> scores = new ArrayList<>(); 1112 synchronized (mLock) { 1113 for (ConnectionEvent event : mConnectionEventList) { 1114 // If this is not incremental, dump full ConnectionEvent list 1115 // Else Dump all un-dumped events except for the current one 1116 if (!incremental || ((mCurrentConnectionEvent != event) 1117 && !event.mConnectionEvent.automaticBugReportTaken)) { 1118 //Get all ConnectionEvents that haven not been dumped as a proto, also exclude 1119 //the current active un-ended connection event 1120 events.add(event.mConnectionEvent); 1121 if (incremental) { 1122 event.mConnectionEvent.automaticBugReportTaken = true; 1123 } 1124 } 1125 } 1126 if (events.size() > 0) { 1127 mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent); 1128 } 1129 1130 //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list 1131 mWifiLogProto.scanReturnEntries = 1132 new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()]; 1133 for (int i = 0; i < mScanReturnEntries.size(); i++) { 1134 mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry(); 1135 mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i); 1136 mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i); 1137 } 1138 1139 // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list 1140 // This one is slightly more complex, as the Sparse are indexed with: 1141 // key: wifiState * 2 + isScreenOn, value: wifiStateCount 1142 mWifiLogProto.wifiSystemStateEntries = 1143 new WifiMetricsProto.WifiLog 1144 .WifiSystemStateEntry[mWifiSystemStateEntries.size()]; 1145 for (int i = 0; i < mWifiSystemStateEntries.size(); i++) { 1146 mWifiLogProto.wifiSystemStateEntries[i] = 1147 new WifiMetricsProto.WifiLog.WifiSystemStateEntry(); 1148 mWifiLogProto.wifiSystemStateEntries[i].wifiState = 1149 mWifiSystemStateEntries.keyAt(i) / 2; 1150 mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount = 1151 mWifiSystemStateEntries.valueAt(i); 1152 mWifiLogProto.wifiSystemStateEntries[i].isScreenOn = 1153 (mWifiSystemStateEntries.keyAt(i) % 2) > 0; 1154 } 1155 mWifiLogProto.recordDurationSec = (int) ((mClock.elapsedRealtime() / 1000) 1156 - mRecordStartTimeSec); 1157 1158 /** 1159 * Convert the SparseIntArray of RSSI poll rssi's and counts to the proto's repeated 1160 * IntKeyVal array. 1161 */ 1162 for (int i = 0; i < mRssiPollCounts.size(); i++) { 1163 WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount(); 1164 keyVal.rssi = mRssiPollCounts.keyAt(i); 1165 keyVal.count = mRssiPollCounts.valueAt(i); 1166 rssis.add(keyVal); 1167 } 1168 mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount); 1169 1170 /** 1171 * Convert the SparseIntArray of alert reasons and counts to the proto's repeated 1172 * IntKeyVal array. 1173 */ 1174 for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) { 1175 WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount(); 1176 keyVal.reason = mWifiAlertReasonCounts.keyAt(i); 1177 keyVal.count = mWifiAlertReasonCounts.valueAt(i); 1178 alertReasons.add(keyVal); 1179 } 1180 mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount); 1181 /** 1182 * Convert the SparseIntArray of Wifi Score and counts to proto's repeated 1183 * IntKeyVal array. 1184 */ 1185 for (int score = 0; score < mWifiScoreCounts.size(); score++) { 1186 WifiMetricsProto.WifiScoreCount keyVal = new WifiMetricsProto.WifiScoreCount(); 1187 keyVal.score = mWifiScoreCounts.keyAt(score); 1188 keyVal.count = mWifiScoreCounts.valueAt(score); 1189 scores.add(keyVal); 1190 } 1191 mWifiLogProto.wifiScoreCount = scores.toArray(mWifiLogProto.wifiScoreCount); 1192 } 1193 } 1194 1195 /** 1196 * Clear all WifiMetrics, except for currentConnectionEvent. 1197 */ 1198 private void clear() { 1199 synchronized (mLock) { 1200 mConnectionEventList.clear(); 1201 if (mCurrentConnectionEvent != null) { 1202 mConnectionEventList.add(mCurrentConnectionEvent); 1203 } 1204 mScanReturnEntries.clear(); 1205 mWifiSystemStateEntries.clear(); 1206 mRecordStartTimeSec = mClock.elapsedRealtime() / 1000; 1207 mRssiPollCounts.clear(); 1208 mWifiAlertReasonCounts.clear(); 1209 mWifiScoreCounts.clear(); 1210 mWifiLogProto.clear(); 1211 } 1212 } 1213 1214 /** 1215 * Set screen state (On/Off) 1216 */ 1217 public void setScreenState(boolean screenOn) { 1218 synchronized (mLock) { 1219 mScreenOn = screenOn; 1220 } 1221 } 1222 1223 /** 1224 * Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED) 1225 */ 1226 public void setWifiState(int wifiState) { 1227 synchronized (mLock) { 1228 mWifiState = wifiState; 1229 } 1230 } 1231 } 1232