1.WiFi重启
在日常生活中,WiFi使用过程中出现异常用户一般都会手动关闭再打开WiFi完成一次重启,那么Android机制是否有类似的呢?
2.重启流程探究
偶然间看到一个类叫做SelfRecovery,该类有将WiFi重启的接口
2.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.
*/
api中简要说明了这个类是用来将WiFi从异常状态恢复的。恢复机制是通过WifiController触发一个重启,基本模拟了一次飞行模式切换。
当前触发条件
- 看门狗
- 正常操作过程中的HAL/wificond crashes
- TBD:正常操作过程中的supplicant crashes(暂未有对应处理)
/**
* 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);
}
/**
* Process the mPastRestartTimes list, removing elements outside the max restarts time window
*/
private void trimPastRestartTimes() {
Iterator<Long> iter = mPastRestartTimes.iterator();
long now = mClock.getElapsedSinceBootMillis();
while (iter.hasNext()) {
Long restartTimeMillis = iter.next();
if (now - restartTimeMillis > MAX_RESTARTS_TIME_WINDOW_MILLIS) {
iter.remove();
} else {
break;
}
}
}
1)首先判断是否是已知的重启原因,若不是,忽略
2)若是wificond/hal crash,那么在指定时间内重启次数有限制,具体为1小时内重启次数不能超过2次。
public static final long MAX_RESTARTS_IN_TIME_WINDOW = 2; // 2 restarts per hour
public static final long MAX_RESTARTS_TIME_WINDOW_MILLIS = 60 * 60 * 1000; // 1 hour
3)发送CMD_RESTART_WIFI命令给WifiController触发重启
2.2 WifiController
(这个水印哈哈哈)
/* Parent: StaEnabledState */
class DeviceActiveState extends State {
@Override
public void enter() {
mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mWifiStateMachine.setHighPerfModeEnabled(false);
}
@Override
public boolean processMessage(Message msg) {
if (msg.what == CMD_DEVICE_IDLE) {
checkLocksAndTransitionWhenDeviceIdle();
// We let default state handle the rest of work
} else if (msg.what == CMD_USER_PRESENT) {
// TLS networks can't connect until user unlocks keystore. KeyStore
// unlocks when the user punches PIN after the reboot. So use this
// trigger to get those networks connected.
if (mFirstUserSignOnSeen == false) {
mWifiStateMachine.reloadTlsNetworksAndReconnect();
}
mFirstUserSignOnSeen = true;
return HANDLED;
} else if (msg.what == CMD_RESTART_WIFI) {
deferMessage(obtainMessage(CMD_RESTART_WIFI_CONTINUE));
transitionTo(mApStaDisabledState);
return HANDLED;
}
return NOT_HANDLED;
}
}
WiFi处于打开状态即DeviceActiveState收到CMD_RESTART_WIFI,延迟一个状态处理CMD_RESTART_WIFI_CONTINUE,切换到ApStaDisabledState状态完成WiFi关闭。
即
class ApStaDisabledState extends State {
private int mDeferredEnableSerialNumber = 0;
private boolean mHaveDeferredEnable = false;
private long mDisabledTimestamp;
@Override
public void enter() {
mWifiStateMachine.setSupplicantRunning(false);
// Supplicant can't restart right away, so not the time we switched off
mDisabledTimestamp = SystemClock.elapsedRealtime();
mDeferredEnableSerialNumber++;
mHaveDeferredEnable = false;
mWifiStateMachine.clearANQPCache();
}
进入到ApStaDisabledState处理延时消息CMD_RESTART_WIFI_CONTINUE
case CMD_RESTART_WIFI_CONTINUE:
transitionTo(mDeviceActiveState);
break;
再回到DeviceActiveState完成WiFi打开操作
class StaEnabledState extends State {
@Override
public void enter() {
mWifiStateMachine.setSupplicantRunning(true);
}
/* Parent: StaEnabledState */
class DeviceActiveState extends State {
@Override
public void enter() {
mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mWifiStateMachine.setHighPerfModeEnabled(false);
}
重启流程完毕
3.总结
重启其实很简单,就是状态机状态正常切换,完成关闭和打开操作。
状态流转就是
关闭:DeviceActiveState->StaEnabledState->ApStaDisabledState
打开:ApStaDisabledState->StaEnabledState->DeviceActiveState