Android R Framework wifi扫描场景总结

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分钟,用于通知用户周围存在可用开放网络
这部分代码没看过,不确定是不是这样

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要设置WiFi静态模式,您需要在Android 10的framework代码中进行以下步骤: 1. 打开WifiManager.java文件并添加以下代码: ``` /** * Set the IP address, gateway, and subnet mask for a static IP configuration. * * @param ipAddress the IP address in integer form * @param gateway the gateway in integer form * @param subnetMask the subnet mask in integer form * @param dns the DNS server addresses in integer form * @return {@code true} if the operation succeeded, {@code false} otherwise * @hide */ public boolean setWifiStaticIpConfiguration(int ipAddress, int gateway, int subnetMask, int[] dns) { WifiConfiguration config = getCurrentWifiConfiguration(); if (config == null) { return false; } config.setIpAssignment(IpAssignment.STATIC); config.setIpAddress(InetAddress.getByAddress(intToByteArray(ipAddress)).getHostAddress()); config.setGateway(InetAddress.getByAddress(intToByteArray(gateway)).getHostAddress()); config.setNetmask(InetAddress.getByAddress(intToByteArray(subnetMask)).getHostAddress()); config.setDns(dns); return saveWifiConfiguration(config); } private byte[] intToByteArray(int value) { return new byte[] { (byte)(value >>> 24), (byte)(value >>> 16), (byte)(value >>> 8), (byte)value}; } ``` 2. 在WifiConfiguration.java文件中,添加以下代码: ``` /** * Set the IP assignment mode. * * @param ipAssignment the IP assignment mode to set * @hide */ public void setIpAssignment(IpAssignment ipAssignment) { mIpAssignment = ipAssignment; } /** * Set the IP address. * * @param ipAddress the IP address to set * @hide */ public void setIpAddress(String ipAddress) { mIpAddress = ipAddress; } /** * Set the gateway. * * @param gateway the gateway to set * @hide */ public void setGateway(String gateway) { mGateway = gateway; } /** * Set the subnet mask. * * @param netmask the subnet mask to set * @hide */ public void setNetmask(String netmask) { mNetmask = netmask; } /** * Set the DNS server addresses. * * @param dns the DNS server addresses to set * @hide */ public void setDns(int[] dns) { mDnsServers.clear(); for (int i = 0; i < dns.length; i++) { mDnsServers.add(InetAddress.getByAddress(intToByteArray(dns[i]))); } } ``` 3. 最后,在Settings app中添加WiFi的静态IP配置。打开WifiSettings.java文件并添加以下代码: ``` /** * Show the dialog for configuring a static IP address. * * @param config the WifiConfiguration to configure * @hide */ public void showWifiStaticIpConfigDialog(WifiConfiguration config) { StaticIpConfigDialogFragment fragment = StaticIpConfigDialogFragment.newInstance(config); fragment.show(getFragmentManager(), StaticIpConfigDialogFragment.TAG); } ``` 这些代码将允许您在Android 10中设置WiFi的静态IP地址。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值