(一百三十三)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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在