美文网首页Android知识Android技术知识Android开发经验谈
Android wifi源码分析(二) Wifi关闭流程

Android wifi源码分析(二) Wifi关闭流程

作者: 朋永 | 来源:发表于2017-09-19 17:00 被阅读0次

    接着上一篇,这篇说一下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关闭完成。

    有什么问题和意见,欢迎提问、交流
    欢迎大家关注、评论、点赞
    你们的支持是我坚持的动力。

    相关文章

      网友评论

        本文标题:Android wifi源码分析(二) Wifi关闭流程

        本文链接:https://www.haomeiwen.com/subject/wvqgsxtx.html