Android wifi源碼分析(二) Wifi關閉流程

接着上一篇,這篇說一下Wifi的關閉流程。

由上一篇可以知道,framework層提供的wifi開關接口都是setWifiEnabled,只是參數不同而已。true表示開啓wifi、false表示關閉wifi。

Wifi開關在WifiManager和WifiService中的流程一樣,接着看WifiController。
wifi開啓的時候,WifiController中狀態爲DeviceActiveState(其父狀態爲StaEnabledState)。
一下是StaEnabledState對CMD_WIFI_TOGGLED消息的處理。

case CMD_WIFI_TOGGLED:
   if (! mSettingsStore.isWifiToggleEnabled()) {
       if (mSettingsStore.isScanAlwaysAvailable()) {
           transitionTo(mStaDisabledWithScanState);
       } else {
           transitionTo(mApStaDisabledState);
       }
   }
   break;

isWifiToggleEnabled爲false表示要關閉wifi,則將狀態切換到StaDisabledWithScanState(如果可以一直掃描)或ApStaDisabledState。
我們這裏主要看下切換到ApStaDisabledState狀態。切換到ApStaDisabledState狀態,會先走其enter函數。

class ApStaDisabledState extends State {
    private int mDeferredEnableSerialNumber = 0;
    private boolean mHaveDeferredEnable = false;
    private long mDisabledTimestamp;

    @Override
    public void enter() {
        mWifiStateMachine.setSupplicantRunning(false);
        // wpa_supplicant 不能立即重啓,所以記錄下關閉的時間。
        mDisabledTimestamp = SystemClock.elapsedRealtime();
        mDeferredEnableSerialNumber++;
        mHaveDeferredEnable = false;
    }
//.....

mWifiStateMachine.setSupplicantRunning(false)用來關閉wifi。

public void setSupplicantRunning(boolean enable) {
    if (enable) {
        sendMessage(CMD_START_SUPPLICANT);
    } else {
        sendMessage(CMD_STOP_SUPPLICANT);
    }
}

WifiStateMachine中發送CMD_STOP_SUPPLICANT消息。
由上一篇可知wifi開啓後,WifiStateMachine狀態可能是DriverStartedState(父狀態是SupplicantStartedState)、DisconnectedState(父狀態是DriverStartedState)。

class SupplicantStartedState extends State {
    @Override
    public boolean processMessage(Message message) {
        switch(message.what) {
            case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
                if (mP2pSupported) {
                    transitionTo(mWaitForP2pDisableState);
                } else {
                    transitionTo(mSupplicantStoppingState);
                }
                break;
//。。。

mP2pSupported表示是否支持wifi直連。支持wifi直連,則WifiStateMachine切換到WaitForP2pDisableState狀態。否則切換到SupplicantStoppingState狀態。

wifi直連的先不管,看下切換到SupplicantStoppingState狀態。

class SupplicantStoppingState extends State {
    @Override
    public void enter() {
        /* Send any reset commands to supplicant before shutting it down */
        handleNetworkDisconnect();
        if (mDhcpStateMachine != null) {
            //退出DhcpStateMachine
            mDhcpStateMachine.doQuit();
        }
        //關閉wpa_supplicant
        if (!mWifiNative.stopSupplicant()) {
            loge("Failed to stop supplicant");
        }

        /* 發送自己一個延遲的消息,指示等待時間後的失敗 */
        sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
                ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
        //發送廣播,wifi狀態改變(WIFI_STATE_DISABLING)
        setWifiState(WIFI_STATE_DISABLING);
        mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
    }
  1. handleNetworkDisconnect 通過清除任何狀態,重新設置Wifi連接,使用該接口重置任何socket,停止DHCP和禁用接口。
  2. mDhcpStateMachine.doQuit(); 退出DhcpStateMachine。
  3. mWifiNative.stopSupplicant() 關閉wpa_supplicant。
  4. setWifiState 發送廣播,wifi狀態改變(WIFI_STATE_DISABLING)。
  5. CMD_RESET_SUPPLICANT_STATE 向SupplicantStateTracker發送消息,重置supplicant state tracker。

看一下handleNetworkDisconnect 函數。

/**
 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
 * using the interface, stopping DHCP & disabling interface
 */
private void handleNetworkDisconnect() {
    //停止dhcp
    stopDhcp();

    try {//清除ip地址
        mNwService.clearInterfaceAddresses(mInterfaceName);
        mNwService.disableIpv6(mInterfaceName);
    } catch (Exception e) {
        loge("Failed to clear addresses or disable ipv6" + e);
    }
    //設置network disconnect。
    setNetworkDetailedState(DetailedState.DISCONNECTED);
    mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);

    /* send event to CM & network change broadcast */
    //發送廣播、網絡狀態改變。
    sendNetworkStateChangeBroadcast(mLastBssid);

    /* 重置數據 */
    mWifiInfo.setInetAddress(null);
    mWifiInfo.setBSSID(null);
    mWifiInfo.setSSID(null);
    mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
    mWifiInfo.setRssi(MIN_RSSI);
    mWifiInfo.setLinkSpeed(-1);
    mWifiInfo.setMeteredHint(false);
    mWifiInfo.setReason(-1);

    /* Clear network properties */
    mLinkProperties.clear();

    /* 如果網絡使用DHCP,清除IP設置 */
    if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
        mWifiConfigStore.clearLinkProperties(mLastNetworkId);
    }

    mLastBssid= null;
    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
}

mWifiNative.stopSupplicant() 關閉wpa_supplicant。向wpa_supplicant發送命令TERMINATE,wpa_supplicant終止並向java層返回狀態TERMINATE,WifiMonitor中會循環從wpa_supplicant接收消息,此時會收到TERMINATE消息,其向WifiStateMachine發送SUP_DISCONNECTION_EVENT消息。
看看WifiStateMachine是如何處理該消息的。

class SupplicantStoppingState extends State {
    @Override
    public boolean processMessage(Message message) {
        switch(message.what) {
            case WifiMonitor.SUP_DISCONNECTION_EVENT:
                handleSupplicantConnectionLoss();
                transitionTo(mInitialState);
                break;
            case CMD_STOP_SUPPLICANT_FAILED:
            //超時未收到supplicant disconnect event,則執行如下
                if (message.arg1 == mSupplicantStopFailureToken) {
                    loge("Timed out on a supplicant stop, kill and proceed");
                    handleSupplicantConnectionLoss();
                    transitionTo(mInitialState);
                }
                break;

handleSupplicantConnectionLoss 向supplicant發送kill信號、斷開連接、發送wifi狀態改變的廣播(WIFI_STATE_DISABLED)。
看handleSupplicantConnectionLoss 函數如下:

private void handleSupplicantConnectionLoss() {
    //向supplicant發送kill信號。
    mWifiNative.killSupplicant(mP2pSupported);
    //斷開連接。
    mWifiNative.closeSupplicantConnection();
    sendSupplicantConnectionChangedBroadcast(false);
    //發送wifi狀態改變的廣播(WIFI_STATE_DISABLED)
    setWifiState(WIFI_STATE_DISABLED);
}

mWifiNative.killSupplicant(mP2pSupported); 向supplicant發送kill信號,使wpa_supplicant進程退出。
mWifiNative.closeSupplicantConnection() 斷開與wpa_supplicant連接。
setWifiState(WIFI_STATE_DISABLED) 向外發送廣播(wifi狀態改變,WIFI_STATE_DISABLED)。

transitionTo(mInitialState) 切換到InitialState狀態。在InitialState的enter函數中調用mWifiNative.unloadDriver(),卸載驅動。此時wifi關閉完成。

有什麼問題和意見,歡迎提問、交流
歡迎大家關注、評論、點贊
你們的支持是我堅持的動力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章