Android Wifi的扫描机制

Android Wifi 的扫描场景分为下面四种情况:

1.亮屏情况下,在Wifi settings界面,固定扫描,扫描时间为10s。

2.亮屏情况下,在非Wifi settings界面,二进制指数退避扫描,退避:interval*(2^n), 最小间隔min=20s, 最大间隔max=160s.

3.灭屏情况下,有保存网络时,若已连接,不扫描,否则,PNO扫描,即只扫描已保存的网络。最小间隔min=20s,最大间隔max=20s*3=60s。

4.无保存网络情况下,固定扫描,间隔为5分钟,用于通知用户周围存在可用开放网络。

1.亮屏情况下,在Wifi settings界面,固定扫描,扫描时间为10s。

从 wifi扫描流程梳理 可以看到wifi扫描流程会走到WifiTracker的handleMessage函数中,我们看sendEmptyMessageDelayed,会发送一条扫描的信息,其中包含了WIFI_RESCAN_INTERVAL_MS,WIFI_RESCAN_INTERVAL_MS就是默认的扫描周期,可以看到系统设置的默认周期是10 * 1000,也就是10秒。

WifiTracker.java

复制代码
public void handleMessage(Message message) {
            if (message.what != MSG_SCAN) return;
            if (mWifiManager.startScan()) {
                mRetry = 0;
            } else if (++mRetry >= 3) {
                mRetry = 0;
                if (mContext != null) {
                    Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
                }
                return;
            }
            sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
        }

2.亮屏情况下,在非Wifi settings界面,二进制指数退避扫描,退避:interval*(2^n), 最小间隔min=20s, 最大间隔max=160s.

WifiConnectivityManager.java

startConnectivityScan --> startPeriodicScan --> startPeriodicSingleScan

复制代码
private void startConnectivityScan(boolean scanImmediately) {
        
        // Always stop outstanding connecivity scan if there is any
        stopConnectivityScan();

        if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) {
            return;
        }

        if (mScreenOn) {
            startPeriodicScan(scanImmediately);
        } else {
            if (mWifiState == WIFI_STATE_DISCONNECTED && !mPnoScanStarted) {
                startDisconnectedPnoScan();
            }
        }

    }

private void startPeriodicScan(boolean scanImmediately) {
        mPnoScanListener.resetLowRssiNetworkRetryDelay();

        if (scanImmediately) {
            resetLastPeriodicSingleScanTimeStamp();
        }
        mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
        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 < 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;
            }
    ...............
    
        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);
        }
    }

对于扫描间隔的设置

复制代码
    // Periodic scan interval in milli-seconds. This is the scan
    // performed when screen is on.
    public static final int PERIODIC_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds
    // When screen is on and WiFi traffic is heavy, exponential backoff
    // connectivity scans are scheduled. This constant defines the maximum
    // scan interval in this scenario.
    @VisibleForTesting
    public static final int MAX_PERIODIC_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds

3.灭屏情况下,有保存网络时,若已连接,不扫描,否则,PNO扫描,即只扫描已保存的网络。最小间隔min=20s,最大间隔max=20s*3=60s。

待续

4.无保存网络情况下,固定扫描,间隔为5分钟,用于通知用户周围存在可用开放网络。

(注:第四种情况属于Android O的逻辑,因为在P的代码里还没有找到关于这个扫描的代码,也可能取消了)

WifiStateMachine.java

复制代码
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;
        }
        /** 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);
    }

mNoNetworksPeriodicScan = mContext.getResources().getInteger(
                R.integer.config_wifi_no_network_periodic_scan_interval);

/frameworks/base/core/res/res/values/config.xml

mNoNetworksPeriodicScan在config.xml中注册,周期为5分钟。

复制代码
<!-- Integer indicating the framework no networks periodic scan interval in milliseconds. -->
<integer translatable="false" name="config_wifi_no_network_periodic_scan_interval">300000</integer>
相关推荐
技术与健康5 分钟前
【Android代码】绘本翻页时通过AI识别,自动通过手机/pad朗读绘本
android·人工智能·智能手机
Kiri霧2 小时前
Kotlin集合分组
android·java·前端·kotlin
l软件定制开发工作室4 小时前
基于Android的旅游计划App
android
apihz4 小时前
全球天气预报5天(经纬度版)免费API接口教程
android·服务器·开发语言·c#·腾讯云
~央千澈~5 小时前
FastAdmin后台登录地址变更原理与手动修改方法-后台入口机制原理解析-优雅草卓伊凡
android·admin入口机制
你过来啊你6 小时前
Android性能优化之包体积优化
android
你过来啊你6 小时前
Android性能优化之UI渲染优化
android
stringwu6 小时前
Android开发者必备:手势冲突处理实用总结
android