前面几步与wifi开启的一样,从后面不一致的开始分析,关闭的时序图如下:
从处理 CMD_WIFI_TOGGLED 消息(即开启step5)开始不一致。之前可以参考另一篇文章。
wifi开启之后WifiController状态机为 EnabledState 状态,因此在EnabledState中去处理 CMD_WIFI_TOGGLED 消息。
shouldEnableSta()返回false,消息处理会走入到else中,进入到stopAllClientModeManagers()方法中
/*** com.android.server.wifi.ActiveModeWarden.WifiController.EnabledState.processMessageFiltered ***/
...
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
if (shouldEnableSta()) {
if (hasAnyClientModeManager()) {
switchAllClientModeManagers();
} else {
startClientModeManager();
}
} else {
stopAllClientModeManagers();
}
break;
...
分析:首先会去判断数据库中是否写入开启wifi的值,这里我们是关闭,因此mSettingsStore.isWifiToggleEnabled()返回的false;那再来具体看 checkScanOnlyModeAvailable(),mSettingsStore.isScanAlwaysAvailable()返回的是是否需要一直能够扫描,这个值需要专门调用WifiManager.setScanAlwaysAvailable()将其设置为true,由于一开始一直没有调用设置,所以mSettingsStore.isScanAlwaysAvailable()返回false,因此shouldEnableSta()返回false,消息处理会走入到else中,进入到stopAllClientModeManagers()方法中。
/*** com.android.server.wifi.ActiveModeWarden.WifiController.shouldEnableSta ***/
private boolean shouldEnableSta() {
return mSettingsStore.isWifiToggleEnabled() || checkScanOnlyModeAvailable();
}
/*** com.android.server.wifi.ActiveModeWarden.checkScanOnlyModeAvailable ***/
private boolean checkScanOnlyModeAvailable() {
return mWifiPermissionsUtil.isLocationModeEnabled()
&& mSettingsStore.isScanAlwaysAvailable();
}
关闭了所有之前开启的ClientModeManager,进入到ClientModeManager.stop()中
/*** com.android.server.wifi.ActiveModeWarden.stopAllClientModeManagers ***/
private void stopAllClientModeManagers() {
Log.d(TAG, "Shutting down all client mode managers");
for (ActiveModeManager manager : mActiveModeManagers) {
if (!(manager instanceof ClientModeManager)) continue;
ClientModeManager clientModeManager = (ClientModeManager) manager;
clientModeManager.stop();
}
}
由于之前是正常打开,所以接口是起来的mIfaceIsUp为true,会对外发送一个wifi状态广播,由WIFI_STATE_ENABLED变换为WIFI_STATE_DISABLING。随后进入到DeferStopHandler.start()方法中
/*** com.android.server.wifi.ClientModeManager.stop ***/
@Override
public void stop() {
Log.d(TAG, " currentstate: " + getCurrentStateName());
mTargetRole = ROLE_UNSPECIFIED;
if (mIfaceIsUp) {
updateConnectModeState(WifiManager.WIFI_STATE_DISABLING,
WifiManager.WIFI_STATE_ENABLED);
} else {
updateConnectModeState(WifiManager.WIFI_STATE_DISABLING,
WifiManager.WIFI_STATE_ENABLING);
}
mDeferStopHandler.start(getWifiOffDeferringTimeMs());
}
###step4
这里传入的是一个延时,表示要延迟多久关闭wifi,假设不延时即delayMs==0(延不延时都会调到continueToStopWifi去停止wifi),则会继续进入continueToStopWifi()
/*** com.android.server.wifi.ClientModeManager.DeferStopHandler.start ***/
public void start(int delayMs) {
...
// Most cases don't need delay, check it first to avoid unnecessary work.
if (delayMs == 0) {
continueToStopWifi();
return;
}
...
}
step3中设置的mTargetRole值为ROLE_UNSPECIFIED,因此走到第一个分支中
WifiMetrics这个类主要用于记录wifi框架中的一些性能指标和打印一些日志,没有很实际的流程在内
所以只需关注mStateMachine.quitNow(),这个状态机对象就是 ClientModeStateMachine
/*** com.android.server.wifi.ClientModeManager.DeferStopHandler.continueToStopWifi ***/
private void continueToStopWifi() {
...
if (mTargetRole == ROLE_UNSPECIFIED) {
Log.d(TAG, "Continue to stop wifi");
mStateMachine.quitNow();
mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis);
} else if (mTargetRole == ROLE_CLIENT_SCAN_ONLY) {
...
} else {
...
}
...//注销一些回调操作
}
因为ClientModeStateMachine没有重写父类quitNow()方法,因此进入状态机父类StateMachine.quitNow()中
/*** com.android.internal.util.StateMachine.quitNow ***/
public final void quitNow() {
// mSmHandler can be null if the state machine is already stopped.
SmHandler smh = mSmHandler;
if (smh == null) return;
smh.quitNow();
}
向状态机内部的SmHandler发送了一个SM_QUIT_CMD消息
/*** com.android.internal.util.StateMachine.SmHandler.quitNow ***/
private final void quitNow() {
if (mDbg) mSm.log("quitNow:");
sendMessageAtFrontOfQueue(obtainMessage(SM_QUIT_CMD, mSmHandlerObj));
}
转入到SmHandler消息处理函数中,发送的是SM_QUIT_CMD消息,因此走入第一个分支,调用processMsg
/*** com.android.internal.util.StateMachine.SmHandler.handleMessage ***/
public final void handleMessage(Message msg) {
if (!mHasQuit) {
...
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
} ...
performTransitions(msgProcessedState, msg);
...
}
}
退出isQuit(msg)为true,切换状态机为QuittingState
/*** com.android.internal.util.StateMachine.SmHandler.processMsg ***/
private final State processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
...
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
...
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
再看step8中的performTransitions()
/*** com.android.internal.util.StateMachine.SmHandler.performTransitions ***/
private void performTransitions(State msgProcessedState, Message msg) {
...
invokeExitMethods(commonStateInfo);
...
cleanupAfterQuitting();
...
}
invokeExitMethods()方法会将切换状态前的所有状态都退出即都会执行exit()方法,之前是处于ConnectModeState状态,所以ConnectModeState和StartedState(其父类状态)的exit()方法都会被执行。
/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.ConnectModeState.exit ***/
public void exit() {
updateConnectModeState(WifiManager.WIFI_STATE_DISABLED,
WifiManager.WIFI_STATE_DISABLING);
// Inform sar manager that wifi is being disabled
mSarManager.setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
}
/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.StartedState.exit ***/
public void exit() {
mClientModeImpl.setOperationalMode(ClientModeImpl.DISABLED_MODE, null);
if (mClientInterfaceName != null) {
mWifiNative.teardownInterface(mClientInterfaceName);
mClientInterfaceName = null;
mIfaceIsUp = false;
}
// once we leave started, nothing else to do... stop the state machine
mRole = ROLE_UNSPECIFIED;
mStateMachine.quitNow();
mModeListener.onStopped();
}
可以看出ConnectModeState的退出方法中对外发送了广播wifi状态由WIFI_STATE_DISABLING变化到WIFI_STATE_DISABLED
然后继续进入StartedState的退出方法,首先是将wifi状态机切到DISABLED_MODE,然后因为mClientInterfaceName为之前打开的wifi的Iface,所以暂时还不为空,进入到WifiNative.teardownInterface()中将开启的Iface关闭,此时wifi其实已经关闭了
后面虽然再一次调用了StateMachine.quitNow(),但其实是在状态机处理消息的队列中再加一个退出消息,所以在前面一次退出执行完之后,这次退出其实是直接就不会执行了,具体可以自行分析StateMachine的源码。执行完invokeExitMethods(),后面会继续进入到step9#cleanupAfterQuitting()中。
/*** com.android.internal.util.StateMachine.SmHandler.cleanupAfterQuitting ***/
private final void cleanupAfterQuitting() {
if (mSm.mSmThread != null) {
// If we made the thread then quit looper which stops the thread.
getLooper().quit();
mSm.mSmThread = null;
}
mSm.mSmHandler = null;
mSm = null;
mMsg = null;
mLogRecords.cleanup();
mStateStack = null;
mTempStateStack = null;
mStateInfo.clear();
mInitialState = null;
mDestState = null;
mDeferredMessages.clear();
mHasQuit = true;
}
此方法就是将状态机内部的所有关键变量都置为空或者清干净。并且处理消息的Looper也会一并别关闭,后续不会再有任何方法执行了。至此,关闭wifi的流程结束。
参考:
https://blog.csdn.net/qq_39036223/article/details/124164745