Android Q WiFi 启动流程分析二
ClientModeImpl 状态机分析
ClientModeImpl 是ClientMode的状态机,是用于控制WiFi 连接,获取IP ,设置网络配置。上一篇我们说到启动后,发送消息使得ClientModeImpl 状态机切换到DisconnectedState 状态;调用DisconnectedState enter 方法;enter主要是调用 WifiConnectivityManager
的handleConnectionStateChanged 方法处理WiFi 网络状态的改变。
public void enter() {
Log.i(TAG, "disconnectedstate enter");
// We don't 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;
mIpReachabilityMonitorActive = false;
removeMessages(CMD_IP_REACHABILITY_SESSION_END);
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
}
WifiConnectivityManager WiFi 网络连接管理类
WifiConnectivityManager 是管理WiFi 连接管理的类,主要管理者WiFi 网络的评分及网络选择,和扫描。handleConnectionStateChanged 实现如下,在上文中我们知道,传进来的参数为 WifiConnectivityManager.WIFI_STATE_DISCONNECTED ,所以我们调用startConnectivityScan(SCAN_IMMEDIATELY) 触发一次快速的连接扫描。
public void handleConnectionStateChanged(int state) {
localLog("handleConnectionStateChanged: state=" + stateToString(state));
mWifiState = state;
// Reset BSSID of last connection attempt and kick off
// the watchdog timer if entering disconnected state.
if (mWifiState == WIFI_STATE_DISCONNECTED) {
mLastConnectionAttemptBssid = null;
startConnectivityScan(SCAN_IMMEDIATELY);
} else {
startConnectivityScan(SCAN_ON_SCHEDULE);
}
}
startConnectivityScan(SCAN_IMMEDIATELY) 方法的实现如下,SCAN_IMMEDIATELY 参数定义是true,首先判断当前WiFi的状态,如果WiFi 不是Enable 状态则退出。然后停止之前的连接扫描,根据当前屏幕的状态;如果是亮屏状态,则启动周期性的扫描,如果是灭屏状态则启动PNO 扫描(背景扫描)
private void startConnectivityScan(boolean scanImmediately) {
localLog("startConnectivityScan: screenOn=" + mScreenOn
+ " wifiState=" + stateToString(mWifiState)
+ " scanImmediately=" + scanImmediately
+ " wifiEnabled=" + mWifiEnabled
+ " wifiConnectivityManagerEnabled="
+ mWifiConnectivityManagerEnabled);
if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
return;
}
// Always stop outstanding connecivity scan if there is any
stopConnectivityScan();
// Don't start a connectivity scan while Wifi is in the transition
// between connected and disconnected states.
if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) {
return;
}
if (mScreenOn) {
startPeriodicScan(scanImmediately);
}
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED && !mPnoScanStarted) {
startDisconnectedPnoScan();
}
}
}
我们先看周期性的扫描startPeriodicScan 设置周期扫描的周期为PERIODIC_SCAN_INTERVAL_MS ;PERIODIC_SCAN_INTERVAL_MS 为20s ,调用startPeriodicSingleScan
// Start a periodic scan when screen is on
private void startPeriodicScan(boolean scanImmediately) {
mPnoScanListener.resetLowRssiNetworkRetryDelay();
// No connectivity scan if auto roaming is disabled.
if (mWifiState == WIFI_STATE_CONNECTED && !mEnableAutoJoinWhenAssociated) {
return;
}
// Due to b/28020168, timer based single scan will be scheduled
// to provide periodic scan in an exponential backoff fashion.
if (scanImmediately) {
resetLastPeriodicSingleScanTimeStamp();
}
mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
startPeriodicSingleScan();
}
startPeriodicSingleScan 实现如下,
由于是第一次打开WiFi ,所以mWifiState 为WIFI_STATE_DISCONNECTED ,所以isScanNeeded 和isFullBandScan 都为true;更新最后单次扫描的时间,启动单次扫描。更新扫描的周期,以2的指数增加,最大160s;然后在启动定时器,时间到了再触发一次扫描
// Start a single scan and set up the interval for next single scan.
private void startPeriodicSingleScan() {
long currentTimeStamp = mClock.getElapsedSinceBootMillis();
if (mLastPeriodicSingleScanTimeStamp != RESET_TIME_STAMP) {
long msSinceLastScan = currentTimeStamp - mLastPeriodicSingleScanTimeStamp;
if (msSinceLastScan < PERIODIC_SCAN_INTERVAL_MS) {
localLog("Last periodic single scan started " + msSinceLastScan
+ "ms ago, defer this new scan request.");
schedulePeriodicScanTimer(PERIODIC_SCAN_INTERVAL_MS - (int) msSinceLastScan);
return;
}
}
boolean isScanNeeded = true;
boolean isFullBandScan = true;
boolean isTrafficOverThreshold = mWifiInfo.txSuccessRate > mFullScanMaxTxRate
|| mWifiInfo.rxSuccessRate > mFullScanMaxRxRate;
// If the WiFi traffic is heavy, only partial scan is proposed.
if (mWifiState == WIFI_STATE_CONNECTED && isTrafficOverThreshold) {
// If only partial scan is proposed and firmware roaming control is supported,
// we will not issue any scan because firmware roaming will take care of
// intra-SSID roam.
if (mConnectivityHelper.isFirmwareRoamingSupported()) {
localLog("No partial scan because firmware roaming is supported.");
isScanNeeded = false;
} else {
localLog("No full band scan due to ongoing traffic");
isFullBandScan = false;
}
}
if (isScanNeeded) {
mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
// Set up the next scan interval in an exponential backoff fashion.
mPeriodicSingleScanInterval *= 2;
if (mPeriodicSingleScanInterval > MAX_PERIODIC_SCAN_INTERVAL_MS) {
mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;
}
} else {
// Since we already skipped this scan, keep the same scan interval for next scan.
schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
}
}
startSingleScan 方法实现构造一个ScanSettings 对象,然后调用Scanner 去触发一次扫描,扫描完成后会返回一个扫描结果。在得到扫描结果的时候会回调之前注册到wifiscanserver 的函数来处理扫描结果。
// Start a single scan
private void startSingleScan(boolean isFullBandScan, WorkSource workSource) {
if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) {
return;
}
// Any scans will impact wifi performance including WFD performance,
// So at least ignore scans triggered internally by ConnectivityManager
// when WFD session is active. We still allow connectivity scans initiated
// by other work source.
if (WIFI_WORK_SOURCE.equals(workSource) &&
(mMiracastMode == WifiP2pManager.MIRACAST_SOURCE ||
mMiracastMode == WifiP2pManager.MIRACAST_SINK)) {
Log.d(TAG,"ignore connectivity scan, MiracastMode:" + mMiracastMode);
return;
}
mPnoScanListener.resetLowRssiNetworkRetryDelay();
ScanSettings settings = new ScanSettings();
if (!isFullBandScan) {
if (!setScanChannels(settings)) {
isFullBandScan = true;
}
}
settings.type = WifiScanner.TYPE_HIGH_ACCURACY; // always do high accuracy scans.
settings.band = getScanBand(isFullBandScan);
settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
settings.numBssidsPerScan = 0;
// retrieve the list of hidden network SSIDs from saved network to scan for
List<ScanSettings.HiddenNetwork> hiddenNetworkList =
new ArrayList<>(mConfigManager.retrieveHiddenNetworkList());
// retrieve the list of hidden network SSIDs from Network suggestion to scan for
hiddenNetworkList.addAll(
mWifiInjector.getWifiNetworkSuggestionsManager().retrieveHiddenNetworkList());
settings.hiddenNetworks =
hiddenNetworkList.toArray(new ScanSettings.HiddenNetwork[0]);
SingleScanListener singleScanListener =
new SingleScanListener(isFullBandScan);
mScanner.startScan(settings, singleScanListener, workSource);
mWifiMetrics.incrementConnectivityOneshotScanCount();
}
当扫描结束,wifiscanserver 获取到扫描结果会回调WifiConnectivityManager 的handleScanResults 方法来处理扫描结果,首先调用selectNetwork 对各类WiFi 网络进行评分,选择出最好的WiFi 网络,然后调用connectToNetwork 来连接该网络
* Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
* Executes selection of potential network candidates, initiation of connection attempt to that
* network.
*
* @return true - if a candidate is selected by WifiNetworkSelector
* false - if no candidate is selected by WifiNetworkSelector
*/
private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {
// Check if any blacklisted BSSIDs can be freed.
refreshBssidBlacklist();
if (mStateMachine.isSupplicantTransientState()) {
localLog(listenerName
+ " onResults: No network selection because supplicantTransientState is "
+ mStateMachine.isSupplicantTransientState());
return false;
}
localLog(listenerName + " onResults: start network selection");
List<ScanDetail> filteredScans = mStateMachine.qtiGetFilteredScan(scanDetails);
WifiConfiguration candidate =
mNetworkSelector.selectNetwork(filteredScans, buildBssidBlacklist(), mWifiInfo,
mStateMachine.isConnected(), mStateMachine.isDisconnected(),
mUntrustedConnectionAllowed);
mWifiLastResortWatchdog.updateAvailableNetworks(
mNetworkSelector.getConnectableScanDetails());
mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {
localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED) {
mOpenNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
if (mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()) {
mCarrierNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForCarrierUnsavedNetworks(
mCarrierNetworkConfig));
}
}
return false;
}
}