Android14 WiFi 打开流程
目录
0.概览
1.App-->Framework状态机的流程
1.0 StateMachine基础知识
1.1 WifiEnabler
1.2 WifiManager
1.3 WifiServiceImpl
1.4 ActiveModeWarden
WifiController状态机
1.5 ConcreteClientModeManager
ClientModeStateMachine状态机
IdleState的处理
StartedState的处理
ConnectModeState
1.6 ClientModeImpl
2.WifiNative-->Hal流程
2.1 setupInterfaceForClientInScanMode 初始化interface
2.1.1 加载驱动和初始化vendor HAL接口
【流程概览】
【Java层的处理】
【Hal层的处理】
2.1.2 创建sta interface
【流程概览】
【Java层的处理】
【Hal层的处理】
2.1.3 wificond配置 interface
2.1.4 小结
2.2 switchClientInterfaceToConnectivityMode 启动supplicant
2.2.1 WifiNative
2.2.2 SupplicantStaIfaceHalAidlImpl.startDaemon()流程
【Java层流程】
【JNI层】
【Native层流程】
参考链接:
0.概览
本篇介绍Android14 WiFi 的 Enable流程。
我们可以在 Settings界面上进行 开/关 Wi-Fi 的操作,打开Wi-Fi涉及的流程比较多,这里先给出大概的流程有个整体的印象,后文会结合源码进行分析。
① WiFi Enable 过程中,Framework层涉及3个状态机:
② 抛开Framework层各种状态的切换,Enable WiFi的操作最终是由 WifiNative 的两个方法触发的:
1.setupInterfaceForClientInScanMode()启动扫描模式:加载驱动和vendor hal、wificond配置interface等;
2.switchClientInterfaceToConnectivityMode()切换到连接模式:启动supplicant服务。
1.App-->Framework状态机的流程
下面分析wifi打开过程中,从 App 到 Framework状态机的流程,下图给出了涉及的关键类:
1.0 StateMachine基础知识
Android状态机的主要工作是消息处理和状态切换。它通过定义一组状态和状态之间的切换,来控制相关行为。
StateMachine路径为:
frameworks/libs/modules-utils/java/com/android/internal/util/StateMachine.java
①State基本结构:
enter():在状态机转入这个状态时调用的方法;
exit():在状态机转出这个状态时调用的方法。
processMessage():用于处理当前状态的消息。如果当前状态处理不了,则将消息交给父状态处理。若根状态依然无法处理,则将事件抛弃并通知系统。
②StateMachine主要API:
addState():添加状态
setInitialState():设置初始状态
start():启动状态机
transitionTo():用于切换状态。在切换过程中,会自动调用旧状态的exit()方法和新状态的enter()方法。
deferMessage():将消息缓存,直到下一次状态切换完成后处理。
...
1.1 WifiEnabler
应用层通过 Context.getSystemService 来获取 WifiManager对象,并通过它调用wifi服务的接口:
//packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListener { ... private final WifiManager mWifiManager; WifiEnabler(Context context, SwitchWidgetController switchWidget, MetricsFeatureProvider metricsFeatureProvider, ConnectivityManager connectivityManager) { mContext = context; ... //1.获取 WifiManager 实例 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); ... } public boolean onSwitchToggled(boolean isChecked) { ... //2.调用 WifiManager的 setWifiEnabled 函数,实现开关wifi if (!mWifiManager.setWifiEnabled(isChecked)) { // Error ... } return true; }
1.2 WifiManager
WifiManager是暴露给应用的api接口类:
//packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java package android.net.wifi; ... @SystemService(Context.WIFI_SERVICE) public class WifiManager { ... IWifiManager mService; ... public boolean setWifiEnabled(boolean enabled) { try { //通过AIDL调用 WifiServiceImpl 的方法 return mService.setWifiEnabled(mContext.getOpPackageName(), enabled); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
1.3 WifiServiceImpl
//packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java /** * 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. */ @Override public synchronized boolean setWifiEnabled(String packageName, boolean enable) { ... setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged); return true; } private void setWifiEnabledInternal(String packageName, boolean enable, int callingUid, int callingPid, boolean isPrivileged) { //打印关键信息: mLog.info("setWifiEnabled package=% uid=% enable=% isPrivileged=%").c(packageName) .c(callingUid).c(enable).c(isPrivileged).flush(); ... //关注点:调用 ActiveModeWarden 的方法 mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName)); ... }
1.4 ActiveModeWarden
//packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java /** * This class provides the implementation for different WiFi operating modes. */ public class ActiveModeWarden { private static final String TAG = "WifiActiveModeWarden"; ... /** Wifi has been toggled. */ public void wifiToggled(WorkSource requestorWs) { //1.向 WifiController 状态机发送 CMD_WIFI_TOGGLED 消息: mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs); }
WifiController状态机
WifiController 是ActiveModeWarden的内部类,是一个状态机,来看下它的构造函数:
/** * WifiController is the class used to manage wifi state for various operating * modes (normal, airplane, wifi hotspot, etc.). */ private class WifiController extends StateMachine { ... // DefaultState // / \ // DisabledState(初始状态) EnabledState // 在 WifiController.start方法中,会设置初始状态为 DisabledState // wifi打开过程中的状态切换:DisabledState --> EnabledState WifiController() { super(TAG, mLooper); final int threshold = mContext.getResources().getInteger( R.integer.config_wifiConfigurationWifiRunnerThresholdInMs); DefaultState defaultState = new DefaultState(threshold); mEnabledState = new EnabledState(threshold); mDisabledState = new DisabledState(threshold); addState(defaultState); { addState(mDisabledState, defaultState); addState(mEnabledState, defaultState); } ... }
当前处于DisabledState状态, 来看下 CMD_WIFI_TOGGLED 消息的处理:
class DisabledState extends BaseState { ... @Override public boolean processMessageFiltered(Message msg) { switch (msg.what) { case CMD_WIFI_TOGGLED: case CMD_SCAN_ALWAYS_MODE_CHANGED: handleStaToggleChangeInDisabledState((WorkSource) msg.obj); break; ... default: return NOT_HANDLED; } return HANDLED; } ... } private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) { if (shouldEnableSta()) { //1.会触发启动wifi流程 startPrimaryOrScanOnlyClientModeManager(requestorWs); //2.状态切换到EnabledState transitionTo(mEnabledState); } } /** * Method to enable a new primary client mode manager. */ private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) { ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager(); if (role == ROLE_CLIENT_PRIMARY) {//走这个分支 return startPrimaryClientModeManager(requestorWs); } else if (role == ROLE_CLIENT_SCAN_ONLY) { return startScanOnlyClientModeManager(requestorWs); } else { return false; } } /** * Method to enable a new primary client mode manager in connect mode. */ private boolean startPrimaryClientModeManager(WorkSource requestorWs) { ... Log.d(TAG, "Starting primary ClientModeManager in connect mode"); //创建 ConcreteClientModeManager 对象(会去启动wifi) ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager( new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled); mClientModeManagers.add(manager); mLastPrimaryClientModeManagerRequestorWs = requestorWs; return true; } //packages/modules/Wifi/service/java/com/android/server/wifi/WifiInjector.java /** * Create a ClientModeManager * * @param listener listener for ClientModeManager state changes * @return a new instance of ClientModeManager */ public ConcreteClientModeManager makeClientModeManager( @NonNull ClientModeManager.Listener listener, @NonNull WorkSource requestorWs, @NonNull ActiveModeManager.ClientRole role, boolean verboseLoggingEnabled) { return new ConcreteClientModeManager( mContext, mWifiHandlerThread.getLooper(), mClock, mWifiNative, listener, mWifiMetrics, mWakeupController, this, mSelfRecovery, mWifiGlobals, mDefaultClientModeManager, mClock.getElapsedSinceBootMillis(), requestorWs, role, mBroadcastQueue, verboseLoggingEnabled); }
1.5 ConcreteClientModeManager
来看下ConcreteClientModeManager 的构造函数:
//packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java ConcreteClientModeManager( Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative, @NonNull Listener listener, WifiMetrics wifiMetrics, WakeupController wakeupController, WifiInjector wifiInjector, SelfRecovery selfRecovery, WifiGlobals wifiGlobals, DefaultClientModeManager defaultClientModeManager, long id, @NonNull WorkSource requestorWs, @NonNull ClientRole role, @NonNull ClientModeManagerBroadcastQueue broadcastQueue, boolean verboseLoggingEnabled) { ... //1.创建并启动 ClientModeStateMachine 状态机 mStateMachine = new ClientModeStateMachine(looper); ... //2.向状态机发送CMD_START的消息 mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo); }
ClientModeStateMachine状态机
ClientModeStateMachine 是 ConcreteClientModeManager的内部类,来看下它的构造函数:
//packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java // IdleState(初始状态) // | // StartedState // / \ // ScanOnlyModeState ConnectModeState //Wifi打开过程中的状态切换:IdleState-->StartedState-->ConnectModeState ClientModeStateMachine(Looper looper) { super(TAG, looper); final int threshold = mContext.getResources().getInteger( R.integer.config_wifiConfigurationWifiRunnerThresholdInMs); mIdleState = new IdleState(threshold); mStartedState = new StartedState(threshold); mScanOnlyModeState = new ScanOnlyModeState(threshold); mConnectModeState = new ConnectModeState(threshold); addState(mIdleState); addState(mStartedState, mIdleState); addState(mScanOnlyModeState, mStartedState); addState(mConnectModeState, mStartedState); //设置初始状态 setInitialState(mIdleState); start(); }
IdleState的处理
当前处于 IdleState 状态, 来看下 CMD_START 消息的处理:
//packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java private class IdleState extends RunnerState { ... @Override public boolean processMessageImpl(Message message) { if (mVerboseLoggingEnabled) { Log.d(getTag(), getName() + " cmd = " + getWhatToString(message.what) + " " + message.toString()); } switch (message.what) { case CMD_START: // Always start in scan mode first. RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; //1.调用WifiNative方法去创建wlan接口(会加载驱动和vendor hal) mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode( mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs, ConcreteClientModeManager.this); ... mWifiNative.setWifiNativeInterfaceEventCallback( mWifiNativeInterfaceEventCallback); if (roleChangeInfo.role instanceof ClientConnectivityRole) {//进入这个分支 //2.发送 CMD_SWITCH_TO_CONNECT_MODE,会触发supplicant的启动 sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo); // 切换到 StartedState 状态 transitionTo(mStartedState); } else { mScanRoleChangeInfoToSetOnTransition = roleChangeInfo; transitionTo(mScanOnlyModeState); } break; ... } return HANDLED; }
从上面看出,IdleState 处理CMD_START消息过程中:
1.会调用 WifiNative.setupInterfaceForClientInScanMode()去创建 wlan 接口进入扫描模式,具体流程会放到下一节进行分析。
2.会切换到 StartedState 状态,来看下 CMD_SWITCH_TO_CONNECT_MODE 消息的处理:
StartedState的处理
//packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java private class StartedState extends RunnerState { ... @Override public boolean processMessageImpl(Message message) { if (mVerboseLoggingEnabled) { Log.d(getTag(), getName() + " cmd = " + getWhatToString(message.what) + " " + message.toString()); } switch (message.what) { ... case CMD_SWITCH_TO_CONNECT_MODE: { RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; updateConnectModeState(roleChangeInfo.role,