Android Q WiFi 启动流程分析
- 1、WiFi 启动流程简介
- 2、WiFi 启动流程应用层分析
- 3、WiFi 启动流程服务层分析
- 3.1 WifiController 分析
- 3.2 WifiController 启动
1、WiFi 启动流程简介
用户可以通过systemUi和设置里的WiFi开关打开WiFi,这时候会调用到WiFi framework的相关接口,继而再继续往下启用具体的硬件完成WiFi启动流程
2、WiFi 启动流程应用层分析
在Android Setting 中,使用WifiEnabler 来控制WiFi 的开关操作,WifiEnabler 实现了OnSwitchChangeListener接口,当用户点击WiFi的开关按钮,就会回调到WifiEnabler onSwitchToggled 方法;在onSwitchToggled 方法调用WifiManager 的setWifiEnabled 方法来实现WiFi 的开关。
@Override
public boolean onSwitchToggled(boolean isChecked) {
//Do nothing if called as a result of a state machine event
if (mStateMachineEvent) {
return true;
}
// Show toast message if Wi-Fi is not allowed in airplane mode
if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off. No infinite check/listener loop.
mSwitchWidget.setChecked(false);
return false;
}
if (isChecked) {
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_ON);
} else {
// Log if user was connected at the time of switching off.
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_OFF,
mConnected.get());
}
if (!mWifiManager.setWifiEnabled(isChecked)) {
// Error
mSwitchWidget.setEnabled(true);
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
return true;
}
2.1 、WifiManager 是WiFi 子系统的管理类,WiFi 子系统绝大部分功能都是通过WifiManager 来实现的,WifiManager 是Wifiserver 的代理类,通过AIDL 来调用Wifiserver 相应的函数。setWifiEnabled 函数实现如下:setWifiEnabled 调用mService setWifiEnabled 方法,mService 是IWifiManager 的实现,是Android wifiserver 的代理类,最终是调到WifiServiceImpl 的setWifiEnabled 方法
@Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
3、WiFi 启动流程服务层分析
WifiManager 的setWifiEnabled 最终调用到了WifiServiceImpl setWifiEnabled 方法,WifiServiceImpl setWifiEnabled 实现如下,参数STA_PRIMARY 表示打开的是主WiFi。如果第二个参数是STA_SECONDARY 则表示打开的是第二个WiFi。目前高通实现了WiFi 双STA 的功能,通过该参数来区别打开的哪一个WiFi。
@Override
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
return setWifiEnabled2(packageName, STA_PRIMARY, enable);
}
WifiServiceImpl setWifiEnabled 调用setWifiEnabled2 方法,setWifiEnabled2 方法实现如下;首先判断应用是有权限打开WiFi ,在Android Q 中,需要有网络设置方面的权限才能打开WiFi ,setWifiEnabled 已经不是SDK 接口,不对第三方开放。只分析主WiFi的启动流程,辅助WiFi 暂时不分析,setWifiEnabled2 通过mWifiController 给自己发送CMD_WIFI_TOGGLED 消息。
public synchronized boolean setWifiEnabled2(String packageName, int staId, boolean enable) {
if (enforceChangePermission(packageName) != MODE_ALLOWED) {
return false;
}
boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid())
&& !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q,
Binder.getCallingUid())
&& !isSystem(packageName, Binder.getCallingUid())) {
mLog.info("setWifiEnabled not allowed for uid=%")
.c(Binder.getCallingUid()).flush();
return false;
}
// If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
return false;
}
// If SoftAp is enabled, only privileged apps are allowed to toggle wifi
boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;
if (apEnabled && !isPrivileged) {
mLog.err("setWifiEnabled SoftAp enabled: only Settings can toggle wifi").flush();
return false;
}
// If we're in crypt debounce, ignore any wifi state change APIs.
if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) {
return false;
}
mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
.c(Binder.getCallingUid()).c(enable).flush();
long ident = Binder.clearCallingIdentity();
try {
if (staId == STA_PRIMARY && !mSettingsStore.handleWifiToggled(enable)) {
// Nothing to do if wifi cannot be toggled
return true;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
if (!mIsControllerStarted) {
Slog.e(TAG,"WifiController is not yet started, abort setWifiEnabled");
return false;
}
mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
if (staId == STA_PRIMARY) {
mWifiController.sendMessage(CMD_WIFI_TOGGLED);
} else if ((getNumConcurrentStaSupported() > 1)
&& (getWifiEnabledState() == WifiManager.WIFI_STATE_ENABLED)
&& staId > STA_PRIMARY) {
mWifiController.sendMessage(CMD_ADD_WIFI_SET, staId, enable ? 1 : 0);
} else {
Slog.e(TAG,"setWifiEnabled not allowed for id:"+staId);
return false;
}
return true;
}
3.1 WifiController 分析
WifiController 是管理WiFi 开关状态的class,WifiController 是一个状态机,一共有六个状态,其中
DefaultState状态是另外五个状态的父状态。
3.2 WifiController 启动
WifiController 是在WifiServiceImpl 中被启动的,在WifiServiceImpl checkAndStartWifi 方法的中调用了WifiController start 的方法
Log.d(TAG, "qcdbg= mWifiStateMachine.syncInitialize()");
if (!mClientModeImpl.syncInitialize(mClientModeImplChannel)) {
Log.wtf(TAG, "Failed to initialize ClientModeImpl");
}
mWifiController.start();
mIsControllerStarted = true;
// If we are already disabled (could be due to airplane mode), avoid changing persist
// state here
if (wifiEnabled) {
setWifiEnabled(mContext.getPackageName(), wifiEnabled);
}
WifiController start 方法实现如下,首先设置初始状态,如果是scanonly模式,设置初始状态为StaDisabledWithScanState,否则设置状态为StaDisabledState;注册一个广播接收器,监听WiFi SoftAP 和STA 状态改变的广播。
public void start() {
boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
boolean isLocationModeActive = mWifiPermissionsUtil.isLocationModeEnabled();
log("isAirplaneModeOn = " + isAirplaneModeOn
+ ", isWifiEnabled = " + isWifiEnabled
+ ", isScanningAvailable = " + isScanningAlwaysAvailable
+ ", isLocationModeActive = " + isLocationModeActive);
if (checkScanOnlyModeAvailable()) {
setInitialState(mStaDisabledWithScanState);
} else {
setInitialState(mStaDisabledState);
}
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE,
WifiManager.WIFI_AP_STATE_FAILED);
if (state == WifiManager.WIFI_AP_STATE_FAILED) {
Log.e(TAG, "SoftAP start failed");
sendMessage(CMD_AP_START_FAILURE);
} else if (state == WifiManager.WIFI_AP_STATE_DISABLED) {
sendMessage(CMD_AP_STOPPED);
}
} else if (action.equals(LocationManager.MODE_CHANGED_ACTION) && mWifiControllerReady) {
// Location mode has been toggled... trigger with the scan change
// update to make sure we are in the correct mode
sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
}
}
},
new IntentFilter(filter));
super.start();
}
我们打开WiFi的时候,并非sanonly 模式,所以WifiController 初始化状态为StaDisabledState ;在StaDisabledState 状态机中处理了CMD_WIFI_TOGGLED 消息,CMD_WIFI_TOGGLED 主要是切换WifiController 的状态,让WifiController 进入StaEnabledState 状态
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_WIFI_TOGGLED:
if (mSettingsStore.isWifiToggleEnabled()) {
if (doDeferEnable(msg)) {
if (mHaveDeferredEnable) {
// have 2 toggles now, inc serial number and ignore both
mDeferredEnableSerialNumber++;
}
mHaveDeferredEnable = !mHaveDeferredEnable;
break;
}
transitionTo(mStaEnabledState);
} else if (checkScanOnlyModeAvailable()) {
// only go to scan mode if we aren't in airplane mode
if (mSettingsStore.isAirplaneModeOn()) {
transitionTo(mStaDisabledWithScanState);
}
}
break;
进入StaEnabledState 状态首先调用的是StaEnabledState 状态机的 enter 方法,enter 调用mActiveModeWarden 对象enterClientMode 方法
public void enter() {
log("StaEnabledState.enter()");
mActiveModeWarden.enterClientMode();
}
enterClientMode 实现如下
public void enterClientMode() {
changeMode(ModeStateMachine.CMD_START_CLIENT_MODE);
}
changeMode 实现,
private void changeMode(int newMode) {
mModeStateMachine.sendMessage(newMode);
}
ModeStateMachine 也是一个状态机,有三个状态 ClientModeActiveState、ScanOnlyModeActiveState、WifiDisabledState;这三个状态相互独立,没有父子关系,初始状态被设置为 WifiDisabledState
ModeStateMachine() {
super(TAG, mLooper);
addState(mClientModeActiveState);
addState(mScanOnlyModeActiveState);
addState(mWifiDisabledState);
Log.d(TAG, "Starting Wifi in WifiDisabledState");
setInitialState(mWifiDisabledState);
start();
}
WifiDisabledState 状态机对消息处理方法如下
public boolean processMessage(Message message) {
Log.d(TAG, "received a message in WifiDisabledState: " + message);
if (checkForAndHandleModeChange(message)) {
return HANDLED;
}
return NOT_HANDLED;
}
最终是调用checkForAndHandleModeChange 对消息进行处理,从上面可知,我们发给WifiDisabledState 状态的消息为CMD_START_CLIENT_MODE ,对CMD_START_CLIENT_MODE 的处理是 ModeStateMachine 状态机切换到 ClientModeActiveState 状态
private boolean checkForAndHandleModeChange(Message message) {
switch(message.what) {
case ModeStateMachine.CMD_START_CLIENT_MODE:
Log.d(TAG, "Switching from " + getCurrentMode() + " to ClientMode");
if (getCurrentMode().equals(mClientModeActiveState.getName()))
return NOT_HANDLED;
mModeStateMachine.transitionTo(mClientModeActiveState);
break;
case ModeStateMachine.CMD_START_SCAN_ONLY_MODE:
Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode");
if (getCurrentMode().equals(mScanOnlyModeActiveState.getName()))
return NOT_HANDLED;
mModeStateMachine.transitionTo(mScanOnlyModeActiveState);
break;
case ModeStateMachine.CMD_DISABLE_WIFI:
Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled");
if (getCurrentMode().equals(mWifiDisabledState.getName()))
return NOT_HANDLED;
mModeStateMachine.transitionTo(mWifiDisabledState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
ModeStateMachine 状态机切换到ClientModeActiveState 状态,首先执行ClientModeActiveState 状态的enter 方法,首先构造一个Manager 是ActiveModeManager 的对象,ActiveModeManager 是一个接口,对于STA模式它的实现类是ClientModeManager
@Override
public void enter() {
Log.d(TAG, "Entering ClientModeActiveState");
mListener = new ClientListener();
mManager = mWifiInjector.makeClientModeManager(mListener);
mManager.start();
mActiveModeManagers.add(mManager);
updateBatteryStatsWifiState(true);
}
makeClientModeManager 方法实现如下:
public ClientModeManager makeClientModeManager(ClientModeManager.Listener listener) {
return new ClientModeManager(mContext, mWifiCoreHandlerThread.getLooper(),
mWifiNative, listener, mWifiMetrics, mClientModeImpl);
}
mManager.start 方法调用的就是ClientModeManager 中的start 方法;ClientModeManager 构造方法如下
ClientModeManager(Context context, @NonNull Looper looper, WifiNative wifiNative,
Listener listener, WifiMetrics wifiMetrics, ClientModeImpl clientModeImpl) {
mContext = context;
mWifiNative = wifiNative;
mListener = listener;
mWifiMetrics = wifiMetrics;
mClientModeImpl = clientModeImpl;
mStateMachine = new ClientModeStateMachine(looper);
}
ClientModeManager 的start 方法如下
public void start() {
mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
}
从ClientModeManager 的构造方法中可知mStateMachine 对象为类ClientModeStateMachine ,ClientModeStateMachine 也是一个状态机,一个有两个独立的状态 mIdleState、mStartedState,初始状态为mIdleState 。
ClientModeStateMachine(Looper looper) {
super(TAG, looper);
addState(mIdleState);
addState(mStartedState);
setInitialState(mIdleState);
start();
}
当ClientModeManager 收到消息CMD_START 处理如下,调用WifiNative setupInterfaceForClientInConnectivityMode 方法来设置底层接口
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
updateWifiState(WifiManager.WIFI_STATE_ENABLING,
WifiManager.WIFI_STATE_DISABLED);
mClientInterfaceName =
mWifiNative.setupInterfaceForClientInConnectivityMode(
mWifiNativeInterfaceCallback);
if (TextUtils.isEmpty(mClientInterfaceName)) {
Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
WifiManager.WIFI_STATE_ENABLING);
updateWifiState(WifiManager.WIFI_STATE_DISABLED,
WifiManager.WIFI_STATE_UNKNOWN);
break;
}
transitionTo(mStartedState);
break;
setupInterfaceForClientInConnectivityMode 方法实现如下,setupInterfaceForClientInConnectivityMode 做的事情很多,主要是启动vendor HAL ,启动wpa_supplicant ,设置接口的client mode ,启动监听对应wlan 的事件。在这里只是笼统总结下,该函数后续单独分析
public String setupInterfaceForClientInConnectivityMode(
@NonNull InterfaceCallback interfaceCallback, boolean lowPriority) {
synchronized (mLock) {
if (!startHal()) {
Log.e(TAG, "Failed to start Hal");
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
if (!startSupplicant()) {
Log.e(TAG, "Failed to start supplicant");
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
return null;
}
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
if (iface == null) {
Log.e(TAG, "Failed to allocate new STA iface");
return null;
}
iface.externalListener = interfaceCallback;
iface.name = createStaIface(iface, lowPriority);
if (TextUtils.isEmpty(iface.name)) {
Log.e(TAG, "Failed to create STA iface in vendor HAL");
mIfaceMgr.removeIface(iface.id);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
return null;
}
if (!setupFstInterface(iface)) {
Log.e(TAG, "Failed to setup fst interface from: " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
return null;
}
if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
Log.e(TAG, "Failed to setup iface in wificond on " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
return null;
}
if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
return null;
}
iface.networkObserver = new NetworkObserverInternal(iface.id);
if (!registerNetworkObserver(iface.networkObserver)) {
Log.e(TAG, "Failed to register network observer on " + iface);
teardownInterface(iface.name);
return null;
}
mWifiMonitor.startMonitoring(iface.name);
// Just to avoid any race conditions with interface state change callbacks,
// update the interface state before we exit.
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
initializeNwParamsForClientInterface(iface.name);
Log.i(TAG, "Successfully setup " + iface);
iface.featureSet = getSupportedFeatureSetInternal(iface.name);
return iface.name;
}
}
setupInterfaceForClientInConnectivityMode 方法执行完后,ClientModeManager 状态机切换到mStartedState 状态,首先执行mStartedState 的enter方法,在enter 中调用了onUpChanged 的方法
@Override
public void enter() {
Log.d(TAG, "entering StartedState");
mIfaceIsUp = false;
onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName));
}
onUpChanged 实现如下,在setupInterfaceForClientInConnectivityMode 方法中,已经把对应的wlan 口设置好,并up起来 ,所有调用这里的时候isUP 是true,调用ClientModeImpl setOperationalMode 设置ClientModeImpl 的状态。ClientModeImpl 的STA 模式的主要的控制状态机,控制的WiFi 的连接,获取ip等流程。后面单独分析该状态机
private void onUpChanged(boolean isUp) {
if (isUp == mIfaceIsUp) {
return; // no change
}
mIfaceIsUp = isUp;
if (isUp) {
Log.d(TAG, "Wifi is ready to use for client mode");
mClientModeImpl.setOperationalMode(ClientModeImpl.CONNECT_MODE,
mClientInterfaceName);
updateWifiState(WifiManager.WIFI_STATE_ENABLED,
WifiManager.WIFI_STATE_ENABLING);
} else {
if (mClientModeImpl.isConnectedMacRandomizationEnabled()) {
// Handle the error case where our underlying interface went down if we
// do not have mac randomization enabled (b/72459123).
return;
}
// if the interface goes down we should exit and go back to idle state.
Log.d(TAG, "interface down!");
updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
WifiManager.WIFI_STATE_ENABLED);
mStateMachine.sendMessage(CMD_INTERFACE_DOWN);
}
}
setOperationalMode 实现如下,由于第一个参数为CONNECT_MODE,所以设置ClientModeImpl 状态机进入mDisconnectedState模式,进入mDisconnectedState会触发一次连接扫描,该流程以后分析,到此,WiFi 的启动流程基本走完。
public void setOperationalMode(int mode, String ifaceName) {
if (mVerboseLoggingEnabled) {
log("setting operational mode to " + String.valueOf(mode) + " for iface: " + ifaceName);
}
new Exception().printStackTrace();
mModeChange = true;
if (mode != CONNECT_MODE) {
// we are disabling client mode... need to exit connect mode now
transitionTo(mDefaultState);
} else {
// do a quick sanity check on the iface name, make sure it isn't null
if (ifaceName != null) {
mInterfaceName = ifaceName;
transitionTo(mDisconnectedState);
} else {
Log.e(TAG, "supposed to enter connect mode, but iface is null -> DefaultState");
transitionTo(mDefaultState);
}
}
// use the CMD_SET_OPERATIONAL_MODE to force the transitions before other messages are
// handled.
sendMessageAtFrontOfQueue(CMD_SET_OPERATIONAL_MODE);
}