工作原因接触到Android 11 framework wifi相关逻辑,参考一些博主的文章之后,自己也整理了一些,记录下来希望对后面的学习有所帮助。
根据下面的时序图进行分析:
从settings APP开始,以下应该是一个按键切换的方法,调用FW api
/*** com.android.settings.wifi.WifiEnabler.onSwitchToggled ***/
public boolean onSwitchToggled(boolean isChecked) {
...
if (!mWifiManager.setWifiEnabled(isChecked)) {...}
...
}
正常打开WiFi是调用这个单参的函数,如果是指定打开哪个STA,就要调用双参的函数 setWifiEnabled(int staId, boolean enabled)
/*** android.net.wifi.WifiManager.setWifiEnabled ***/
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
setWifiEnabled 是 setWifiEnabled2 的一个封装
/*** com.android.server.wifi.WifiServiceImpl.setWifiEnabled2 ***/
public synchronized boolean setWifiEnabled2(String packageName, int staId,boolean enable) {
...
mActiveModeWarden.wifiToggled();
...
}
发送 CMD_WIFI_TOGGLED 消息,通知WiFi切换
/*** com.android.server.wifi.ActiveModeWarden.wifiToggled ***/
public void wifiToggled() {
mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED);
}
WifiController 是 ActiveModeWarden 中的一个状态机,用来管理WiFi的操作,包括热点、飞行模式等
WiFi没开启之前状态机应该是在 DisabledState 状态,因此在 DisabledState 状态中处理CMD_WIFI_TOGGLED消息
/*** com.android.server.wifi.ActiveModeWarden.WifiController.DisabledState.processMessageFiltered ***/
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
if (shouldEnableSta()) {
startClientModeManager();
transitionTo(mEnabledState);
}
break;
启动一个新的客户端管理
/*** com.android.server.wifi.ActiveModeWarden.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;
}
ClientModeManager 启用之后,发送了一个 CMD_START 的消息
/*** com.android.server.wifi.ClientModeManager.start ***/
public void start() {
Log.d(TAG, "Starting with role ROLE_CLIENT_SCAN_ONLY");
mRole = ROLE_CLIENT_SCAN_ONLY;
mTargetRole = ROLE_CLIENT_SCAN_ONLY;
mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
}
没开启之前应该是 IdleState ,于是处理这个 START 消息,状态机状态切换
/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.IdleState.processMessage ***/
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
// Always start in scan mode first.
mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode(mWifiNativeInterfaceCallback);
...
transitionTo(mScanOnlyModeState);
break;
...
}
}
调用到了WifiNative中的 setupInterfaceForClientInScanMode() 方法开启wifi模块分配一个Iface,在 setupInterfaceForClientInScanMode() 方法中开启了wifi芯片驱动、获得芯片信息、注册回调并开始监听Iface消息等。接下来会调用WifiNl80211Manager类的 setupInterfaceForClientMode() 方法。
setupInterfaceForClientMode() 方法主要为Station模式设置接口。到这里, ClientModeStateMachine 状态机在 IdleState 状态成功处理完了 CMD_START 消息。
/*** com.android.server.wifi.WifiNative.setupInterfaceForClientInScanMode ***/
public String setupInterfaceForClientInScanMode(@NonNull InterfaceCallback interfaceCallback) {
synchronized (mLock) {
if (!startHal()) {
...
}
...
if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
new NormalScanEventCallback(iface.name),
new PnoScanEventCallback(iface.name))) {
Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
return null;
}
...
}
}
在step6的时候调用了 startClientModeManager 函数,start以后会执行 switchClientModeManagerRole ,step6的时候状态机切换为 ScanOnlyModeState ,由于在一开始就写入数据库中开启wifi,所以 mSettingsStore.isWifiToggleEnabled() 会返回true,于是设置 ROLE_CLIENT_PRIMARY
/*** com.android.server.wifi.ActiveModeWarden.switchClientModeManagerRole ***/
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;
}
上一步 setRole 的参数为 ROLE_CLIENT_PRIMARY ,所以这里发送的是 CMD_SWITCH_TO_CONNECT_MODE 广播
/*** com.android.server.wifi.ClientModeManager.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);
}
}
StartedState 是 ScanOnlyModeState 的父状态, ScanOnlyModeState 中不作处理,于是到 StartedState 看一下 CMD_SWITCH_TO_CONNECT_MODE 的处理,这里先执行了 switchClientInterfaceToConnectivityMode ,随后将状态切换到 ConnectModeState
/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.StartedState.processMessage ***/
public boolean processMessage(Message message) {
switch(message.what) {
case CMD_SWITCH_TO_CONNECT_MODE:
mRole = message.arg1; // could be any one of possible connect mode roles.
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;
...
}
}
更新wifi的状态,并且对外发送广播,这不正是发送的wifi开启或关闭状态的广播么 WifiManager.WIFI_STATE_CHANGED_ACTION
/*** com.android.server.wifi.ClientModeManager.updateConnectModeState ***/
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);
}
Native之后:
调用hal层接口去启用请求接口
/*** com.android.server.wifi.WifiNative.switchClientInterfaceToConnectivityMode ***/
public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName) {
...
if (!startSupplicant) {...}
if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {...}
...
}
/*** com.android.server.wifi.WifiNative.startSupplicant ***/
public boolean startSupplicant() {
...
if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
if (!startAndWaitForSupplicantConnection()) {...}
if (!mSupplicantStaIfaceHal.registerDeathHandler(new SupplicantDeathHandlerInternal)) {...}
}
...
}
先用addIfaceV1_1或addIfaceV1_0方法来获得一个ISupplicantIface的Binder对象,然后将调用setupStaIface方法
/*** com.android.server.wifi.SupplicantStaIfaceHal.setupIface ***/
public boolean setupIface(@NonNull String ifaceName) {
...
ISupplicantIface ifaceHwBinder;
if (isV1_1()) {
ifaceHwBinder = addIfaceV1_1(ifaceName);
} else {
ifaceHwBinder = getIfaceV1_0(ifaceName);
}
...
ISupplicantStaIface iface = setupStaIface(ifaceName, ifaceHwBinder);
mISupplicantStaIfaces.put(ifaceName, iface);
...
SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
...
}
根据状态机的特点,消息处理完后会进入到新的状态,并且调用enter()方法。进入到ConnectModeState.enter()中
/*** com.android.server.wifi.ClientModeManager.ClientModeStateMachine.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消息处理完成了。
那么step6 ActiveModeWarden.startClientModeManager()方法也执行完并返回true。
再次回到ActiveModeWarden中状态机的DisabledState状态中的消息处理方法processMessageFiltered中(step5),将状态机WifiController的状态切换到了EnabledState,而EnabledState的enter()方法没有再次对外发送消息或其他操作,所以step5 WifiController状态机对消息CMD_WIFI_TOGGLED也处理完毕了。
至此step3 WifiServiceImpl.setWifiEnabled()方法执行完毕,wifi成功打开,并对外发送了两次开启状态的广播。
参考:
https://blog.csdn.net/qq_43804080/article/details/118763791
https://blog.csdn.net/qq_39036223/article/details/124164745