(一百三十二)Android O WiFi重启机制学习——重启流程

时间:2024-04-05 20:38:02

1.WiFi重启

在日常生活中,WiFi使用过程中出现异常用户一般都会手动关闭再打开WiFi完成一次重启,那么Android机制是否有类似的呢?

 

2.重启流程探究

(一百三十二)Android O WiFi重启机制学习——重启流程偶然间看到一个类叫做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

(一百三十二)Android O WiFi重启机制学习——重启流程

(这个水印哈哈哈)

    /* 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

(一百三十二)Android O WiFi重启机制学习——重启流程