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>
相关推荐
大白要努力!7 分钟前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟1 小时前
Android音频采集
android·音视频
小白也想学C2 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程2 小时前
初级数据结构——树
android·java·数据结构
闲暇部落4 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX6 小时前
Android 分区相关介绍
android
大白要努力!7 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee7 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood8 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-11 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记