系列文章目录

【安卓Framework学习】Wifi框架学习之核心类
【安卓Framework学习】Wifi框架学习之wifi状态机
【安卓Framework学习】Wifi框架学习之连接与断开流程
【【安卓Framework学习】Wifi框架学习之扫描模式及扫描流程.
【安卓Framework学习】Wifi框架学习之热点评分机制.
【安卓Framework学习】安卓连接管理(ConnectivityService)之wifi连接及注册.


文章目录

  • 系列文章目录
  • 前言
  • 一、wifi开启流程
    • 1、wifi开启源码流程分析
    • 2、wifi开启流程图
  • 二、wifi关闭流程
    • 1、wifi关闭源码分析
    • 2、wifi关闭流程图
  • 总结

前言

上一篇记录了安卓wifi框架中的主要的核心类,后续学习内容主要从实际的操作动作或者业务流程出发,分析其在wifi框架中的主要流程。本次学习内容针对常见的开启和关闭wifi来梳理其中的流程。文中出现的代码大部分基于android11源码。


一、wifi开启流程

1、wifi开启源码流程分析

wifi的开启和关闭在应用层部分是一样的,都是通过拿到系统服务在应用层的管理类WifiManager对象,然后通过调用WifiManager中系统服务的Binder对象的相关方法实现功能。应用层较为简单,调用如下方法。

/*** Enable or disable Wi-Fi.* <p>* 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.* <b>Compatibility Note:</b> 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.* <p>* Deprecation Exemptions:* <ul>* <li>Device Owner (DO), Profile Owner (PO) and system apps.* </ul>*/@Deprecatedpublic 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 toggledreturn 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状态机,一开始初始化了三个状态,DefaultStateDisabledStateEnabledState,其中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状态处理方法中。

@Overridepublic 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);}

可以看到,在ClientModeManagerstart()方法中,又给一个状态机发送了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 enabledmSarManager.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);mWakeupController.start();
}

上面的setOperationalMode()方法是通知wifi状态机切换状态的,在安卓11里是ClientModeImpl类,在安卓9中是WifiStateMachinemModeListener.onStarted()方法是在实例化ClientModeManager对象时传入进来的监听器的回调方法。在进入到StartedStateenter()方法中(因为StartedStateScanOnlyModeState的父状态)。

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接口是否起来,如果未起来就发送接口被关闭的消息然后做后续处理。其实到这里ClientModeManagerCMD_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;
}

看注释可以大致了解到,这个方法是帮助ClientModeManagerScanOnlyModeState状态切换到ConnectModeState状态中的。由于在一开始就写入数据库中开启wifi,所以mSettingsStore.isWifiToggleEnabled()会返回true,那么会继续调用ClientModeManagersetRole()方法,这里注意传入的参数是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 conneupdateConnectModeState(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 systemreturn;}if (mRole != ROLE_CLIENT_PRIMARY) {// do not raise public broadcast unless this is the primary client mode managerreturn;}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 EnabledmSarManager.setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
}

这里可以看到,先将ClientModeImpl状态机切换了,然后继续调用了updateConnectModeState()对外发送了一个广播,表示当前的wifi状态处于WifiManager.WIFI_STATE_ENABLED状态,至此ClientModeManagerCMD_SWITCH_TO_CONNECT_MODE消息处理完成了,那么ActiveModeWarden.startClientModeManager()方法也执行完并返回true,再次回到ActiveModeWarden中状态机的DisabledState状态中的消息处理方法processMessageFiltered中(前面有,这里不放代码了),将状态机WifiController的状态切换到了EnabledState,而EnabledStateenter()方法没有再次对外发送消息或其他操作,所以WifiController状态机对消息CMD_WIFI_TOGGLED也处理完毕了。至此WifiServiceImpl.setWifiEnabled()方法执行完毕,wifi成功打开,并对外发送了两次开启状态的广播。

2、wifi开启流程图


二、wifi关闭流程

1、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这一句注意现在记住,后面会用到。由于之前是正常打开没有问题,所以接口是起来的mIfaceIsUptrue,会对外发送一个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.quitNowpublic 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.quitNowprivate 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 statemTransitionInProgress = 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 loopingdestState = mDestState;} else {// No change in mDestState so we're donebreak;}}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状态,所以ConnectModeStateStartedStateexit()方法都会被执行。

ConnectModeState
public void exit() {updateConnectModeState(WifiManager.WIFI_STATE_DISABLED,WifiManager.WIFI_STATE_DISABLING);// Inform sar manager that wifi is being disabledmSarManager.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 machinemRole = 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的流程结束。


2、wifi关闭流程图


总结

以上对wifi开启和关闭的java层Framework的源码学习分析,中间对WifiNative以及后面的方法没有分析,我认为这部分是到了HAL层,所以待学习和理清楚里面的逻辑后需要单独拧出来介绍。个人认为在学习Framework时,还是需要带着一定实际使用场景来分析源码,不然进入到源码后会无头绪的发散,导致后面不知道自己到底要看哪部分代码,得不偿失。文中有表述或分析不对之处望大佬们及时批评。

【安卓Framework学习】Wifi框架学习之开启与关闭流程相关推荐

  1. 【安卓Framework学习】Wifi框架学习之热点评分机制

    系列文章目录 [安卓Framework学习]Wifi框架学习之核心类 [安卓Framework学习]Wifi框架学习之wifi状态机 [安卓Framework学习]Wifi框架学习之连接与断开流程 [ ...

  2. 【安卓Framework学习】Wifi框架学习之核心类

    系列文章目录 [安卓Framework学习]Wifi框架学习之开启与关闭流程 [安卓Framework学习]Wifi框架学习之wifi状态机 [安卓Framework学习]Wifi框架学习之连接与断开 ...

  3. 【安卓Framework学习】Wifi框架学习之wifi状态机

    系列文章目录 [安卓Framework学习]Wifi框架学习之核心类. [安卓Framework学习]Wifi框架学习之开启与关闭流程. [安卓Framework学习]Wifi框架学习之连接与断开流程 ...

  4. 数据增强 transform_深度学习-Pytorch框架学习之数据处理篇

    前言 数据是深度学习的核心,大部分论文里都会提到data-driven这个词,也就是数据驱动的意思.基本的模型搭建完成后,如何处理数据,如何将数据送给网络,如何做数据增强等等,对于提高网络的性能都十分 ...

  5. 华为荣耀2s设置虚拟服务器教程,荣耀路由2S怎么开启和关闭wifi

    荣耀路由2S在设置成功后即可打开wifi供用户使用,而且还能关闭5G优选功能,同时开启2.4G和5G双频wifi.下面小编将具体开启和关闭wifi的操作步骤告诉大家,快来看看吧! 开启或关闭wifi方 ...

  6. 联邦学习开源框架简介

    0.FATE平台 该平台是微众银行开发的,是全球第一个联邦学习工业级开源框架.不管是对初级人门者,还是联邦学习产品级系统的开发人员,FATE都是一个非常合适的选择.相比于利用Python从零开发,FA ...

  7. 推荐44个最具潜力的顶极深度学习开源框架和平台!!!

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 来源:AI开发者@微信公众号 工欲善其事必先利其器,这也是大部分开发者在日常工作中 ...

  8. mybatis框架--学习笔记(下)

    上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021 8.高级映射: (1)一对一查询: ①使 ...

  9. mybatis框架--学习笔记(上)

    使用JDBC操作数据库的问题总结: (1)数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能. 设想:使用数据库连接池管理数据库连接. (2) ...

最新文章

  1. webkit内核 css,纯CSS改变webkit内核浏览器的滚动条样式
  2. rails笔记 cache系统
  3. 关于bootstrap的treeview不显示多选(复选框)的问题,以及联动选择的问题,外加多选后取值...
  4. mysql 的 外连查询
  5. if转java_java 使用if将String内字符转换 递归
  6. 约瑟夫问题java 递归_从约瑟夫问题的递归实现的问题说起
  7. mysql基准测试总结 一
  8. sql server 提取汉字/数字/字母的方法
  9. 安防巨头们集体造车 跳出安防已成常态
  10. WinApi学习笔记-内存管理
  11. dematel法分析系统中各要素的重要程度
  12. python数学实验与建模百度云_Python数学实验与建模
  13. 一个简体/繁体字在线转换工具源码
  14. PS快速处理证件照(给证件照拉直)
  15. Python 音频随机播放器脚本
  16. chmod命令用法(linux中chmod命令用法)
  17. 张小庆,在路上-开始(6)真心话还是大冒险
  18. 开启 Linux 版的 Window 子系统(WSL)
  19. 直接存储器存取(DMA)有哪3种工作方式?
  20. dhu复试基础——64 统计字母

热门文章

  1. 初创项目如何获得媒体的曝光
  2. Python爬虫(1)------爬取网站图片
  3. Spring boot+hutool 定时发送邮件
  4. 利用python和循环实现赶鸭子问题
  5. CreatorPrimer|从zIndex开始
  6. Codeforces Global Round 4-D. Prime Graph(伯特兰-切比雪夫定理)
  7. 第三次作业 --必应词典 测试评价
  8. python k线顶分型_K线战法之『顶底分型』高手懂的!
  9. 用程序自动登陆58同城网的时候遇到的一些参数处理
  10. 未来的区块链格局,开放联盟链占主流