【安卓Framework学习】Wifi框架学习之核心类
【安卓Framework学习】Wifi框架学习之wifi状态机
【安卓Framework学习】Wifi框架学习之连接与断开流程
【【安卓Framework学习】Wifi框架学习之扫描模式及扫描流程.
【安卓Framework学习】Wifi框架学习之热点评分机制.
【安卓Framework学习】安卓连接管理(ConnectivityService)之wifi连接及注册.
上一篇记录了安卓wifi框架中的主要的核心类,后续学习内容主要从实际的操作动作或者业务流程出发,分析其在wifi框架中的主要流程。本次学习内容针对常见的开启和关闭wifi来梳理其中的流程。文中出现的代码大部分基于android11源码。
wifi的开启和关闭在应用层部分是一样的,都是通过拿到系统服务在应用层的管理类WifiManager对象,然后通过调用WifiManager中系统服务的Binder对象的相关方法实现功能。应用层较为简单,调用如下方法。
/**
* Enable or disable Wi-Fi.
*
* Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
* permission to toggle wifi.
*
* @param enabled {@code true} to enable, {@code false} to disable.
* @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
* either already in the requested state, or in progress toward the requested state.
* @throws {@link java.lang.SecurityException} if the caller is missing required permissions.
*
* @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
* enable/disable Wi-Fi.
* Compatibility Note: For applications targeting
* {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
* {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
* or below), they can continue to use this API.
*
* Deprecation Exemptions:
*
* - Device Owner (DO), Profile Owner (PO) and system apps.
*
*/
@Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
由注释可以看出,通过传入一个boolean
型参数来设置wifi的开关。但是,注释中标明此方法在android11中已经被弃用,从安卓10开始,系统不支持应用开关wifi,安卓9及早一点的系统还能使用此api.
在方法中没有做别的,直接调用了Binder对象对应服务的同名方法。而对应的mService
为系统中的服务类WifiServiceImpl
继承于BaseWifiService
,其实现了IWifiManager
接口。再 来看WifiServiceImpl
实现类中同名方法的具体实现。
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
/*
*此处省略开启前的一些校验,具体都是什么校验目前还没完全研究清楚
*/
try {
if (!mSettingsStore.handleWifiToggled(enable)) {
// Nothing to do if wifi cannot be toggled
return true;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) {
mWifiMetrics.logUserActionEvent(enable ? UserActionEvent.EVENT_TOGGLE_WIFI_ON
: UserActionEvent.EVENT_TOGGLE_WIFI_OFF);
}
mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
mActiveModeWarden.wifiToggled();
return true;
}
方法中会先在系统设置数据库中写入wifi需要处于开启还是关闭的状态值,如果写入失败,则直接返回true
了。这里为了分析开启流程,姑且认为它能够正常写入数据库中,并且传入的enable
形参为true
表示开启。随后会调用到mActiveModeWarden.wifiToggled()
中。mActiveModeWarden
中有一个WifiController
状态机,wifiToggled()
方法如下,直接给状态机发送了一个CMD_WIFI_TOGGLED
消息。
/** Wifi has been toggled. */
public void wifiToggled() {
mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED);
}
再看WifiController
状态机,一开始初始化了三个状态,DefaultState
、DisabledState
、EnabledState
,其中DefaultState
为另外两个的父状态,这是在状态机构造函数中确定的。在初始化了状态机后会调用状态机的start()
方法,这个方法初始化了状态机初始所处的状态,如下。
public void start() {
/*
* 此处省略
*/
if (shouldEnableSta()) {
startClientModeManager();
setInitialState(mEnabledState);
} else {
setInitialState(mDisabledState);
}
/*
* 此处省略
*/
super.start();
}
可见一开始wifi处于关闭状态,那时候还没有写Settings的数据库,shouldEnableSta()
会返回false
,状态机的初始状态会进入DisabledState
,所以在开启wifi时,发送的CMD_WIFI_TOGGLED
消息会被DisabledState
所处理,再次转到DisabledState
状态处理方法中。
@Override
public boolean processMessageFiltered(Message msg) {
switch (msg.what) {
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
if (shouldEnableSta()) {
startClientModeManager();
transitionTo(mEnabledState);
}
break;
/*省略其他分支处理*/
default:
return NOT_HANDLED;
}
return HANDLED;
}
这里再一次调用了shouldEnableSta()
,由于刚刚状态机初始化是在应用开启wifi之前,所以这一次在调用WifiServiceImpl.setWifiEnabled()
时写了数据库,所以shouldEnableSta()
返回true
。随后进入处理CMD_WIFI_TOGGLED
消息的分支。分支中调用了两个方法transitionTo()
会将状态机的状态切换到EnabledState
,而startClientModeManager()
如下分析。
private boolean startClientModeManager() {
Log.d(TAG, "Starting ClientModeManager");
ClientListener listener = new ClientListener();
ClientModeManager manager = mWifiInjector.makeClientModeManager(listener);
listener.setActiveModeManager(manager);
manager.start();
if (!switchClientModeManagerRole(manager)) {
return false;
}
mActiveModeManagers.add(manager);
return true;
}
方法中通过WifiInjector
获得了一个ClientModeManager
对象,并且调用了其start()
方法,switchClientModeManagerRole(manager)
这个方法大家注意一下,跑完前面的start()
会继续进入这个方法。转入到ClientModeManager
中。
public void start() {
mTargetRole = ROLE_CLIENT_SCAN_ONLY;
mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
}
可以看到,在ClientModeManager
的start()
方法中,又给一个状态机发送了CMD_START
消息,这个状态机是ClientModeManager
内部定义的一个ClientModeStateMachine
状态机,其初始状态为IdleState
,也可以看到只有IdleState
状态对消息CMD_START
做了实质性的处理。转入到IdleState
状态的消息处理方法中。
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
// Always start in scan mode first.
mClientInterfaceName =
mWifiNative.setupInterfaceForClientInScanMode(
mWifiNativeInterfaceCallback);
if (TextUtils.isEmpty(mClientInterfaceName)) {
Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
mModeListener.onStartFailure();
break;
}
transitionTo(mScanOnlyModeState);
break;
default:
Log.d(TAG, "received an invalid message: " + message);
return NOT_HANDLED;
}
return HANDLED;
}
调用到了WifiNative
中的setupInterfaceForClientInScanMode()
方法开启wifi模块分配一个Iface,在setupInterfaceForClientInScanMode()
方法中开启了wifi芯片驱动、获得芯片信息、注册回调并开始监听Iface消息等,方法较为复杂这里暂不展开描述。然后判断返回的Iface
的名字是否为空,不为空说明开启成功,并且将状态切到ScanOnlyModeState
。根据状态机的实现,在处理完当前消息后会去切换到目的状态,这里状态机的内容较多不多赘述。在切换到ScanOnlyModeState
后,状态机会根据状态树向上索引,并执行每一个状态的enter()
方法,首先进入ScanOnlyModeState.enter()
.
public void enter() {
Log.d(TAG, "entering ScanOnlyModeState");
mClientModeImpl.setOperationalMode(ClientModeImpl.SCAN_ONLY_MODE,
mClientInterfaceName);
mRole = ROLE_CLIENT_SCAN_ONLY;
mModeListener.onStarted();
// Inform sar manager that scan only is being enabled
mSarManager.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
mWakeupController.start();
}
上面的setOperationalMode()
方法是通知wifi状态机切换状态的,在安卓11里是ClientModeImpl
类,在安卓9中是WifiStateMachine
。mModeListener.onStarted()
方法是在实例化ClientModeManager
对象时传入进来的监听器的回调方法。在进入到StartedState
的enter()
方法中(因为StartedState
为ScanOnlyModeState
的父状态)。
public void enter() {
Log.d(TAG, "entering StartedState");
mIfaceIsUp = false;
onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName));
}
这里调用了WifiNative.isInterfaceUp()
方法,判断当前获得到的Iface接口是否已经起来,由于之前是正常开启,那这里Iface肯定是起来的,所以返回true
,进入到onUpChanged()
方法中。
private void onUpChanged(boolean isUp) {
if (isUp == mIfaceIsUp) {
return; // no change
}
mIfaceIsUp = isUp;
if (!isUp) {
// if the interface goes down we should exit and go back to idle state.
Log.d(TAG, "interface down!");
mStateMachine.sendMessage(CMD_INTERFACE_DOWN);
}
}
其实这个回调就是判断所需要开启的Iface接口是否起来,如果未起来就发送接口被关闭的消息然后做后续处理。其实到这里ClientModeManager
对CMD_START
消息的处理就告一段落了,我们再返回到ActiveModeWarden
中去看前面遗留下来的switchClientModeManagerRole()
方法。
/**
* Method to switch a client mode manager mode of operation (from ScanOnly To Connect &
* vice-versa) based on the toggle state.
*/
private boolean switchClientModeManagerRole(@NonNull ClientModeManager modeManager) {
if (mSettingsStore.isWifiToggleEnabled()) {
modeManager.setRole(ActiveModeManager.ROLE_CLIENT_PRIMARY);
} else if (checkScanOnlyModeAvailable()) {
modeManager.setRole(ActiveModeManager.ROLE_CLIENT_SCAN_ONLY);
} else {
Log.e(TAG, "Something is wrong, no client mode toggles enabled");
return false;
}
return true;
}
看注释可以大致了解到,这个方法是帮助ClientModeManager
由ScanOnlyModeState
状态切换到ConnectModeState
状态中的。由于在一开始就写入数据库中开启wifi,所以mSettingsStore.isWifiToggleEnabled()
会返回true
,那么会继续调用ClientModeManager
的setRole()
方法,这里注意传入的参数是ActiveModeManager.ROLE_CLIENT_PRIMARY
。进入到setRole()
方法中。
public void setRole(@Role int role) {
Preconditions.checkState(CLIENT_ROLES.contains(role));
if (role == ROLE_CLIENT_SCAN_ONLY) {
mTargetRole = role;
// Switch client mode manager to scan only mode.
mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE);
} else if (CLIENT_CONNECTIVITY_ROLES.contains(role)) {
mTargetRole = role;
// Switch client mode manager to connect mode.
mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, role);
}
}
第一句Preconditions.checkState(CLIENT_ROLES.contains(role))
不用理会,就是检测CLIENT_ROLES
是否包含此角色,不包含就抛异常。但是后面发现并没有ActiveModeManager.ROLE_CLIENT_PRIMARY
条件出现,这里再次进入CLIENT_CONNECTIVITY_ROLES
,看看这个List
中有什么,其在ActiveModeManager
这个接口中,如下。
/** List of Client roles that could initiate a wifi connection */
List<Integer> CLIENT_CONNECTIVITY_ROLES = Arrays.asList(
ROLE_CLIENT_PRIMARY,
ROLE_CLIENT_SECONDARY,
ROLE_CLIENT_LOCAL_ONLY);
可以看到里面包含了ActiveModeManager.ROLE_CLIENT_PRIMARY
,所以上面setRole()
方法中走入第二个分支,给ClientModeStateMachine
状态机发送了一个切换状态的消息ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE
,由于之前在开启wifi的时候已经切换到了ScanOnlyModeState
状态,所以再次进入到ScanOnlyModeState
的处理方法中。
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_SWITCH_TO_SCAN_ONLY_MODE:
// Already in scan only mode, ignore this command.
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
由于其并没有处理此消息,所以会交给父状态处理,进入StartedState
的处理方法中。
public boolean processMessage(Message message) {
switch(message.what) {
case CMD_START:
// Already started, ignore this command.
break;
case CMD_SWITCH_TO_CONNECT_MODE:
mRole = message.arg1; // could be any one of possible conne
updateConnectModeState(WifiManager.WIFI_STATE_ENABLING,
WifiManager.WIFI_STATE_DISABLED);
if (!mWifiNative.switchClientInterfaceToConnectivityMode(
mClientInterfaceName)) {
updateConnectModeState(WifiManager.WIFI_STATE_UNKNOWN,
WifiManager.WIFI_STATE_ENABLING);
updateConnectModeState(WifiManager.WIFI_STATE_DISABLED,
WifiManager.WIFI_STATE_UNKNOWN);
mModeListener.onStartFailure();
break;
}
transitionTo(mConnectModeState);
break;
/*此处省略其他分支,详细的可以自行去看源码*/
default:
return NOT_HANDLED;
}
return HANDLED;
}
可以看到,调用了updateConnectModeState()
方法,并且传入了两个wifi的开启状态,进入此方法中。
/**
* Update Wifi state and send the broadcast.
* @param newState new Wifi state
* @param currentState current wifi state
*/
private void updateConnectModeState(int newState, int currentState) {
if (newState == WifiManager.WIFI_STATE_UNKNOWN) {
// do not need to broadcast failure to system
return;
}
if (mRole != ROLE_CLIENT_PRIMARY) {
// do not raise public broadcast unless this is the primary client mode manager
return;
}
mClientModeImpl.setWifiStateForApiCalls(newState);
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
这个方法就比较明确了,注释也说的非常清楚,更新wifi的状态,并且非对外发送广播,这不正是发送的wifi开启或关闭状态的广播么WifiManager.WIFI_STATE_CHANGED_ACTION
。然后继续看消息处理方法,会调用WifiNative.switchClientInterfaceToConnectivityMode()
,这里其实是让下面C层Framework和硬件切换到一个能够连接的状态中,此方法和前面的WifiNative
方法一样较为繁琐,这里不赘述。随后将状态切换到ConnectModeState
,根据状态机的特点,消息处理完后会进入到新的状态,并且调用enter()
方法。进入到ConnectModeState.enter()
中。
public void enter() {
Log.d(TAG, "entering ConnectModeState");
mClientModeImpl.setOperationalMode(ClientModeImpl.CONNECT_MODE,
mClientInterfaceName);
mModeListener.onStarted();
updateConnectModeState(WifiManager.WIFI_STATE_ENABLED,
WifiManager.WIFI_STATE_ENABLING);
// Inform sar manager that wifi is Enabled
mSarManager.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
}
这里可以看到,先将ClientModeImpl
状态机切换了,然后继续调用了updateConnectModeState()
对外发送了一个广播,表示当前的wifi状态处于WifiManager.WIFI_STATE_ENABLED
状态,至此ClientModeManager
对CMD_SWITCH_TO_CONNECT_MODE
消息处理完成了,那么ActiveModeWarden.startClientModeManager()
方法也执行完并返回true
,再次回到ActiveModeWarden
中状态机的DisabledState
状态中的消息处理方法processMessageFiltered
中(前面有,这里不放代码了),将状态机WifiController
的状态切换到了EnabledState
,而EnabledState
的enter()
方法没有再次对外发送消息或其他操作,所以WifiController
状态机对消息CMD_WIFI_TOGGLED
也处理完毕了。至此WifiServiceImpl.setWifiEnabled()
方法执行完毕,wifi成功打开,并对外发送了两次开启状态的广播。
由上一部分开启wifi流程可知,在完成开启wifi后,ActiveModeWarden
中的状态机WifiController
会切换到EnabledState
,与开启wifi重复的部分省略,直接进入到EnabledState
状态处理函数中,如下。
public boolean processMessageFiltered(Message msg) {
switch (msg.what) {
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
if (shouldEnableSta()) {
if (hasAnyClientModeManager()) {
switchAllClientModeManagers();
} else {
startClientModeManager();
}
} else {
stopAllClientModeManagers();
}
break;
/*省略其他消息处理分支*/
default:
return NOT_HANDLED;
}
return HANDLED;
}
这里需要分析一下shouldEnableSta()
这个方法了。
private boolean shouldEnableSta() {
return mSettingsStore.isWifiToggleEnabled() || checkScanOnlyModeAvailable();
}
...
private boolean checkScanOnlyModeAvailable() {
return mWifiPermissionsUtil.isLocationModeEnabled()
&& mSettingsStore.isScanAlwaysAvailable();
}
首先会去判断数据库中是否写入开启wifi的值,这里我们是关闭,说明mSettingsStore.isWifiToggleEnabled()
返回的false
,那再来具体看checkScanOnlyModeAvailable()
,mSettingsStore.isScanAlwaysAvailable()
返回的是是否需要一直能够扫描,这个值需要专门调用WifiManager.setScanAlwaysAvailable()
将其设置为true
,由于一开始一直没有调用设置,所以mSettingsStore.isScanAlwaysAvailable()
返回false
,因此shouldEnableSta()
返回false
,消息处理会走入到else
中,进入到stopAllClientModeManagers()
方法中。
/**
* Method to stop all client mode mangers.
*/
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();
}
}
这里可以看到,关闭了所有之前开启的ClientModeManager
,这里为什么会有多个,我猜测是一个应用会有一个ClientModeManager
对象。进入到ClientModeManager.stop()
中。
/**
* Disconnect from any currently connected networks and stop client mode.
*/
@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());
}
mTargetRole = ROLE_UNSPECIFIED
这一句注意现在记住,后面会用到。由于之前是正常打开没有问题,所以接口是起来的mIfaceIsUp
为true
,会对外发送一个wifi状态广播,由WIFI_STATE_ENABLED
变换为WIFI_STATE_DISABLING
。随后进入到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;
}
/*省略其他代码*/
}
这里传入的是一个延时,表示要延迟多久关闭wifi,这里我们姑且认为不延时delayMs==0
,则会继续进入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) {
if (!mWifiNative.switchClientInterfaceToScanMode(mClientInterfaceName)) {
mModeListener.onStartFailure();
} else {
mStateMachine.sendMessage(
ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE);
mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis);
}
} else {
updateConnectModeState(WifiManager.WIFI_STATE_ENABLED,
WifiManager.WIFI_STATE_DISABLING);
}
/*注销一些回调*/
}
由于前面在stop()
方法中mTargetRole = ROLE_UNSPECIFIED
,所以会进入第一个分支WifiMetrics
这个类主要用于记录wifi框架中的一些性能指标和打印一些日志,所以没有很实际的流程在内,所以只需关注mStateMachine.quitNow()
,这个状态机对象就是ClientModeStateMachine
了,进入了退出的流程。进入状态机父类StateMachine.quitNow()
中。
/**
* Quit the state machine immediately all currently queued messages will be discarded.
*/
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();
}
/** @see StateMachine#quitNow() */
SmHandler.quitNow
private final void quitNow() {
if (mDbg) mSm.log("quitNow:");
sendMessageAtFrontOfQueue(obtainMessage(SM_QUIT_CMD, mSmHandlerObj));
}
可以看到,实际是向状态机内部的SmHandler
发送了一个SM_QUIT_CMD
消息,转入到SmHandler
消息处理函数中。
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);
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
mIsConstructionCompleted = true;
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: "
+ "The start method not called, received msg: " + msg);
}
performTransitions(msgProcessedState, msg);
/** 省略一些不重要代码 */
}
}
那么会继续走入第一个分支中,进入到processMsg()
.
/**
* Process the message. If the current state doesn't handle
* it, call the states parent and so on. If it is never handled then
* call the state machines unhandledMessage method.
* @return the state that processed the message
*/
private final State processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
/*省略日志打印*/
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
while (!curStateInfo.state.processMessage(msg)) {
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
break;
}
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
由于是退出消息,所以isQuit(msg)
直接返回的true
,因此接下来直接切换到退出的状态了QuittingState
,再看performTransitions()
方法。
private void performTransitions(State msgProcessedState, Message msg) {
/*省略一些代码*/
State destState = mDestState;
if (destState != null) {
/**
* Process the transitions including transitions in the enter/exit methods
*/
while (true) {
if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
/**
* Determine the states to exit and enter and return the
* common ancestor state of the enter/exit states. Then
* invoke the exit methods then the enter methods.
*/
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
invokeExitMethods(commonStateInfo);
int stateStackEnteringIndex = moveTempStateStackToStateStack();
invokeEnterMethods(stateStackEnteringIndex);
/**
* Since we have transitioned to a new state we need to have
* any deferred messages moved to the front of the message queue
* so they will be processed before any other messages in the
* message queue.
*/
moveDeferredMessageAtFrontOfQueue();
if (destState != mDestState) {
// A new mDestState so continue looping
destState = mDestState;
} else {
// No change in mDestState so we're done
break;
}
}
mDestState = null;
}
/**
* After processing all transitions check and
* see if the last transition was to quit or halt.
*/
if (destState != null) {
if (destState == mQuittingState) {
/**
* Call onQuitting to let subclasses cleanup.
*/
mSm.onQuitting();
cleanupAfterQuitting();
} else if (destState == mHaltingState) {
/**
* Call onHalting() if we've transitioned to the halting
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
mSm.onHalting();
}
}
}
invokeExitMethods()
方法会将切换状态前的所有状态都退出即都会执行exit()
方法,之前是处于ConnectModeState
状态,所以ConnectModeState
和StartedState
的exit()
方法都会被执行。
ConnectModeState
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);
}
StartedState
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()
,后面会继续进入到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的流程结束。
以上对wifi开启和关闭的java层Framework的源码学习分析,中间对WifiNative
以及后面的方法没有分析,我认为这部分是到了HAL层,所以待学习和理清楚里面的逻辑后需要单独拧出来介绍。个人认为在学习Framework时,还是需要带着一定实际使用场景来分析源码,不然进入到源码后会无头绪的发散,导致后面不知道自己到底要看哪部分代码,得不偿失。文中有表述或分析不对之处望大佬们及时批评。