文章目录
Android Framework wifi扫描
当打开wifi时、进入wifi settings时、亮屏时、灭屏时、连接状态变化时,都会触发扫描
以下场景1/2/4中的扫描是全信道扫描,扫描控制逻辑在Android framework,涉及模块依次是WifiTracker、WifiConnectivityManager、WifiStateMachine
场景3中的扫描是PNO扫描,即只扫描已保存的网络,PNO扫描的控制逻辑涉及较广,从上到下:WifiConnectivityManager、WifiScanner、WifiScanningServiceImpl、WifiNative、wificond、wifi driver、firmware
Android R wifi扫描场景(包含客制化项)
代码只展示关键部分
亮屏情况下,在 WifiSetting 界面
固定扫描,时间间隔为 10s
注意,进入 WifiSettings 界面是一定会扫描的!
验证手段可见 adb logcat -s WifiService startScan uid = 1000
/* WifiSettings2.java */
// Interval between initiating WifiPickerTracker scans
private static final long SCAN_INTERVAL_MILLIS = 10_000;
mWifiPickerTracker = new WifiPickerTracker(getSettingsLifecycle(), mAppContext == null?context:mAppContext,
mAppContext.getSystemService(WifiManager.class),
mAppContext.getSystemService(ConnectivityManager.class),
mAppContext.getSystemService(NetworkScoreManager.class),
new Handler(Looper.getMainLooper()),
mWorkerThread.getThreadHandler(),
elapsedRealtimeClock,
MAX_SCAN_AGE_MILLIS,
SCAN_INTERVAL_MILLIS,
this);
/* WifiPickerTracker.java */
public class WifiPickerTracker extends BaseWifiTracker
WifiPickerTracker Constructor
/* BaseWifiTracker.java */
BaseWifiTracker Constructor
mScanIntervalMillis = scanIntervalMillis;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 监听wifi打开事件
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
mScanner.start();
} else {
mScanner.stop();
}
}
}
}
private class Scanner extends Handler {
private static final int SCAN_RETRY_TIMES = 3;
private void start() {
postScan();
}
private void postScan() {
if (mWifiManager.startScan()) {
mRetry = 0;
} else if (++mRetry >= SCAN_RETRY_TIMES) {
mRetry = 0;
return;
}
postDelayed(this::postScan, mScanIntervalMillis);
}
}
亮屏情况下,在非 WifiSettings 界面
分以下几种情形:
-
已连接,且满足以下条件之一,就不进行扫描
- 通过 sufficiency check,主要是信号值的检查,2.4G -73dBm, 5G -70dBm
- 网络状态好
- 有活跃的数据流
-
已连接,但不满足上述条件的任意一个,进行配置的全频段扫描
- 前3min,5s扫描一次
- 3 ~ 10min,10s扫描一次
- 10min后,20s,而后二进制指数退避,即 20-40-80-160
/* WifiConnectivityManager.java */
private static final boolean SCAN_ON_SCHEDULE = false;
private static final int QUICK_SCAN_TIME = 3 * 60 * 1000;
public static final int QUICK_PERIODIC_SCAN_INTERVAL_MS = 5 * 1000;
private static final int QUICK_SCAN_TIME_LONG = 10 * 60 * 1000;
private static final int QUICK_PERIODIC_SCAN_INTERVAL_MS_LONG = 10 * 1000;
public void handleScreenStateChanged(boolean screenOn){
mScreenOn = screenOn;
if(mScreenOn){
mScreenOnTimeStamp = mClock.getElapsedSinceBootMillis();
}
startConnectivityScan(SCAN_ON_SCHEDULE);
}
private void startConnectivityScan(boolean scanImmediately) {
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)
|| (getSingleScanningSchedule() == null)) {
return;
}
if (mScreenOn) {
//此处 scanImmediately 为 false,表明不是立即扫描
startPeriodicScan(scanImmediately);
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED && !mPnoScanStarted) {
startDisconnectedPnoScan();
}
}
}
// Start a periodic scan when screen is on
private void startPeriodicScan(boolean scanImmediately) {
if (scanImmediately) {
resetLastPeriodicSingleScanTimeStamp();
}
mCurrentSingleScanScheduleIndex = 0;
startPeriodicSingleScan();
}
// 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 < getScheduledSingleScanIntervalMs(0)) {
localLog("Last periodic single scan started " + msSinceLastScan
+ "ms ago, defer this new scan request.");
schedulePeriodicScanTimer(
getScheduledSingleScanIntervalMs(0) - (int) msSinceLastScan);
return;
}
}
boolean isScanNeeded = true;
boolean isFullBandScan = true;
// Check it is one of following conditions to skip scan (with firmware roaming)
// or do partial scan only (without firmware roaming).
// 1) Network is sufficient
// 2) link is good, internet status is acceptable
// and it is a short time since last network selection
// 3) There is active stream such that scan will be likely disruptive
if (mWifiState == WIFI_STATE_CONNECTED
&& (mNetworkSelector.isNetworkSufficient(mWifiInfo)
|| isGoodLinkAndAcceptableInternetAndShortTimeSinceLastNetworkSelection
|| mNetworkSelector.hasActiveStream(mWifiInfo))) {
// 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.
// 此处返回 true,将 isScanNeeded 置为 false
if (mConnectivityHelper.isFirmwareRoamingSupported()) {
localLog("No partial scan because firmware roaming is supported.");
isScanNeeded = false;
} else {
localLog("No full band scan because current network is sufficient");
isFullBandScan = false;
}
}
if (isScanNeeded) {
mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
if (mWifiState == WIFI_STATE_DISCONNECTED
&& mInitialScanState == INITIAL_SCAN_STATE_START) {
startSingleScan(false, WIFI_WORK_SOURCE);
return;
}
startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
schedulePeriodicScanTimer(
getScheduledSingleScanIntervalMs(mCurrentSingleScanScheduleIndex));
// Set up the next scan interval in an exponential backoff fashion.
mCurrentSingleScanScheduleIndex++;
} else {
// Since we already skipped this scan, keep the same scan interval for next scan.
schedulePeriodicScanTimer(
getScheduledSingleScanIntervalMs(mCurrentSingleScanScheduleIndex));
}
}
// Retrieve a value from single scanning schedule in ms
private int getScheduledSingleScanIntervalMs(int index) {
synchronized (mLock) {
long currentTimeStamp = mClock.getElapsedSinceBootMillis();
boolean qucikScanProcess = (currentTimeStamp - mScreenOnTimeStamp) < QUICK_SCAN_TIME
|| (currentTimeStamp - mDisconnectTimeStamp) < QUICK_SCAN_TIME;
boolean qucikScanProcessSecond = (currentTimeStamp - mScreenOnTimeStamp) < QUICK_SCAN_TIME_LONG
|| (currentTimeStamp - mDisconnectTimeStamp) < QUICK_SCAN_TIME_LONG;
if(qucikScanProcess){
mCurrentSingleScanScheduleIndex = 0;
return QUICK_PERIODIC_SCAN_INTERVAL_MS;
}else if(qucikScanProcessSecond){
mCurrentSingleScanScheduleIndex = 0;
return QUICK_PERIODIC_SCAN_INTERVAL_MS_LONG;
}
if (mCurrentSingleScanScheduleSec == null) {
Log.e(TAG, "Invalid attempt to get schedule interval, Schedule array is null ");
// Use a default value
return DEFAULT_SCANNING_SCHEDULE_SEC[0] * 1000;
}
if (index >= mCurrentSingleScanScheduleSec.length) {
index = mCurrentSingleScanScheduleSec.length - 1;
}
return mCurrentSingleScanScheduleSec[index] * 1000;
}
}
灭屏情况下
-
有连接,不扫描
-
无连接,又分以下情形
- 没有保存网络,不扫描
- 有保存网络,根据设备移动状态来决定扫描间隔,20s或者60s
// Start a DisconnectedPNO scan when screen is off and Wifi is disconnected
private void startDisconnectedPnoScan() {
PnoSettings pnoSettings = new PnoSettings();
List<PnoSettings.PnoNetwork> pnoNetworkList = retrievePnoNetworkList();
int listSize = pnoNetworkList.size();
if (listSize == 0) {
return;
}
pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize];
pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList);
pnoSettings.min6GHzRssi = mScoringParams.getEntryRssi(ScanResult.BAND_6_GHZ_START_FREQ_MHZ);
pnoSettings.min5GHzRssi = mScoringParams.getEntryRssi(ScanResult.BAND_5_GHZ_START_FREQ_MHZ);
pnoSettings.min24GHzRssi = mScoringParams.getEntryRssi(
ScanResult.BAND_24_GHZ_START_FREQ_MHZ);
// Initialize scan settings
ScanSettings scanSettings = new ScanSettings();
scanSettings.band = getScanBand();
scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
scanSettings.numBssidsPerScan = 0;
scanSettings.periodInMs = deviceMobilityStateToPnoScanIntervalMs(mDeviceMobilityState);
mPnoScanListener.clearScanDetails();
mScanner.startDisconnectedPnoScan(
scanSettings, pnoSettings, new HandlerExecutor(mEventHandler), mPnoScanListener);
mPnoScanStarted = true;
}
private int deviceMobilityStateToPnoScanIntervalMs(@DeviceMobilityState int state) {
switch (state) {
case WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN:
case WifiManager.DEVICE_MOBILITY_STATE_LOW_MVMT:
case WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT:
return mContext.getResources()
.getInteger(R.integer.config_wifiMovingPnoScanIntervalMillis);
case WifiManager.DEVICE_MOBILITY_STATE_STATIONARY:
return mContext.getResources()
.getInteger(R.integer.config_wifiStationaryPnoScanIntervalMillis);
default:
return -1;
}
}
无保存网络情况下,固定扫描
间隔为5分钟,用于通知用户周围存在可用开放网络
这部分代码没看过,不确定是不是这样