Android -- Wifi的断开及关闭流程简介
2017-05-10 13:59
465 查看
Android -- Wifi的断开及关闭流程简介
当我们连接上一个AP时,Wifi的断开及关闭都会导致设备与AP之间的连接中断;关闭Wifi同时会导致Wifi断开。下面就简单介绍Wifi断开及关闭的流程。一、Wifi的断开
我们断开Wifi,调用WifiManager::disconnect()方法,嵌套调用WifiServiceImpl的同名方法:[java]
view plain
copy
/**
* see {@link android.net.wifi.WifiManager#disconnect()}
*/
public void disconnect() {
enforceChangePermission();
mWifiStateMachine.disconnectCommand();
}
调用Wifi状态机的内部方法,发送断开Wifi的指令CMD_DISCONNECT。由于之前网络连接成功时,State Machine停在ConnectedState,所以由它的父状态L2ConnectedState处理该消息:
[java]
view plain
copy
case CMD_DISCONNECT:
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
break;
通过WifiNative::disconnect()方法下发断开指令,当驱动断开AP连接后,wpa_s反馈断开事件,WifiMonitor接收来自wpa_s的event,并向WifiStateMachine反馈NETWORK_DISCONNECTION_EVENT消息(该过程参考前面的博文)。切换到DisconnectingState状态,断开的消息尤其父状态ConnectModeState处理:
[java]
view plain
copy
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
// Calling handleNetworkDisconnect here is redundant because we might already
// have called it when leaving L2ConnectedState to go to disconnecting state
// or thru other path
// We should normally check the mWifiInfo or mLastNetworkId so as to check
// if they are valid, and only in this case call handleNEtworkDisconnect,
// TODO: this should be fixed for a L MR release
// The side effect of calling handleNetworkDisconnect twice is that a bunch of
// idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode
// at the chip etc...
if (DBG) log("ConnectModeState: Network connection lost ");
handleNetworkDisconnect();
transitionTo(mDisconnectedState);
break;
由代码中的注释可知,我们或许会在别的地方已经调用过handleNetworkDisconnect(),事实也确实如此;当我们离开L2ConnectedState状态时,会调用它的exit()方法:
[java]
view plain
copy
@Override
public void exit() {
if (mIpReachabilityMonitor != null) {
mIpReachabilityMonitor.stop();
mIpReachabilityMonitor = null;
}
// This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
// Bug: 15347363
// For paranoia's sake, call handleNetworkDisconnect
// only if BSSID is null or last networkId
// is not invalid.
if (DBG) {
StringBuilder sb = new StringBuilder();
sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId));
if (mLastBssid !=null) {
sb.append(" ").append(mLastBssid);
}
}
if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) {
handleNetworkDisconnect();//call the function,执行忘了断开时的处理
}
}
我们发现该方法中确实可能会调用handleNetworkDisconnect(),接着看该函数做了哪些处理:
[java]
view plain
copy
/**
* Resets the Wi-Fi Connections by clearing any state, resetting any sockets
* using the interface, stopping DHCP & disabling interface
*/
private void handleNetworkDisconnect() {
clearCurrentConfigBSSID("handleNetworkDisconnect");
stopDhcp();
try {
mNwService.clearInterfaceAddresses(mInterfaceName);
mNwService.disableIpv6(mInterfaceName);
} catch (Exception e) {
loge("Failed to clear addresses or disable ipv6" + e);
}
/* Reset data structures */
mBadLinkspeedcount = 0;
mWifiInfo.reset();
linkDebouncing = false;
/* Reset roaming parameters */
mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
/**
* fullBandConnectedTimeIntervalMilli:
* - start scans at mWifiConfigStore.wifiAssociatedShortScanIntervalMilli seconds interval
* - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli
* Initialize to sane value = 20 seconds
*/
fullBandConnectedTimeIntervalMilli = 20 * 1000;
setNetworkDetailedState(DetailedState.DISCONNECTED);
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent = null;
}
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
/* Clear network properties */
clearLinkProperties();
/* Cend event to CM & network change broadcast */
sendNetworkStateChangeBroadcast(mLastBssid);
/* Cancel auto roam requests */
autoRoamSetBSSID(mLastNetworkId, "any");
mLastBssid = null;
registerDisconnected();
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
}
当一个AP连接断开时,主要会做如下几处理:
stopDhcp():停止DHCP过程,即停止dhcpcd进程
mNwService.clearInterfaceAddresses(mInterfaceName):通过NetworkManagementService通知Netd清除wlan0的地址信息
mWifiInfo.reset():重置WifiInfo对象的状态
setNetworkDetailedState(DetailedState.DISCONNECTED):将mNetworkInfo的连接状态设为DISCONNECTED
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED):将mLastNetworkId对应的 WifiConfiguration对象状态设为DISCONNECTED
clearLinkProperties():清除mLinkProperties对象的配置信息
sendNetworkStateChangeBroadcast():发广播通知上层网络状态变化
registerDisconnected():做一些清理、记录工作
最后状态切换到DisconnectedState,等待下一次连接的发起,断开流程结束。
二、Wifi的关闭
从前面的博文可知,Wifi的开启、关闭都是调用WifiManager::setWifiEnabled(),嵌套调用WifiServiceImpl中的同名方法,向WifiController发送CMD_WIFI_TOGGLED消息:[java]
view plain
copy
/**
* see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
* @param enable {@code true} to enable, {@code false} to disable.
* @return {@code true} if the enable/disable operation was
* started or is already in the queue.
*/
public synchronized boolean setWifiEnabled(boolean enable) {
enforceChangePermission();
Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
if (DBG) {
Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
}
/*
* Caller might not have WRITE_SECURE_SETTINGS,
* only CHANGE_WIFI_STATE is enforced
*/
long ident = Binder.clearCallingIdentity();
try {
if (! mSettingsStore.handleWifiToggled(enable)) {
// Nothing to do if wifi cannot be toggled
return true;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
mWifiController.sendMessage(CMD_WIFI_TOGGLED);
return true;
}
前面的博文介绍过Wifi的启动流程,当WifiController向Wifi状态机发送启动wpa_s消息的时候,状态停留在DeviceActiveState。DeviceActiveState不处理CMD_WIFI_TOGGLED消息,交由其父状态StaEnabledState处理:
[java]
view plain
copy
case CMD_WIFI_TOGGLED:
if (! mSettingsStore.isWifiToggleEnabled()) {
if (mSettingsStore.isScanAlwaysAvailable()) {
transitionTo(mStaDisabledWithScanState);
} else {
transitionTo(mApStaDisabledState);
}
}
break;
结合前面的所讲的内容,可知状态切换到ApStaDisabledState,进行关闭流程,调用它的enter()方法:
[java]
view plain
copy
@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();
}
调用WifiStateMachine::setSupplicantRunning(false)向WifiStateMachine发送停止wpa_s的消息:CMD_STOP_SUPPLICANT。
SupplicantStartedState接收、处理该消息:
[java]
view plain
copy
case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
if (mP2pSupported) {
transitionTo(mWaitForP2pDisableState);
} else {
transitionTo(mSupplicantStoppingState);
}
break;
切换到SupplicantStoppingState,进入enter()方法:
[java]
view plain
copy
public void enter() {
/* Send any reset commands to supplicant before shutting it down */
handleNetworkDisconnect();
if (mDhcpStateMachine != null) {
mDhcpStateMachine.doQuit();
}
String suppState = System.getProperty("init.svc.wpa_supplicant");
if (suppState == null) suppState = "unknown";
String p2pSuppState = System.getProperty("init.svc.p2p_supplicant");
if (p2pSuppState == null) p2pSuppState = "unknown";
logd("SupplicantStoppingState: stopSupplicant "
+ " init.svc.wpa_supplicant=" + suppState
+ " init.svc.p2p_supplicant=" + p2pSuppState);
mWifiMonitor.stopSupplicant();
/* Send ourselves a delayed message to indicate failure after a wait time */
sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
setWifiState(WIFI_STATE_DISABLING);
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
}
调用handleNetworkDisconnect()处理AP连接的断开部分,第一部分已经讲过。
设置DhcpStateMachine的状态,停止DhcpStateMachine
调用WifiMonitor::stopSupplicant()停掉wpa_s
将wifi状态设置为disabling;setWifiState()函数会设置当前Wifi的状态,比如disabled、disabling、enabled等;我们通过监听函数发送的WifiManager.WIFI_STATE_CHANGED_ACTION广播,可以得知当前Wifi的具体状态。
WifiMonitor中下发终止指令后,会收到wpa_s断开的event:
[java]
view plain
copy
else if (event == TERMINATING) {
/**
* Close the supplicant connection if we see
* too many recv errors
*/
if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
if (++sRecvErrors > MAX_RECV_ERRORS) {
if (DBG) {
Log.d(TAG, "too many recv errors, closing connection");
}
} else {
eventLogCounter++;
return false;
}
}
// Notify and exit
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT, eventLogCounter);
return true;
WifiMonitor会向wifi状态机发送SUP_DISCONNECTION_EVENT消息并最终退出,等待下一次重新与wpa_s建立通信。SupplicantStoppingState处理该消息:
[java]
view plain
copy
case WifiMonitor.SUP_DISCONNECTION_EVENT:
if (DBG) log("Supplicant connection lost");
handleSupplicantConnectionLoss(false);
transitionTo(mInitialState);
break;
[java]
view plain
copy
private void handleSupplicantConnectionLoss(boolean killSupplicant) {
/* Socket connection can be lost when we do a graceful shutdown
* or when the driver is hung. Ensure supplicant is stopped here.
*/
if (killSupplicant) {
mWifiMonitor.killSupplicant(mP2pSupported);
}
mWifiNative.closeSupplicantConnection();
sendSupplicantConnectionChangedBroadcast(false);
setWifiState(WIFI_STATE_DISABLED);
}
handleSupplicantConnectionLoss()函数中,因为之前已经执行过stopSupplicant()的操作,killSupplicant传入false,所以不会重复执行关闭wpa_s的killSupplicant()函数;随后关闭wpa_s与wifi之间传递指令、事件的socket连接,最后设置当前Wifi状态为disabled,代表Wifi已经关闭完成。
handleSupplicantConnectionLoss()执行完毕后,wpa_s的状态已经被彻底清除掉,随之将Wifi状态机切换到InitialState:
[java]
view plain
copy
@Override
public void enter() {
WifiNative.stopHal();
mWifiNative.unloadDriver();
if (mWifiP2pChannel == null) {
mWifiP2pChannel = new AsyncChannel();
mWifiP2pChannel.connect(mContext, getHandler(),
mWifiP2pServiceImpl.getP2pStateMachineMessenger());
}
if (mWifiApConfigChannel == null) {
mWifiApConfigChannel = new AsyncChannel();
mWifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
mContext, getHandler());
mWifiApConfigStore.loadApConfiguration();
mWifiApConfigChannel.connectSync(mContext, getHandler(),
mWifiApConfigStore.getMessenger());
}
if (mWifiConfigStore.enableHalBasedPno.get()) {
// make sure developer Settings are in sync with the config option
mHalBasedPnoEnableInDevSettings = true;
}
}
在enter()函数中,比较重要的操作就是mWifiNative.unloadDriver(),当Wifi完全关闭后,将驱动也卸载掉。当下一次Wifi启动流程启动时,再重新加载驱动、启动wpa_s。
到此,Wifi关闭的流程就结束了。
相关文章推荐
- Android -- Wifi热点的打开与关闭流程简介
- Android wifi源码分析(二) Wifi关闭流程
- Android: wifi打开和关闭的流程解析
- Android: wifi打开和关闭的流程解析
- android中wifi原理及流程分析
- Android中使用BroadcastReceiver打开和关闭WIFI
- android wifi断开原因分析
- Android -- Wifi连接流程分析
- Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程
- Android -- ConnectifyService网络更新流程简介
- Android WiFi 框架代码流程
- Android WIFI流程全分析
- Android wifi开发流程总结(1)
- Android 4.0 WIFI初始化与启动流程
- android WIFI 流程
- Android 设置Wifi热点、打开与关闭的监听
- android中wifi原理及流程分析(很经典)
- Android WIFI 架构和控制流程
- Android系统Recovery工作原理之使用update.zip升级过程---updater-script脚本语法简介以及执行流程
- android之wifi体系架构源码流程分析