(一百三十三)Android O WiFi重启机制学习——重启原因

2023-12-19 07:38

本文主要是介绍(一百三十三)Android O WiFi重启机制学习——重启原因,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:在之前一篇博客中(一百三十二)Android O WiFi重启机制学习——重启流程 提及

“api中简要说明了这个类是用来将WiFi从异常状态恢复的。恢复机制是通过WifiController触发一个重启,基本模拟了一次飞行模式切换。

当前触发条件

看门狗
正常操作过程中的HAL/wificond crashes
TBD:正常操作过程中的supplicant crashes(暂未有对应处理)”

继续看下重启原因

 

 

1.重启原因

从截图来看触发重启主要的3个地方也已经很明显的搜索到了,分别为watchdog、wificond_crash和hal_crash

 

2.重启原因流程探究

分别看下watchdog、wificond_crash和hal_crash

2.1 watchdog

    /*** Increments the failure reason count for the given bssid. Performs a check to see if we have* exceeded a failure threshold for all available networks, and executes the last resort restart* @param bssid of the network that has failed connection, can be "any"* @param reason Message id from WifiStateMachine for this failure* @return true if watchdog triggers, returned for test visibility*/public boolean noteConnectionFailureAndTriggerIfNeeded(String ssid, String bssid, int reason) {if (mVerboseLoggingEnabled) {Log.v(TAG, "noteConnectionFailureAndTriggerIfNeeded: [" + ssid + ", " + bssid + ", "+ reason + "]");}// Update failure count for the failing networkupdateFailureCountForNetwork(ssid, bssid, reason);// Have we met conditions to trigger the Watchdog Wifi restart?boolean isRestartNeeded = checkTriggerCondition();if (mVerboseLoggingEnabled) {Log.v(TAG, "isRestartNeeded = " + isRestartNeeded);}if (isRestartNeeded) {// Stop the watchdog from triggering until re-enabledsetWatchdogTriggerEnabled(false);Log.e(TAG, "Watchdog triggering recovery");mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);// increment various watchdog trigger count statsincrementWifiMetricsTriggerCounts();clearAllFailureCounts();}return isRestartNeeded;}

看了下这个方法只有WifiStateMachine会调用,分别是FAILURE_CODE_AUTHENTICATION、FAILURE_CODE_ASSOCIATION和FAILURE_CODE_DHCP

 

2.1.1 FAILURE_CODE_AUTHENTICATION

                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_AUTH_FAILURE);mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);int disableReason = WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE;// Check if this is a permanent wrong password failure.if (isPermanentWrongPasswordFailure(mTargetNetworkId, message.arg2)) {disableReason = WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD;WifiConfiguration targetedNetwork =mWifiConfigManager.getConfiguredNetwork(mTargetNetworkId);if (targetedNetwork != null) {mWrongPasswordNotifier.onWrongPasswordError(targetedNetwork.SSID);}}mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId, disableReason);mWifiConfigManager.clearRecentFailureReason(mTargetNetworkId);//If failure occurred while Metrics is tracking a ConnnectionEvent, end it.reportConnectionAttemptEnd(WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,WifiMetricsProto.ConnectionEvent.HLF_NONE);mWifiInjector.getWifiLastResortWatchdog().noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), mTargetRoamBSSID,WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);break;

2.1.2 FAILURE_CODE_ASSOCIATION

                case WifiMonitor.ASSOCIATION_REJECTION_EVENT:mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_ASSOC_FAILURE);didBlackListBSSID = false;bssid = (String) message.obj;timedOut = message.arg1 > 0;reasonCode = message.arg2;Log.d(TAG, "Assocation Rejection event: bssid=" + bssid + " reason code="+ reasonCode + " timedOut=" + Boolean.toString(timedOut));if (bssid == null || TextUtils.isEmpty(bssid)) {// If BSSID is null, use the target roam BSSIDbssid = mTargetRoamBSSID;}if (bssid != null) {// If we have a BSSID, tell configStore to black list itdidBlackListBSSID = mWifiConnectivityManager.trackBssid(bssid, false,reasonCode);}mWifiConfigManager.updateNetworkSelectionStatus(mTargetNetworkId,WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION);mWifiConfigManager.setRecentFailureAssociationStatus(mTargetNetworkId,reasonCode);mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);// If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.reportConnectionAttemptEnd(WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,WifiMetricsProto.ConnectionEvent.HLF_NONE);mWifiInjector.getWifiLastResortWatchdog().noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), bssid,WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);break;

2.1.3 FAILURE_CODE_DHCP

        @Overridepublic void onNewDhcpResults(DhcpResults dhcpResults) {if (dhcpResults != null) {sendMessage(CMD_IPV4_PROVISIONING_SUCCESS, dhcpResults);} else {sendMessage(CMD_IPV4_PROVISIONING_FAILURE);mWifiInjector.getWifiLastResortWatchdog().noteConnectionFailureAndTriggerIfNeeded(getTargetSsid(), mTargetRoamBSSID,WifiLastResortWatchdog.FAILURE_CODE_DHCP);}

2.1.4 流程探究

再回头看下WifiLastResortWatchdog的逻辑

    /*** Increments the failure reason count for the given network, in 'mSsidFailureCount'* Failures are counted per SSID, either; by using the ssid string when the bssid is "any"* or by looking up the ssid attached to a specific bssid* An unused set of counts is also kept which is bssid specific, in 'mRecentAvailableNetworks'* @param ssid of the network that has failed connection* @param bssid of the network that has failed connection, can be "any"* @param reason Message id from WifiStateMachine for this failure*/private void updateFailureCountForNetwork(String ssid, String bssid, int reason) {if (mVerboseLoggingEnabled) {Log.v(TAG, "updateFailureCountForNetwork: [" + ssid + ", " + bssid + ", "+ reason + "]");}if (BSSID_ANY.equals(bssid)) {incrementSsidFailureCount(ssid, reason);} else {// Bssid count is actually unused except for logging purposes// SSID count is incremented within the BSSID counting methodincrementBssidFailureCount(ssid, bssid, reason);}}/*** Map of SSID to <FailureCount, AP count>, used to count failures & number of access points* belonging to an SSID.*/private Map<String, Pair<AvailableNetworkFailureCount, Integer>> mSsidFailureCount =new HashMap<>();/*** Update the per-SSID failure count* @param ssid the ssid to increment failure count for* @param reason the failure type to increment count for*/private void incrementSsidFailureCount(String ssid, int reason) {Pair<AvailableNetworkFailureCount, Integer> ssidFails = mSsidFailureCount.get(ssid);if (ssidFails == null) {Log.d(TAG, "updateFailureCountForNetwork: No networks for ssid = " + ssid);return;}AvailableNetworkFailureCount failureCount = ssidFails.first;failureCount.incrementFailureCount(reason);}/*** Update the per-BSSID failure count* @param bssid the bssid to increment failure count for* @param reason the failure type to increment count for*/private void incrementBssidFailureCount(String ssid, String bssid, int reason) {AvailableNetworkFailureCount availableNetworkFailureCount =mRecentAvailableNetworks.get(bssid);if (availableNetworkFailureCount == null) {Log.d(TAG, "updateFailureCountForNetwork: Unable to find Network [" + ssid+ ", " + bssid + "]");return;}if (!availableNetworkFailureCount.ssid.equals(ssid)) {Log.d(TAG, "updateFailureCountForNetwork: Failed connection attempt has"+ " wrong ssid. Failed [" + ssid + ", " + bssid + "], buffered ["+ availableNetworkFailureCount.ssid + ", " + bssid + "]");return;}if (availableNetworkFailureCount.config == null) {if (mVerboseLoggingEnabled) {Log.v(TAG, "updateFailureCountForNetwork: network has no config ["+ ssid + ", " + bssid + "]");}}availableNetworkFailureCount.incrementFailureCount(reason);incrementSsidFailureCount(ssid, reason);}

根据bssid是否是any进行两种失败次数的统计,分别是incrementSsidFailureCount和incrementBssidFailureCount

分别看下这两个方法

1. incrementSsidFailureCount

先看下初始化和添加

    /*** Map of SSID to <FailureCount, AP count>, used to count failures & number of access points* belonging to an SSID.*/private Map<String, Pair<AvailableNetworkFailureCount, Integer>> mSsidFailureCount =new HashMap<>();/*** Refreshes recentAvailableNetworks with the latest available networks* Adds new networks, removes old ones that have timed out. Should be called after Wifi* framework decides what networks it is potentially connecting to.* @param availableNetworks ScanDetail & Config list of potential connection* candidates*/public void updateAvailableNetworks(List<Pair<ScanDetail, WifiConfiguration>> availableNetworks) {if (mVerboseLoggingEnabled) {Log.v(TAG, "updateAvailableNetworks: size = " + availableNetworks.size());}// Add new networks to mRecentAvailableNetworksif (availableNetworks != null) {for (Pair<ScanDetail, WifiConfiguration> pair : availableNetworks) {final ScanDetail scanDetail = pair.first;final WifiConfiguration config = pair.second;ScanResult scanResult = scanDetail.getScanResult();if (scanResult == null) continue;String bssid = scanResult.BSSID;String ssid = "\"" + scanDetail.getSSID() + "\"";if (mVerboseLoggingEnabled) {Log.v(TAG, " " + bssid + ": " + scanDetail.getSSID());}// Cache the scanResult & WifiConfigAvailableNetworkFailureCount availableNetworkFailureCount =mRecentAvailableNetworks.get(bssid);if (availableNetworkFailureCount == null) {// New network is availableavailableNetworkFailureCount = new AvailableNetworkFailureCount(config);availableNetworkFailureCount.ssid = ssid;// Count AP for this SSIDPair<AvailableNetworkFailureCount, Integer> ssidFailsAndApCount =mSsidFailureCount.get(ssid);if (ssidFailsAndApCount == null) {// This is a new SSID, create new FailureCount for it and set AP count to 1ssidFailsAndApCount = Pair.create(new AvailableNetworkFailureCount(config),1);setWatchdogTriggerEnabled(true);} else {final Integer numberOfAps = ssidFailsAndApCount.second;// This is not a new SSID, increment the AP count for itssidFailsAndApCount = Pair.create(ssidFailsAndApCount.first,numberOfAps + 1);}mSsidFailureCount.put(ssid, ssidFailsAndApCount);}// refresh config if it is not nullif (config != null) {availableNetworkFailureCount.config = config;}// If we saw a network, set its Age to -1 here, aging iteration will set it to 0availableNetworkFailureCount.age = -1;mRecentAvailableNetworks.put(bssid, availableNetworkFailureCount);}}// Iterate through available networks updating timeout counts & removing networks.Iterator<Map.Entry<String, AvailableNetworkFailureCount>> it =mRecentAvailableNetworks.entrySet().iterator();while (it.hasNext()) {Map.Entry<String, AvailableNetworkFailureCount> entry = it.next();if (entry.getValue().age < MAX_BSSID_AGE - 1) {entry.getValue().age++;} else {// Decrement this SSID : AP countString ssid = entry.getValue().ssid;Pair<AvailableNetworkFailureCount, Integer> ssidFails =mSsidFailureCount.get(ssid);if (ssidFails != null) {Integer apCount = ssidFails.second - 1;if (apCount > 0) {ssidFails = Pair.create(ssidFails.first, apCount);mSsidFailureCount.put(ssid, ssidFails);} else {mSsidFailureCount.remove(ssid);}} else {Log.d(TAG, "updateAvailableNetworks: SSID to AP count mismatch for " + ssid);}it.remove();}}if (mVerboseLoggingEnabled) Log.v(TAG, toString());}

之前在梳理WiFi自动连接的时候有梳理到WifiConnectivityManager$handleScanResults,这个方法也会调用到WifiLastResortWatchdog$updateAvailableNetworks

http://androidxref.com/8.0.0_r4/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java

    /*** Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.* Executes selection of potential network candidates, initiation of connection attempt to that* network.** @return true - if a candidate is selected by WifiNetworkSelector*         false - if no candidate is selected by WifiNetworkSelector*/private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {// Check if any blacklisted BSSIDs can be freed.refreshBssidBlacklist();if (mStateMachine.isLinkDebouncing() || mStateMachine.isSupplicantTransientState()) {localLog(listenerName + " onResults: No network selection because linkDebouncing is "+ mStateMachine.isLinkDebouncing() + " and supplicantTransient is "+ mStateMachine.isSupplicantTransientState());return false;}localLog(listenerName + " onResults: start network selection");WifiConfiguration candidate =mNetworkSelector.selectNetwork(scanDetails, buildBssidBlacklist(), mWifiInfo,mStateMachine.isConnected(), mStateMachine.isDisconnected(),mUntrustedConnectionAllowed);mWifiLastResortWatchdog.updateAvailableNetworks(mNetworkSelector.getConnectableScanDetails());mWifiMetrics.countScanResults(scanDetails);if (candidate != null) {localLog(listenerName + ":  WNS candidate-" + candidate.SSID);connectToNetwork(candidate);return true;} else {if (mWifiState == WIFI_STATE_DISCONNECTED) {mOpenNetworkNotifier.handleScanResults(mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());}return false;}}

继续看下WifiNetworkSelector

    /*** @return the list of ScanDetails scored as potential candidates by the last run of* selectNetwork, this will be empty if Network selector determined no selection was* needed on last run. This includes scan details of sufficient signal strength, and* had an associated WifiConfiguration.*/public List<Pair<ScanDetail, WifiConfiguration>> getConnectableScanDetails() {return mConnectableNetworks;}

这边还要看下mConnectableNetworks的处理

    // Buffer of filtered scan results (Scan results considered by network selection) & associated// WifiConfiguration (if any).private volatile List<Pair<ScanDetail, WifiConfiguration>> mConnectableNetworks =new ArrayList<>();/*** Select the best network from the ones in range.** @param scanDetails    List of ScanDetail for all the APs in range* @param bssidBlacklist Blacklisted BSSIDs* @param wifiInfo       Currently connected network* @param connected      True if the device is connected* @param disconnected   True if the device is disconnected* @param untrustedNetworkAllowed True if untrusted networks are allowed for connection* @return Configuration of the selected network, or Null if nothing*/@Nullablepublic WifiConfiguration selectNetwork(List<ScanDetail> scanDetails,HashSet<String> bssidBlacklist, WifiInfo wifiInfo,boolean connected, boolean disconnected, boolean untrustedNetworkAllowed) {mFilteredNetworks.clear();mConnectableNetworks.clear();if (scanDetails.size() == 0) {localLog("Empty connectivity scan result");return null;}WifiConfiguration currentNetwork =mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId());// Always get the current BSSID from WifiInfo in case that firmware initiated// roaming happened.String currentBssid = wifiInfo.getBSSID();// Shall we start network selection at all?if (!isNetworkSelectionNeeded(scanDetails, wifiInfo, connected, disconnected)) {return null;}// Update the registered network evaluators.for (NetworkEvaluator registeredEvaluator : mEvaluators) {if (registeredEvaluator != null) {registeredEvaluator.update(scanDetails);}}// Filter out unwanted networks.mFilteredNetworks = filterScanResults(scanDetails, bssidBlacklist,connected, currentBssid);if (mFilteredNetworks.size() == 0) {return null;}// Go through the registered network evaluators from the highest priority// one to the lowest till a network is selected.WifiConfiguration selectedNetwork = null;for (NetworkEvaluator registeredEvaluator : mEvaluators) {if (registeredEvaluator != null) {localLog("About to run " + registeredEvaluator.getName() + " :");selectedNetwork = registeredEvaluator.evaluateNetworks(new ArrayList<>(mFilteredNetworks), currentNetwork, currentBssid, connected,untrustedNetworkAllowed, mConnectableNetworks);if (selectedNetwork != null) {localLog(registeredEvaluator.getName() + " selects "+ WifiNetworkSelector.toNetworkString(selectedNetwork) + " : "+ selectedNetwork.getNetworkSelectionStatus().getCandidate().BSSID);break;}}}if (selectedNetwork != null) {selectedNetwork = overrideCandidateWithUserConnectChoice(selectedNetwork);mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();}return selectedNetwork;}

有三个Evalutor,这边只看下最熟悉的SavedNetworkEvaluator

    /*** Evaluate all the networks from the scan results and return* the WifiConfiguration of the network chosen for connection.** @return configuration of the chosen network;*         null if no network in this category is available.*/public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,WifiConfiguration currentNetwork, String currentBssid, boolean connected,boolean untrustedNetworkAllowed,List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {int highestScore = Integer.MIN_VALUE;ScanResult scanResultCandidate = null;WifiConfiguration candidate = null;StringBuffer scoreHistory = new StringBuffer();for (ScanDetail scanDetail : scanDetails) {ScanResult scanResult = scanDetail.getScanResult();int highestScoreOfScanResult = Integer.MIN_VALUE;int candidateIdOfScanResult = WifiConfiguration.INVALID_NETWORK_ID;// One ScanResult can be associated with more than one networks, hence we calculate all// the scores and use the highest one as the ScanResult's score.List<WifiConfiguration> associatedConfigurations = null;WifiConfiguration associatedConfiguration =mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail);if (associatedConfiguration == null) {continue;} else {associatedConfigurations =new ArrayList<>(Arrays.asList(associatedConfiguration));}for (WifiConfiguration network : associatedConfigurations) {/*** Ignore Passpoint and Ephemeral networks. They are configured networks,* but without being persisted to the storage. They are evaluated by* {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator}* respectively.*/if (network.isPasspoint() || network.isEphemeral()) {continue;}WifiConfiguration.NetworkSelectionStatus status =network.getNetworkSelectionStatus();status.setSeenInLastQualifiedNetworkSelection(true);if (!status.isNetworkEnabled()) {continue;} else if (network.BSSID != null &&  !network.BSSID.equals("any")&& !network.BSSID.equals(scanResult.BSSID)) {// App has specified the only BSSID to connect for this// configuration. So only the matching ScanResult can be a candidate.localLog("Network " + WifiNetworkSelector.toNetworkString(network)+ " has specified BSSID " + network.BSSID + ". Skip "+ scanResult.BSSID);continue;} else if (TelephonyUtil.isSimConfig(network)&& !mWifiConfigManager.isSimPresent()) {// Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present.continue;}int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,scoreHistory);// Set candidate ScanResult for all saved networks to ensure that users can// override network selection. See WifiNetworkSelector#setUserConnectChoice.// TODO(b/36067705): consider alternative designs to push filtering/selecting of// user connect choice networks to RecommendedNetworkEvaluator.if (score > status.getCandidateScore() || (score == status.getCandidateScore()&& status.getCandidate() != null&& scanResult.level > status.getCandidate().level)) {mWifiConfigManager.setNetworkCandidateScanResult(network.networkId, scanResult, score);}// If the network is marked to use external scores, or is an open network with// curate saved open networks enabled, do not consider it for network selection.if (network.useExternalScores) {localLog("Network " + WifiNetworkSelector.toNetworkString(network)+ " has external score.");continue;}if (score > highestScoreOfScanResult) {highestScoreOfScanResult = score;candidateIdOfScanResult = network.networkId;}}if (connectableNetworks != null) {connectableNetworks.add(Pair.create(scanDetail,mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult)));}if (highestScoreOfScanResult > highestScore|| (highestScoreOfScanResult == highestScore&& scanResultCandidate != null&& scanResult.level > scanResultCandidate.level)) {highestScore = highestScoreOfScanResult;scanResultCandidate = scanResult;mWifiConfigManager.setNetworkCandidateScanResult(candidateIdOfScanResult, scanResultCandidate, highestScore);// Reload the network config with the updated info.candidate = mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult);}}if (scoreHistory.length() > 0) {localLog("\n" + scoreHistory.toString());}if (scanResultCandidate == null) {localLog("did not see any good candidates.");}return candidate;}

这个方法会把搜索到的有资格连接(不一定要是最高分)的都加入到集合connectableNetworks中,最后更新到mWifiLastResortWatchdog,比如被enable的bssid相符的普通网络,比如插卡情况下的eap-sim网络

再回头看下WifiLastResortWatchdog的updateAvailableNetworks方法

    /*** Map of SSID to <FailureCount, AP count>, used to count failures & number of access points* belonging to an SSID.*/private Map<String, Pair<AvailableNetworkFailureCount, Integer>> mSsidFailureCount =new HashMap<>();/*** Refreshes recentAvailableNetworks with the latest available networks* Adds new networks, removes old ones that have timed out. Should be called after Wifi* framework decides what networks it is potentially connecting to.* @param availableNetworks ScanDetail & Config list of potential connection* candidates*/public void updateAvailableNetworks(List<Pair<ScanDetail, WifiConfiguration>> availableNetworks) {if (mVerboseLoggingEnabled) {Log.v(TAG, "updateAvailableNetworks: size = " + availableNetworks.size());}// Add new networks to mRecentAvailableNetworksif (availableNetworks != null) {for (Pair<ScanDetail, WifiConfiguration> pair : availableNetworks) {final ScanDetail scanDetail = pair.first;final WifiConfiguration config = pair.second;ScanResult scanResult = scanDetail.getScanResult();if (scanResult == null) continue;String bssid = scanResult.BSSID;String ssid = "\"" + scanDetail.getSSID() + "\"";if (mVerboseLoggingEnabled) {Log.v(TAG, " " + bssid + ": " + scanDetail.getSSID());}// Cache the scanResult & WifiConfigAvailableNetworkFailureCount availableNetworkFailureCount =mRecentAvailableNetworks.get(bssid);if (availableNetworkFailureCount == null) {// New network is availableavailableNetworkFailureCount = new AvailableNetworkFailureCount(config);availableNetworkFailureCount.ssid = ssid;// Count AP for this SSIDPair<AvailableNetworkFailureCount, Integer> ssidFailsAndApCount =mSsidFailureCount.get(ssid);if (ssidFailsAndApCount == null) {// This is a new SSID, create new FailureCount for it and set AP count to 1ssidFailsAndApCount = Pair.create(new AvailableNetworkFailureCount(config),1);setWatchdogTriggerEnabled(true);} else {final Integer numberOfAps = ssidFailsAndApCount.second;// This is not a new SSID, increment the AP count for itssidFailsAndApCount = Pair.create(ssidFailsAndApCount.first,numberOfAps + 1);}mSsidFailureCount.put(ssid, ssidFailsAndApCount);}// refresh config if it is not nullif (config != null) {availableNetworkFailureCount.config = config;}// If we saw a network, set its Age to -1 here, aging iteration will set it to 0availableNetworkFailureCount.age = -1;mRecentAvailableNetworks.put(bssid, availableNetworkFailureCount);}}// Iterate through available networks updating timeout counts & removing networks.Iterator<Map.Entry<String, AvailableNetworkFailureCount>> it =mRecentAvailableNetworks.entrySet().iterator();while (it.hasNext()) {Map.Entry<String, AvailableNetworkFailureCount> entry = it.next();if (entry.getValue().age < MAX_BSSID_AGE - 1) {entry.getValue().age++;} else {// Decrement this SSID : AP countString ssid = entry.getValue().ssid;Pair<AvailableNetworkFailureCount, Integer> ssidFails =mSsidFailureCount.get(ssid);if (ssidFails != null) {Integer apCount = ssidFails.second - 1;if (apCount > 0) {ssidFails = Pair.create(ssidFails.first, apCount);mSsidFailureCount.put(ssid, ssidFails);} else {mSsidFailureCount.remove(ssid);}} else {Log.d(TAG, "updateAvailableNetworks: SSID to AP count mismatch for " + ssid);}it.remove();}}if (mVerboseLoggingEnabled) Log.v(TAG, toString());}

看下

    /*** Maximum number of scan results received since we last saw a BSSID.* If it is not seen before this limit is reached, the network is culled*/public static final int MAX_BSSID_AGE = 10;

大致意思是从第一次缓存availableNetworks,即可连接网络,会最多缓存10次,若后续有次update包含该网络则会重新将age变为-1,否则一直增加,到10次后就会被移除掉,说明10次扫描都没有被认为是可连接的网络,那缓存没有意义了,移除即可。

这边完成了mSsidFailureCount和mRecentAvailableNetworks集合的增删

看了半天,这两个集合区别还是在于bssid是不是any,如果bssid不是any,那么ap数目肯定是1,可以用bssid作为key;若bssid为any,那么同名ssid的ap有可能有不止一个,所以需要apCount来计数。

下面就是最早看到的incrementSsidFailureCount对失败次数进行计数

    /*** Update the per-SSID failure count* @param ssid the ssid to increment failure count for* @param reason the failure type to increment count for*/private void incrementSsidFailureCount(String ssid, int reason) {Pair<AvailableNetworkFailureCount, Integer> ssidFails = mSsidFailureCount.get(ssid);if (ssidFails == null) {Log.d(TAG, "updateFailureCountForNetwork: No networks for ssid = " + ssid);return;}AvailableNetworkFailureCount failureCount = ssidFails.first;failureCount.incrementFailureCount(reason);}

然后下面是根据bssid对失败次数进行计数

    /*** Update the per-BSSID failure count* @param bssid the bssid to increment failure count for* @param reason the failure type to increment count for*/private void incrementBssidFailureCount(String ssid, String bssid, int reason) {AvailableNetworkFailureCount availableNetworkFailureCount =mRecentAvailableNetworks.get(bssid);if (availableNetworkFailureCount == null) {Log.d(TAG, "updateFailureCountForNetwork: Unable to find Network [" + ssid+ ", " + bssid + "]");return;}if (!availableNetworkFailureCount.ssid.equals(ssid)) {Log.d(TAG, "updateFailureCountForNetwork: Failed connection attempt has"+ " wrong ssid. Failed [" + ssid + ", " + bssid + "], buffered ["+ availableNetworkFailureCount.ssid + ", " + bssid + "]");return;}if (availableNetworkFailureCount.config == null) {if (mVerboseLoggingEnabled) {Log.v(TAG, "updateFailureCountForNetwork: network has no config ["+ ssid + ", " + bssid + "]");}}availableNetworkFailureCount.incrementFailureCount(reason);incrementSsidFailureCount(ssid, reason);}

可以看到incrementSsidFailureCount肯定会被调用的

更新完失败次数就是对次数进行校验看下次数是否达到重启的标准了

    /*** Increments the failure reason count for the given bssid. Performs a check to see if we have* exceeded a failure threshold for all available networks, and executes the last resort restart* @param bssid of the network that has failed connection, can be "any"* @param reason Message id from WifiStateMachine for this failure* @return true if watchdog triggers, returned for test visibility*/public boolean noteConnectionFailureAndTriggerIfNeeded(String ssid, String bssid, int reason) {if (mVerboseLoggingEnabled) {Log.v(TAG, "noteConnectionFailureAndTriggerIfNeeded: [" + ssid + ", " + bssid + ", "+ reason + "]");}// Update failure count for the failing networkupdateFailureCountForNetwork(ssid, bssid, reason);// Have we met conditions to trigger the Watchdog Wifi restart?boolean isRestartNeeded = checkTriggerCondition();if (mVerboseLoggingEnabled) {Log.v(TAG, "isRestartNeeded = " + isRestartNeeded);}if (isRestartNeeded) {// Stop the watchdog from triggering until re-enabledsetWatchdogTriggerEnabled(false);Log.e(TAG, "Watchdog triggering recovery");mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);// increment various watchdog trigger count statsincrementWifiMetricsTriggerCounts();clearAllFailureCounts();}return isRestartNeeded;}/*** Check trigger condition: For all available networks, have we met a failure threshold for each* of them, and have previously connected to at-least one of the available networks* @return is the trigger condition true*/private boolean checkTriggerCondition() {if (mVerboseLoggingEnabled) Log.v(TAG, "checkTriggerCondition.");// Don't check Watchdog trigger if wifi is in a connected state// (This should not occur, but we want to protect against any race conditions)if (mWifiIsConnected) return false;// Don't check Watchdog trigger if trigger is not enabledif (!mWatchdogAllowedToTrigger) return false;boolean atleastOneNetworkHasEverConnected = false;for (Map.Entry<String, AvailableNetworkFailureCount> entry: mRecentAvailableNetworks.entrySet()) {if (entry.getValue().config != null&& entry.getValue().config.getNetworkSelectionStatus().getHasEverConnected()) {atleastOneNetworkHasEverConnected = true;}if (!isOverFailureThreshold(entry.getKey())) {// This available network is not over failure threshold, meaning we still have a// network to try connecting toreturn false;}}// We have met the failure count for every available network & there is at-least one network// we have previously connected to present.if (mVerboseLoggingEnabled) {Log.v(TAG, "checkTriggerCondition: return = " + atleastOneNetworkHasEverConnected);}return atleastOneNetworkHasEverConnected;}

重启有两个条件

1.是否可选网络之前有连接过

2.是否可选网络失败次数已达到阈值

只有之前有连接过并且失败次数达到阈值才会认为需要重启,重启之后清空失败次数统计

    /*** @param bssid bssid to check the failures for* @return true if any failure count is over FAILURE_THRESHOLD*/public boolean isOverFailureThreshold(String bssid) {if ((getFailureCount(bssid, FAILURE_CODE_ASSOCIATION) >= FAILURE_THRESHOLD)|| (getFailureCount(bssid, FAILURE_CODE_AUTHENTICATION) >= FAILURE_THRESHOLD)|| (getFailureCount(bssid, FAILURE_CODE_DHCP) >= FAILURE_THRESHOLD)) {return true;}return false;}

失败次数统计呢主要是看下FAILURE_CODE_ASSOCIATION、FAILURE_CODE_AUTHENTICATION和FAILURE_CODE_DHCP失败次数是否超过FAILURE_THRESHOLD即7次

    /*** Failure count that each available networks must meet to possibly trigger the Watchdog*/public static final int FAILURE_THRESHOLD = 7;

 

2.2 REASON_WIFICOND_CRASH

                case CMD_CLIENT_INTERFACE_BINDER_DEATH:Log.e(TAG, "wificond died unexpectedly. Triggering recovery");mWifiMetrics.incrementNumWificondCrashes();mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_WIFICOND_CRASH);mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFICOND_CRASH);break;

 

2.3 REASON_HAL_CRASH

                case CMD_VENDOR_HAL_HWBINDER_DEATH:Log.e(TAG, "Vendor HAL died unexpectedly. Triggering recovery");mWifiMetrics.incrementNumHalCrashes();mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_HAL_CRASH);mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_HAL_CRASH);break;

 

3.总结

触发重启主要有3个原因,分别为watchdog、wificond_crash和hal_crash

其中watchdog触发条件是

1)可连接网络之前进行过连接

2)可连接网络ASSOCIATION/AUTHENTICATION/DHCP失败次数不小于7次

这篇关于(一百三十三)Android O WiFi重启机制学习——重启原因的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511389

相关文章

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Java报NoClassDefFoundError异常的原因及解决

《Java报NoClassDefFoundError异常的原因及解决》在Java开发过程中,java.lang.NoClassDefFoundError是一个令人头疼的运行时错误,本文将深入探讨这一问... 目录一、问题分析二、报错原因三、解决思路四、常见场景及原因五、深入解决思路六、预http://www

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式