转自http://blog.csdn.net/csdn_of_coder/article/details/51541094
Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了;下面就简单介绍下Android中Wifi的启动流程。
当我在Setting菜单里点击打开Wifi时,调用的入口函数是WifiManager::setWifiEnabled(boolean enabled):
-
-
-
-
-
-
- public boolean setWifiEnabled(boolean enabled) {
- try {
- return mService.setWifiEnabled(enabled);
- } catch (RemoteException e) {
- return false;
- }
- }
通过AIDL方式,在Android6.0中,实际调用的是WifiServiceImpl::setWifiEnabled(boolean enable):
-
-
-
-
-
-
- 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");
- }
-
-
-
-
-
-
- long ident = Binder.clearCallingIdentity();
- try {
- if (! mSettingsStore.handleWifiToggled(enable)) {
-
- return true;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- mWifiController.sendMessage(CMD_WIFI_TOGGLED);
- return true;
- }
从代码可以看出,这里主要的操作是将wifi是否enable的状态存入数据库、向WiFiController发送了CMD_WIFI_TOGGLED消息。WifiController实际上是一个状态机,相比WifiStateMachine,它的状态较少,结构也比较简单。WifiController的定义及构造函数:
- class WifiController extends StateMachine {
- ...
- WifiController(Context context, WifiServiceImpl 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);
-
- boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
- boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
- boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
-
- log("isAirplaneModeOn = " + isAirplaneModeOn +
- ", isWifiEnabled = " + isWifiEnabled +
- ", isScanningAvailable = " + isScanningAlwaysAvailable);
-
- if (isScanningAlwaysAvailable) {
- setInitialState(mStaDisabledWithScanState);
- } else {
- setInitialState(mApStaDisabledState);
- }
-
- ...
- }
- ...
- }
WifiController状态机的创建、开启工作在WifiServiceImpl中完成:
- public WifiServiceImpl(Context context) {
- mContext = context;
-
- mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
-
- mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
- mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller);
- mWifiStateMachine.enableRssiPolling(true);
- mBatteryStats = BatteryStatsService.getService();
- mPowerManager = context.getSystemService(PowerManager.class);
- mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
- mUserManager = UserManager.get(mContext);
-
- mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
- mSettingsStore = new WifiSettingsStore(mContext);
-
- HandlerThread wifiThread = new HandlerThread("WifiService");
- wifiThread.start();
- mClientHandler = new ClientHandler(wifiThread.getLooper());
- mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
- mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
- }
WifiController中的各状态之间的关系如图:
WifiControlle状态机的初始状态由一些配置信息决定。当ApStaDisabledState为初始状态时,看对CMD_WIFI_TOGGLED消息的处理:
- class ApStaDisabledState extends State {
- ...
- @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) {
-
- mDeferredEnableSerialNumber++;
- }
- mHaveDeferredEnable = !mHaveDeferredEnable;
- break;
- }
- if (mDeviceIdle == false) {
- transitionTo(mDeviceActiveState);
- } else {
- checkLocksAndTransitionWhenDeviceIdle();
- }
- } else if (mSettingsStore.isScanAlwaysAvailable()) {
- transitionTo(mStaDisabledWithScanState);
- }
- break;
- case CMD_SCAN_ALWAYS_MODE_CHANGED:
- if (mSettingsStore.isScanAlwaysAvailable()) {
- transitionTo(mStaDisabledWithScanState);
- }
- break;
- ...
- default:
- return NOT_HANDLED;
- }
- 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");
-
-
- Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
- deferredMsg.obj = Message.obtain(msg);
- deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
- sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
- return true;
- }
-
- }
调试过程中发现,ApStaDisabledState会同时忽略两个时间间隔小于500ms的 CMD_WIFI_TOGGLED消息,接着转换到DeviceActiveState状态。StaEnabledState是它的父状态,由StateMachine的知识可知,转换到该状态时,会依次调用父、子状态的enter()函数。我们看两个状态的enter()函数:
- class StaEnabledState extends State {
- @Override
- public void enter() {
- mWifiStateMachine.setSupplicantRunning(true);
- }
- ...
- }
- }
-
- class DeviceActiveState extends State {
- @Override
- public void enter() {
- mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- mWifiStateMachine.setDriverStart(true);
- mWifiStateMachine.setHighPerfModeEnabled(false);
- }
-
- ...
- }
这里依次会向WifiStateMachine发送三个消息,最后一个消息这里忽略:
- WifiStateMachine.setSupplicantRunning(true):发送CMD_START_SUPPLICANT消息
- WifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE):发送CMD_SET_OPERATIONAL_MODE消息,参数是CONNECT_MODE
- WifiStateMachine.setDriverStart(true):发送CMD_START_DRIVER消息
在此之前,我们先看下第二点中的参数CONNECT_MODE的含义。在WifiStateMachine中,已经有了如下定义:
-
-
- public static final int CONNECT_MODE = 1;
-
- public static final int SCAN_ONLY_MODE = 2;
-
- public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
-
-
-
-
-
- private int mOperationalMode = CONNECT_MODE;
可知Wifi状态机一共有三种处理模式:
- CONNECT_MODE:该状态下Wifi可以扫描AP,也可以连接AP
- SCAN_ONLY_MODE:该状态下Wifi尽可以扫描AP
- SCAN_ONLY_WIFI_OFF_MODE:该状态下,Wifi仅可以当Wifi toogle off时允许扫描AP
现在,我们将处理的过程转换到WifiStateMachine。WifiStateMachine是一个复杂的状态机,它维护了Wifi的启动、扫描、连接、断开等多个状态。它运行在自己独有的线程中,拥有自己的消息队列。WifiStateMachine中各状态的关系如图所示:
分别来看WifiStateMachine是怎么处理这三个消息的。InitialState首先接收到CMD_START_SUPPLICANT消息并处理:
- case CMD_START_SUPPLICANT:
- if (mWifiNative.loadDriver()) {
- try {
- mNwService.wifiFirmwareReload(mInterfaceName, "STA");
- } catch (Exception e) {
- loge("Failed to reload STA firmware " + e);
-
- }
-
- try {
-
-
-
-
-
- mNwService.setInterfaceDown(mInterfaceName);
- mNwService.clearInterfaceAddresses(mInterfaceName);
-
-
- mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
-
-
-
-
-
- mNwService.disableIpv6(mInterfaceName);
- } catch (RemoteException re) {
- loge("Unable to change interface settings: " + re);
- } catch (IllegalStateException ie) {
- loge("Unable to change interface settings: " + ie);
- }
-
-
-
-
-
- mWifiMonitor.killSupplicant(mP2pSupported);
-
- if (WifiNative.startHal() == false) {
-
- loge("Failed to start HAL");
- }
-
- 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驱动,实际的实现是在wifi.c中
- NetworkManagementService.wifiFirmwareReload(mInterfaceName, "STA"):加载wlan固件
- WifiNative.startSupplicant(mP2pSupported):启动wpa_supplicant
- WifiMonitor.startMonitoring():在前面一篇博文中已经介绍过WifiMonitor,这一步主要是在WifiMonitor中建立与wpa_supplicant通信的socket通道、创建一个线程接收底层事件并分发处理。这里会创建两个socket通道与wpa_s通信,一个用于下发指令,另一个用于接收事件。成功后WifiMonitor会向WifiStateMachine发送一个代表socket通信建立成功的消息:SUP_CONNECTION_EVENT;收到这个消息就表示Wifi已经启动成功了。
- 切换到SupplicantStartingState。
进入SupplicantStartingState后,第一个消息就处理完毕,这时消息队列中按处理先后顺序仍有三个消息:
- CMD_SET_OPERATIONAL_MODE,参数是CONNECT_MODE
- CMD_START_DRIVER
- SUP_CONNECTION_EVENT
切换到SupplicantStartingState,消息队列中的前两个消息在该状态会被延迟处理,直接看SUP_CONNECTION_EVENT的处理过程:
- case WifiMonitor.SUP_CONNECTION_EVENT:
- if (DBG) log("Supplicant connection established");
- setWifiState(WIFI_STATE_ENABLED);
- mSupplicantRestartCount = 0;
-
-
- mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
-
- mLastBssid = null;
- mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
- mLastSignalLevel = -1;
-
- mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
-
- setFrequencyBand();
- mWifiNative.enableSaveConfig();
- mWifiConfigStore.loadAndEnableAllNetworks();
- if (mWifiConfigStore.enableVerboseLogging.get() > 0) {
- enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get());
- }
- initializeWpsDetails();
-
- sendSupplicantConnectionChangedBroadcast(true);
- transitionTo(mDriverStartedState);
- break;
这里主要是调用WifiConfigStore.loadAndEnableAllNetworks()加载并enable所有保存在wpa_s中的AP,然后做一些其他的初始化工作,切换到DriverStartedState状态。关注其父状态和自身的enter()函数:
SupplicantStartedState的enter()函数设置了Wifi扫描间隔;DriverStartedState的enter()函数主要进行了一些相关的设置工作,根据配置启动p2p。最后在enter()函数中会将状态切换到DisconnectedState。消息队列中被延迟的两条消息此时会被处理:
- CMD_SET_OPERATIONAL_MODE消息在DisconnectedState被处理,将mOperationalMode设置为CONNECT_MODE;Wifi状态机中该字段的默认值也是该值。
- CMD_START_DRIVER消息则在DriverStartedState中被处理。
最后转换到DisconnectedState状态,关注enter()函数:
- public void enter() {
-
-
- if (mTemporarilyDisconnectWifi) {
- mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE);
- return;
- }
-
- if (PDBG) {
- logd(" Enter DisconnectedState scan interval "
- + mWifiConfigStore.wifiDisconnectedShortScanIntervalMilli.get()
- + " mLegacyPnoEnabled= " + mLegacyPnoEnabled
- + " screenOn=" + mScreenOn
- + " useGscan=" + mHalBasedPnoDriverSupported + "/"
- + mWifiConfigStore.enableHalBasedPno.get());
- }
-
-
- mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
-
- if (useHalBasedAutoJoinOffload()) {
- startGScanDisconnectedModeOffload("disconnectedEnter");
- } else {
- if (mScreenOn) {
-
-
-
- startDelayedScan(500, null, null);
- } else {
-
-
-
- if (mBackgroundScanSupported) {
-
-
-
-
-
-
- if (!mIsScanOngoing) {
- enableBackgroundScan(true);
- }
- } else {
- setScanAlarm(true);
- }
- }
- }
-
-
-
-
-
-
- if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
- && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
- sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
- ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
- }
-
- mDisconnectedTimeStamp = System.currentTimeMillis();
- mDisconnectedPnoAlarmCount = 0;
- }
在enter()函数中,会进行scan动作;WifiStateMachine处理SCAN_RESULTS_EVENT消息时,就会进入autojoin流程,尝试AP重连。