WifiMetrics.java revision 2b152feb1c574f30557581770d4f8c06c770ba34
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.net.wifi.ScanResult; 20import android.net.wifi.WifiConfiguration; 21import android.os.SystemClock; 22import android.util.Base64; 23import android.util.SparseArray; 24 25import com.android.server.wifi.hotspot2.NetworkDetail; 26import com.android.server.wifi.util.InformationElementUtil; 27 28import java.io.FileDescriptor; 29import java.io.PrintWriter; 30import java.util.ArrayList; 31import java.util.Calendar; 32import java.util.List; 33 34/** 35 * Provides storage for wireless connectivity metrics, as they are generated. 36 * Metrics logged by this class include: 37 * Aggregated connection stats (num of connections, num of failures, ...) 38 * Discrete connection event stats (time, duration, failure codes, ...) 39 * Router details (technology type, authentication type, ...) 40 * Scan stats 41 */ 42public class WifiMetrics { 43 private static final String TAG = "WifiMetrics"; 44 private final Object mLock = new Object(); 45 private static final int MAX_CONNECTION_EVENTS = 256; 46 /** 47 * Metrics are stored within an instance of the WifiLog proto during runtime, 48 * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during 49 * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced 50 * together at dump-time 51 */ 52 private final WifiMetricsProto.WifiLog mWifiLogProto; 53 /** 54 * Session information that gets logged for every Wifi connection attempt. 55 */ 56 private final List<ConnectionEvent> mConnectionEventList; 57 /** 58 * The latest started (but un-ended) connection attempt 59 */ 60 private ConnectionEvent mCurrentConnectionEvent; 61 /** 62 * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode 63 */ 64 private final SparseArray<WifiMetricsProto.WifiLog.ScanReturnEntry> mScanReturnEntries; 65 /** 66 * Mapping of system state to the counts of scans requested in that wifi state * screenOn 67 * combination. Indexed by WifiLog.WifiState * (1 + screenOn) 68 */ 69 private final SparseArray<WifiMetricsProto.WifiLog.WifiSystemStateEntry> 70 mWifiSystemStateEntries; 71 72 class RouterFingerPrint { 73 private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto; 74 RouterFingerPrint() { 75 mRouterFingerPrintProto = new WifiMetricsProto.RouterFingerPrint(); 76 } 77 78 public String toString() { 79 StringBuilder sb = new StringBuilder(); 80 synchronized (mLock) { 81 sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType); 82 sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo); 83 sb.append(", mDtim=" + mRouterFingerPrintProto.dtim); 84 sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication); 85 sb.append(", mHidden=" + mRouterFingerPrintProto.hidden); 86 sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology); 87 sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6); 88 } 89 return sb.toString(); 90 } 91 public void updateFromWifiConfiguration(WifiConfiguration config) { 92 if (config != null) { 93 /*<TODO> 94 mRouterFingerPrintProto.roamType 95 mRouterFingerPrintProto.supportsIpv6 96 */ 97 mRouterFingerPrintProto.hidden = config.hiddenSSID; 98 mRouterFingerPrintProto.channelInfo = config.apChannel; 99 // Config may not have a valid dtimInterval set yet, in which case dtim will be zero 100 // (These are only populated from beacon frame scan results, which are returned as 101 // scan results from the chip far less frequently than Probe-responses) 102 if (config.dtimInterval > 0) { 103 mRouterFingerPrintProto.dtim = config.dtimInterval; 104 } 105 } 106 } 107 } 108 109 /** 110 * Log event, tracking the start time, end time and result of a wireless connection attempt. 111 */ 112 class ConnectionEvent { 113 WifiMetricsProto.ConnectionEvent mConnectionEvent; 114 //<TODO> Move these constants into a wifi.proto Enum 115 // Level 2 Failure Codes 116 // Failure is unknown 117 public static final int LLF_UNKNOWN = 0; 118 // NONE 119 public static final int LLF_NONE = 1; 120 // ASSOCIATION_REJECTION_EVENT 121 public static final int LLF_ASSOCIATION_REJECTION = 2; 122 // AUTHENTICATION_FAILURE_EVENT 123 public static final int LLF_AUTHENTICATION_FAILURE = 3; 124 // SSID_TEMP_DISABLED (Also Auth failure) 125 public static final int LLF_SSID_TEMP_DISABLED = 4; 126 // reconnect() or reassociate() call to WifiNative failed 127 public static final int LLF_CONNECT_NETWORK_FAILED = 5; 128 // NETWORK_DISCONNECTION_EVENT 129 public static final int LLF_NETWORK_DISCONNECTION = 6; 130 // NEW_CONNECTION_ATTEMPT before previous finished 131 public static final int LLF_NEW_CONNECTION_ATTEMPT = 7; 132 RouterFingerPrint mRouterFingerPrint; 133 private long mRealStartTime; 134 private long mRealEndTime; 135 private String mConfigSsid; 136 private String mConfigBssid; 137 138 private ConnectionEvent() { 139 mConnectionEvent = new WifiMetricsProto.ConnectionEvent(); 140 mRealEndTime = 0; 141 mRealStartTime = 0; 142 mRouterFingerPrint = new RouterFingerPrint(); 143 mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto; 144 mConfigSsid = "<NULL>"; 145 mConfigBssid = "<NULL>"; 146 } 147 148 public String toString() { 149 StringBuilder sb = new StringBuilder(); 150 sb.append("startTime="); 151 Calendar c = Calendar.getInstance(); 152 synchronized (mLock) { 153 c.setTimeInMillis(mConnectionEvent.startTimeMillis); 154 sb.append(mConnectionEvent.startTimeMillis == 0 ? " <null>" : 155 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); 156 sb.append(", SSID="); 157 sb.append(mConfigSsid); 158 sb.append(", BSSID="); 159 sb.append(mConfigBssid); 160 sb.append(", durationMillis="); 161 sb.append(mConnectionEvent.durationTakenToConnectMillis); 162 sb.append(", roamType="); 163 switch(mConnectionEvent.roamType) { 164 case 1: 165 sb.append("ROAM_NONE"); 166 break; 167 case 2: 168 sb.append("ROAM_DBDC"); 169 break; 170 case 3: 171 sb.append("ROAM_ENTERPRISE"); 172 break; 173 case 4: 174 sb.append("ROAM_USER_SELECTED"); 175 break; 176 case 5: 177 sb.append("ROAM_UNRELATED"); 178 break; 179 default: 180 sb.append("ROAM_UNKNOWN"); 181 } 182 sb.append(", connectionResult="); 183 sb.append(mConnectionEvent.connectionResult); 184 sb.append(", level2FailureCode="); 185 switch(mConnectionEvent.level2FailureCode) { 186 case LLF_NONE: 187 sb.append("NONE"); 188 break; 189 case LLF_ASSOCIATION_REJECTION: 190 sb.append("ASSOCIATION_REJECTION"); 191 break; 192 case LLF_AUTHENTICATION_FAILURE: 193 sb.append("AUTHENTICATION_FAILURE"); 194 break; 195 case LLF_SSID_TEMP_DISABLED: 196 sb.append("SSID_TEMP_DISABLED"); 197 break; 198 case LLF_CONNECT_NETWORK_FAILED: 199 sb.append("CONNECT_NETWORK_FAILED"); 200 break; 201 case LLF_NETWORK_DISCONNECTION: 202 sb.append("NETWORK_DISCONNECTION"); 203 break; 204 case LLF_NEW_CONNECTION_ATTEMPT: 205 sb.append("NEW_CONNECTION_ATTEMPT"); 206 break; 207 default: 208 sb.append("UNKNOWN"); 209 break; 210 } 211 sb.append(", connectivityLevelFailureCode="); 212 switch(mConnectionEvent.connectivityLevelFailureCode) { 213 case WifiMetricsProto.ConnectionEvent.HLF_NONE: 214 sb.append("NONE"); 215 break; 216 case WifiMetricsProto.ConnectionEvent.HLF_DHCP: 217 sb.append("DHCP"); 218 break; 219 case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET: 220 sb.append("NO_INTERNET"); 221 break; 222 case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED: 223 sb.append("UNWANTED"); 224 break; 225 default: 226 sb.append("UNKNOWN"); 227 break; 228 } 229 sb.append(", signalStrength="); 230 sb.append(mConnectionEvent.signalStrength); 231 sb.append("\n "); 232 sb.append("mRouterFingerprint: "); 233 sb.append(mRouterFingerPrint.toString()); 234 } 235 return sb.toString(); 236 } 237 } 238 239 public WifiMetrics() { 240 mWifiLogProto = new WifiMetricsProto.WifiLog(); 241 mConnectionEventList = new ArrayList<>(); 242 mCurrentConnectionEvent = null; 243 mScanReturnEntries = new SparseArray<WifiMetricsProto.WifiLog.ScanReturnEntry>(); 244 mWifiSystemStateEntries = new SparseArray<WifiMetricsProto.WifiLog.WifiSystemStateEntry>(); 245 } 246 247 /** 248 * Create a new connection event. Call when wifi attempts to make a new network connection 249 * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity 250 * failure code. 251 * Gathers and sets the RouterFingerPrint data as well 252 * 253 * @param config WifiConfiguration of the config used for the current connection attempt 254 * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X 255 */ 256 public void startConnectionEvent(WifiConfiguration config, int roamType) { 257 if (mCurrentConnectionEvent != null) { 258 endConnectionEvent(ConnectionEvent.LLF_NEW_CONNECTION_ATTEMPT, 259 WifiMetricsProto.ConnectionEvent.HLF_NONE); 260 } 261 synchronized (mLock) { 262 //If at maximum connection events, start removing the oldest 263 while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) { 264 mConnectionEventList.remove(0); 265 } 266 mCurrentConnectionEvent = new ConnectionEvent(); 267 mCurrentConnectionEvent.mConnectionEvent.startTimeMillis = 268 System.currentTimeMillis(); 269 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; 270 mCurrentConnectionEvent.mRouterFingerPrint.updateFromWifiConfiguration(config); 271 if (config != null) { 272 ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); 273 if (candidate != null) { 274 updateMetricsFromScanResult(candidate); 275 } 276 mCurrentConnectionEvent.mConfigSsid = config.SSID; 277 mCurrentConnectionEvent.mConfigBssid = config.BSSID; 278 } 279 mCurrentConnectionEvent.mRealStartTime = SystemClock.elapsedRealtime(); 280 mConnectionEventList.add(mCurrentConnectionEvent); 281 } 282 } 283 284 /** 285 * set the RoamType of the current ConnectionEvent (if any) 286 */ 287 public void setConnectionEventRoamType(int roamType) { 288 if (mCurrentConnectionEvent != null) { 289 mCurrentConnectionEvent.mConnectionEvent.roamType = roamType; 290 } 291 } 292 293 /** 294 * Set AP related metrics from ScanDetail 295 */ 296 public void setConnectionScanDetail(ScanDetail scanDetail) { 297 if (mCurrentConnectionEvent != null && scanDetail != null) { 298 NetworkDetail networkDetail = scanDetail.getNetworkDetail(); 299 ScanResult scanResult = scanDetail.getScanResult(); 300 //Ensure that we have a networkDetail, and that it corresponds to the currently 301 //tracked connection attempt 302 if (networkDetail != null && scanResult != null 303 && mCurrentConnectionEvent.mConfigSsid != null 304 && mCurrentConnectionEvent.mConfigSsid 305 .equals("\"" + networkDetail.getSSID() + "\"")) { 306 updateMetricsFromNetworkDetail(networkDetail); 307 updateMetricsFromScanResult(scanResult); 308 } 309 } 310 } 311 312 /** 313 * End a Connection event record. Call when wifi connection attempt succeeds or fails. 314 * If a Connection event has not been started and is active when .end is called, a new one is 315 * created with zero duration. 316 * 317 * @param level2FailureCode Level 2 failure code returned by supplicant 318 * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X 319 */ 320 public void endConnectionEvent(int level2FailureCode, int connectivityFailureCode) { 321 synchronized (mLock) { 322 if (mCurrentConnectionEvent != null) { 323 boolean result = (level2FailureCode == 1) 324 && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE); 325 mCurrentConnectionEvent.mConnectionEvent.connectionResult = result ? 1 : 0; 326 mCurrentConnectionEvent.mRealEndTime = SystemClock.elapsedRealtime(); 327 mCurrentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = (int) 328 (mCurrentConnectionEvent.mRealEndTime 329 - mCurrentConnectionEvent.mRealStartTime); 330 mCurrentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode; 331 mCurrentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode = 332 connectivityFailureCode; 333 // ConnectionEvent already added to ConnectionEvents List. Safe to null current here 334 mCurrentConnectionEvent = null; 335 } 336 } 337 } 338 339 /** 340 * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail 341 */ 342 private void updateMetricsFromNetworkDetail(NetworkDetail networkDetail) { 343 int dtimInterval = networkDetail.getDtimInterval(); 344 if (dtimInterval > 0) { 345 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim = 346 dtimInterval; 347 } 348 int connectionWifiMode; 349 switch (networkDetail.getWifiMode()) { 350 case InformationElementUtil.WifiMode.MODE_UNDEFINED: 351 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN; 352 break; 353 case InformationElementUtil.WifiMode.MODE_11A: 354 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A; 355 break; 356 case InformationElementUtil.WifiMode.MODE_11B: 357 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B; 358 break; 359 case InformationElementUtil.WifiMode.MODE_11G: 360 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G; 361 break; 362 case InformationElementUtil.WifiMode.MODE_11N: 363 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N; 364 break; 365 case InformationElementUtil.WifiMode.MODE_11AC : 366 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC; 367 break; 368 default: 369 connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER; 370 break; 371 } 372 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto 373 .routerTechnology = connectionWifiMode; 374 } 375 376 /** 377 * Set ConnectionEvent RSSI and authentication type from ScanResult 378 */ 379 private void updateMetricsFromScanResult(ScanResult scanResult) { 380 mCurrentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level; 381 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 382 WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; 383 if (scanResult.capabilities != null) { 384 if (scanResult.capabilities.contains("WEP")) { 385 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 386 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 387 } else if (scanResult.capabilities.contains("PSK")) { 388 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 389 WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; 390 } else if (scanResult.capabilities.contains("EAP")) { 391 mCurrentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = 392 WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; 393 } 394 } 395 } 396 397 void setNumSavedNetworks(int num) { 398 synchronized (mLock) { 399 mWifiLogProto.numSavedNetworks = num; 400 } 401 } 402 403 void setNumOpenNetworks(int num) { 404 synchronized (mLock) { 405 mWifiLogProto.numOpenNetworks = num; 406 } 407 } 408 409 void setNumPersonalNetworks(int num) { 410 synchronized (mLock) { 411 mWifiLogProto.numPersonalNetworks = num; 412 } 413 } 414 415 void setNumEnterpriseNetworks(int num) { 416 synchronized (mLock) { 417 mWifiLogProto.numEnterpriseNetworks = num; 418 } 419 } 420 421 void setNumNetworksAddedByUser(int num) { 422 synchronized (mLock) { 423 mWifiLogProto.numNetworksAddedByUser = num; 424 } 425 } 426 427 void setNumNetworksAddedByApps(int num) { 428 synchronized (mLock) { 429 mWifiLogProto.numNetworksAddedByApps = num; 430 } 431 } 432 433 void setIsLocationEnabled(boolean enabled) { 434 synchronized (mLock) { 435 mWifiLogProto.isLocationEnabled = enabled; 436 } 437 } 438 439 void setIsScanningAlwaysEnabled(boolean enabled) { 440 synchronized (mLock) { 441 mWifiLogProto.isScanningAlwaysEnabled = enabled; 442 } 443 } 444 445 /** 446 * Increment Airplane mode toggle count 447 */ 448 public void incrementAirplaneToggleCount() { 449 synchronized (mLock) { 450 mWifiLogProto.numWifiToggledViaAirplane++; 451 } 452 } 453 454 /** 455 * Increment Wifi Toggle count 456 */ 457 public void incrementWifiToggleCount() { 458 synchronized (mLock) { 459 mWifiLogProto.numWifiToggledViaSettings++; 460 } 461 } 462 463 /** 464 * Increment Non Empty Scan Results count 465 */ 466 public void incrementNonEmptyScanResultCount() { 467 synchronized (mLock) { 468 mWifiLogProto.numNonEmptyScanResults++; 469 } 470 } 471 472 /** 473 * Increment Empty Scan Results count 474 */ 475 public void incrementEmptyScanResultCount() { 476 synchronized (mLock) { 477 mWifiLogProto.numEmptyScanResults++; 478 } 479 } 480 481 /** 482 * Increment count of scan return code occurrence 483 * 484 * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X 485 */ 486 public void incrementScanReturnEntry(int scanReturnCode) { 487 synchronized (mLock) { 488 WifiMetricsProto.WifiLog.ScanReturnEntry entry = mScanReturnEntries.get(scanReturnCode); 489 if (entry == null) { 490 entry = new WifiMetricsProto.WifiLog.ScanReturnEntry(); 491 entry.scanReturnCode = scanReturnCode; 492 entry.scanResultsCount = 0; 493 } 494 entry.scanResultsCount++; 495 mScanReturnEntries.put(scanReturnCode, entry); 496 } 497 } 498 499 /** 500 * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off 501 * 502 * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X 503 * @param screenOn Is the screen on 504 */ 505 public void incrementWifiSystemScanStateCount(int state, boolean screenOn) { 506 synchronized (mLock) { 507 int index = state * (screenOn ? 2 : 1); 508 WifiMetricsProto.WifiLog.WifiSystemStateEntry entry = 509 mWifiSystemStateEntries.get(index); 510 if (entry == null) { 511 entry = new WifiMetricsProto.WifiLog.WifiSystemStateEntry(); 512 entry.wifiState = state; 513 entry.wifiStateCount = 0; 514 entry.isScreenOn = screenOn; 515 } 516 entry.wifiStateCount++; 517 mWifiSystemStateEntries.put(state, entry); 518 } 519 } 520 521 public static final String PROTO_DUMP_ARG = "wifiMetricsProto"; 522 /** 523 * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager 524 * at this time 525 * 526 * @param fd unused 527 * @param pw PrintWriter for writing dump to 528 * @param args unused 529 */ 530 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 531 synchronized (mLock) { 532 pw.println("WifiMetrics:"); 533 if (args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) { 534 //Dump serialized WifiLog proto 535 consolidateProto(true); 536 for (ConnectionEvent event : mConnectionEventList) { 537 if (mCurrentConnectionEvent != event) { 538 //indicate that automatic bug report has been taken for all valid 539 //connection events 540 event.mConnectionEvent.automaticBugReportTaken = true; 541 } 542 } 543 byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto); 544 String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT); 545 pw.println(metricsProtoDump); 546 pw.println("EndWifiMetrics"); 547 clear(); 548 } else { 549 pw.println("mConnectionEvents:"); 550 for (ConnectionEvent event : mConnectionEventList) { 551 String eventLine = event.toString(); 552 if (event == mCurrentConnectionEvent) { 553 eventLine += "CURRENTLY OPEN EVENT"; 554 } 555 pw.println(eventLine); 556 } 557 pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks); 558 pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks); 559 pw.println("mWifiLogProto.numPersonalNetworks=" 560 + mWifiLogProto.numPersonalNetworks); 561 pw.println("mWifiLogProto.numEnterpriseNetworks=" 562 + mWifiLogProto.numEnterpriseNetworks); 563 pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled); 564 pw.println("mWifiLogProto.isScanningAlwaysEnabled=" 565 + mWifiLogProto.isScanningAlwaysEnabled); 566 pw.println("mWifiLogProto.numWifiToggledViaSettings=" 567 + mWifiLogProto.numWifiToggledViaSettings); 568 pw.println("mWifiLogProto.numWifiToggledViaAirplane=" 569 + mWifiLogProto.numWifiToggledViaAirplane); 570 pw.println("mWifiLogProto.numNetworksAddedByUser=" 571 + mWifiLogProto.numNetworksAddedByUser); 572 //TODO - Pending scanning refactor 573 pw.println("mWifiLogProto.numNetworksAddedByApps=" + "<TODO>"); 574 pw.println("mWifiLogProto.numNonEmptyScanResults=" + "<TODO>"); 575 pw.println("mWifiLogProto.numEmptyScanResults=" + "<TODO>"); 576 pw.println("mWifiLogProto.numOneshotScans=" + "<TODO>"); 577 pw.println("mWifiLogProto.numBackgroundScans=" + "<TODO>"); 578 pw.println("mScanReturnEntries:" + " <TODO>"); 579 pw.println("mSystemStateEntries:" + " <TODO>"); 580 } 581 } 582 } 583 584 /** 585 * Assign the separate ConnectionEvent, SystemStateEntry and ScanReturnCode lists to their 586 * respective lists within mWifiLogProto, and clear the original lists managed here. 587 * 588 * @param incremental Only include ConnectionEvents created since last automatic bug report 589 */ 590 private void consolidateProto(boolean incremental) { 591 List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>(); 592 synchronized (mLock) { 593 for (ConnectionEvent event : mConnectionEventList) { 594 if (!incremental || ((mCurrentConnectionEvent != event) 595 && !event.mConnectionEvent.automaticBugReportTaken)) { 596 //Get all ConnectionEvents that haven not been dumped as a proto, also exclude 597 //the current active un-ended connection event 598 events.add(event.mConnectionEvent); 599 event.mConnectionEvent.automaticBugReportTaken = true; 600 } 601 } 602 if (events.size() > 0) { 603 mWifiLogProto.connectionEvent = events.toArray(mWifiLogProto.connectionEvent); 604 } 605 //<TODO> SystemStateEntry and ScanReturnCode list consolidation 606 } 607 } 608 609 /** 610 * Serializes all of WifiMetrics to WifiLog proto, and returns the byte array. 611 * Does not count as taking an automatic bug report 612 * 613 * @return byte array of the deserialized & consolidated Proto 614 */ 615 public byte[] toByteArray() { 616 consolidateProto(false); 617 return mWifiLogProto.toByteArray(mWifiLogProto); 618 } 619 620 /** 621 * Clear all WifiMetrics, except for currentConnectionEvent. 622 */ 623 private void clear() { 624 synchronized (mLock) { 625 mConnectionEventList.clear(); 626 if (mCurrentConnectionEvent != null) { 627 mConnectionEventList.add(mCurrentConnectionEvent); 628 } 629 mScanReturnEntries.clear(); 630 mWifiSystemStateEntries.clear(); 631 mWifiLogProto.clear(); 632 } 633 } 634} 635