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