Android Wi-Fi扫描机制(Android P)

本文详细解析了AndroidP系统下WiFi扫描的四种核心场景,包括亮屏与灭屏状态下不同界面的扫描策略,以及针对有无保存网络的特定扫描间隔设定。深入探讨了系统内部的实现机制,如二进制指数退避扫描、PNO扫描流程等。

Android P的扫描场景可以归结为以下四种:

1、 亮屏情况下,在Wifi settings界面,固定扫描,时间间隔为10s。
2、 亮屏情况下,非Wifi settings界面,二进制指数退避扫描,退避:interval*(2^n), 最小间隔min=20s, 最大间隔max=160s.
3、 灭屏情况下,有保存网络时,若已连接,不扫描,否则,PNO扫描,即只扫描已保存的网络。最小间隔min=20s,最大间隔max=20s*3=60s
4、 无保存网络情况下,固定扫描,间隔为5分钟,用于通知用户周围存在可用开放网络。

正常扫描流程可以看我之前写的: wifi扫描流程梳理

1、 亮屏情况下,在Wifi settings界面,固定扫描,时间间隔为10s。
wifi扫描流程梳理 可以看到wifi扫描流程会走到WifiTracker的handleMessage函数中,我们看sendEmptyMessageDelayed,会发送一条扫描的信息,其中包含了WIFI_RESCAN_INTERVAL_MS,WIFI_RESCAN_INTERVAL_MS就是默认的扫描周期,可以看到系统设置的默认周期是10 * 1000,也就是10秒。

WifiTracker.java

private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
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

Android P Wi-Fi PNO扫描流程

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>

关注公众号,获取更多开发必备知识
在这里插入图片描述

<think>好的,我需要回答用户关于Android系统中WiFi扫描类型的问题。首先,根据用户提供的引用内容,特别是引用[1]中的代码片段,提到了`setScanningEnabled`方法,这说明系统中有开启或关闭扫描的机制。接下来,我需要回忆Android开发文档中的相关内容,结合现有的知识来组织回答。 Android系统中的WiFi扫描类型主要分为主动扫描和被动扫描。主动扫描是指设备主动发送探测请求来搜索附近的网络,而被动扫描则是监听信道上AP发送的信标帧。此外,系统还可能支持后台扫描,这在引用[1]和[2]提到的框架代码中可能有所体现,特别是`WifiScanner`类和相关的服务实现。 需要注意的是,用户提供的引用中提到了`WifiScanner`和相关的服务代码路径,这可能涉及到系统API和权限控制,比如`NETWORK_STACK`权限,这在回答中需要适当提及,但不需要深入代码细节。同时,用户可能还关心这些扫描类型的使用场景和限制,例如耗电问题或权限要求。 在组织回答时,应按照系统级指令的要求,使用中文,正确应用LaTeX格式,并生成相关问题。同时,引用用户提供的参考资料,如引用[1]、[2]、[3],但需要自然地在相关内容后添加标识。例如,在讨论后台扫描时,引用[1]中的`setScanningEnabled`方法可以作为支持点。 最后,生成的相关问题需要与主题紧密相关,帮助用户进一步探索,例如扫描优化、耗电分析或API使用权限等。确保问题具有针对性,并且覆盖用户可能感兴趣的方面。</think>Android系统中的WiFi扫描类型主要通过`WifiManager`和`WifiScanner`类实现[^1][^2],主要分为以下三类: 1. **主动扫描(Active Scan)** 设备主动发送探测请求帧(Probe Request),接收接入点(AP)返回的探测响应帧。该模式扫描速度快,但会增加功耗。对应的API调用例如: ```java wifiManager.startScan() ``` 2. **被动扫描(Passive Scan)** 仅监听AP周期性发送的信标帧(Beacon Frame),无需主动发送信号,适用于低功耗场景。例如在WiFi休眠策略中会使用此类扫描[^2]。 3. **后台扫描(Background Scan)** 系统根据预设策略自动执行扫描,例如通过`WifiScanner`配置扫描间隔: ```java WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings(); settings.type = WifiScanner.TYPE_LOW_LATENCY; //低延迟扫描类型 mWifiScanner.startScan(settings, ...); ``` 此类扫描需系统权限`NETWORK_STACK`,常用于定位服务或网络质量优化。 $$ \text{扫描频率选择公式:} \quad f = \frac{1}{T_{\text{interval}}} \times N_{\text{channels}} $$ 其中$T_{\text{interval}}$为扫描间隔,$N_{\text{channels}}$为信道数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值