WIFI学习笔记 - Framework (2)
前言
- 更多细节详见上一篇;
- 基于Android P源码学习;
- 代码片为了方便阅读段经过删、裁减,请以实际源码为准;
调用栈 - 关闭WIFI
与WIFI开启的调用入口一致,只是参数不同:
开启:
WifiManager.setWifiEnabled(true)
关闭:
WifiManager.setWifiEnabled(false)
因此从App调用到WifiServiceImpl这一部分链路是完全一致的;
从WifiController开始,两者执行逻辑分叉:
mWifiController.sendMessage(CMD_WIFI_TOGGLED)
同样,要确认这里的具体实现,就需要先确认现在工作的State:
通过上图以及代码确认,响应CMD_WIFI_TOGGLED
的State
只能是如下三种:
DeviceActiveState
(由父状态StaEnabledState
处理)StaEnabledState
StaDisabledState
由于是关闭WIFI,因此当前WIFI状态一定不是StaDisabledState
;
且DeviceActiveState
的processMessage
并未处理CMD_WIFI_TOGGLED
,因此WifiController
处理关闭WIFI流程时,响应CMD_WIFI_TOGGLED
的只能是StaEnabledState
中的processMessage
:
class StaEnabledState extends State {
...
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_WIFI_TOGGLED:
if (! mSettingsStore.isWifiToggleEnabled()) {
if (checkScanOnlyModeAvailable()) {
transitionTo(mStaDisabledWithScanState);
} else {
transitionTo(mStaDisabledState);
}
}
break;
...
}
return HANDLED;
}
与WifiController
初始状态时的判断逻辑一样,这里会视“WIFI始终扫描”选项是否开启来决定切换为StaDisabledWithScanState
还是StaDisabledState
这里同理,以StaDisabledState
为例继续;
不同于开启WIFI,关闭WIFI没有考虑到频繁开关导致的紊乱而添加doDeferDisable
这样的方法,个人理解有如下两个原因:
- 关闭后上层状态直接更新,底层关闭慢了也无所谓;
- 下次开启时会做延时判断,因此关闭时没必要做;
在执行到StaDisabledState
的enter()
方法时:
class StaDisabledState extends State {
@Override
public void enter() {
mWifiStateMachinePrime.disableWifi();
// Supplicant can't restart right away, so note the time we switched off
mDisabledTimestamp = SystemClock.elapsedRealtime();
mDeferredEnableSerialNumber++;
mHaveDeferredEnable = false;
mWifiStateMachine.clearANQPCache();
}
...
}
有两个关键调用:
-
mWifiStateMachinePrime.disableWifi();
-
mWifiStateMachine.clearANQPCache();
后者在Android P上是空实现,因此暂不讨论:
public void clearANQPCache() {
// TODO(b/31065385)
// mWifiConfigManager.trimANQPCache(true);
}
回到前者,其实现是发送消息给ModeStateMachine:
public void disableWifi() {
changeMode(ModeStateMachine.CMD_DISABLE_WIFI);
}
这里再回顾下ModeStateMachine的三种平级状态:
ClientModeActiveState
ScanOnlyModeActiveState
(暂不讨论)WifiDisabledState
需要关闭WIFI的状态只会是ScanOnlyModeActiveState
或WifiDisabledState
,而这两个状态的processMessage()
方法均是通过checkForAndHandleModeChange
进行处理的:
private boolean checkForAndHandleModeChange(Message message) {
switch(message.what) {
...
case ModeStateMachine.CMD_DISABLE_WIFI:
mModeStateMachine.transitionTo(mWifiDisabledState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
可见,ModeStateMachine
会在处理消息时将状态切至WifiDisabledState
,首先查看ScanOnlyModeActiveState
与WifiDisabledState
的exit()
方法:
public void exit() {
super.exit();
mListener = null;
}
由于两者均继承自ModeActiveState
(实际上WifiDisabledState
也是继承的ModeActiveState
,但其exit()
被重写为空实现了),因此需要查看父类的exit()
方法实现:
public void exit() {
if (mManager != null) {
mManager.stop();
mActiveModeManagers.remove(mManager);
}
updateBatteryStatsWifiState(false);
}
此处会调用当前生效的接口ActiveModeManager
的实现类的stop()
方法,并将其从mActiveModeManagers
移除
(这与开启WIFI是创建ClientModeManager
,并将其添加到mActiveModeManagers
相对应);
此处ActiveModeManager
的子类实现只有两种可能:
ClientModeManager
public void stop() {
mExpectedStop = true;
if (mClientInterfaceName != null) {
if (mIfaceIsUp) {
updateWifiState(WifiManager.WIFI_STATE_DISABLING,
WifiManager.WIFI_STATE_ENABLED);
} else {
updateWifiState(WifiManager.WIFI_STATE_DISABLING,
WifiManager.WIFI_STATE_ENABLING);
}
}
mStateMachine.quitNow();
}
ScanOnlyModeManager
public void stop() {
Log.d(TAG, " currentstate: " + getCurrentStateName());
mExpectedStop = true;
mStateMachine.quitNow();
}
可见,无论是ClientModeManager
,还是ScanOnlyModeManager
,其stop()
方法中始终调用了mStateMachine.quitNow()
来停止其内部的状态机;
而当StateMachine的子类调用quitNow()
时,会将内部状态切换至一个内部维护的QuittingState
,此时必然会调用到当前状态的exit()
方法;这里为了方便理解,仅列举ClientModeManager
的情况,不讨论ScanOnlyModeManager
;
ClientModeStateMachine.StartedState
public void exit() {
//通知WifiStateMachine切换到DefaultState
mWifiStateMachine.setOperationalMode(WifiStateMachine.DISABLED_MODE, null);
if (mClientInterfaceName != null) {
//关键代码,会调用到HAL移除对应iFace
mWifiNative.teardownInterface(mClientInterfaceName);
mClientInterfaceName = null;
mIfaceIsUp = false;
}
//更新状态,并发送广播
updateWifiState(WifiManager.WIFI_STATE_DISABLED,
WifiManager.WIFI_STATE_DISABLING);
mStateMachine.quitNow();
}
代码调用再次来到WifiNative
,这里依旧不进一步深入了,会在HAL部分深入分析;
最后附上一副总结性质的时序图,其中部分非关键调用已经略去,关键调用加粗显示,蓝色框选的部分是与开启WIFI不同的区域;