版权声明:本文为博主原创文章,未经授权禁止转载,O(∩_∩)O谢谢 https://blog.csdn.net/sinat_20059415/article/details/85196871
1.WifiLastResortWatchdog的初始化
public WifiInjector(Context context) {
if (context == null) {
throw new IllegalStateException(
"WifiInjector should not be initialized with a null Context.");
}
if (sWifiInjector != null) {
throw new IllegalStateException(
"WifiInjector was already created, use getInstance instead.");
}
sWifiInjector = this;
...
WifiAwareMetrics awareMetrics = new WifiAwareMetrics(mClock);
mWifiMetrics = new WifiMetrics(mClock, wifiStateMachineLooper, awareMetrics);
...
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
mSelfRecovery = new SelfRecovery(mWifiController, mClock);
mWifiLastResortWatchdog = new WifiLastResortWatchdog(mSelfRecovery, mWifiMetrics);
}
主要类的注释:
1) SelfRecovery
/**
* This class is used to recover the wifi stack from a fatal failure. The recovery mechanism
* involves triggering a stack restart (essentially simulating an airplane mode toggle) using
* {@link WifiController}.
* The current triggers for:
* 1. Last resort watchdog bite.
* 2. HAL/wificond crashes during normal operation.
* 3. TBD: supplicant crashes during normal operation.
*/
public class SelfRecovery
2)WifiMetrics
/**
* Provides storage for wireless connectivity metrics, as they are generated.
* Metrics logged by this class include:
* Aggregated connection stats (num of connections, num of failures, ...)
* Discrete connection event stats (time, duration, failure codes, ...)
* Router details (technology type, authentication type, ...)
* Scan stats
*/
public class WifiMetrics
3)WifiLastResortWatchdog
/**
* This Class is a Work-In-Progress, intended behavior is as follows:
* Essentially this class automates a user toggling 'Airplane Mode' when WiFi "won't work".
* IF each available saved network has failed connecting more times than the FAILURE_THRESHOLD
* THEN Watchdog will restart Supplicant, wifi driver and return WifiStateMachine to InitialState.
*/
public class WifiLastResortWatchdog
2.WifiStateMachine中的调用
2.1 调用罗列
2.1.1 dhcp失败
class IpClientCallback extends IpClient.Callback {
@Override
public void onPreDhcpAction() {
sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION);
}
@Override
public void onPostDhcpAction() {
sendMessage(DhcpClient.CMD_POST_DHCP_ACTION);
}
@Override
public 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.2 启动supplicant
class InitialState extends State {
private void cleanup() {
// Tearing down the client interfaces below is going to stop our supplicant.
mWifiMonitor.stopAllMonitoring();
mDeathRecipient.unlinkToDeath();
mWifiNative.tearDown();
}
@Override
public void enter() {
mWifiStateTracker.updateState(WifiStateTracker.INVALID);
cleanup();
}
@Override
public boolean processMessage(Message message) {
logStateAndMessage(message, this);
switch (message.what) {
case CMD_START_SUPPLICANT:
...
mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();
setSupplicantLogLevel();
transitionTo(mSupplicantStartingState);
break;
2.1.3 ASSOCIATION_REJECTION_EVENT
class ConnectModeState extends State {
...
@Override
public boolean processMessage(Message message) {
WifiConfiguration config;
int netId;
boolean ok;
boolean didDisconnect;
String bssid;
String ssid;
NetworkUpdateResult result;
Set<Integer> removedNetworkIds;
int reasonCode;
boolean timedOut;
logStateAndMessage(message, this);
switch (message.what) {
case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
...
mWifiInjector.getWifiLastResortWatchdog()
.noteConnectionFailureAndTriggerIfNeeded(
getTargetSsid(), bssid,
WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
break;
2.1.4 AUTHENTICATION_FAILURE_EVENT
class ConnectModeState extends State {
...
case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
...
mWifiInjector.getWifiLastResortWatchdog()
.noteConnectionFailureAndTriggerIfNeeded(
getTargetSsid(), mTargetRoamBSSID,
WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
2.1.5 ConnectedState$enter&exit
class ConnectedState extends State {
@Override
public void enter() {
...
mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(true);
mWifiStateTracker.updateState(WifiStateTracker.CONNECTED);
}
...
@Override
public void exit() {
logd("WifiStateMachine: Leaving Connected state");
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
mLastDriverRoamAttempt = 0;
mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(false);
}
一共调用了6次。
2.2 WifiStateMachine状态机
2.3 流程梳理
2.3.1 清空失败次数
首先肯定是启动supplicant的时候最先调用
/**
* Clear failure counts for each network in recentAvailableNetworks
*/
public void clearAllFailureCounts() {
if (mVerboseLoggingEnabled) Log.v(TAG, "clearAllFailureCounts.");
for (Map.Entry<String, AvailableNetworkFailureCount> entry
: mRecentAvailableNetworks.entrySet()) {
final AvailableNetworkFailureCount failureCount = entry.getValue();
entry.getValue().resetCounts();
}
for (Map.Entry<String, Pair<AvailableNetworkFailureCount, Integer>> entry
: mSsidFailureCount.entrySet()) {
final AvailableNetworkFailureCount failureCount = entry.getValue().first;
failureCount.resetCounts();
}
}
2.3.2 连接过程失败次数统计
class ConnectModeState extends State {
...
@Override
public boolean processMessage(Message message) {
WifiConfiguration config;
int netId;
boolean ok;
boolean didDisconnect;
String bssid;
String ssid;
NetworkUpdateResult result;
Set<Integer> removedNetworkIds;
int reasonCode;
boolean timedOut;
logStateAndMessage(message, this);
switch (message.what) {
case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
...
mWifiInjector.getWifiLastResortWatchdog()
.noteConnectionFailureAndTriggerIfNeeded(
getTargetSsid(), bssid,
WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
break;
class ConnectModeState extends State {
...
case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
...
mWifiInjector.getWifiLastResortWatchdog()
.noteConnectionFailureAndTriggerIfNeeded(
getTargetSsid(), mTargetRoamBSSID,
WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
class IpClientCallback extends IpClient.Callback {
@Override
public void onPreDhcpAction() {
sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION);
}
@Override
public void onPostDhcpAction() {
sendMessage(DhcpClient.CMD_POST_DHCP_ACTION);
}
@Override
public 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);
}
}
api注释
/**
* 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) {
大致意思是说对失败原因进行计数,当达到阈值时进行重启。
/**
* 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 network
updateFailureCountForNetwork(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-enabled
setWatchdogTriggerEnabled(false);
Log.e(TAG, "Watchdog triggering recovery");
mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
// increment various watchdog trigger count stats
incrementWifiMetricsTriggerCounts();
clearAllFailureCounts();
}
return isRestartNeeded;
}
- 更新失败次数 updateFailureCountForNetwork
- 检验是否需要重启 checkTriggerCondition
- 触发重启 mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
先看下checkTriggerCondition
/**
* 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 enabled
if (!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 to
return 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;
}
/**
* @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 count that each available networks must meet to possibly trigger the Watchdog
*/
public static final int FAILURE_THRESHOLD = 7;
阈值为7,当失败次数超过7次并且至少曾经已连接过1次,那么触发重启。
至于重启实现就是通过WifiController发送重启命令
/**
* Trigger recovery.
*
* This method does the following:
* 1. Raises a wtf.
* 2. Sends {@link WifiController#CMD_RESTART_WIFI} to {@link WifiController} to initiate the
* stack restart.
* @param reason One of the above |REASON_*| codes.
*/
public void trigger(int reason) {
if (!(reason == REASON_LAST_RESORT_WATCHDOG || reason == REASON_HAL_CRASH
|| reason == REASON_WIFICOND_CRASH)) {
Log.e(TAG, "Invalid trigger reason. Ignoring...");
return;
}
Log.e(TAG, "Triggering recovery for reason: " + REASON_STRINGS[reason]);
if (reason == REASON_WIFICOND_CRASH || reason == REASON_HAL_CRASH) {
trimPastRestartTimes();
// Ensure there haven't been too many restarts within MAX_RESTARTS_TIME_WINDOW
if (mPastRestartTimes.size() >= MAX_RESTARTS_IN_TIME_WINDOW) {
Log.e(TAG, "Already restarted wifi (" + MAX_RESTARTS_IN_TIME_WINDOW + ") times in"
+ " last (" + MAX_RESTARTS_TIME_WINDOW_MILLIS + "ms ). Ignoring...");
return;
}
mPastRestartTimes.add(mClock.getElapsedSinceBootMillis());
}
mWifiController.sendMessage(WifiController.CMD_RESTART_WIFI);
}
2.3.3 已连接状态
class ConnectedState extends State {
@Override
public void enter() {
...
mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(true);
mWifiStateTracker.updateState(WifiStateTracker.CONNECTED);
}
...
@Override
public void exit() {
logd("WifiStateMachine: Leaving Connected state");
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_TRANSITIONING);
mLastDriverRoamAttempt = 0;
mWifiInjector.getWifiLastResortWatchdog().connectedStateTransition(false);
}
/**
* Handles transitions entering and exiting WifiStateMachine ConnectedState
* Used to track wifistate, and perform watchdog count reseting
* @param isEntering true if called from ConnectedState.enter(), false for exit()
*/
public void connectedStateTransition(boolean isEntering) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "connectedStateTransition: isEntering = " + isEntering);
}
mWifiIsConnected = isEntering;
if (!mWatchdogAllowedToTrigger) {
// WiFi has connected after a Watchdog trigger, without any new networks becoming
// available, log a Watchdog success in wifi metrics
mWifiMetrics.incrementNumLastResortWatchdogSuccesses();
}
if (isEntering) {
// We connected to something! Reset failure counts for everything
clearAllFailureCounts();
// If the watchdog trigger was disabled (it triggered), connecting means we did
// something right, re-enable it so it can fire again.
setWatchdogTriggerEnabled(true);
}
}
当成功进入已连接状态的话自然是需要清空所有失败计数的,并且重新启用watchdog。进入和退出已连接状态时若watchdog没有被打开,那就增加一下成功计数。
3.总结
WifiLastResortWatchdog总体来看就是对WiFi连接过程的监控,当某一环境失败达到阈值那就触发重启。