本文共 22013 字,大约阅读时间需要 73 分钟。
前言:之前只知道WiFi开关有所变化是由于接收到了WiFi state变化的广播,根据广播所携带的state信息更新开关,那变化的深层原因是什么呢?
先期工作:
1)
先抓取了小米Mix2 8.0的WiFi开启log:
09-01 00:07:19.994 1561 2456 D WifiStateMachine: setting operational mode to 109-01 00:07:19.995 1561 2457 D WifiStateMachine: InitialState !CMD_SET_OPERATIONAL_MODE rt=386651444/1132848219 1 009-01 00:07:19.995 1561 2457 D WifiStateMachine: InitialState !CMD_START_SUPPLICANT rt=386651445/1132848220 0 009-01 00:07:20.245 1561 2457 D WifiStateMachine: Supplicant start successful09-01 00:07:20.447 1561 2457 D WifiStateMachine: SupplicantStartingState !CMD_START_SUPPLICANT rt=386651897/1132848672 0 009-01 00:07:20.448 1561 2457 D WifiStateMachine: SupplicantStartingState !SUP_CONNECTION_EVENT rt=386651897/1132848672 0 009-01 00:07:20.448 1561 2457 D WifiStateMachine: Supplicant connection established09-01 00:07:20.454 1561 2457 D WifiStateMachine: SupplicantStartedState enter09-01 00:07:20.454 1561 2457 D WifiStateMachine: Setting OUI to DA-A1-1909-01 00:07:20.461 1561 2457 D WifiStateMachine: setDetailed state, old =DISCONNECTED and new state=DISCONNECTED hidden=false09-01 00:07:20.466 1561 2457 D WifiStateMachine: setWifiState: enabling09-01 00:07:20.492 1561 2457 D WifiStateMachine: setWifiState: enabled09-01 00:07:20.494 1561 2456 D WifiStateMachine: setting operational mode to 109-01 00:07:20.496 1561 2457 D WifiStateMachine: setDetailed state, old =DISCONNECTED and new state=DISCONNECTED hidden=false09-01 00:07:20.501 1561 2457 I WifiStateMachine: disconnectedstate enter09-01 00:07:20.501 1561 2457 D WifiStateMachine: Enter DisconnectedState screenOn=true
2)wifiStateMachine状态机
3)WiFi启动时序图
1.设置WiFi开关刷新
我比较熟悉设置,就以设置的WiFi开关开始梳理
WifiEnabler
1.注册广播接收器
@VisibleForTesting WifiEnabler(Context context, SwitchWidgetController switchWidget, MetricsFeatureProvider metricsFeatureProvider, ConnectivityManagerWrapper connectivityManagerWrapper) { mContext = context; mSwitchWidget = switchWidget; mSwitchWidget.setListener(this); mMetricsFeatureProvider = metricsFeatureProvider; mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mConnectivityManager = connectivityManagerWrapper; mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); // The order matters! We really should not depend on this. :( mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); setupSwitchController(); } public void resume(Context context) { mContext = context; // Wi-Fi state is sticky, so just let the receiver update UI mContext.registerReceiver(mReceiver, mIntentFilter); if (!mListeningToOnSwitchChange) { mSwitchWidget.startListening(); mListeningToOnSwitchChange = true; } } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { handleWifiStateChanged(mWifiManager.getWifiState()); } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) { if (!mConnected.get()) { handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE))); } } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( WifiManager.EXTRA_NETWORK_INFO); mConnected.set(info.isConnected()); handleStateChanged(info.getDetailedState()); } } };
2.当接收到WifiManager.WIFI_STATE_CHANGED_ACTION时调用handleWifiStateChanged刷新开关状态
private void handleWifiStateChanged(int state) { // Clear any previous state mSwitchWidget.setDisabledByAdmin(null); switch (state) { case WifiManager.WIFI_STATE_ENABLING: break; case WifiManager.WIFI_STATE_ENABLED: setSwitchBarChecked(true); mSwitchWidget.setEnabled(true); break; case WifiManager.WIFI_STATE_DISABLING: break; case WifiManager.WIFI_STATE_DISABLED: setSwitchBarChecked(false); mSwitchWidget.setEnabled(true); break; default: setSwitchBarChecked(false); mSwitchWidget.setEnabled(true); } if (mayDisableTethering(!mSwitchWidget.isChecked())) { if (RestrictedLockUtils.hasBaseUserRestriction(mContext, UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) { mSwitchWidget.setEnabled(false); } else { final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()); mSwitchWidget.setDisabledByAdmin(admin); } } }
2.广播的发起者
那WiFi开启完毕后WifiManager.WIFI_STATE_CHANGED_ACTION这个广播是由谁发出的呢?之前梳理WiFi启动流程的时候不够细致,这里补充一下。
基于 继续梳理
这里补充梳理setSupplicantRunning以后的wifiStateMachine的状态机变化。
2.1 InitialState
class InitialState extends State { private void cleanup() { // Tearing down the client interfaces below is going to stop our supplicant. mWifiMonitor.stopAllMonitoring(); mDeathRecipient.unlinkToDeath(); mWifiNative.tearDown(); } @Override public void enter() { mWifiStateTracker.updateState(WifiStateTracker.INVALID); cleanup(); } @Override public boolean processMessage(Message message) { logStateAndMessage(message, this); switch (message.what) { case CMD_START_SUPPLICANT: PairstatusAndInterface = mWifiNative.setupForClientMode(); if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) { mClientInterface = statusAndInterface.second; } else { incrementMetricsForSetupFailure(statusAndInterface.first); } if (mClientInterface == null || !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) { setWifiState(WifiManager.WIFI_STATE_UNKNOWN); cleanup(); break; } try { // A runtime crash or shutting down AP mode can leave // IP addresses configured, and this affects // connectivity when supplicant starts up. // Ensure we have no IP addresses before a supplicant start. 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); } if (!mWifiNative.enableSupplicant()) { loge("Failed to start supplicant!"); setWifiState(WifiManager.WIFI_STATE_UNKNOWN); cleanup(); break; } if (mVerboseLoggingEnabled) log("Supplicant start successful"); mWifiMonitor.startMonitoring(mInterfaceName, true); mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts(); setSupplicantLogLevel(); transitionTo(mSupplicantStartingState); break;
WifiStateMachine的初始状态是InitialState状态,接收到CMD_START_SUPPLICANT消息后开始做如下几步操作后变化到SupplicantStartingState状态。
1.mWifiNative.setupForClientMode()
2.mWifiNative.enableSupplicant()
3.mWifiMonitor.startMonitoring(mInterfaceName, true);
之前梳理忽略了第3步,这第3步里文章比较大。
WifiMonitor:
/** * Start Monitoring for wpa_supplicant events. * * @param iface Name of iface. * TODO: Add unit tests for these once we remove the legacy code. */ public synchronized void startMonitoring(String iface, boolean isStaIface) { if (ensureConnectedLocked()) { setMonitoring(iface, true); broadcastSupplicantConnectionEvent(iface); } else { boolean originalMonitoring = isMonitoring(iface); setMonitoring(iface, true); broadcastSupplicantDisconnectionEvent(iface); setMonitoring(iface, originalMonitoring); Log.e(TAG, "startMonitoring(" + iface + ") failed!"); } }
/** * Wait for wpa_supplicant's control interface to be ready. * * TODO: Add unit tests for these once we remove the legacy code. */ private boolean ensureConnectedLocked() { if (mConnected) { return true; } if (mVerboseLoggingEnabled) Log.d(TAG, "connecting to supplicant"); int connectTries = 0; while (true) { mConnected = mWifiInjector.getWifiNative().connectToSupplicant(); if (mConnected) { return true; } if (connectTries++ < 50) { try { Thread.sleep(100); } catch (InterruptedException ignore) { } } else { return false; } } }
这个ensureConnectedLocked是个轮询方法,会每隔100ms,上限50次的去查看与supplicant的连接有没有建立起来。
WifiNative
/** * This method is called repeatedly until the connection to wpa_supplicant is established. * * @return true if connection is established, false otherwise. * TODO: Add unit tests for these once we remove the legacy code. */ public boolean connectToSupplicant() { // Start initialization if not already started. if (!mSupplicantStaIfaceHal.isInitializationStarted() && !mSupplicantStaIfaceHal.initialize()) { return false; } // Check if the initialization is complete. return mSupplicantStaIfaceHal.isInitializationComplete(); }
如果建立好了,就做两个事,启动对某iface的监控并其向该注册该事件的所有handler发送supplicant的连接消息。
/** * Enable/Disable monitoring for the provided iface. * * @param iface Name of the iface. * @param enabled true to enable, false to disable. */ @VisibleForTesting public void setMonitoring(String iface, boolean enabled) { mMonitoringMap.put(iface, enabled); }
/** * Broadcast the connection to wpa_supplicant event to all the handlers registered for * this event. * * @param iface Name of iface on which this occurred. */ public void broadcastSupplicantConnectionEvent(String iface) { sendMessage(iface, SUP_CONNECTION_EVENT); }
PS:
1)iface除非特意指定wifi.interface,一般是wlan0
mWifiNative = new WifiNative(SystemProperties.get("wifi.interface", "wlan0"), mWifiVendorHal, mSupplicantStaIfaceHal, mWificondControl);
2)wifistateMachine是注册supplicant连接消息的。
mWifiMonitor.registerHandler(mInterfaceName, WifiMonitor.SUP_CONNECTION_EVENT, getHandler());
2.2 SupplicantStartingState
class SupplicantStartingState extends State { private void initializeWpsDetails() { ... } @Override public boolean processMessage(Message message) { logStateAndMessage(message, this); switch(message.what) { case WifiMonitor.SUP_CONNECTION_EVENT: if (mVerboseLoggingEnabled) log("Supplicant connection established"); 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()); initializeWpsDetails(); sendSupplicantConnectionChangedBroadcast(true); transitionTo(mSupplicantStartedState); break;
SupplicantStartingState并没有特殊的enter方法,只是在收到supplicant连接好的消息后会有相应的处理并将状态切到SupplicantStartedState。
2.3 SupplicantStartedState
class SupplicantStartedState extends State { @Override public void enter() { if (mVerboseLoggingEnabled) { logd("SupplicantStartedState enter"); } mWifiNative.setExternalSim(true); setRandomMacOui(); mCountryCode.setReadyForChange(true); // We can't do this in the constructor because WifiStateMachine is created before the // wifi scanning service is initialized if (mWifiScanner == null) { mWifiScanner = mWifiInjector.getWifiScanner(); synchronized (mWifiReqCountLock) { mWifiConnectivityManager = mWifiInjector.makeWifiConnectivityManager(mWifiInfo, hasConnectionRequests()); mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0); mWifiConnectivityManager.handleScreenStateChanged(mScreenOn); } } mWifiDiagnostics.startLogging(mVerboseLoggingEnabled); mIsRunning = true; 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); // Check if there is a voice call on-going and set/reset the tx power limit // appropriately. if (mEnableVoiceCallSarTxPowerLimit) { if (getTelephonyManager().isOffhook()) { sendMessage(CMD_SELECT_TX_POWER_SCENARIO, WifiNative.TX_POWER_SCENARIO_VOICE_CALL); } else { sendMessage(CMD_SELECT_TX_POWER_SCENARIO, WifiNative.TX_POWER_SCENARIO_NORMAL); } } // initialize network state setNetworkDetailedState(DetailedState.DISCONNECTED); // Disable legacy multicast filtering, which on some chipsets defaults to enabled. // Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6 // provisioning. Legacy IPv4 multicast filtering may be re-enabled later via // IpClient.Callback.setFallbackMulticastFilter() mWifiNative.stopFilteringMulticastV4Packets(); mWifiNative.stopFilteringMulticastV6Packets(); if (mOperationalMode == SCAN_ONLY_MODE || mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { mWifiNative.disconnect(); setWifiState(WIFI_STATE_DISABLED); transitionTo(mScanModeState); } else if (mOperationalMode == CONNECT_MODE) { setWifiState(WIFI_STATE_ENABLING); // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin transitionTo(mDisconnectedState); } else if (mOperationalMode == DISABLED_MODE) { transitionTo(mSupplicantStoppingState); } // Set the right suspend mode settings mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()); mWifiNative.setPowerSave(true); if (mP2pSupported) { if (mOperationalMode == CONNECT_MODE) { p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P); } else { // P2P state machine 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); // Disable wpa_supplicant from auto reconnecting. mWifiNative.enableStaAutoReconnect(false); // STA has higher priority over P2P mWifiNative.setConcurrencyPriority(true); }
由于之前启动WiFi的时候设置操作模式为CONNECT_MODE,所以会走这边
} else if (mOperationalMode == CONNECT_MODE) { setWifiState(WIFI_STATE_ENABLING); // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin transitionTo(mDisconnectedState); }
private void setWifiState(int wifiState) { final int previousWifiState = mWifiState.get(); try { if (wifiState == WIFI_STATE_ENABLED) { mBatteryStats.noteWifiOn(); } else if (wifiState == WIFI_STATE_DISABLED) { mBatteryStats.noteWifiOff(); } } catch (RemoteException e) { loge("Failed to note battery stats in wifi"); } mWifiState.set(wifiState); if (mVerboseLoggingEnabled) log("setWifiState: " + syncGetWifiStateByName()); 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, wifiState); intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); }
这边的setWifiState会修改wifi state状态为WIFI_STATE_ENABLING并发出广播通知各个App更新状态,表示WiFi正在打开,之后会切换到DisconnectedState状态。
2.4 DisconnectedState(ConnectModeState)
这里先提下DisconnectedState的父状态是ConnectModeState
addState(mDisconnectedState, mConnectModeState);
所以会先调用ConnectModeState的enter方法
class ConnectModeState extends State { @Override public void enter() { if (!mWifiNative.removeAllNetworks()) { loge("Failed to remove networks on entering connect mode"); } mWifiInfo.reset(); mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED); // Let the system know that wifi is available in client mode. setWifiState(WIFI_STATE_ENABLED); mNetworkInfo.setIsAvailable(true); if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); // initialize network state setNetworkDetailedState(DetailedState.DISCONNECTED); // Inform WifiConnectivityManager that Wifi is enabled mWifiConnectivityManager.setWifiEnabled(true); // Inform metrics that Wifi is Enabled (but not yet connected) mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED); // Inform p2p service that wifi is up and ready when applicable p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P); }
看到setWifiState(WIFI_STATE_ENABLED);表示WiFi状态被设为已打开状态并通知给各app,这时候设置收到这个广播自然就刷新开关状态为开啦,其实梳理到这边就结束了。
之后进入DisconnectedState的enter方法
class DisconnectedState extends State { @Override public void enter() { Log.i(TAG, "disconnectedstate enter"); // We dont scan frequently if this is a temporary disconnect // due to p2p if (mTemporarilyDisconnectWifi) { p2pSendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); return; } if (mVerboseLoggingEnabled) { logd(" Enter DisconnectedState screenOn=" + mScreenOn); } /** clear the roaming state, if we were roaming, we failed */ mIsAutoRoaming = false; mWifiConnectivityManager.handleConnectionStateChanged( WifiConnectivityManager.WIFI_STATE_DISCONNECTED); /** * 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() && mWifiConfigManager.getSavedNetworks().size() == 0) { sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, ++mPeriodicScanToken, 0), mNoNetworksPeriodicScan); } mDisconnectedTimeStamp = mClock.getWallClockMillis(); mWifiStateTracker.updateState(WifiStateTracker.DISCONNECTED); }
3.总结
灵魂画师
转载地址:https://jiatai.blog.csdn.net/article/details/82263373 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!