Android -- Wifi的断开及关闭流程简介

Android -- Wifi的断开及关闭流程简介


当我们连接上一个AP时,Wifi的断开及关闭都会导致设备与AP之间的连接中断;关闭Wifi同时会导致Wifi断开。下面就简单介绍Wifi断开及关闭的流程。

一、Wifi的断开

我们断开Wifi,调用WifiManager::disconnect()方法,嵌套调用WifiServiceImpl的同名方法:
[java] view plain copy
  1. /** 
  2.  * see {@link android.net.wifi.WifiManager#disconnect()} 
  3.  */  
  4. public void disconnect() {  
  5.     enforceChangePermission();  
  6.     mWifiStateMachine.disconnectCommand();  
  7. }  
调用Wifi状态机的内部方法,发送断开Wifi的指令CMD_DISCONNECT。由于之前网络连接成功时,State Machine停在ConnectedState,所以由它的父状态L2ConnectedState处理该消息:
[java] view plain copy
  1. case CMD_DISCONNECT:  
  2.     mWifiNative.disconnect();  
  3.     transitionTo(mDisconnectingState);  
  4.     break;  
通过WifiNative::disconnect()方法下发断开指令,当驱动断开AP连接后,wpa_s反馈断开事件,WifiMonitor接收来自wpa_s的event,并向WifiStateMachine反馈NETWORK_DISCONNECTION_EVENT消息(该过程参考前面的博文)。切换到DisconnectingState状态,断开的消息尤其父状态ConnectModeState处理:
[java] view plain copy
  1. case WifiMonitor.NETWORK_DISCONNECTION_EVENT:  
  2.                     // Calling handleNetworkDisconnect here is redundant because we might already  
  3.                     // have called it when leaving L2ConnectedState to go to disconnecting state  
  4.                     // or thru other path  
  5.                     // We should normally check the mWifiInfo or mLastNetworkId so as to check  
  6.                     // if they are valid, and only in this case call handleNEtworkDisconnect,  
  7.                     // TODO: this should be fixed for a L MR release  
  8.                     // The side effect of calling handleNetworkDisconnect twice is that a bunch of  
  9.                     // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode  
  10.                     // at the chip etc...  
  11.                     if (DBG) log("ConnectModeState: Network connection lost ");  
  12.                     handleNetworkDisconnect();  
  13.                     transitionTo(mDisconnectedState);  
  14.                     break;  
由代码中的注释可知,我们或许会在别的地方已经调用过handleNetworkDisconnect(),事实也确实如此;当我们离开L2ConnectedState状态时,会调用它的exit()方法:
[java] view plain copy
  1. @Override  
  2.  public void exit() {  
  3.      if (mIpReachabilityMonitor != null) {  
  4.          mIpReachabilityMonitor.stop();  
  5.          mIpReachabilityMonitor = null;  
  6.      }  
  7.   
  8.      // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState  
  9.      // Bug: 15347363  
  10.      // For paranoia's sake, call handleNetworkDisconnect  
  11.      // only if BSSID is null or last networkId  
  12.      // is not invalid.  
  13.      if (DBG) {  
  14.          StringBuilder sb = new StringBuilder();  
  15.          sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));  
  16.          if (mLastBssid !=null) {  
  17.              sb.append(" ").append(mLastBssid);  
  18.          }  
  19.      }  
  20.      if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {  
  21.          handleNetworkDisconnect();//call the function,执行忘了断开时的处理  
  22.      }  
  23.  }  
我们发现该方法中确实可能会调用handleNetworkDisconnect(),接着看该函数做了哪些处理:
[java] view plain copy
  1. /** 
  2.      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 
  3.      * using the interface, stopping DHCP & disabling interface 
  4.      */  
  5.     private void handleNetworkDisconnect() {  
  6.   
  7.         clearCurrentConfigBSSID("handleNetworkDisconnect");  
  8.   
  9.         stopDhcp();  
  10.   
  11.         try {  
  12.             mNwService.clearInterfaceAddresses(mInterfaceName);  
  13.             mNwService.disableIpv6(mInterfaceName);  
  14.         } catch (Exception e) {  
  15.             loge("Failed to clear addresses or disable ipv6" + e);  
  16.         }  
  17.   
  18.         /* Reset data structures */  
  19.         mBadLinkspeedcount = 0;  
  20.         mWifiInfo.reset();  
  21.         linkDebouncing = false;  
  22.         /* Reset roaming parameters */  
  23.         mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;  
  24.   
  25.         /** 
  26.          *  fullBandConnectedTimeIntervalMilli: 
  27.          *  - start scans at mWifiConfigStore.wifiAssociatedShortScanIntervalMilli seconds interval 
  28.          *  - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli 
  29.          *  Initialize to sane value = 20 seconds 
  30.          */  
  31.         fullBandConnectedTimeIntervalMilli = 20 * 1000;  
  32.   
  33.         setNetworkDetailedState(DetailedState.DISCONNECTED);  
  34.         if (mNetworkAgent != null) {  
  35.             mNetworkAgent.sendNetworkInfo(mNetworkInfo);  
  36.             mNetworkAgent = null;  
  37.         }  
  38.         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);  
  39.   
  40.         /* Clear network properties */  
  41.         clearLinkProperties();  
  42.   
  43.         /* Cend event to CM & network change broadcast */  
  44.         sendNetworkStateChangeBroadcast(mLastBssid);  
  45.   
  46.         /* Cancel auto roam requests */  
  47.         autoRoamSetBSSID(mLastNetworkId, "any");  
  48.   
  49.         mLastBssid = null;  
  50.         registerDisconnected();  
  51.         mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;  
  52.     }  
当一个AP连接断开时,主要会做如下几处理:
  1. stopDhcp():停止DHCP过程,即停止dhcpcd进程
  2. mNwService.clearInterfaceAddresses(mInterfaceName):通过NetworkManagementService通知Netd清除wlan0的地址信息
  3. mWifiInfo.reset():重置WifiInfo对象的状态
  4. setNetworkDetailedState(DetailedState.DISCONNECTED):将mNetworkInfo的连接状态设为DISCONNECTED
  5. mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED):将mLastNetworkId对应的 WifiConfiguration对象状态设为DISCONNECTED
  6. clearLinkProperties():清除mLinkProperties对象的配置信息
  7. sendNetworkStateChangeBroadcast():发广播通知上层网络状态变化
  8. registerDisconnected():做一些清理、记录工作
最后状态切换到DisconnectedState,等待下一次连接的发起,断开流程结束。

二、Wifi的关闭

从前面的博文可知,Wifi的开启、关闭都是调用WifiManager::setWifiEnabled(),嵌套调用WifiServiceImpl中的同名方法,向WifiController发送CMD_WIFI_TOGGLED消息:
[java] view plain copy
  1. /** 
  2.  * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 
  3.  * @param enable {@code true} to enable, {@code false} to disable. 
  4.  * @return {@code true} if the enable/disable operation was 
  5.  *         started or is already in the queue. 
  6.  */  
  7. public synchronized boolean setWifiEnabled(boolean enable) {  
  8.     enforceChangePermission();  
  9.     Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()  
  10.                 + ", uid=" + Binder.getCallingUid());  
  11.     if (DBG) {  
  12.         Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");  
  13.     }  
  14.   
  15.     /* 
  16.     * Caller might not have WRITE_SECURE_SETTINGS, 
  17.     * only CHANGE_WIFI_STATE is enforced 
  18.     */  
  19.   
  20.     long ident = Binder.clearCallingIdentity();  
  21.     try {  
  22.         if (! mSettingsStore.handleWifiToggled(enable)) {  
  23.             // Nothing to do if wifi cannot be toggled  
  24.             return true;  
  25.         }  
  26.     } finally {  
  27.         Binder.restoreCallingIdentity(ident);  
  28.     }  
  29.   
  30.     mWifiController.sendMessage(CMD_WIFI_TOGGLED);  
  31.     return true;  
  32. }  
前面的博文介绍过Wifi的启动流程,当WifiController向Wifi状态机发送启动wpa_s消息的时候,状态停留在DeviceActiveState。DeviceActiveState不处理CMD_WIFI_TOGGLED消息,交由其父状态StaEnabledState处理:
[java] view plain copy
  1. case CMD_WIFI_TOGGLED:  
  2.                    if (! mSettingsStore.isWifiToggleEnabled()) {  
  3.                        if (mSettingsStore.isScanAlwaysAvailable()) {  
  4.                            transitionTo(mStaDisabledWithScanState);  
  5.                        } else {  
  6.                            transitionTo(mApStaDisabledState);  
  7.                        }  
  8.                    }  
  9.                    break;  
结合前面的所讲的内容,可知状态切换到ApStaDisabledState,进行关闭流程,调用它的enter()方法:
[java] view plain copy
  1. @Override  
  2. public void enter() {  
  3.     mWifiStateMachine.setSupplicantRunning(false);  
  4.     // Supplicant can't restart right away, so not the time we switched off  
  5.     mDisabledTimestamp = SystemClock.elapsedRealtime();  
  6.     mDeferredEnableSerialNumber++;  
  7.     mHaveDeferredEnable = false;  
  8.     mWifiStateMachine.clearANQPCache();  
  9. }  
调用WifiStateMachine::setSupplicantRunning(false)向WifiStateMachine发送停止wpa_s的消息:CMD_STOP_SUPPLICANT。
SupplicantStartedState接收、处理该消息:
[java] view plain copy
  1. case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */  
  2.     if (mP2pSupported) {  
  3.         transitionTo(mWaitForP2pDisableState);  
  4.     } else {  
  5.         transitionTo(mSupplicantStoppingState);  
  6.     }  
  7.     break;  
切换到SupplicantStoppingState,进入enter()方法:
[java] view plain copy
  1. public void enter() {  
  2.             /* Send any reset commands to supplicant before shutting it down */  
  3.             handleNetworkDisconnect();  
  4.             if (mDhcpStateMachine != null) {  
  5.                 mDhcpStateMachine.doQuit();  
  6.             }  
  7.   
  8.             String suppState = System.getProperty("init.svc.wpa_supplicant");  
  9.             if (suppState == null) suppState = "unknown";  
  10.             String p2pSuppState = System.getProperty("init.svc.p2p_supplicant");  
  11.             if (p2pSuppState == null) p2pSuppState = "unknown";  
  12.   
  13.             logd("SupplicantStoppingState: stopSupplicant "  
  14.                     + " init.svc.wpa_supplicant=" + suppState  
  15.                     + " init.svc.p2p_supplicant=" + p2pSuppState);  
  16.             mWifiMonitor.stopSupplicant();  
  17.   
  18.             /* Send ourselves a delayed message to indicate failure after a wait time */  
  19.             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,  
  20.                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);  
  21.             setWifiState(WIFI_STATE_DISABLING);  
  22.             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);  
  23.         }  
  1. 调用handleNetworkDisconnect()处理AP连接的断开部分,第一部分已经讲过。
  2. 设置DhcpStateMachine的状态,停止DhcpStateMachine
  3. 调用WifiMonitor::stopSupplicant()停掉wpa_s
  4. 将wifi状态设置为disabling;setWifiState()函数会设置当前Wifi的状态,比如disabled、disabling、enabled等;我们通过监听函数发送的WifiManager.WIFI_STATE_CHANGED_ACTION广播,可以得知当前Wifi的具体状态。
WifiMonitor中下发终止指令后,会收到wpa_s断开的event:
[java] view plain copy
  1. else if (event == TERMINATING) {  
  2.             /** 
  3.              * Close the supplicant connection if we see 
  4.              * too many recv errors 
  5.              */  
  6.             if (eventData.startsWith(WPA_RECV_ERROR_STR)) {  
  7.                 if (++sRecvErrors > MAX_RECV_ERRORS) {  
  8.                     if (DBG) {  
  9.                         Log.d(TAG, "too many recv errors, closing connection");  
  10.                     }  
  11.                 } else {  
  12.                     eventLogCounter++;  
  13.                     return false;  
  14.                 }  
  15.             }  
  16.   
  17.             // Notify and exit  
  18.             mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT, eventLogCounter);  
  19.             return true;  
WifiMonitor会向wifi状态机发送SUP_DISCONNECTION_EVENT消息并最终退出,等待下一次重新与wpa_s建立通信。SupplicantStoppingState处理该消息:
[java] view plain copy
  1. case WifiMonitor.SUP_DISCONNECTION_EVENT:  
  2.      if (DBG) log("Supplicant connection lost");  
  3.      handleSupplicantConnectionLoss(false);  
  4.      transitionTo(mInitialState);  
  5.      break;  
[java] view plain copy
  1. private void handleSupplicantConnectionLoss(boolean killSupplicant) {  
  2.     /* Socket connection can be lost when we do a graceful shutdown 
  3.     * or when the driver is hung. Ensure supplicant is stopped here. 
  4.     */  
  5.     if (killSupplicant) {  
  6.         mWifiMonitor.killSupplicant(mP2pSupported);  
  7.     }  
  8.     mWifiNative.closeSupplicantConnection();  
  9.     sendSupplicantConnectionChangedBroadcast(false);  
  10.     setWifiState(WIFI_STATE_DISABLED);  
  11. }  
handleSupplicantConnectionLoss()函数中,因为之前已经执行过stopSupplicant()的操作,killSupplicant传入false,所以不会重复执行关闭wpa_s的killSupplicant()函数;随后关闭wpa_s与wifi之间传递指令、事件的socket连接,最后设置当前Wifi状态为disabled,代表Wifi已经关闭完成。
handleSupplicantConnectionLoss()执行完毕后,wpa_s的状态已经被彻底清除掉,随之将Wifi状态机切换到InitialState:
[java] view plain copy
  1. @Override  
  2. public void enter() {  
  3.     WifiNative.stopHal();  
  4.     mWifiNative.unloadDriver();  
  5.     if (mWifiP2pChannel == null) {  
  6.         mWifiP2pChannel = new AsyncChannel();  
  7.         mWifiP2pChannel.connect(mContext, getHandler(),  
  8.             mWifiP2pServiceImpl.getP2pStateMachineMessenger());  
  9.     }  
  10.   
  11.     if (mWifiApConfigChannel == null) {  
  12.         mWifiApConfigChannel = new AsyncChannel();  
  13.         mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(  
  14.                 mContext, getHandler());  
  15.         mWifiApConfigStore.loadApConfiguration();  
  16.         mWifiApConfigChannel.connectSync(mContext, getHandler(),  
  17.                 mWifiApConfigStore.getMessenger());  
  18.     }  
  19.   
  20.     if (mWifiConfigStore.enableHalBasedPno.get()) {  
  21.         // make sure developer Settings are in sync with the config option  
  22.         mHalBasedPnoEnableInDevSettings = true;  
  23.     }  
  24. }  
在enter()函数中,比较重要的操作就是mWifiNative.unloadDriver(),当Wifi完全关闭后,将驱动也卸载掉。当下一次Wifi启动流程启动时,再重新加载驱动、启动wpa_s。
到此,Wifi关闭的流程就结束了。

你可能感兴趣的:(android,网络框架接入分析)