Target platform: android Q10 platform
android 会将已连接的wifi AP保存到这个文件: data/misc/wifi/WifiConfigStore.xml
然后当wifi 再次打开的时候 scan results后 会将scan results和保存的已连接的wifi AP 中对比, 如果有已保存的wifi网络,则自动重连。
以下是一个已保存的网络节点
ID: 0 SSID: "Pixel_8287" PROVIDER-NAME: null BSSID: null FQDN: null PRIO: 0 HIDDEN: false PMF: false
NetworkSelectionStatus NETWORK_SELECTION_ENABLED
hasEverConnected: true
numAssociation 3
update time=04-13 15:58:20.958
creation time=04-13 15:56:48.640
validatedInternetAccess trusted
macRandomizationSetting: 0
mRandomizedMacAddress: 4e:c2:34:a4:04:79
KeyMgmt: WPA_PSK Protocols: WPA RSN
AuthAlgorithms: OPEN
PairwiseCiphers: TKIP CCMP
GroupCiphers: WEP40 WEP104 TKIP CCMP
GroupMgmtCiphers:
SuiteBCiphers:
PSK/SAE: *
Enterprise config:
IP config:
IP assignment: DHCP
Proxy settings: NONE
cuid=1000 cname=android.uid.system:1000 luid=1000 lname=android.uid.system:1000 lcuid=1000 userApproved=USER_UNSPECIFIED noInternetAccessExpected=true
lastConnected: 04-13 18:04:49.865
recentFailure: Association Rejection code: 0
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
handleScanResults
WifiConfiguration candidate = mNetworkSelector.selectNetwork(scanDetails, buildBssidBlacklist(), mWifiInfo, mStateMachine.isConnected(), mStateMachine.isDisconnected(), mUntrustedConnectionAllowed);
685 /** 686 * Select the best network from the ones in range. 687 * 688 * @param scanDetails List of ScanDetail for all the APs in range 689 * @param bssidBlacklist Blacklisted BSSIDs 690 * @param wifiInfo Currently connected network 691 * @param connected True if the device is connected 692 * @param disconnected True if the device is disconnected 693 * @param untrustedNetworkAllowed True if untrusted networks are allowed for connection 694 * @return Configuration of the selected network, or Null if nothing 695 */ 696 @Nullable 697 public WifiConfiguration selectNetwork(ListscanDetails, 698 HashSet bssidBlacklist, WifiInfo wifiInfo, 699 boolean connected, boolean disconnected, boolean untrustedNetworkAllowed) { 700 mFilteredNetworks.clear(); 701 mConnectableNetworks.clear(); 702 if (scanDetails.size() == 0) { 703 localLog("Empty connectivity scan result"); 704 return null; 705 } 706 707 WifiConfiguration currentNetwork = 708 mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId()); 709 710 // Always get the current BSSID from WifiInfo in case that firmware initiated 711 // roaming happened. 712 String currentBssid = wifiInfo.getBSSID(); 713 714 // Shall we start network selection at all? 715 if (!isNetworkSelectionNeeded(scanDetails, wifiInfo, connected, disconnected)) { 716 return null; 717 } 718 719 // Update all configured networks before initiating network selection. 720 updateConfiguredNetworks(); 721 722 // Update the registered network evaluators. 723 for (NetworkEvaluator registeredEvaluator : mEvaluators) { 724 registeredEvaluator.update(scanDetails); 725 } 726 727 // Filter out unwanted networks. 728 mFilteredNetworks = filterScanResults(scanDetails, bssidBlacklist, 729 connected && wifiInfo.score >= WIFI_POOR_SCORE, currentBssid); 730 if (mFilteredNetworks.size() == 0) { 731 return null; 732 } 733 734 // Determine the weight for the last user selection 735 final int lastUserSelectedNetworkId = mWifiConfigManager.getLastSelectedNetwork(); 736 final double lastSelectionWeight = calculateLastSelectionWeight(); 737 final ArraySet mNetworkIds = new ArraySet<>(); 738 739 // Go through the registered network evaluators in order 740 WifiConfiguration selectedNetwork = null; 741 WifiCandidates wifiCandidates = new WifiCandidates(mWifiScoreCard); 742 if (currentNetwork != null) { 743 wifiCandidates.setCurrent(currentNetwork.networkId, currentBssid); 744 } 745 for (NetworkEvaluator registeredEvaluator : mEvaluators) { 746 localLog("About to run " + registeredEvaluator.getName() + " :"); 747 WifiConfiguration choice = registeredEvaluator.evaluateNetworks( 748 new ArrayList<>(mFilteredNetworks), currentNetwork, currentBssid, connected, 749 untrustedNetworkAllowed, 750 (scanDetail, config, score) -> { 751 if (config != null) { 752 mConnectableNetworks.add(Pair.create(scanDetail, config)); 753 mNetworkIds.add(config.networkId); 754 if (config.networkId == lastUserSelectedNetworkId) { 755 wifiCandidates.add(scanDetail, config, 756 registeredEvaluator.getId(), score, lastSelectionWeight); 757 } else { 758 wifiCandidates.add(scanDetail, config, 759 registeredEvaluator.getId(), score); 760 } 761 mWifiMetrics.setNominatorForNetwork(config.networkId, 762 evaluatorIdToNominatorId(registeredEvaluator.getId())); 763 } 764 }); 765 if (choice != null && !mNetworkIds.contains(choice.networkId)) { 766 Log.wtf(TAG, registeredEvaluator.getName() 767 + " failed to report choice with noConnectibleListener"); 768 } 769 if (selectedNetwork == null && choice != null) { 770 selectedNetwork = choice; // First one wins 771 localLog(registeredEvaluator.getName() + " selects " 772 + WifiNetworkSelector.toNetworkString(selectedNetwork)); 773 } 774 } 775 776 if (mConnectableNetworks.size() != wifiCandidates.size()) { 777 localLog("Connectable: " + mConnectableNetworks.size() 778 + " Candidates: " + wifiCandidates.size()); 779 } 780 781 // Update the NetworkSelectionStatus in the configs for the current candidates 782 // This is needed for the legacy user connect choice, at least 783 Collection > groupedCandidates = 784 wifiCandidates.getGroupedCandidates(); 785 for (Collection group: groupedCandidates) { 786 WifiCandidates.Candidate best = null; 787 for (WifiCandidates.Candidate candidate: group) { 788 // Of all the candidates with the same networkId, choose the 789 // one with the smallest evaluatorId, and break ties by 790 // picking the one with the highest score. 791 if (best == null 792 || candidate.getEvaluatorId() < best.getEvaluatorId() 793 || (candidate.getEvaluatorId() == best.getEvaluatorId() 794 && candidate.getEvaluatorScore() > best.getEvaluatorScore())) { 795 best = candidate; 796 } 797 } 798 if (best != null) { 799 ScanDetail scanDetail = best.getScanDetail(); 800 if (scanDetail != null) { 801 mWifiConfigManager.setNetworkCandidateScanResult(best.getNetworkConfigId(), 802 scanDetail.getScanResult(), best.getEvaluatorScore()); 803 } 804 } 805 } 806 807 ArrayMap experimentNetworkSelections = new ArrayMap<>(); // for metrics 808 809 final int legacySelectedNetworkId = selectedNetwork == null 810 ? WifiConfiguration.INVALID_NETWORK_ID 811 : selectedNetwork.networkId; 812 813 int selectedNetworkId = legacySelectedNetworkId; 814 815 // Run all the CandidateScorers 816 boolean legacyOverrideWanted = true; 817 final WifiCandidates.CandidateScorer activeScorer = getActiveCandidateScorer(); 818 for (WifiCandidates.CandidateScorer candidateScorer : mCandidateScorers.values()) { 819 WifiCandidates.ScoredCandidate choice; 820 try { 821 choice = wifiCandidates.choose(candidateScorer); 822 } catch (RuntimeException e) { 823 Log.wtf(TAG, "Exception running a CandidateScorer", e); 824 continue; 825 } 826 int networkId = choice.candidateKey == null 827 ? WifiConfiguration.INVALID_NETWORK_ID 828 : choice.candidateKey.networkId; 829 String chooses = " would choose "; 830 if (candidateScorer == activeScorer) { 831 chooses = " chooses "; 832 legacyOverrideWanted = candidateScorer.userConnectChoiceOverrideWanted(); 833 selectedNetworkId = networkId; 834 } 835 String id = candidateScorer.getIdentifier(); 836 int expid = experimentIdFromIdentifier(id); 837 localLog(id + chooses + networkId 838 + " score " + choice.value + "+/-" + choice.err 839 + " expid " + expid); 840 experimentNetworkSelections.put(expid, networkId); 841 } 842 843 // Update metrics about differences in the selections made by various methods 844 final int activeExperimentId = activeScorer == null ? LEGACY_CANDIDATE_SCORER_EXP_ID 845 : experimentIdFromIdentifier(activeScorer.getIdentifier()); 846 experimentNetworkSelections.put(LEGACY_CANDIDATE_SCORER_EXP_ID, legacySelectedNetworkId); 847 for (Map.Entry entry : 848 experimentNetworkSelections.entrySet()) { 849 int experimentId = entry.getKey(); 850 if (experimentId == activeExperimentId) continue; 851 int thisSelectedNetworkId = entry.getValue(); 852 mWifiMetrics.logNetworkSelectionDecision(experimentId, activeExperimentId, 853 selectedNetworkId == thisSelectedNetworkId, 854 groupedCandidates.size()); 855 } 856 857 // Get a fresh copy of WifiConfiguration reflecting any scan result updates 858 selectedNetwork = mWifiConfigManager.getConfiguredNetwork(selectedNetworkId); 859 if (selectedNetwork != null && legacyOverrideWanted) { 860 selectedNetwork = overrideCandidateWithUserConnectChoice(selectedNetwork); 861 mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis(); 862 } 863 return selectedNetwork; 864 }
303 private boolean isNetworkSelectionNeeded(ListscanDetails, WifiInfo wifiInfo, 304 boolean connected, boolean disconnected) { 305 if (scanDetails.size() == 0) { 306 localLog("Empty connectivity scan results. Skip network selection."); 307 return false; 308 } 309 310 if (connected) { 311 // Is roaming allowed? 312 if (!mEnableAutoJoinWhenAssociated) { 313 localLog("Switching networks in connected state is not allowed." 314 + " Skip network selection."); 315 return false; 316 } 317 318 // Has it been at least the minimum interval since last network selection? 319 if (mLastNetworkSelectionTimeStamp != INVALID_TIME_STAMP) { 320 long gap = mClock.getElapsedSinceBootMillis() 321 - mLastNetworkSelectionTimeStamp; 322 if (gap < MINIMUM_NETWORK_SELECTION_INTERVAL_MS) { 323 localLog("Too short since last network selection: " + gap + " ms." 324 + " Skip network selection."); 325 return false; 326 } 327 } 328 329 if (isCurrentNetworkSufficient(wifiInfo, scanDetails)) { 330 localLog("Current connected network already sufficient. Skip network selection."); 331 return false; 332 } else { 333 localLog("Current connected network is not sufficient."); 334 return true; 335 } 336 } else if (disconnected) { 337 return true; 338 } else { 339 // No network selection if ClientModeImpl is in a state other than 340 // CONNECTED or DISCONNECTED. 341 localLog("ClientModeImpl is in neither CONNECTED nor DISCONNECTED state." 342 + " Skip network selection."); 343 return false; 344 } 345 }
221 private boolean isCurrentNetworkSufficient(WifiInfo wifiInfo, ListscanDetails) { 222 // Currently connected? 223 if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) { 224 localLog("No current connected network."); 225 return false; 226 } else { 227 localLog("Current connected network: " + wifiInfo.getSSID() 228 + " , ID: " + wifiInfo.getNetworkId()); 229 } 230 231 int currentRssi = wifiInfo.getRssi(); 232 boolean hasQualifiedRssi = currentRssi 233 > mScoringParams.getSufficientRssi(wifiInfo.getFrequency()); 234 boolean hasActiveStream = (wifiInfo.txSuccessRate > mStayOnNetworkMinimumTxRate) 235 || (wifiInfo.rxSuccessRate > mStayOnNetworkMinimumRxRate); 236 if (hasQualifiedRssi && hasActiveStream) { 237 localLog("Stay on current network because of good RSSI and ongoing traffic"); 238 return true; 239 } 240 WifiConfiguration network = 241 mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId()); 242 243 if (network == null) { 244 localLog("Current network was removed."); 245 return false; 246 } 247 248 if (mWifiConfigManager.getLastSelectedNetwork() == network.networkId 249 && (mClock.getElapsedSinceBootMillis() 250 - mWifiConfigManager.getLastSelectedTimeStamp()) 251 <= LAST_USER_SELECTION_SUFFICIENT_MS) { 252 localLog("Current network is recently user-selected."); 253 return true; 254 } 255 256 // OSU (Online Sign Up) network for Passpoint Release 2 is sufficient network. 257 if (network.osu) { 258 return true; 259 } 260 261 // Ephemeral network is not qualified. 262 if (wifiInfo.isEphemeral()) { 263 localLog("Current network is an ephemeral one."); 264 return false; 265 } 266 267 if (wifiInfo.is24GHz()) { 268 // 2.4GHz networks is not qualified whenever 5GHz is available 269 if (is5GHzNetworkAvailable(scanDetails)) { 270 localLog("Current network is 2.4GHz. 5GHz networks available."); 271 return false; 272 } 273 } 274 if (!hasQualifiedRssi) { 275 localLog("Current network RSSI[" + currentRssi + "]-acceptable but not qualified."); 276 return false; 277 } 278 279 // Open network is not qualified. 280 if (WifiConfigurationUtil.isConfigForOpenNetwork(network)) { 281 localLog("Current network is a open one."); 282 return false; 283 } 284 285 // Network with no internet access reports is not qualified. 286 if (network.numNoInternetAccessReports > 0 && !network.noInternetAccessExpected) { 287 localLog("Current network has [" + network.numNoInternetAccessReports 288 + "] no-internet access reports."); 289 return false; 290 } 291 return true; 292 }