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>
相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui