WifiScoreReport.java revision 9b256a5cb87062b7ae1696324e2bd7c9b1ceca27
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.content.Context; 20import android.net.NetworkAgent; 21import android.net.wifi.WifiConfiguration; 22import android.net.wifi.WifiInfo; 23import android.util.Log; 24 25import com.android.internal.R; 26 27/** 28 * Class used to calculate scores for connected wifi networks and report it to the associated 29 * network agent. 30 * TODO: Add unit tests for this class. 31*/ 32public class WifiScoreReport { 33 private static final String TAG = "WifiScoreReport"; 34 35 // TODO: This score was hardcorded to 56. Need to understand why after finishing code refactor 36 private static final int STARTING_SCORE = 56; 37 38 // TODO: Understand why these values are used 39 private static final int MAX_BAD_LINKSPEED_COUNT = 6; 40 private static final int SCAN_CACHE_VISIBILITY_MS = 12000; 41 private static final int HOME_VISIBLE_NETWORK_MAX_COUNT = 6; 42 private static final int SCAN_CACHE_COUNT_PENALTY = 2; 43 private static final int AGGRESSIVE_HANDOVER_PENALTY = 6; 44 private static final int MIN_SUCCESS_COUNT = 5; 45 private static final int MAX_SUCCESS_COUNT_OF_STUCK_LINK = 3; 46 private static final int MAX_STUCK_LINK_COUNT = 5; 47 private static final int MIN_NUM_TICKS_AT_STATE = 1000; 48 private static final int USER_DISCONNECT_PENALTY = 5; 49 private static final int MAX_BAD_RSSI_COUNT = 7; 50 private static final int BAD_RSSI_COUNT_PENALTY = 2; 51 private static final int MAX_LOW_RSSI_COUNT = 1; 52 private static final double MIN_TX_RATE_FOR_WORKING_LINK = 0.3; 53 private static final int MIN_SUSTAINED_LINK_STUCK_COUNT = 1; 54 private static final int LINK_STUCK_PENALTY = 2; 55 private static final int BAD_LINKSPEED_PENALTY = 4; 56 private static final int GOOD_LINKSPEED_BONUS = 4; 57 58 // Device configs. The values are examples. 59 private final int mThresholdMinimumRssi5; // -82 60 private final int mThresholdQualifiedRssi5; // -70 61 private final int mThresholdSaturatedRssi5; // -57 62 private final int mThresholdMinimumRssi24; // -85 63 private final int mThresholdQualifiedRssi24; // -73 64 private final int mThresholdSaturatedRssi24; // -60 65 private final int mBadLinkSpeed24; // 6 Mbps 66 private final int mBadLinkSpeed5; // 12 Mbps 67 private final int mGoodLinkSpeed24; // 24 Mbps 68 private final int mGoodLinkSpeed5; // 36 Mbps 69 private final boolean mEnableWifiCellularHandoverUserTriggeredAdjustment; // true 70 71 private final WifiConfigManager mWifiConfigManager; 72 private boolean mVerboseLoggingEnabled = false; 73 74 // Cache of the last score report. 75 private String mReport; 76 private int mBadLinkspeedcount = 0; 77 private boolean mReportValid = false; 78 79 WifiScoreReport(Context context, WifiConfigManager wifiConfigManager) { 80 // Fetch all the device configs. 81 mThresholdMinimumRssi5 = context.getResources().getInteger( 82 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz); 83 mThresholdQualifiedRssi5 = context.getResources().getInteger( 84 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz); 85 mThresholdSaturatedRssi5 = context.getResources().getInteger( 86 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz); 87 mThresholdMinimumRssi24 = context.getResources().getInteger( 88 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz); 89 mThresholdQualifiedRssi24 = context.getResources().getInteger( 90 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz); 91 mThresholdSaturatedRssi24 = context.getResources().getInteger( 92 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz); 93 mBadLinkSpeed24 = context.getResources().getInteger( 94 R.integer.config_wifi_framework_wifi_score_bad_link_speed_24); 95 mBadLinkSpeed5 = context.getResources().getInteger( 96 R.integer.config_wifi_framework_wifi_score_bad_link_speed_5); 97 mGoodLinkSpeed24 = context.getResources().getInteger( 98 R.integer.config_wifi_framework_wifi_score_good_link_speed_24); 99 mGoodLinkSpeed5 = context.getResources().getInteger( 100 R.integer.config_wifi_framework_wifi_score_good_link_speed_5); 101 mEnableWifiCellularHandoverUserTriggeredAdjustment = context.getResources().getBoolean( 102 R.bool.config_wifi_framework_cellular_handover_enable_user_triggered_adjustment); 103 104 mWifiConfigManager = wifiConfigManager; 105 } 106 107 /** 108 * Method returning the String representation of the last score report. 109 * 110 * @return String score report 111 */ 112 public String getLastReport() { 113 return mReport; 114 } 115 116 /** 117 * Method returning the bad link speed count at the time of the last score report. 118 * 119 * @return int bad linkspeed count 120 */ 121 public int getLastBadLinkspeedcount() { 122 return mBadLinkspeedcount; 123 } 124 125 /** 126 * Reset the last calculated score. 127 */ 128 public void reset() { 129 mBadLinkspeedcount = 0; 130 mReport = ""; 131 mReportValid = false; 132 } 133 134 /** 135 * Checks if the last report data is valid or not. This will be cleared when {@link #reset()} is 136 * invoked. 137 * 138 * @return true if valid, false otherwise. 139 */ 140 public boolean isLastReportValid() { 141 return mReportValid; 142 } 143 144 /** 145 * Enable/Disable verbose logging in score report generation. 146 */ 147 public void enableVerboseLogging(boolean enable) { 148 mVerboseLoggingEnabled = enable; 149 } 150 151 /** 152 * Calculate wifi network score based on updated link layer stats and send the score to 153 * the provided network agent. 154 * 155 * If the score has changed from the previous value, update the WifiNetworkAgent. 156 * 157 * Called periodically (POLL_RSSI_INTERVAL_MSECS) about every 3 seconds. 158 * 159 * @param wifiInfo WifiInfo instance pointing to the currently connected network. 160 * @param networkAgent NetworkAgent to be notified of new score. 161 * @param aggressiveHandover int current aggressiveHandover setting. 162 * @param wifiMetrics for reporting our scores. 163 */ 164 public void calculateAndReportScore( 165 WifiInfo wifiInfo, NetworkAgent networkAgent, int aggressiveHandover, 166 WifiMetrics wifiMetrics) { 167 WifiInfo checkWifiInfo = new WifiInfo(wifiInfo); 168 StringBuilder sb = new StringBuilder(); 169 170 int score = STARTING_SCORE; 171 boolean isBadLinkspeed = (wifiInfo.is24GHz() 172 && wifiInfo.getLinkSpeed() < mBadLinkSpeed24) 173 || (wifiInfo.is5GHz() && wifiInfo.getLinkSpeed() 174 < mBadLinkSpeed5); 175 boolean isGoodLinkspeed = (wifiInfo.is24GHz() 176 && wifiInfo.getLinkSpeed() >= mGoodLinkSpeed24) 177 || (wifiInfo.is5GHz() && wifiInfo.getLinkSpeed() 178 >= mGoodLinkSpeed5); 179 180 if (isBadLinkspeed) { 181 if (mBadLinkspeedcount < MAX_BAD_LINKSPEED_COUNT) { 182 mBadLinkspeedcount++; 183 } 184 } else { 185 if (mBadLinkspeedcount > 0) { 186 mBadLinkspeedcount--; 187 } 188 } 189 190 if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")"); 191 if (isGoodLinkspeed) sb.append(" gl"); 192 193 WifiConfiguration currentConfiguration = 194 mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId()); 195 ScanDetailCache scanDetailCache = 196 mWifiConfigManager.getScanDetailCacheForNetwork(wifiInfo.getNetworkId()); 197 /** 198 * We want to make sure that we use the 2.4GHz RSSI thresholds if 199 * there are 2.4GHz scan results otherwise we end up lowering the score based on 5GHz values 200 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 201 * We also might unblacklist the configuation based on 2.4GHz 202 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 203 */ 204 boolean use24Thresholds = false; 205 boolean homeNetworkBoost = false; 206 if (currentConfiguration != null && scanDetailCache != null) { 207 currentConfiguration.setVisibility( 208 scanDetailCache.getVisibility(SCAN_CACHE_VISIBILITY_MS)); 209 if (currentConfiguration.visibility != null) { 210 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 211 && currentConfiguration.visibility.rssi24 212 >= (currentConfiguration.visibility.rssi5 - SCAN_CACHE_COUNT_PENALTY)) { 213 use24Thresholds = true; 214 } 215 } 216 if (scanDetailCache.size() <= HOME_VISIBLE_NETWORK_MAX_COUNT 217 && currentConfiguration.allowedKeyManagement.cardinality() == 1 218 && currentConfiguration.allowedKeyManagement 219 .get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 220 // A PSK network with less than 6 known BSSIDs 221 // This is most likely a home network and thus we want to stick to wifi more 222 homeNetworkBoost = true; 223 } 224 } 225 if (homeNetworkBoost) sb.append(" hn"); 226 if (use24Thresholds) sb.append(" u24"); 227 228 int rssi = wifiInfo.getRssi() - AGGRESSIVE_HANDOVER_PENALTY * aggressiveHandover 229 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 230 sb.append(String.format(" rssi=%d ag=%d", rssi, aggressiveHandover)); 231 232 boolean is24GHz = use24Thresholds || wifiInfo.is24GHz(); 233 234 boolean isBadRSSI = (is24GHz && rssi < mThresholdMinimumRssi24) 235 || (!is24GHz && rssi < mThresholdMinimumRssi5); 236 boolean isLowRSSI = (is24GHz && rssi < mThresholdQualifiedRssi24) 237 || (!is24GHz 238 && rssi < mThresholdQualifiedRssi5); 239 boolean isHighRSSI = (is24GHz && rssi >= mThresholdSaturatedRssi24) 240 || (!is24GHz 241 && rssi >= mThresholdSaturatedRssi5); 242 243 if (isBadRSSI) sb.append(" br"); 244 if (isLowRSSI) sb.append(" lr"); 245 if (isHighRSSI) sb.append(" hr"); 246 247 if (mVerboseLoggingEnabled) { 248 String rssiStatus = ""; 249 if (isBadRSSI) { 250 rssiStatus += " badRSSI "; 251 } else if (isHighRSSI) { 252 rssiStatus += " highRSSI "; 253 } else if (isLowRSSI) { 254 rssiStatus += " lowRSSI "; 255 } 256 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 257 Log.d(TAG, " wifi scoring details freq=" + Integer.toString(wifiInfo.getFrequency()) 258 + " speed=" + Integer.toString(wifiInfo.getLinkSpeed()) 259 + " score=" + Integer.toString(wifiInfo.score) // Previous score 260 + rssiStatus 261 + " -> txbadrate=" + String.format("%.2f", wifiInfo.txBadRate) 262 + " txgoodrate=" + String.format("%.2f", wifiInfo.txSuccessRate) 263 + " txretriesrate=" + String.format("%.2f", wifiInfo.txRetriesRate) 264 + " rxrate=" + String.format("%.2f", wifiInfo.rxSuccessRate)); 265 } 266 267 if ((wifiInfo.txBadRate >= 1) 268 && (wifiInfo.txSuccessRate < MAX_SUCCESS_COUNT_OF_STUCK_LINK) 269 && (isBadRSSI || isLowRSSI)) { 270 // Link is stuck 271 if (wifiInfo.linkStuckCount < MAX_STUCK_LINK_COUNT) { 272 wifiInfo.linkStuckCount += 1; 273 } 274 sb.append(String.format(" ls+=%d", wifiInfo.linkStuckCount)); 275 if (mVerboseLoggingEnabled) { 276 Log.d(TAG, " bad link -> stuck count =" 277 + Integer.toString(wifiInfo.linkStuckCount)); 278 } 279 } else if (wifiInfo.txBadRate < MIN_TX_RATE_FOR_WORKING_LINK) { 280 if (wifiInfo.linkStuckCount > 0) { 281 wifiInfo.linkStuckCount -= 1; 282 } 283 sb.append(String.format(" ls-=%d", wifiInfo.linkStuckCount)); 284 if (mVerboseLoggingEnabled) { 285 Log.d(TAG, " good link -> stuck count =" 286 + Integer.toString(wifiInfo.linkStuckCount)); 287 } 288 } 289 290 sb.append(String.format(" [%d", score)); 291 292 if (wifiInfo.linkStuckCount > MIN_SUSTAINED_LINK_STUCK_COUNT) { 293 // Once link gets stuck for more than 3 seconds, start reducing the score 294 score = score - LINK_STUCK_PENALTY * (wifiInfo.linkStuckCount - 1); 295 } 296 sb.append(String.format(",%d", score)); 297 298 if (isBadLinkspeed) { 299 score -= BAD_LINKSPEED_PENALTY; 300 if (mVerboseLoggingEnabled) { 301 Log.d(TAG, " isBadLinkspeed ---> count=" + mBadLinkspeedcount 302 + " score=" + Integer.toString(score)); 303 } 304 } else if ((isGoodLinkspeed) && (wifiInfo.txSuccessRate > 5)) { 305 score += GOOD_LINKSPEED_BONUS; // So as bad rssi alone dont kill us 306 } 307 sb.append(String.format(",%d", score)); 308 309 if (isBadRSSI) { 310 if (wifiInfo.badRssiCount < MAX_BAD_RSSI_COUNT) { 311 wifiInfo.badRssiCount += 1; 312 } 313 } else if (isLowRSSI) { 314 wifiInfo.lowRssiCount = MAX_LOW_RSSI_COUNT; // Dont increment the lowRssi count above 1 315 if (wifiInfo.badRssiCount > 0) { 316 // Decrement bad Rssi count 317 wifiInfo.badRssiCount -= 1; 318 } 319 } else { 320 wifiInfo.badRssiCount = 0; 321 wifiInfo.lowRssiCount = 0; 322 } 323 324 score -= wifiInfo.badRssiCount * BAD_RSSI_COUNT_PENALTY + wifiInfo.lowRssiCount; 325 sb.append(String.format(",%d", score)); 326 327 if (mVerboseLoggingEnabled) { 328 Log.d(TAG, " badRSSI count" + Integer.toString(wifiInfo.badRssiCount) 329 + " lowRSSI count" + Integer.toString(wifiInfo.lowRssiCount) 330 + " --> score " + Integer.toString(score)); 331 } 332 333 if (isHighRSSI) { 334 score += 5; 335 if (mVerboseLoggingEnabled) Log.d(TAG, " isHighRSSI ---> score=" + score); 336 } 337 sb.append(String.format(",%d]", score)); 338 339 sb.append(String.format(" brc=%d lrc=%d", wifiInfo.badRssiCount, wifiInfo.lowRssiCount)); 340 341 //sanitize boundaries 342 if (score > NetworkAgent.WIFI_BASE_SCORE) { 343 score = NetworkAgent.WIFI_BASE_SCORE; 344 } 345 if (score < 0) { 346 score = 0; 347 } 348 349 updateScoringState(checkWifiInfo, aggressiveHandover); 350 int checkScore = calculateScore(checkWifiInfo, aggressiveHandover); 351 352 if (score != checkScore) { 353 Log.e(TAG, "recalculated score does not match: " + score + "," + checkScore); 354 } 355 if (wifiInfo.linkStuckCount != checkWifiInfo.linkStuckCount) { 356 Log.e(TAG, "recalculated linkStuckCount does not match: " 357 + wifiInfo.linkStuckCount + "," + checkWifiInfo.linkStuckCount); 358 } 359 if (wifiInfo.badRssiCount != checkWifiInfo.badRssiCount) { 360 Log.e(TAG, "recalculated badRssiCount does not match: " 361 + wifiInfo.badRssiCount + "," + checkWifiInfo.badRssiCount); 362 } 363 if (wifiInfo.lowRssiCount != checkWifiInfo.lowRssiCount) { 364 Log.e(TAG, "recalculated lowRssiCount does not match: " 365 + wifiInfo.lowRssiCount + "," + checkWifiInfo.lowRssiCount); 366 } 367 368 //report score 369 if (score != wifiInfo.score) { 370 if (mVerboseLoggingEnabled) { 371 Log.d(TAG, " report new wifi score " + Integer.toString(score)); 372 } 373 wifiInfo.score = score; 374 if (networkAgent != null) { 375 networkAgent.sendNetworkScore(score); 376 } 377 } 378 379 mReport = sb.toString(); 380 mReportValid = true; 381 wifiMetrics.incrementWifiScoreCount(score); 382 Log.e(TAG, mReport); // fur debug 383 } 384 385 /** 386 * Updates the state. 387 */ 388 public void updateScoringState(WifiInfo wifiInfo, int aggressiveHandover) { 389 int rssiThreshBad = mThresholdMinimumRssi24; 390 int rssiThreshLow = mThresholdQualifiedRssi24; 391 392 if (wifiInfo.is5GHz()) { 393 if (!multiBandScanResults(wifiInfo)) { 394 rssiThreshBad = mThresholdMinimumRssi5; 395 rssiThreshLow = mThresholdQualifiedRssi5; 396 } 397 } 398 399 int rssi = wifiInfo.getRssi(); 400 if (aggressiveHandover != 0) { 401 rssi -= AGGRESSIVE_HANDOVER_PENALTY * aggressiveHandover; 402 } 403 if (isHomeNetwork(wifiInfo)) { 404 rssi += WifiConfiguration.HOME_NETWORK_RSSI_BOOST; 405 } 406 407 if ((wifiInfo.txBadRate >= 1) 408 && (wifiInfo.txSuccessRate < MAX_SUCCESS_COUNT_OF_STUCK_LINK) 409 && rssi < rssiThreshLow) { 410 // Link is stuck 411 if (wifiInfo.linkStuckCount < MAX_STUCK_LINK_COUNT) { 412 wifiInfo.linkStuckCount += 1; 413 } 414 } else if (wifiInfo.txBadRate < MIN_TX_RATE_FOR_WORKING_LINK) { 415 if (wifiInfo.linkStuckCount > 0) { 416 wifiInfo.linkStuckCount -= 1; 417 } 418 } 419 420 if (rssi < rssiThreshBad) { 421 if (wifiInfo.badRssiCount < MAX_BAD_RSSI_COUNT) { 422 wifiInfo.badRssiCount += 1; 423 } 424 } else if (rssi < rssiThreshLow) { 425 wifiInfo.lowRssiCount = MAX_LOW_RSSI_COUNT; // Dont increment the lowRssi count above 1 426 if (wifiInfo.badRssiCount > 0) { 427 // Decrement bad Rssi count 428 wifiInfo.badRssiCount -= 1; 429 } 430 } else { 431 wifiInfo.badRssiCount = 0; 432 wifiInfo.lowRssiCount = 0; 433 } 434 435 } 436 437 /** 438 * Calculates the score, without all the cruft. 439 */ 440 public int calculateScore(WifiInfo wifiInfo, int aggressiveHandover) { 441 int score = STARTING_SCORE; 442 443 int rssiThreshSaturated = mThresholdSaturatedRssi24; 444 int linkspeedThreshBad = mBadLinkSpeed24; 445 int linkspeedThreshGood = mGoodLinkSpeed24; 446 447 if (wifiInfo.is24GHz() != !(wifiInfo.is5GHz())) { 448 throw new AssertionError("What is happening here?"); 449 } 450 451 if (wifiInfo.is5GHz()) { 452 if (!multiBandScanResults(wifiInfo)) { 453 rssiThreshSaturated = mThresholdSaturatedRssi5; 454 } 455 linkspeedThreshBad = mBadLinkSpeed5; 456 linkspeedThreshGood = mGoodLinkSpeed5; 457 } 458 459 int rssi = wifiInfo.getRssi(); 460 if (aggressiveHandover != 0) { 461 rssi -= AGGRESSIVE_HANDOVER_PENALTY * aggressiveHandover; 462 } 463 if (isHomeNetwork(wifiInfo)) { 464 rssi += WifiConfiguration.HOME_NETWORK_RSSI_BOOST; 465 } 466 467 int linkSpeed = wifiInfo.getLinkSpeed(); 468 469 // Updates to wifiInfo.linkStuckCount skipped here 470 471 if (wifiInfo.linkStuckCount > MIN_SUSTAINED_LINK_STUCK_COUNT) { 472 // Once link gets stuck for more than 3 seconds, start reducing the score 473 score = score - LINK_STUCK_PENALTY * (wifiInfo.linkStuckCount - 1); 474 } 475 476 if (linkSpeed < linkspeedThreshBad) { 477 score -= BAD_LINKSPEED_PENALTY; 478 } else if ((linkSpeed >= linkspeedThreshGood) && (wifiInfo.txSuccessRate > 5)) { 479 score += GOOD_LINKSPEED_BONUS; // So as bad rssi alone doesn't kill us 480 } 481 482 // Updates to wifiInfo.badRssiCount skipped here 483 484 score -= wifiInfo.badRssiCount * BAD_RSSI_COUNT_PENALTY + wifiInfo.lowRssiCount; 485 486 if (rssi >= rssiThreshSaturated) score += 5; 487 488 if (score > NetworkAgent.WIFI_BASE_SCORE) score = NetworkAgent.WIFI_BASE_SCORE; 489 if (score < 0) score = 0; 490 491 return score; 492 } 493 494 /** 495 * Determines if we can see both 2.4GHz and 5GHz for current config 496 */ 497 private boolean multiBandScanResults(WifiInfo wifiInfo) { 498 WifiConfiguration currentConfiguration = 499 mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId()); 500 if (currentConfiguration == null) return false; 501 ScanDetailCache scanDetailCache = 502 mWifiConfigManager.getScanDetailCacheForNetwork(wifiInfo.getNetworkId()); 503 if (scanDetailCache == null) return false; 504 // TODO(b/36364366): Nasty that we change state here... 505 currentConfiguration.setVisibility(scanDetailCache.getVisibility(SCAN_CACHE_VISIBILITY_MS)); 506 if (currentConfiguration.visibility == null) return false; 507 if (currentConfiguration.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) return false; 508 // TODO: this does not do exactly what is claimed! 509 if (currentConfiguration.visibility.rssi24 510 >= currentConfiguration.visibility.rssi5 - SCAN_CACHE_COUNT_PENALTY) { 511 return true; 512 } 513 return false; 514 } 515 516 /** 517 * Decides whether the current network is a "home" network 518 */ 519 private boolean isHomeNetwork(WifiInfo wifiInfo) { 520 WifiConfiguration currentConfiguration = 521 mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId()); 522 if (currentConfiguration == null) return false; 523 // TODO: This seems like it will only return true for really old routers! 524 if (currentConfiguration.allowedKeyManagement.cardinality() != 1) return false; 525 if (!currentConfiguration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 526 return false; 527 } 528 ScanDetailCache scanDetailCache = 529 mWifiConfigManager.getScanDetailCacheForNetwork(wifiInfo.getNetworkId()); 530 if (scanDetailCache == null) return false; 531 if (scanDetailCache.size() <= HOME_VISIBLE_NETWORK_MAX_COUNT) { 532 return true; 533 } 534 return false; 535 } 536} 537