Android wifi源码分析(一) Wifi启动流程
2017-09-06 14:49
585 查看
最近在解决wifi的一些问题,故研究下wifi源码。
该源码是基于Android4.3,其他版本略有改动,大致流程一样。
这篇主要说一下wifi的启动流程。
该方法调用到WifiService中的setWifiEnabled。
enforceChangePermission 判断调用的进程是否有权限。想要开关wifi需要CHANGE_WIFI_STATE 权限。
handleWifiToggled 判断飞行模式、保存wifi 操作的状态。
向WifiController发送消息。CMD_WIFI_TOGGLED
WifiController继承了StateMachine,是一个状态机。其构造函数如下
上述函数中addState的格式,可以看出各状态之间的关系。
然后通过wifi是否可以一直扫描(isScanAlwaysAvailable)设置状态机初始状态。
ApStaDisabledState和StaDisabledWithScanState两种状态处理CMD_WIFI_TOGGLED消息时一样的。
看看ApStaDisabledState是如何处理的。
mSettingsStore.isWifiToggleEnabled()用来获取保存的wifi操作的状态,如果是开则继续。
wpa supplicant 关闭后不能立即启动,mReEnableDelayMillis为重新开启wifi的延时时间(从系统数据库获取,获取不到则默认值为500ms),这里deferEnable用来判断时间,延缓启动。
之后切换到DeviceActiveState。
DeviceActiveState为StaEnabledState的子状态,所以会先调用父状态的enter()函数,然后调用子状态的enter()函数。分别看一下两个enter函数。
mWifiStateMachine.setSupplicantRunning(true),WifiStateMachine发送Message--CMD_STAET_SUPPLICANT。
WifiNative.loadDriver():加载Wifi驱动。
WifiNative.loadDriver()–>android_net_wifi_wifi.cpp(android_net_wifi_loadDriver)
->wifi.c(wifi_load_driver)。
mNwService.wifiFirmwareReload(mInterfaceName, “STA”); 加载固件
mWifiNative.startSupplicant(mP2pSupported) 先保证没有运行的wpa supplicant,然后开启wpa supplicant,其中参数mP2pSupported表示是否支持wifi 直连。
WifiNative.startSupplicant()–>android_net_wifi_wifi.cpp(android_net_wifi_startSupplicant)
->wifi.c(wifi_start_supplicant)。
setWifiState(WIFI_STATE_ENABLING) 发送广播(wifi状态改变 ,正在开启)。
mWifiMonitor.startMonitoring()
WifiMonitor创建一个线程MonitorThrad
connectToSupplicant最终调到wifi.c 中的wifi_connect_on_socket_path。在该函数中,将通过wpa_ctrl_open函数分别创建两个socket,一个是ctrl_conn, 用于向wpa_supplicant发送命令并接收response, 另一个是monitor_conn, 它一直阻塞等待从wpa_supplicant过来的event。连接成功后WifiMonitor会向WifiStateMachine发送一个代表socket通信建立成功的消息:SUP_CONNECTION_EVENT。
mWifiNative.waitForEvent-》wifi_wait_on_socket ,循环调用该函数,接收底层事件并分发处理。
WifiStateMachine切换到SupplicantStartingState状态。步骤5是在另一个线程中运行,并且是耗时操作,所以WifiStateMachine先切换到SupplicantStartingState状态,然后接收到SUP_CONNECTION_EVENT消息。
下面看看如何处理SUP_CONNECTION_EVENT消息。
setWifiState(WIFI_STATE_ENABLED),发送WIFI_STATE_ENABLED的广播。
WifiConfigStore.loadAndEnableAllNetworks() 加载并enable所有保存在wpa_supplicant中的AP。这样会使这些保存的wifi实现自动重连。
切换到DriverStartedState状态。
DriverStartedState是SupplicantStartedState的子状态,所以先后运行SupplicantStartedState、DriverStartedState的enter方法。
frameworks/base/core/res/res/values/config.xml中可以修改config_wifi_supplicant_scan_interval 的值。
mNetworkInfo.setIsAvailable(true); 连接到wpa_supplicant,就可以使用wifi。
setScanInterval 设置wifi扫描间隔时间。
setBluetoothCoexistenceScanMode 启用蓝牙连接时启用蓝牙共存扫描模式。当此模式打开时,驱动程序使用的一些低级扫描参数会被更改,以减少对蓝牙的干扰。
mOperationalMode 默认为CONNECT_MODE,enableAllNetworks 将保存的wifi置为可连接的,并进行重连。
mWifiNative.status() 将wpa_supplicant中状态进行同步。
切换到DisconnectedState状态。
STA的3个操作状态:CONNECT_MODE,SCAN_ONLY_MODE,SCAN_ONLY_WIFI_OFF_MODE
*在CONNECT_MODE中,STA可以扫描并连接到接入点
*在SCAN_ONLY_MODE中,STA只能扫描接入点
*在SCAN_ONLY_WIFI_OFF_MODE中,STA只能扫描(wifi关闭状态下)
setOperationalMode 这里设置模式 可扫描、可连接。
setDriverStart(true) 发送CMD_START_DRIVER 消息。该消息在DriverStartedState中处理。
如果正在延时关闭驱动,则取消关闭。并将保存的wifi都Enable。
setHighPerfModeEnabled暂时不清楚什么情况。
这就差不多整理完wifi启动的流程了。
有什么问题和意见,欢迎提问、交流。
欢迎大家关注、评论、点赞。
你们的支持是我坚持的动力。
该源码是基于Android4.3,其他版本略有改动,大致流程一样。
这篇主要说一下wifi的启动流程。
WifiManager
先从wifi的开启来看,WifiManager中提供了接口用来控制wifi开关,setWifiEnabled,参数true表示开启、false表示关闭。public boolean setWifiEnabled(boolean enabled) { try { return mService.setWifiEnabled(enabled); } catch (RemoteException e) { return false; } }
该方法调用到WifiService中的setWifiEnabled。
WifiService
public synchronized boolean setWifiEnabled(boolean enable) { enforceChangePermission(); Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); if (DBG) { Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); } /* * Caller might not have WRITE_SECURE_SETTINGS, * only CHANGE_WIFI_STATE is enforced */ long ident = Binder.clearCallingIdentity(); try { if (! mSettingsStore.handleWifiToggled(enable)) { // Nothing to do if wifi cannot be toggled return true; } } finally { Binder.restoreCallingIdentity(ident); } mWifiController.sendMessage(CMD_WIFI_TOGGLED); return true; }
enforceChangePermission 判断调用的进程是否有权限。想要开关wifi需要CHANGE_WIFI_STATE 权限。
handleWifiToggled 判断飞行模式、保存wifi 操作的状态。
向WifiController发送消息。CMD_WIFI_TOGGLED
WifiController
WifiController在WIfiService的构造函数中初始化、并开始运行。WifiController继承了StateMachine,是一个状态机。其构造函数如下
WifiController(Context context, WifiService service, Looper looper) { super(TAG, looper); //.... addState(mDefaultState); addState(mApStaDisabledState, mDefaultState); addState(mStaEnabledState, mDefaultState); addState(mDeviceActiveState, mStaEnabledState); addState(mDeviceInactiveState, mStaEnabledState); addState(mScanOnlyLockHeldState, mDeviceInactiveState); addState(mFullLockHeldState, mDeviceInactiveState); addState(mFullHighPerfLockHeldState, mDeviceInactiveState); addState(mNoLockHeldState, mDeviceInactiveState); addState(mStaDisabledWithScanState, mDefaultState); addState(mApEnabledState, mDefaultState); addState(mEcmState, mDefaultState); if (mSettingsStore.isScanAlwaysAvailable()) { setInitialState(mApStaDisabledState); } else { setInitialState(mApStaDisabledState); } }
上述函数中addState的格式,可以看出各状态之间的关系。
然后通过wifi是否可以一直扫描(isScanAlwaysAvailable)设置状态机初始状态。
ApStaDisabledState和StaDisabledWithScanState两种状态处理CMD_WIFI_TOGGLED消息时一样的。
看看ApStaDisabledState是如何处理的。
class ApStaDisabledState extends State { private int mDeferredEnableSerialNumber = 0; private boolean mHaveDeferredEnable = false; private long mDisabledTimestamp; @Override public void enter() { mWifiStateMachine.setSupplicantRunning(false); // Supplicant can't restart right away, so not the time we switched off mDisabledTimestamp = SystemClock.elapsedRealtime(); mDeferredEnableSerialNumber++; mHaveDeferredEnable = false; } @Override public boolean processMessage(Message msg) { switch (msg.what) { case CMD_WIFI_TOGGLED: case CMD_AIRPLANE_TOGGLED: if (mSettingsStore.isWifiToggleEnabled()) { if (doDeferEnable(msg)) { if (mHaveDeferredEnable) { // have 2 toggles now, inc serial number an ignore both mDeferredEnableSerialNumber++; } mHaveDeferredEnable = !mHaveDeferredEnable; break; } if (mDeviceIdle == false) { transitionTo(mDeviceActiveState); } else { checkLocksAndTransitionWhenDeviceIdle(); } } break; //。。。。。 } return HANDLED; } private boolean doDeferEnable(Message msg) { long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; if (delaySoFar >= mReEnableDelayMillis) { return false; } log("WifiController msg " + msg + " deferred for " + (mReEnableDelayMillis - delaySoFar) + "ms"); // need to defer this action. Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); deferredMsg.obj = Message.obtain(msg); deferredMsg.arg1 = ++mDeferredEnableSerialNumber; sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); return true; } }
mSettingsStore.isWifiToggleEnabled()用来获取保存的wifi操作的状态,如果是开则继续。
wpa supplicant 关闭后不能立即启动,mReEnableDelayMillis为重新开启wifi的延时时间(从系统数据库获取,获取不到则默认值为500ms),这里deferEnable用来判断时间,延缓启动。
之后切换到DeviceActiveState。
DeviceActiveState为StaEnabledState的子状态,所以会先调用父状态的enter()函数,然后调用子状态的enter()函数。分别看一下两个enter函数。
1 WifiController –StaEnabledState
先看看StaEnabledState的enter()函数:class StaEnabledState extends State { @Override public void enter() { mWifiStateMachine.setSupplicantRunning(true); } ... } }
mWifiStateMachine.setSupplicantRunning(true),WifiStateMachine发送Message--CMD_STAET_SUPPLICANT。
WIfiStateMachine
看看处理该消息class InitialState extends State { @Override public boolean processMessage(Message message) { switch (message.what) { case CMD_START_SUPPLICANT: //加载Wifi驱动 if (mWifiNative.loadDriver()) { try {//加载固件 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); } catch (Exception e) { } try { // A runtime crash can leave the interface up and // this affects connectivity when supplicant starts up. // Ensure interface is down before a supplicant start. mNwService.setInterfaceDown(mInterfaceName); // Set privacy extensions mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); // IPv6 is enabled only as long as access point is connected since: // - IPv6 addresses and routes stick around after disconnection // - kernel is unaware when connected and fails to start IPv6 negotiation // - kernel can start autoconfiguration when 802.1x is not complete mNwService.disableIpv6(mInterfaceName); } catch (RemoteException re) { loge("Unable to change interface settings: " + re); } catch (IllegalStateException ie) { loge("Unable to change interface settings: " + ie); } /* Stop a running supplicant after a runtime restart * Avoids issues with drivers that do not handle interface down * on a running supplicant properly. */ mWifiNative.killSupplicant(mP2pSupported); //开启wpa_supplicant if(mWifiNative.startSupplicant(mP2pSupported)) { setWifiState(WIFI_STATE_ENABLING); if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); transitionTo(mSupplicantStartingState); } else { loge("Failed to start supplicant!"); } } else { loge("Failed to load driver"); } break; //....... }
WifiNative.loadDriver():加载Wifi驱动。
WifiNative.loadDriver()–>android_net_wifi_wifi.cpp(android_net_wifi_loadDriver)
->wifi.c(wifi_load_driver)。
mNwService.wifiFirmwareReload(mInterfaceName, “STA”); 加载固件
mWifiNative.startSupplicant(mP2pSupported) 先保证没有运行的wpa supplicant,然后开启wpa supplicant,其中参数mP2pSupported表示是否支持wifi 直连。
WifiNative.startSupplicant()–>android_net_wifi_wifi.cpp(android_net_wifi_startSupplicant)
->wifi.c(wifi_start_supplicant)。
setWifiState(WIFI_STATE_ENABLING) 发送广播(wifi状态改变 ,正在开启)。
mWifiMonitor.startMonitoring()
WifiMonitor创建一个线程MonitorThrad
connectToSupplicant最终调到wifi.c 中的wifi_connect_on_socket_path。在该函数中,将通过wpa_ctrl_open函数分别创建两个socket,一个是ctrl_conn, 用于向wpa_supplicant发送命令并接收response, 另一个是monitor_conn, 它一直阻塞等待从wpa_supplicant过来的event。连接成功后WifiMonitor会向WifiStateMachine发送一个代表socket通信建立成功的消息:SUP_CONNECTION_EVENT。
mWifiNative.waitForEvent-》wifi_wait_on_socket ,循环调用该函数,接收底层事件并分发处理。
WifiStateMachine切换到SupplicantStartingState状态。步骤5是在另一个线程中运行,并且是耗时操作,所以WifiStateMachine先切换到SupplicantStartingState状态,然后接收到SUP_CONNECTION_EVENT消息。
下面看看如何处理SUP_CONNECTION_EVENT消息。
class SupplicantStartingState extends State { @Override public boolean processMessage(Message message) { switch(message.what) { case WifiMonitor.SUP_CONNECTION_EVENT: if (DBG) log("Supplicant connection established"); setWifiState(WIFI_STATE_ENABLED); mSupplicantRestartCount = 0; /* Reset the supplicant state to indicate the supplicant * state is not known at this time */ mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); /* Initialize data structures */ mLastBssid = null; mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; mLastSignalLevel = -1; mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); mWifiConfigStore.loadAndEnableAllNetworks(); initializeWpsDetails(); sendSupplicantConnectionChangedBroadcast(true); transitionTo(mDriverStartedState); break; //...... }
setWifiState(WIFI_STATE_ENABLED),发送WIFI_STATE_ENABLED的广播。
WifiConfigStore.loadAndEnableAllNetworks() 加载并enable所有保存在wpa_supplicant中的AP。这样会使这些保存的wifi实现自动重连。
切换到DriverStartedState状态。
DriverStartedState是SupplicantStartedState的子状态,所以先后运行SupplicantStartedState、DriverStartedState的enter方法。
class SupplicantStartedState extends State { @Override public void enter() { /* Wifi is available as long as we have a connection to supplicant */ mNetworkInfo.setIsAvailable(true); int defaultInterval = mContext.getResources().getInteger( R.integer.config_wifi_supplicant_scan_interval); mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, defaultInterval); //设置扫描时间间隔。 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); } //.....
frameworks/base/core/res/res/values/config.xml中可以修改config_wifi_supplicant_scan_interval 的值。
mNetworkInfo.setIsAvailable(true); 连接到wpa_supplicant,就可以使用wifi。
setScanInterval 设置wifi扫描间隔时间。
class DriverStartedState extends State { @Override public void enter() { mIsRunning = true; mInDelayedStop = false; mDelayedStopCounter++; updateBatteryWorkSource(null); /** * Enable bluetooth coexistence scan mode when bluetooth connection is active. * When this mode is on, some of the low-level scan parameters used by the * driver are changed to reduce interference with bluetooth */ mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); /* set country code */ setCountryCode(); /* set frequency band of operation */ setFrequencyBand(); /* initialize network state */ setNetworkDetailedState(DetailedState.DISCONNECTED); /* Remove any filtering on Multicast v6 at start */ mWifiNative.stopFilteringMulticastV6Packets(); /* Reset Multicast v4 filtering state */ if (mFilteringMulticastV4Packets.get()) { mWifiNative.startFilteringMulticastV4Packets(); } else { mWifiNative.stopFilteringMulticastV4Packets(); } if (mOperationalMode != CONNECT_MODE) { mWifiNative.disconnect(); transitionTo(mScanModeState); } else { /* Driver stop may have disabled networks, enable right after start */ mWifiConfigStore.enableAllNetworks(); mWifiNative.reconnect(); // Status pulls in the current supplicant state and network connection state // events over the monitor connection. This helps framework sync up with // current supplicant state mWifiNative.status(); transitionTo(mDisconnectedState); } // We may have missed screen update at boot if (mScreenBroadcastReceived.get() == false) { PowerManager powerManager = (PowerManager)mContext.getSystemService( Context.POWER_SERVICE); handleScreenStateChanged(powerManager.isScreenOn()); } else { // Set the right suspend mode settings mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()); } mWifiNative.setPowerSave(true); if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } //.....
setBluetoothCoexistenceScanMode 启用蓝牙连接时启用蓝牙共存扫描模式。当此模式打开时,驱动程序使用的一些低级扫描参数会被更改,以减少对蓝牙的干扰。
mOperationalMode 默认为CONNECT_MODE,enableAllNetworks 将保存的wifi置为可连接的,并进行重连。
mWifiNative.status() 将wpa_supplicant中状态进行同步。
切换到DisconnectedState状态。
2 WifiController –DeviceActiveState
/* Parent: StaEnabledState */ class DeviceActiveState extends State { @Override public void enter() { mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWifiStateMachine.setDriverStart(true); mWifiStateMachine.setHighPerfModeEnabled(false); } ... }
STA的3个操作状态:CONNECT_MODE,SCAN_ONLY_MODE,SCAN_ONLY_WIFI_OFF_MODE
*在CONNECT_MODE中,STA可以扫描并连接到接入点
*在SCAN_ONLY_MODE中,STA只能扫描接入点
*在SCAN_ONLY_WIFI_OFF_MODE中,STA只能扫描(wifi关闭状态下)
setOperationalMode 这里设置模式 可扫描、可连接。
setDriverStart(true) 发送CMD_START_DRIVER 消息。该消息在DriverStartedState中处理。
case CMD_START_DRIVER: if (mInDelayedStop) { mInDelayedStop = false; mDelayedStopCounter++; mAlarmManager.cancel(mDriverStopIntent); if (DBG) log("Delayed stop ignored due to start"); if (mOperationalMode == CONNECT_MODE) { mWifiConfigStore.enableAllNetworks(); } } break;
如果正在延时关闭驱动,则取消关闭。并将保存的wifi都Enable。
setHighPerfModeEnabled暂时不清楚什么情况。
这就差不多整理完wifi启动的流程了。
有什么问题和意见,欢迎提问、交流。
欢迎大家关注、评论、点赞。
你们的支持是我坚持的动力。
相关文章推荐
- WIFI操作流程源码分析—启动
- Android WifiService的启动流程分析
- Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】
- Android进阶——Small源码分析之启动流程详解
- Android 5.0 Camera系统源码分析(1):CameraService启动流程
- [android]WIFI热点启动流程分析
- android之wifi体系架构源码流程分析
- Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】
- [Android]Android系统启动流程源码分析
- android之wifi体系架构源码流程分析
- android开发之源码级分析(系统启动流程 & Handler消息机制 & AsyncTask机制)
- Android WifiService的启动流程分析
- [Android]从Launcher开始启动App流程源码分析
- [android源码分析]bluetoothd service的启动的总体流程分析
- 【源码分析】Android系统启动流程.
- Android -- Wifi启动流程分析
- 【Android】源码分析 - Activity启动流程
- Android Service的启动流程源码分析(8.0)
- Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】
- [Android]Android系统启动流程源码分析