1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS; 20 21 import static com.android.server.wifi.WifiScoreCard.TS_NONE; 22 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.app.AlarmManager; 26 import android.content.Context; 27 import android.content.pm.ModuleInfo; 28 import android.content.pm.PackageManager; 29 import android.net.MacAddress; 30 import android.net.wifi.ScanResult; 31 import android.net.wifi.WifiConfiguration; 32 import android.net.wifi.WifiManager; 33 import android.net.wifi.WifiManager.DeviceMobilityState; 34 import android.net.wifi.WifiScanner; 35 import android.os.Build; 36 import android.os.Handler; 37 import android.util.Log; 38 39 import com.android.internal.annotations.VisibleForTesting; 40 import com.android.server.wifi.WifiScoreCard.MemoryStore; 41 import com.android.server.wifi.WifiScoreCard.MemoryStoreAccessBase; 42 import com.android.server.wifi.WifiScoreCard.PerNetwork; 43 import com.android.server.wifi.proto.WifiScoreCardProto.SoftwareBuildInfo; 44 import com.android.server.wifi.proto.WifiScoreCardProto.SystemInfoStats; 45 import com.android.server.wifi.proto.WifiStatsLog; 46 import com.android.server.wifi.proto.nano.WifiMetricsProto.HealthMonitorFailureStats; 47 import com.android.server.wifi.proto.nano.WifiMetricsProto.HealthMonitorMetrics; 48 import com.android.server.wifi.util.ScanResultUtil; 49 50 import com.google.protobuf.InvalidProtocolBufferException; 51 52 import java.io.FileDescriptor; 53 import java.io.PrintWriter; 54 import java.lang.annotation.Retention; 55 import java.lang.annotation.RetentionPolicy; 56 import java.util.ArrayList; 57 import java.util.Calendar; 58 import java.util.List; 59 60 import javax.annotation.concurrent.NotThreadSafe; 61 62 /** 63 * Monitor and detect potential WiFi health issue when RSSI is sufficiently high. 64 * There are two detections, daily detection and post-boot detection. 65 * Post-boot detection is to detect abnormal scan/connection behavior change after device reboot 66 * and/or SW build change. 67 * Daily detection is to detect connection and other behavior changes especially after SW change. 68 */ 69 70 @NotThreadSafe 71 public class WifiHealthMonitor { 72 private static final String TAG = "WifiHealthMonitor"; 73 private boolean mVerboseLoggingEnabled = false; 74 public static final String DAILY_DETECTION_TIMER_TAG = 75 "WifiHealthMonitor Schedule Daily Detection Timer"; 76 public static final String POST_BOOT_DETECTION_TIMER_TAG = 77 "WifiHealthMonitor Schedule Post-Boot Detection Timer"; 78 // Package name of WiFi mainline module found from the following adb command 79 // adb shell pm list packages --apex-only| grep wifi 80 private static final String WIFI_APEX_NAME = "com.android.wifi"; 81 private static final String SYSTEM_INFO_DATA_NAME = "systemInfoData"; 82 // The time that device waits after device boot before triggering post-boot detection. 83 // This needs be long enough so that memory read can complete before post-boot detection. 84 private static final int POST_BOOT_DETECTION_WAIT_TIME_MS = 25_000; 85 // The time interval between two daily detections 86 private static final long DAILY_DETECTION_INTERVAL_MS = 24 * 3600_000; 87 public static final int DAILY_DETECTION_HOUR = 23; 88 private static final int DAILY_DETECTION_MIN = 00; 89 private static final long MIN_WAIT_TIME_BEFORE_FIRST_DETECTION_MS = 100_000; 90 // Max interval between pre-boot scan and post-boot scan to qualify post-boot scan detection 91 private static final long MAX_INTERVAL_BETWEEN_TWO_SCAN_MS = 60_000; 92 // The minimum number of BSSIDs that should be found during a normal scan to trigger detection 93 // of an abnormal scan which happens either before or after the normal scan within a short time. 94 // Minimum number of BSSIDs found at 2G with a normal scan 95 private static final int MIN_NUM_BSSID_SCAN_2G = 2; 96 // Minimum number of BSSIDs found above 2G with a normal scan 97 private static final int MIN_NUM_BSSID_SCAN_ABOVE_2G = 2; 98 // Minimum Tx speed in Mbps for disconnection stats collection 99 static final int HEALTH_MONITOR_COUNT_TX_SPEED_MIN_MBPS = 54; 100 // Minimum Tx packet per seconds for disconnection stats collection 101 static final int HEALTH_MONITOR_MIN_TX_PACKET_PER_SEC = 4; 102 private static final long MAX_TIME_SINCE_LAST_CONNECTION_MS = 48 * 3600_000; 103 104 105 private final Context mContext; 106 private final WifiConfigManager mWifiConfigManager; 107 private final WifiScoreCard mWifiScoreCard; 108 private final Clock mClock; 109 private final AlarmManager mAlarmManager; 110 private final Handler mHandler; 111 private final WifiNative mWifiNative; 112 private final WifiInjector mWifiInjector; 113 private final DeviceConfigFacade mDeviceConfigFacade; 114 private final ActiveModeWarden mActiveModeWarden; 115 private WifiScanner mScanner; 116 private MemoryStore mMemoryStore; 117 private boolean mWifiEnabled; 118 private WifiSystemInfoStats mWifiSystemInfoStats; 119 private ScanStats mFirstScanStats = new ScanStats(); 120 // Detected significant increase of failure stats between daily data and historical data 121 private FailureStats mFailureStatsIncrease = new FailureStats(); 122 // Detected significant decrease of failure stats between daily data and historical data 123 private FailureStats mFailureStatsDecrease = new FailureStats(); 124 // Detected high failure stats from daily data without historical data 125 private FailureStats mFailureStatsHigh = new FailureStats(); 126 private int mNumNetworkSufficientRecentStatsOnly = 0; 127 private int mNumNetworkSufficientRecentPrevStats = 0; 128 private boolean mHasNewDataForWifiMetrics = false; 129 private int mDeviceMobilityState = WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN; 130 131 private class ModeChangeCallback implements ActiveModeWarden.ModeChangeCallback { 132 @Override onActiveModeManagerAdded(@onNull ActiveModeManager activeModeManager)133 public void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager) { 134 update(); 135 } 136 137 @Override onActiveModeManagerRemoved(@onNull ActiveModeManager activeModeManager)138 public void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager) { 139 update(); 140 } 141 142 @Override onActiveModeManagerRoleChanged(@onNull ActiveModeManager activeModeManager)143 public void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager) { 144 update(); 145 } 146 update()147 private void update() { 148 setWifiEnabled(mActiveModeWarden.getPrimaryClientModeManagerNullable() != null); 149 } 150 } 151 WifiHealthMonitor(Context context, WifiInjector wifiInjector, Clock clock, WifiConfigManager wifiConfigManager, WifiScoreCard wifiScoreCard, Handler handler, WifiNative wifiNative, String l2KeySeed, DeviceConfigFacade deviceConfigFacade, ActiveModeWarden activeModeWarden)152 WifiHealthMonitor(Context context, WifiInjector wifiInjector, Clock clock, 153 WifiConfigManager wifiConfigManager, WifiScoreCard wifiScoreCard, Handler handler, 154 WifiNative wifiNative, String l2KeySeed, DeviceConfigFacade deviceConfigFacade, 155 ActiveModeWarden activeModeWarden) { 156 mContext = context; 157 mWifiInjector = wifiInjector; 158 mClock = clock; 159 mWifiConfigManager = wifiConfigManager; 160 mWifiScoreCard = wifiScoreCard; 161 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 162 mHandler = handler; 163 mWifiNative = wifiNative; 164 mDeviceConfigFacade = deviceConfigFacade; 165 mActiveModeWarden = activeModeWarden; 166 mWifiSystemInfoStats = new WifiSystemInfoStats(l2KeySeed); 167 mWifiConfigManager.addOnNetworkUpdateListener(new OnNetworkUpdateListener()); 168 mActiveModeWarden.registerModeChangeCallback(new ModeChangeCallback()); 169 } 170 171 /** 172 * Enable/Disable verbose logging. 173 * 174 * @param verbose true to enable and false to disable. 175 */ enableVerboseLogging(boolean verbose)176 public void enableVerboseLogging(boolean verbose) { 177 mVerboseLoggingEnabled = verbose; 178 } 179 180 private final AlarmManager.OnAlarmListener mDailyDetectionListener = 181 new AlarmManager.OnAlarmListener() { 182 public void onAlarm() { 183 dailyDetectionHandler(); 184 } 185 }; 186 187 private final AlarmManager.OnAlarmListener mPostBootDetectionListener = 188 new AlarmManager.OnAlarmListener() { 189 public void onAlarm() { 190 postBootDetectionHandler(); 191 } 192 }; 193 194 /** 195 * Installs a memory store, request read for post-boot detection and set up detection alarms. 196 */ installMemoryStoreSetUpDetectionAlarm(@onNull MemoryStore memoryStore)197 public void installMemoryStoreSetUpDetectionAlarm(@NonNull MemoryStore memoryStore) { 198 if (mMemoryStore == null) { 199 mMemoryStore = memoryStore; 200 Log.i(TAG, "Installing MemoryStore"); 201 } else { 202 mMemoryStore = memoryStore; 203 Log.e(TAG, "Reinstalling MemoryStore"); 204 } 205 requestReadForPostBootDetection(); 206 setFirstHealthDetectionAlarm(); 207 setPostBootDetectionAlarm(); 208 } 209 210 /** 211 * Set WiFi enable state. 212 * During the off->on transition, retrieve scanner. 213 * During the on->off transition, issue MemoryStore write to save data. 214 */ setWifiEnabled(boolean enable)215 private void setWifiEnabled(boolean enable) { 216 if (mWifiEnabled == enable) return; 217 mWifiEnabled = enable; 218 logd("Set WiFi " + (enable ? "enabled" : "disabled")); 219 if (enable) { 220 retrieveWifiScanner(); 221 } else { 222 doWrites(); 223 } 224 } 225 226 /** 227 * Issue MemoryStore write. This should be called from time to time 228 * to save the state to persistent storage. 229 */ doWrites()230 public void doWrites() { 231 mWifiSystemInfoStats.writeToMemory(); 232 } 233 234 /** 235 * Set device mobility state to assist abnormal scan failure detection 236 */ setDeviceMobilityState(@eviceMobilityState int newState)237 public void setDeviceMobilityState(@DeviceMobilityState int newState) { 238 logd("Device mobility state: " + newState); 239 mDeviceMobilityState = newState; 240 mWifiSystemInfoStats.setMobilityState(newState); 241 } 242 243 /** 244 * Get the maximum scan RSSI valid time for scan RSSI search which is done by finding 245 * the maximum RSSI found among all valid scan detail entries of each network's scanDetailCache 246 * If a scanDetail was older than the returned value, it will not be considered valid. 247 */ getScanRssiValidTimeMs()248 public int getScanRssiValidTimeMs() { 249 return (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_STATIONARY) 250 ? mDeviceConfigFacade.getStationaryScanRssiValidTimeMs() : 251 mDeviceConfigFacade.getNonstationaryScanRssiValidTimeMs(); 252 } 253 254 /** 255 * Issue read request to prepare for post-boot detection. 256 */ requestReadForPostBootDetection()257 private void requestReadForPostBootDetection() { 258 mWifiSystemInfoStats.readFromMemory(); 259 // Potential SW change detection may require to update all networks. 260 // Thus read all networks. 261 requestReadAllNetworks(); 262 } 263 264 /** 265 * Helper method to populate WifiScanner handle. This is done lazily because 266 * WifiScanningService is started after WifiService. 267 */ retrieveWifiScanner()268 private void retrieveWifiScanner() { 269 if (mScanner != null) return; 270 mScanner = mWifiInjector.getWifiScanner(); 271 if (mScanner == null) return; 272 // Register for all single scan results 273 mScanner.registerScanListener(new ScanListener()); 274 } 275 276 /** 277 * Handle scan results when scan results come back from WiFi scanner. 278 */ handleScanResults(List<ScanDetail> scanDetails)279 private void handleScanResults(List<ScanDetail> scanDetails) { 280 ScanStats scanStats = mWifiSystemInfoStats.getCurrScanStats(); 281 scanStats.clear(); 282 scanStats.setLastScanTimeMs(mClock.getWallClockMillis()); 283 for (ScanDetail scanDetail : scanDetails) { 284 ScanResult scanResult = scanDetail.getScanResult(); 285 if (scanResult.is24GHz()) { 286 scanStats.incrementNumBssidLastScan2g(); 287 } else { 288 scanStats.incrementNumBssidLastScanAbove2g(); 289 } 290 } 291 if (mFirstScanStats.getLastScanTimeMs() == TS_NONE) { 292 mFirstScanStats.copy(scanStats); 293 } 294 mWifiSystemInfoStats.setChanged(true); 295 logd(" 2G scanResult count: " + scanStats.getNumBssidLastScan2g() 296 + ", Above2g scanResult count: " + scanStats.getNumBssidLastScanAbove2g()); 297 } 298 setFirstHealthDetectionAlarm()299 private void setFirstHealthDetectionAlarm() { 300 long currTimeMs = mClock.getWallClockMillis(); 301 Calendar calendar = Calendar.getInstance(); 302 calendar.setTimeInMillis(currTimeMs); 303 calendar.set(Calendar.HOUR_OF_DAY, DAILY_DETECTION_HOUR); 304 calendar.set(Calendar.MINUTE, DAILY_DETECTION_MIN); 305 long targetTimeMs = calendar.getTimeInMillis(); 306 long waitTimeMs = targetTimeMs - currTimeMs; 307 if (waitTimeMs < MIN_WAIT_TIME_BEFORE_FIRST_DETECTION_MS) { 308 waitTimeMs += DAILY_DETECTION_INTERVAL_MS; 309 } 310 scheduleDailyDetectionAlarm(waitTimeMs); 311 } 312 scheduleDailyDetectionAlarm(long waitTimeMs)313 private void scheduleDailyDetectionAlarm(long waitTimeMs) { 314 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, 315 mClock.getElapsedSinceBootMillis() + waitTimeMs, 316 DAILY_DETECTION_TIMER_TAG, 317 mDailyDetectionListener, mHandler); 318 } 319 setPostBootDetectionAlarm()320 private void setPostBootDetectionAlarm() { 321 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 322 mClock.getElapsedSinceBootMillis() + POST_BOOT_DETECTION_WAIT_TIME_MS, 323 POST_BOOT_DETECTION_TIMER_TAG, 324 mPostBootDetectionListener, mHandler); 325 } 326 327 /** 328 * Dump the internal state of WifiHealthMonitor. 329 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)330 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 331 pw.println("Dump of WifiHealthMonitor"); 332 pw.println("WifiHealthMonitor - Log Begin ----"); 333 pw.println("System Info Stats"); 334 pw.println(mWifiSystemInfoStats); 335 pw.println("configured network connection stats"); 336 List<WifiConfiguration> configuredNetworks = mWifiConfigManager.getConfiguredNetworks(); 337 for (WifiConfiguration network : configuredNetworks) { 338 if (isInvalidConfiguredNetwork(network)) continue; 339 boolean isRecentlyConnected = (mClock.getWallClockMillis() - network.lastConnected) 340 < MAX_TIME_SINCE_LAST_CONNECTION_MS; 341 PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(network.SSID); 342 int cntName = WifiScoreCard.CNT_CONNECTION_ATTEMPT; 343 if (perNetwork.getStatsCurrBuild().getCount(cntName) > 0 344 || perNetwork.getRecentStats().getCount(cntName) > 0 345 || isRecentlyConnected) { 346 pw.println(mWifiScoreCard.lookupNetwork(network.SSID)); 347 } 348 } 349 pw.println("networks with failure increase: "); 350 pw.println(mFailureStatsIncrease); 351 pw.println("networks with failure drop: "); 352 pw.println(mFailureStatsDecrease); 353 pw.println("networks with high failure without previous stats: "); 354 pw.println(mFailureStatsHigh); 355 pw.println("WifiHealthMonitor - Log End ----"); 356 } 357 358 /** 359 * Get current wifi mainline module long version code 360 * @Return a non-zero value if version code is available, 0 otherwise. 361 */ getWifiStackVersion()362 public long getWifiStackVersion() { 363 PackageManager packageManager = mContext.getPackageManager(); 364 long wifiStackVersion = 0; 365 try { 366 ModuleInfo wifiModule = packageManager.getModuleInfo( 367 WIFI_APEX_NAME, PackageManager.MODULE_APEX_NAME); 368 String wifiPackageName = wifiModule.getPackageName(); 369 if (wifiPackageName != null) { 370 wifiStackVersion = packageManager.getPackageInfo( 371 wifiPackageName, PackageManager.MATCH_APEX).getLongVersionCode(); 372 } 373 } catch (PackageManager.NameNotFoundException e) { 374 Log.e(TAG, " Hit PackageManager exception", e); 375 } 376 return wifiStackVersion; 377 } 378 dailyDetectionHandler()379 private synchronized void dailyDetectionHandler() { 380 logd("Run daily detection"); 381 // Clear daily detection result 382 mFailureStatsDecrease.clear(); 383 mFailureStatsIncrease.clear(); 384 mFailureStatsHigh.clear(); 385 mNumNetworkSufficientRecentStatsOnly = 0; 386 mNumNetworkSufficientRecentPrevStats = 0; 387 mHasNewDataForWifiMetrics = true; 388 int connectionDurationSec = 0; 389 // Set the alarm for the next day 390 scheduleDailyDetectionAlarm(DAILY_DETECTION_INTERVAL_MS); 391 List<WifiConfiguration> configuredNetworks = mWifiConfigManager.getConfiguredNetworks(); 392 for (WifiConfiguration network : configuredNetworks) { 393 if (isInvalidConfiguredNetwork(network)) { 394 continue; 395 } 396 PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(network.SSID); 397 398 int detectionFlag = perNetwork.dailyDetection(mFailureStatsDecrease, 399 mFailureStatsIncrease, mFailureStatsHigh); 400 if (detectionFlag == WifiScoreCard.SUFFICIENT_RECENT_STATS_ONLY) { 401 mNumNetworkSufficientRecentStatsOnly++; 402 } 403 if (detectionFlag == WifiScoreCard.SUFFICIENT_RECENT_PREV_STATS) { 404 mNumNetworkSufficientRecentPrevStats++; 405 } 406 407 connectionDurationSec += perNetwork.getRecentStats().getCount( 408 WifiScoreCard.CNT_CONNECTION_DURATION_SEC); 409 410 logd("before daily update: " + perNetwork); 411 // Update historical stats with dailyStats and clear dailyStats 412 perNetwork.updateAfterDailyDetection(); 413 logd("after daily update: " + perNetwork); 414 } 415 logd("total connection duration: " + connectionDurationSec); 416 logd("#networks w/ sufficient recent stats: " + mNumNetworkSufficientRecentStatsOnly); 417 logd("#networks w/ sufficient recent and prev stats: " 418 + mNumNetworkSufficientRecentPrevStats); 419 // Write metrics to statsd 420 writeToWifiStatsLog(); 421 doWrites(); 422 mWifiScoreCard.doWrites(); 423 } 424 writeToWifiStatsLog()425 private void writeToWifiStatsLog() { 426 writeToWifiStatsLogPerStats(mFailureStatsIncrease, 427 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__ABNORMALITY_TYPE__SIGNIFICANT_INCREASE); 428 writeToWifiStatsLogPerStats(mFailureStatsDecrease, 429 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__ABNORMALITY_TYPE__SIGNIFICANT_DECREASE); 430 writeToWifiStatsLogPerStats(mFailureStatsHigh, 431 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__ABNORMALITY_TYPE__SIMPLY_HIGH); 432 } 433 writeToWifiStatsLogPerStats(FailureStats failureStats, int abnormalityType)434 private void writeToWifiStatsLogPerStats(FailureStats failureStats, int abnormalityType) { 435 int cntAssocRejection = failureStats.getCount(REASON_ASSOC_REJECTION); 436 if (cntAssocRejection > 0) { 437 WifiStatsLog.write(WifiStatsLog.WIFI_FAILURE_STAT_REPORTED, abnormalityType, 438 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__FAILURE_TYPE__FAILURE_ASSOCIATION_REJECTION, 439 cntAssocRejection); 440 } 441 int cntAssocTimeout = failureStats.getCount(REASON_ASSOC_TIMEOUT); 442 if (cntAssocTimeout > 0) { 443 WifiStatsLog.write(WifiStatsLog.WIFI_FAILURE_STAT_REPORTED, abnormalityType, 444 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__FAILURE_TYPE__FAILURE_ASSOCIATION_TIMEOUT, 445 cntAssocTimeout); 446 } 447 int cntAuthFailure = failureStats.getCount(REASON_AUTH_FAILURE); 448 if (cntAuthFailure > 0) { 449 WifiStatsLog.write(WifiStatsLog.WIFI_FAILURE_STAT_REPORTED, abnormalityType, 450 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__FAILURE_TYPE__FAILURE_AUTHENTICATION, 451 cntAuthFailure); 452 } 453 int cntConnectionFailure = failureStats.getCount(REASON_CONNECTION_FAILURE); 454 if (cntConnectionFailure > 0) { 455 WifiStatsLog.write(WifiStatsLog.WIFI_FAILURE_STAT_REPORTED, abnormalityType, 456 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__FAILURE_TYPE__FAILURE_CONNECTION, 457 cntConnectionFailure); 458 } 459 int cntDisconnectionNonlocal = failureStats.getCount(REASON_DISCONNECTION_NONLOCAL); 460 if (cntDisconnectionNonlocal > 0) { 461 WifiStatsLog.write(WifiStatsLog.WIFI_FAILURE_STAT_REPORTED, abnormalityType, 462 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__FAILURE_TYPE__FAILURE_NON_LOCAL_DISCONNECTION, 463 cntDisconnectionNonlocal); 464 } 465 int cntShortConnectionNonlocal = failureStats.getCount(REASON_SHORT_CONNECTION_NONLOCAL); 466 if (cntShortConnectionNonlocal > 0) { 467 WifiStatsLog.write(WifiStatsLog.WIFI_FAILURE_STAT_REPORTED, abnormalityType, 468 WifiStatsLog.WIFI_FAILURE_STAT_REPORTED__FAILURE_TYPE__FAILURE_SHORT_CONNECTION_DUE_TO_NON_LOCAL_DISCONNECTION, 469 cntShortConnectionNonlocal); 470 } 471 } 472 473 /** 474 * Build HealthMonitor proto for WifiMetrics 475 * @return counts of networks with significant connection failure stats if there is a new 476 * detection, or a empty proto with default values if there is no new detection 477 */ buildProto()478 public synchronized HealthMonitorMetrics buildProto() { 479 if (!mHasNewDataForWifiMetrics) return null; 480 HealthMonitorMetrics metrics = new HealthMonitorMetrics(); 481 metrics.failureStatsIncrease = failureStatsToProto(mFailureStatsIncrease); 482 metrics.failureStatsDecrease = failureStatsToProto(mFailureStatsDecrease); 483 metrics.failureStatsHigh = failureStatsToProto(mFailureStatsHigh); 484 485 metrics.numNetworkSufficientRecentStatsOnly = mNumNetworkSufficientRecentStatsOnly; 486 metrics.numNetworkSufficientRecentPrevStats = mNumNetworkSufficientRecentPrevStats; 487 mHasNewDataForWifiMetrics = false; 488 return metrics; 489 } 490 failureStatsToProto(FailureStats failureStats)491 private HealthMonitorFailureStats failureStatsToProto(FailureStats failureStats) { 492 HealthMonitorFailureStats stats = new HealthMonitorFailureStats(); 493 stats.cntAssocRejection = failureStats.getCount(REASON_ASSOC_REJECTION); 494 stats.cntAssocTimeout = failureStats.getCount(REASON_ASSOC_TIMEOUT); 495 stats.cntAuthFailure = failureStats.getCount(REASON_AUTH_FAILURE); 496 stats.cntConnectionFailure = failureStats.getCount(REASON_CONNECTION_FAILURE); 497 stats.cntDisconnectionNonlocalConnecting = 498 failureStats.getCount(REASON_CONNECTION_FAILURE_DISCONNECTION); 499 stats.cntDisconnectionNonlocal = 500 failureStats.getCount(REASON_DISCONNECTION_NONLOCAL); 501 stats.cntShortConnectionNonlocal = 502 failureStats.getCount(REASON_SHORT_CONNECTION_NONLOCAL); 503 return stats; 504 } 505 isInvalidConfiguredNetwork(WifiConfiguration config)506 private boolean isInvalidConfiguredNetwork(WifiConfiguration config) { 507 return (config == null || WifiManager.UNKNOWN_SSID.equals(config.SSID) 508 || config.SSID == null); 509 } 510 postBootDetectionHandler()511 private void postBootDetectionHandler() { 512 logd("Run post-boot detection"); 513 postBootSwBuildCheck(); 514 mWifiSystemInfoStats.postBootAbnormalScanDetection(mFirstScanStats); 515 logd(" postBootAbnormalScanDetection: " + mWifiSystemInfoStats.getScanFailure()); 516 // TODO: Check if scan is not empty but all high RSSI connection attempts failed 517 // while connection attempt with the same network succeeded before boot. 518 doWrites(); 519 } 520 postBootSwBuildCheck()521 private void postBootSwBuildCheck() { 522 WifiSoftwareBuildInfo currSoftwareBuildInfo = extractCurrentSoftwareBuildInfo(); 523 if (currSoftwareBuildInfo == null) return; 524 logd(currSoftwareBuildInfo.toString()); 525 526 mWifiSystemInfoStats.finishPendingRead(); 527 if (mWifiSystemInfoStats.getCurrSoftwareBuildInfo() == null) { 528 logd("Miss current software build info from memory"); 529 mWifiSystemInfoStats.setCurrSoftwareBuildInfo(currSoftwareBuildInfo); 530 return; 531 } 532 if (mWifiSystemInfoStats.detectSwBuildChange(currSoftwareBuildInfo)) { 533 logd("Detect SW build change"); 534 updateAllNetworkAfterSwBuildChange(); 535 mWifiSystemInfoStats.updateBuildInfoAfterSwBuildChange(currSoftwareBuildInfo); 536 } else { 537 logd("Detect no SW build change"); 538 } 539 } 540 541 /** 542 * Issue NetworkStats read request for all configured networks. 543 */ requestReadAllNetworks()544 private void requestReadAllNetworks() { 545 List<WifiConfiguration> configuredNetworks = mWifiConfigManager.getConfiguredNetworks(); 546 for (WifiConfiguration network : configuredNetworks) { 547 if (isInvalidConfiguredNetwork(network)) { 548 continue; 549 } 550 logd(network.SSID); 551 WifiScoreCard.PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(network.SSID); 552 if (perNetwork == null) { 553 // This network is not in cache. Move it to cache and read it out from MemoryStore. 554 mWifiScoreCard.lookupNetwork(network.SSID); 555 } else { 556 // This network is already in cache before memoryStore is stalled. 557 mWifiScoreCard.requestReadNetwork(perNetwork); 558 } 559 } 560 } 561 562 /** 563 * Update NetworkStats of all configured networks after a SW build change is detected 564 */ updateAllNetworkAfterSwBuildChange()565 private void updateAllNetworkAfterSwBuildChange() { 566 List<WifiConfiguration> configuredNetworks = mWifiConfigManager.getConfiguredNetworks(); 567 for (WifiConfiguration network : configuredNetworks) { 568 if (isInvalidConfiguredNetwork(network)) { 569 continue; 570 } 571 logd(network.SSID); 572 WifiScoreCard.PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(network.SSID); 573 574 logd("before SW build update: " + perNetwork); 575 perNetwork.updateAfterSwBuildChange(); 576 logd("after SW build update: " + perNetwork); 577 } 578 } 579 580 /** 581 * Extract current software build information from the running software. 582 */ extractCurrentSoftwareBuildInfo()583 private WifiSoftwareBuildInfo extractCurrentSoftwareBuildInfo() { 584 if (!mWifiEnabled) { 585 return null; 586 } 587 long wifiStackVersion = getWifiStackVersion(); 588 String osBuildVersion = replaceNullByEmptyString(Build.DISPLAY); 589 if (mWifiNative == null) { 590 return null; 591 } 592 String driverVersion = replaceNullByEmptyString(mWifiNative.getDriverVersion()); 593 String firmwareVersion = replaceNullByEmptyString(mWifiNative.getFirmwareVersion()); 594 return (new WifiSoftwareBuildInfo(osBuildVersion, 595 wifiStackVersion, driverVersion, firmwareVersion)); 596 } 597 replaceNullByEmptyString(String str)598 private String replaceNullByEmptyString(String str) { 599 return str == null ? "" : str; 600 } 601 602 /** 603 * Clears the internal state. 604 * This is called in response to a factoryReset call from Settings. 605 */ clear()606 public void clear() { 607 mWifiSystemInfoStats.clearAll(); 608 } 609 610 public static final int REASON_NO_FAILURE = -1; 611 public static final int REASON_ASSOC_REJECTION = 0; 612 public static final int REASON_ASSOC_TIMEOUT = 1; 613 public static final int REASON_AUTH_FAILURE = 2; 614 public static final int REASON_CONNECTION_FAILURE = 3; 615 public static final int REASON_DISCONNECTION_NONLOCAL = 4; 616 public static final int REASON_SHORT_CONNECTION_NONLOCAL = 5; 617 public static final int REASON_CONNECTION_FAILURE_DISCONNECTION = 6; 618 public static final int NUMBER_FAILURE_REASON_CODE = 7; 619 public static final String[] FAILURE_REASON_NAME = { 620 "association rejection failure", 621 "association timeout failure", 622 "authentication failure", 623 "connection failure", 624 "disconnection", 625 "short connection", 626 "connection failure disconnection", 627 }; 628 @IntDef(prefix = { "REASON_" }, value = { 629 REASON_NO_FAILURE, 630 REASON_ASSOC_REJECTION, 631 REASON_ASSOC_TIMEOUT, 632 REASON_AUTH_FAILURE, 633 REASON_CONNECTION_FAILURE, 634 REASON_DISCONNECTION_NONLOCAL, 635 REASON_SHORT_CONNECTION_NONLOCAL, 636 REASON_CONNECTION_FAILURE_DISCONNECTION 637 }) 638 @Retention(RetentionPolicy.SOURCE) 639 public @interface FailureReasonCode {} 640 641 /** 642 * A class maintaining the number of networks with high failure rate or 643 * with a significant change of failure rate 644 */ 645 public static class FailureStats { 646 private final int[] mCount = new int[NUMBER_FAILURE_REASON_CODE]; clear()647 void clear() { 648 for (int i = 0; i < NUMBER_FAILURE_REASON_CODE; i++) { 649 mCount[i] = 0; 650 } 651 } 652 getCount(@ailureReasonCode int reasonCode)653 int getCount(@FailureReasonCode int reasonCode) { 654 return mCount[reasonCode]; 655 } 656 setCount(@ailureReasonCode int reasonCode, int cnt)657 void setCount(@FailureReasonCode int reasonCode, int cnt) { 658 mCount[reasonCode] = cnt; 659 } 660 incrementCount(@ailureReasonCode int reasonCode)661 void incrementCount(@FailureReasonCode int reasonCode) { 662 mCount[reasonCode]++; 663 } 664 665 @Override toString()666 public String toString() { 667 StringBuilder sb = new StringBuilder(); 668 for (int i = 0; i < NUMBER_FAILURE_REASON_CODE; i++) { 669 if (mCount[i] == 0) continue; 670 sb.append(FAILURE_REASON_NAME[i]).append(": ").append(mCount[i]).append(" "); 671 } 672 return sb.toString(); 673 } 674 } 675 /** 676 * A class maintaining current OS, Wifi APK, Wifi driver and firmware build version information. 677 */ 678 final class WifiSoftwareBuildInfo { 679 private String mOsBuildVersion; 680 private long mWifiStackVersion; 681 private String mWifiDriverVersion; 682 private String mWifiFirmwareVersion; WifiSoftwareBuildInfo(@onNull String osBuildVersion, long wifiStackVersion, @NonNull String wifiDriverVersion, @NonNull String wifiFirmwareVersion)683 WifiSoftwareBuildInfo(@NonNull String osBuildVersion, long wifiStackVersion, 684 @NonNull String wifiDriverVersion, @NonNull String wifiFirmwareVersion) { 685 mOsBuildVersion = osBuildVersion; 686 mWifiStackVersion = wifiStackVersion; 687 mWifiDriverVersion = wifiDriverVersion; 688 mWifiFirmwareVersion = wifiFirmwareVersion; 689 } WifiSoftwareBuildInfo(@onNull WifiSoftwareBuildInfo wifiSoftwareBuildInfo)690 WifiSoftwareBuildInfo(@NonNull WifiSoftwareBuildInfo wifiSoftwareBuildInfo) { 691 mOsBuildVersion = wifiSoftwareBuildInfo.getOsBuildVersion(); 692 mWifiStackVersion = wifiSoftwareBuildInfo.getWifiStackVersion(); 693 mWifiDriverVersion = wifiSoftwareBuildInfo.getWifiDriverVersion(); 694 mWifiFirmwareVersion = wifiSoftwareBuildInfo.getWifiFirmwareVersion(); 695 } getOsBuildVersion()696 String getOsBuildVersion() { 697 return mOsBuildVersion; 698 } getWifiStackVersion()699 long getWifiStackVersion() { 700 return mWifiStackVersion; 701 } getWifiDriverVersion()702 String getWifiDriverVersion() { 703 return mWifiDriverVersion; 704 } getWifiFirmwareVersion()705 String getWifiFirmwareVersion() { 706 return mWifiFirmwareVersion; 707 } 708 @Override equals(Object otherObj)709 public boolean equals(Object otherObj) { 710 if (this == otherObj) { 711 return true; 712 } 713 if (!(otherObj instanceof WifiSoftwareBuildInfo)) { 714 return false; 715 } 716 if (otherObj == null) { 717 return false; 718 } 719 WifiSoftwareBuildInfo other = (WifiSoftwareBuildInfo) otherObj; 720 return mOsBuildVersion.equals(other.getOsBuildVersion()) 721 && mWifiStackVersion == other.getWifiStackVersion() 722 && mWifiDriverVersion.equals(other.getWifiDriverVersion()) 723 && mWifiFirmwareVersion.equals(other.getWifiFirmwareVersion()); 724 } 725 @Override toString()726 public String toString() { 727 StringBuilder sb = new StringBuilder(); 728 sb.append("OS build version: "); 729 sb.append(mOsBuildVersion); 730 sb.append(" Wifi stack version: "); 731 sb.append(mWifiStackVersion); 732 sb.append(" Wifi driver version: "); 733 sb.append(mWifiDriverVersion); 734 sb.append(" Wifi firmware version: "); 735 sb.append(mWifiFirmwareVersion); 736 return sb.toString(); 737 } 738 } 739 740 /** 741 * A class maintaining various WiFi system information and statistics. 742 */ 743 final class WifiSystemInfoStats extends MemoryStoreAccessBase { 744 private WifiSoftwareBuildInfo mCurrSoftwareBuildInfo; 745 private WifiSoftwareBuildInfo mPrevSoftwareBuildInfo; 746 private ScanStats mCurrScanStats = new ScanStats(); 747 private ScanStats mPrevScanStats = new ScanStats(); 748 private int mScanFailure; 749 private @DeviceMobilityState int mMobilityState; 750 private boolean mChanged = false; WifiSystemInfoStats(String l2KeySeed)751 WifiSystemInfoStats(String l2KeySeed) { 752 super(WifiScoreCard.computeHashLong( 753 "", MacAddress.fromString(DEFAULT_MAC_ADDRESS), l2KeySeed)); 754 } 755 getCurrScanStats()756 ScanStats getCurrScanStats() { 757 return mCurrScanStats; 758 } 759 setChanged(boolean changed)760 void setChanged(boolean changed) { 761 mChanged = changed; 762 } 763 setCurrSoftwareBuildInfo(WifiSoftwareBuildInfo currSoftwareBuildInfo)764 void setCurrSoftwareBuildInfo(WifiSoftwareBuildInfo currSoftwareBuildInfo) { 765 mCurrSoftwareBuildInfo = currSoftwareBuildInfo; 766 mChanged = true; 767 } 768 setMobilityState(@eviceMobilityState int mobilityState)769 void setMobilityState(@DeviceMobilityState int mobilityState) { 770 mMobilityState = mobilityState; 771 } 772 getCurrSoftwareBuildInfo()773 WifiSoftwareBuildInfo getCurrSoftwareBuildInfo() { 774 return mCurrSoftwareBuildInfo; 775 } 776 getPrevSoftwareBuildInfo()777 WifiSoftwareBuildInfo getPrevSoftwareBuildInfo() { 778 return mPrevSoftwareBuildInfo; 779 } 780 clearAll()781 void clearAll() { 782 mCurrSoftwareBuildInfo = null; 783 mPrevSoftwareBuildInfo = null; 784 mCurrScanStats.clear(); 785 mPrevScanStats.clear(); 786 mChanged = true; 787 } 788 789 /** 790 * Detect if there is a SW build change by comparing current SW build version vs. SW build 791 * version previously saved in MemoryStore. 792 * @param currSoftwareBuildInfo is current SW build info derived from running SW 793 * @return true if a SW build change is detected, false if no change is detected. 794 */ detectSwBuildChange(@onNull WifiSoftwareBuildInfo currSoftwareBuildInfo)795 boolean detectSwBuildChange(@NonNull WifiSoftwareBuildInfo currSoftwareBuildInfo) { 796 if (mCurrSoftwareBuildInfo == null) { 797 return false; 798 } 799 800 logd(" from Memory: " + mCurrSoftwareBuildInfo); 801 logd(" from SW: " + currSoftwareBuildInfo); 802 return (!mCurrSoftwareBuildInfo.equals(currSoftwareBuildInfo)); 803 } 804 updateBuildInfoAfterSwBuildChange(@onNull WifiSoftwareBuildInfo currBuildInfo)805 void updateBuildInfoAfterSwBuildChange(@NonNull WifiSoftwareBuildInfo currBuildInfo) { 806 mPrevSoftwareBuildInfo = new WifiSoftwareBuildInfo(mCurrSoftwareBuildInfo); 807 mCurrSoftwareBuildInfo = new WifiSoftwareBuildInfo(currBuildInfo); 808 mChanged = true; 809 } 810 readFromMemory()811 void readFromMemory() { 812 if (mMemoryStore != null) { 813 mMemoryStore.read(getL2Key(), SYSTEM_INFO_DATA_NAME, 814 (value) -> readBackListener(value)); 815 } 816 } 817 818 // Read may not be completed in theory when finishPendingRead() is called. 819 // Currently it relies on the fact that memory read is issued right after boot complete 820 // while finishPendingRead() is called only POST_BOOT_DETECTION_WAIT_TIME_MS after that. finishPendingRead()821 private void finishPendingRead() { 822 final byte[] serialized = finishPendingReadBytes(); 823 if (serialized == null) { 824 logd("Fail to read systemInfoStats from memory"); 825 return; 826 } 827 SystemInfoStats systemInfoStats; 828 try { 829 systemInfoStats = SystemInfoStats.parseFrom(serialized); 830 } catch (InvalidProtocolBufferException e) { 831 Log.e(TAG, "Failed to deserialize", e); 832 return; 833 } 834 readFromMemory(systemInfoStats); 835 } 836 readFromMemory(@onNull SystemInfoStats systemInfoStats)837 private void readFromMemory(@NonNull SystemInfoStats systemInfoStats) { 838 if (systemInfoStats.hasCurrSoftwareBuildInfo()) { 839 mCurrSoftwareBuildInfo = fromSoftwareBuildInfo( 840 systemInfoStats.getCurrSoftwareBuildInfo()); 841 } 842 if (systemInfoStats.hasPrevSoftwareBuildInfo()) { 843 mPrevSoftwareBuildInfo = fromSoftwareBuildInfo( 844 systemInfoStats.getPrevSoftwareBuildInfo()); 845 } 846 if (systemInfoStats.hasNumBssidLastScan2G()) { 847 mPrevScanStats.setNumBssidLastScan2g(systemInfoStats.getNumBssidLastScan2G()); 848 } 849 if (systemInfoStats.hasNumBssidLastScanAbove2G()) { 850 mPrevScanStats.setNumBssidLastScanAbove2g(systemInfoStats 851 .getNumBssidLastScanAbove2G()); 852 } 853 if (systemInfoStats.hasLastScanTimeMs()) { 854 mPrevScanStats.setLastScanTimeMs(systemInfoStats.getLastScanTimeMs()); 855 } 856 } 857 writeToMemory()858 void writeToMemory() { 859 if (mMemoryStore == null || !mChanged) return; 860 byte[] serialized = toSystemInfoStats().toByteArray(); 861 mMemoryStore.write(getL2Key(), SYSTEM_INFO_DATA_NAME, serialized); 862 mChanged = false; 863 } 864 toSystemInfoStats()865 SystemInfoStats toSystemInfoStats() { 866 SystemInfoStats.Builder builder = SystemInfoStats.newBuilder(); 867 if (mCurrSoftwareBuildInfo != null) { 868 builder.setCurrSoftwareBuildInfo(toSoftwareBuildInfo(mCurrSoftwareBuildInfo)); 869 } 870 if (mPrevSoftwareBuildInfo != null) { 871 builder.setPrevSoftwareBuildInfo(toSoftwareBuildInfo(mPrevSoftwareBuildInfo)); 872 } 873 builder.setLastScanTimeMs(mCurrScanStats.getLastScanTimeMs()); 874 builder.setNumBssidLastScan2G(mCurrScanStats.getNumBssidLastScan2g()); 875 builder.setNumBssidLastScanAbove2G(mCurrScanStats.getNumBssidLastScanAbove2g()); 876 return builder.build(); 877 } 878 toSoftwareBuildInfo( @onNull WifiSoftwareBuildInfo softwareBuildInfo)879 private SoftwareBuildInfo toSoftwareBuildInfo( 880 @NonNull WifiSoftwareBuildInfo softwareBuildInfo) { 881 SoftwareBuildInfo.Builder builder = SoftwareBuildInfo.newBuilder(); 882 builder.setOsBuildVersion(softwareBuildInfo.getOsBuildVersion()); 883 builder.setWifiStackVersion(softwareBuildInfo.getWifiStackVersion()); 884 builder.setWifiDriverVersion(softwareBuildInfo.getWifiDriverVersion()); 885 builder.setWifiFirmwareVersion(softwareBuildInfo.getWifiFirmwareVersion()); 886 return builder.build(); 887 } 888 fromSoftwareBuildInfo( @onNull SoftwareBuildInfo softwareBuildInfo)889 WifiSoftwareBuildInfo fromSoftwareBuildInfo( 890 @NonNull SoftwareBuildInfo softwareBuildInfo) { 891 String osBuildVersion = softwareBuildInfo.hasOsBuildVersion() 892 ? softwareBuildInfo.getOsBuildVersion() : "NA"; 893 long stackVersion = softwareBuildInfo.hasWifiStackVersion() 894 ? softwareBuildInfo.getWifiStackVersion() : 0; 895 String driverVersion = softwareBuildInfo.hasWifiDriverVersion() 896 ? softwareBuildInfo.getWifiDriverVersion() : "NA"; 897 String firmwareVersion = softwareBuildInfo.hasWifiFirmwareVersion() 898 ? softwareBuildInfo.getWifiFirmwareVersion() : "NA"; 899 return new WifiSoftwareBuildInfo(osBuildVersion, stackVersion, 900 driverVersion, firmwareVersion); 901 } 902 /** 903 * Detect pre-boot or post-boot detection failure. 904 * @return 0 if no failure is found or a positive integer if failure is found where 905 * b0 for pre-boot 2G scan failure 906 * b1 for pre-boot Above2g scan failure 907 * b2 for post-boot 2G scan failure 908 * b3 for post-boot Above2g scan failure 909 */ postBootAbnormalScanDetection(ScanStats firstScanStats)910 void postBootAbnormalScanDetection(ScanStats firstScanStats) { 911 long preBootScanTimeMs = mPrevScanStats.getLastScanTimeMs(); 912 long postBootScanTimeMs = firstScanStats.getLastScanTimeMs(); 913 logd(" preBootScanTimeMs: " + preBootScanTimeMs); 914 logd(" postBootScanTimeMs: " + postBootScanTimeMs); 915 int preBootNumBssid2g = mPrevScanStats.getNumBssidLastScan2g(); 916 int preBootNumBssidAbove2g = mPrevScanStats.getNumBssidLastScanAbove2g(); 917 int postBootNumBssid2g = firstScanStats.getNumBssidLastScan2g(); 918 int postBootNumBssidAbove2g = firstScanStats.getNumBssidLastScanAbove2g(); 919 logd(" preBootScan 2G count: " + preBootNumBssid2g 920 + ", Above2G count: " + preBootNumBssidAbove2g); 921 logd(" postBootScan 2G count: " + postBootNumBssid2g 922 + ", Above2G count: " + postBootNumBssidAbove2g); 923 mScanFailure = 0; 924 if (postBootScanTimeMs == TS_NONE || preBootScanTimeMs == TS_NONE) return; 925 if ((postBootScanTimeMs - preBootScanTimeMs) > MAX_INTERVAL_BETWEEN_TWO_SCAN_MS) { 926 return; 927 } 928 if (preBootNumBssid2g == 0 && postBootNumBssid2g >= MIN_NUM_BSSID_SCAN_2G) { 929 mScanFailure += 1; 930 } 931 if (preBootNumBssidAbove2g == 0 && postBootNumBssidAbove2g 932 >= MIN_NUM_BSSID_SCAN_ABOVE_2G) { 933 mScanFailure += 2; 934 } 935 if (postBootNumBssid2g == 0 && preBootNumBssid2g >= MIN_NUM_BSSID_SCAN_2G) { 936 mScanFailure += 4; 937 } 938 if (postBootNumBssidAbove2g == 0 && preBootNumBssidAbove2g 939 >= MIN_NUM_BSSID_SCAN_ABOVE_2G) { 940 mScanFailure += 8; 941 } 942 } 943 getScanFailure()944 int getScanFailure() { 945 return mScanFailure; 946 } 947 948 @Override toString()949 public String toString() { 950 StringBuilder sb = new StringBuilder(); 951 if (mCurrSoftwareBuildInfo != null) { 952 sb.append("current SW build: "); 953 sb.append(mCurrSoftwareBuildInfo); 954 } 955 if (mPrevSoftwareBuildInfo != null) { 956 sb.append("\n"); 957 sb.append("previous SW build: "); 958 sb.append(mPrevSoftwareBuildInfo); 959 } 960 sb.append("\n"); 961 sb.append("currScanStats: "); 962 sb.append(mCurrScanStats); 963 sb.append("\n"); 964 sb.append("prevScanStats: "); 965 sb.append(mPrevScanStats); 966 return sb.toString(); 967 } 968 } 969 970 final class ScanStats { 971 private long mLastScanTimeMs = TS_NONE; 972 private int mNumBssidLastScan2g; 973 private int mNumBssidLastScanAbove2g; copy(ScanStats source)974 void copy(ScanStats source) { 975 mLastScanTimeMs = source.mLastScanTimeMs; 976 mNumBssidLastScan2g = source.mNumBssidLastScan2g; 977 mNumBssidLastScanAbove2g = source.mNumBssidLastScanAbove2g; 978 } setLastScanTimeMs(long lastScanTimeMs)979 void setLastScanTimeMs(long lastScanTimeMs) { 980 mLastScanTimeMs = lastScanTimeMs; 981 } setNumBssidLastScan2g(int numBssidLastScan2g)982 void setNumBssidLastScan2g(int numBssidLastScan2g) { 983 mNumBssidLastScan2g = numBssidLastScan2g; 984 } setNumBssidLastScanAbove2g(int numBssidLastScanAbove2g)985 void setNumBssidLastScanAbove2g(int numBssidLastScanAbove2g) { 986 mNumBssidLastScanAbove2g = numBssidLastScanAbove2g; 987 } getLastScanTimeMs()988 long getLastScanTimeMs() { 989 return mLastScanTimeMs; 990 } getNumBssidLastScan2g()991 int getNumBssidLastScan2g() { 992 return mNumBssidLastScan2g; 993 } getNumBssidLastScanAbove2g()994 int getNumBssidLastScanAbove2g() { 995 return mNumBssidLastScanAbove2g; 996 } incrementNumBssidLastScan2g()997 void incrementNumBssidLastScan2g() { 998 mNumBssidLastScan2g++; 999 } incrementNumBssidLastScanAbove2g()1000 void incrementNumBssidLastScanAbove2g() { 1001 mNumBssidLastScanAbove2g++; 1002 } clear()1003 void clear() { 1004 mLastScanTimeMs = TS_NONE; 1005 mNumBssidLastScan2g = 0; 1006 mNumBssidLastScanAbove2g = 0; 1007 } 1008 @Override toString()1009 public String toString() { 1010 StringBuilder sb = new StringBuilder(); 1011 sb.append("last scan time: "); 1012 sb.append(mLastScanTimeMs); 1013 sb.append(" APs found at 2G: "); 1014 sb.append(mNumBssidLastScan2g); 1015 sb.append(" APs found above 2g: "); 1016 sb.append(mNumBssidLastScanAbove2g); 1017 return sb.toString(); 1018 } 1019 } 1020 1021 @VisibleForTesting getWifiSystemInfoStats()1022 WifiSystemInfoStats getWifiSystemInfoStats() { 1023 return mWifiSystemInfoStats; 1024 } 1025 logd(String string)1026 private void logd(String string) { 1027 if (mVerboseLoggingEnabled) { 1028 Log.d(TAG, string); 1029 } 1030 } 1031 1032 /** 1033 * Listener for config manager network config related events. 1034 */ 1035 private class OnNetworkUpdateListener implements 1036 WifiConfigManager.OnNetworkUpdateListener { 1037 1038 @Override onNetworkAdded(WifiConfiguration config)1039 public void onNetworkAdded(WifiConfiguration config) { 1040 if (config == null) return; 1041 mWifiScoreCard.lookupNetwork(config.SSID); 1042 } 1043 1044 @Override onNetworkRemoved(WifiConfiguration config)1045 public void onNetworkRemoved(WifiConfiguration config) { 1046 if (config == null || (config.fromWifiNetworkSuggestion && !config.isPasspoint())) { 1047 // If a suggestion non-passpoint network is removed from wifiConfigManager do not 1048 // remove the ScoreCard. That will be removed when suggestion is removed. 1049 return; 1050 } 1051 mWifiScoreCard.removeNetwork(config.SSID); 1052 } 1053 } 1054 1055 /** 1056 * Scan listener for any full band scan. 1057 */ 1058 private class ScanListener implements WifiScanner.ScanListener { 1059 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 1060 clearScanDetails()1061 public void clearScanDetails() { 1062 mScanDetails.clear(); 1063 } 1064 1065 @Override onSuccess()1066 public void onSuccess() { 1067 } 1068 1069 @Override onFailure(int reason, String description)1070 public void onFailure(int reason, String description) { 1071 logd("registerScanListener onFailure:" 1072 + " reason: " + reason + " description: " + description); 1073 } 1074 1075 @Override onPeriodChanged(int periodInMs)1076 public void onPeriodChanged(int periodInMs) { 1077 } 1078 1079 @Override onResults(WifiScanner.ScanData[] results)1080 public void onResults(WifiScanner.ScanData[] results) { 1081 if (!mWifiEnabled || results == null || results.length == 0) { 1082 clearScanDetails(); 1083 return; 1084 } 1085 1086 if (WifiScanner.isFullBandScan(results[0].getScannedBandsInternal(), true)) { 1087 handleScanResults(mScanDetails); 1088 } 1089 clearScanDetails(); 1090 } 1091 1092 @Override onFullResult(ScanResult fullScanResult)1093 public void onFullResult(ScanResult fullScanResult) { 1094 if (!mWifiEnabled) { 1095 return; 1096 } 1097 mScanDetails.add(ScanResultUtil.toScanDetail(fullScanResult)); 1098 } 1099 } 1100 } 1101