转自http://blog.csdn.net/csdn_of_coder/article/details/51541094
Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了;下面就简单介绍下Android中Wifi的启动流程。
当我在Setting菜单里点击打开Wifi时,调用的入口函数是WifiManager::setWifiEnabled(boolean enabled):
通过AIDL方式,在Android6.0中,实际调用的是WifiServiceImpl::setWifiEnabled(boolean enable):
从代码可以看出,这里主要的操作是将wifi是否enable的状态存入数据库、向WiFiController发送了CMD_WIFI_TOGGLED消息。WifiController实际上是一个状态机,相比WifiStateMachine,它的状态较少,结构也比较简单。WifiController的定义及构造函数:
- /**
- * Enable or disable Wi-Fi.
- * @param enabled {@code true} to enable, {@code false} to disable.
- * @return {@code true} if the operation succeeds (or if the existing state
- * is the same as the requested state).
- */
- public boolean setWifiEnabled(boolean enabled) {
- try {
- return mService.setWifiEnabled(enabled);
- } catch (RemoteException e) {
- return false;
- }
- }
- /**
- * 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.
- */
- 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;
- }
- 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中完成:
WifiController中的各状态之间的关系如图:
- 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());
- }
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) {
- // have 2 toggles now, inc serial number an ignore both
- 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");
- // 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;
- }
- }
- class StaEnabledState extends State {
- @Override
- public void enter() {
- mWifiStateMachine.setSupplicantRunning(true);
- }
- ...
- }
- }
- /* Parent: StaEnabledState */
- class DeviceActiveState extends State {
- @Override
- public void enter() {
- mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- mWifiStateMachine.setDriverStart(true);
- mWifiStateMachine.setHighPerfModeEnabled(false);//此处分析忽略,关系不大
- }
- ...
- }
- 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中,已经有了如下定义:
可知Wifi状态机一共有三种处理模式:
- /* Wifi state machine modes of operation */
- /* CONNECT_MODE - connect to any 'known' AP when it becomes available */
- public static final int CONNECT_MODE = 1;
- /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */
- public static final int SCAN_ONLY_MODE = 2;
- /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */
- public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
- /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
- * In CONNECT_MODE, the STA can scan and connect to an access point
- * In SCAN_ONLY_MODE, the STA can only scan for access points
- * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
- */
- private int mOperationalMode = CONNECT_MODE;
- 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");//加载wlan固件
- } catch (Exception e) {
- loge("Failed to reload STA firmware " + e);
- // Continue
- }
- try {
- // A runtime crash can leave the interface up and
- // IP addresses configured, and this affects
- // connectivity when supplicant starts up.
- // Ensure interface is down and we have no IP
- // addresses before a supplicant start.
- mNwService.setInterfaceDown(mInterfaceName);
- mNwService.clearInterfaceAddresses(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.
- */
- mWifiMonitor.killSupplicant(mP2pSupported);
- if (WifiNative.startHal() == false) {
- /* starting HAL is optional */
- loge("Failed to start HAL");
- }
- if (mWifiNative.startSupplicant(mP2pSupported)) {//启动wpa_s
- setWifiState(WIFI_STATE_ENABLING);
- if (DBG) log("Supplicant start successful");
- mWifiMonitor.startMonitoring();//建立与wpa_s之间的socket通信连接;开启线程,循环接收来自wpa_s的event,并分发处理
- 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。
- CMD_SET_OPERATIONAL_MODE,参数是CONNECT_MODE
- CMD_START_DRIVER
- SUP_CONNECTION_EVENT
- 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());
- /* set frequency band of operation */
- setFrequencyBand();
- mWifiNative.enableSaveConfig();
- mWifiConfigStore.loadAndEnableAllNetworks();//加载并enable保存的AP
- if (mWifiConfigStore.enableVerboseLogging.get() > 0) {
- enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get());
- }
- initializeWpsDetails();
- sendSupplicantConnectionChangedBroadcast(true);//广播通知Wpa_s连接已建立,此时已经可以准备连接或扫描Wifi了
- transitionTo(mDriverStartedState);
- break;
- class SupplicantStartedState extends State {
- @Override
- public void enter() {
- /* Wifi is available as long as we have a connection to supplicant */
- mNetworkInfo.setIsAvailable(true);
- if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
- 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);//设置扫描时间间隔
- mWifiNative.setExternalSim(true);
- /* turn on use of DFS channels */
- WifiNative.setDfsFlag(true);
- /* set country code */
- setCountryCode();
- setRandomMacOui();
- mWifiNative.enableAutoConnect(false); //可以事先注意该设置
- }
- }
- class DriverStartedState extends State {
- @Override
- public void enter() {
- if (PDBG) {
- logd("DriverStartedState enter");
- }
- mWifiLogger.startLogging(mVerboseLoggingLevel > 0);
- 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);
- /* 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();
- }
- mDhcpActive = false;
- if (mOperationalMode != CONNECT_MODE) {
- mWifiNative.disconnect();
- mWifiConfigStore.disableAllNetworks();
- if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
- setWifiState(WIFI_STATE_DISABLED);
- }
- transitionTo(mScanModeState);
- } else {
- // 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
- // TODO: actually check th supplicant status string and make sure the supplicant
- // is in disconnecte4d state.
- mWifiNative.status();
- // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin
- transitionTo(mDisconnectedState);
- 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) {
- if (mOperationalMode == CONNECT_MODE) {
- mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);//支持p2p,则会发送命令enbale p2p
- } else {
- // P2P statemachine starts in disabled state, and is not enabled until
- // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to
- // keep it disabled.
- }
- }
- 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);
- mHalFeatureSet = WifiNative.getSupportedFeatureSet();
- if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO)
- == WifiManager.WIFI_FEATURE_HAL_EPNO) {
- mHalBasedPnoDriverSupported = true;
- }
- // Enable link layer stats gathering
- mWifiNative.setWifiLinkLayerStats("wlan0", 1);
- if (PDBG) {
- logd("Driverstarted State enter done, epno=" + mHalBasedPnoDriverSupported
- + " feature=" + mHalFeatureSet);
- }
- }
- }
- CMD_SET_OPERATIONAL_MODE消息在DisconnectedState被处理,将mOperationalMode设置为CONNECT_MODE;Wifi状态机中该字段的默认值也是该值。
- CMD_START_DRIVER消息则在DriverStartedState中被处理。
最后转换到DisconnectedState状态,关注enter()函数:
在enter()函数中,会进行scan动作;WifiStateMachine处理SCAN_RESULTS_EVENT消息时,就会进入autojoin流程,尝试AP重连。
- public void enter() {
- // We dont scan frequently if this is a temporary disconnect
- // due to p2p
- 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());
- }
- /** clear the roaming state, if we were roaming, we failed */
- mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE;
- if (useHalBasedAutoJoinOffload()) {
- startGScanDisconnectedModeOffload("disconnectedEnter");
- } else {
- if (mScreenOn) {
- /**
- * screen lit and => delayed timer
- */
- startDelayedScan(500, null, null);
- } else {
- /**
- * screen dark and PNO supported => scan alarm disabled
- */
- if (mBackgroundScanSupported) {
- /* If a regular scan result is pending, do not initiate background
- * scan until the scan results are returned. This is needed because
- * initiating a background scan will cancel the regular scan and
- * scan results will not be returned until background scanning is
- * cleared
- */
- if (!mIsScanOngoing) {
- enableBackgroundScan(true);//启动wifi扫描,随后会触发autojoin,进行连接操作
- }
- } else {
- setScanAlarm(true);//启动一个扫描定时器
- }
- }
- }
- /**
- * If we have no networks saved, the supplicant stops doing the periodic scan.
- * The scans are useful to notify the user of the presence of an open network.
- * Note that these are not wake up scans.
- */
- if (mNoNetworksPeriodicScan != 0 && !mP2pConnected.get()
- && mWifiConfigStore.getConfiguredNetworks().size() == 0) {
- sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
- ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan);
- }
- mDisconnectedTimeStamp = System.currentTimeMillis();
- mDisconnectedPnoAlarmCount = 0;
- }