接着上一篇,这篇说一下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);
}
- handleNetworkDisconnect 通过清除任何状态,重新设置Wifi连接,使用该接口重置任何socket,停止DHCP和禁用接口。
- mDhcpStateMachine.doQuit(); 退出DhcpStateMachine。
- mWifiNative.stopSupplicant() 关闭wpa_supplicant。
- setWifiState 发送广播,wifi状态改变(WIFI_STATE_DISABLING)。
- 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关闭完成。
有什么问题和意见,欢迎提问、交流。
欢迎大家关注、评论、点赞。
你们的支持是我坚持的动力。