文章目录

  • Android Framework wifi扫描
  • Android R wifi扫描场景(包含客制化项)
    • 亮屏情况下,在 WifiSetting 界面
    • 亮屏情况下,在非 WifiSettings 界面
    • 灭屏情况下
    • 无保存网络情况下,固定扫描

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

Android R Framework wifi扫描场景总结相关推荐

  1. Android开发之 Wifi扫描分析

    使用 开始wifi扫描的代码很简单: val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager v ...

  2. android R 修改wifi信号强度

    遇到的坑:之前都是通过java代码来判断wifi的信号强度的,但是现在修改完成后,验证没有生效: frameworks/base/wifi/java/android/net/wifi/WifiMana ...

  3. (Android开发)WiFi扫描列表有多个相同SSID的热点过滤

    在WiFi开发中,使用getScanResults()方法获取扫描到的WiFi列表时,列表中会出现多个SSID相同,BSSID最后4位不相同的热点,而且两个都能连接.参照系统WiFi过滤机制,这里实现 ...

  4. Android wifi扫描机制(Android O)

    版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/h784707460/article/details/79658950,未经博主允许不得转载. 一. Android ...

  5. Android-O wifi扫描机制及功耗优化

    一. Android O wifi扫描场景 Android O上的wifi扫面场景可以归结为以下四种: 1. 亮屏情况下,在Wifi settings界面,固定扫描,时间间隔为10s. 2. 亮屏情况 ...

  6. android p wifi一直在扫描_(一百六十八)Android P wifi 扫描失败结果上报流程梳理-扫描上报梳理②...

    接(一百五十五)Android P wifi 扫描失败结果上报流程梳理-扫描上报梳理 扫描失败上报梳理发现梳理的差了很多,特补充 1.WificondScannerImpl @Override pub ...

  7. Android中Wi-Fi扫描、连接和信息(一)

    1.Wi-Fi介绍 Wi-Fi是一种允许电子设备连接到一个无线局域网(WLAN)的技术,通常使用2.4G UHF或5G SHF ISM 射频频段.连接到无线局域网通常是有密码保护的:但也可是开放的,这 ...

  8. android wifi 扫描频率,Android WIFI扫描时延

    希望大家能够给个评论,支持下新人,感激不尽. 本文第一篇CSDN博客,欢迎大家关注,如有错误,欢迎批评指正. 本人在做WIFI室内定位时发现Android扫描WIFI的时延不小.在此先附上我扫描wif ...

  9. Android R WiFi热点流程浅析

    Android R WiFi热点流程浅析 Android上的WiFi SoftAp功能是用户常用的功能之一,它能让我们分享手机的网络给其他设备使用. 那Android系统是如何实现SoftAp的呢,这 ...

最新文章

  1. UBUNTU下SUBLIME TEXT3的安装+破解+汉化+中文输入
  2. 在CentOS上安装Java环境—openjdk1.7 解决https配置问题
  3. wamp 安装monggo扩展
  4. android ndk 界面开发教程,Android NDK开发之入门教程
  5. [How TO]-如何编写Linux kernel documentation
  6. 深度学习入门初步——MNIST数据格式如何使用
  7. fullcalendar v5.3.2 日历插件+LayerUi弹窗,实现自定义HTML表格
  8. [react] 怎么防止HTML被转义?
  9. python 判断是否有余数_判断多个坐标是否在同一条直线上|Python练习系列[13]
  10. windows10使用VMvare Pro开启虚拟机提示与Device/Credential Guard不兼容
  11. Spark修炼之道(进阶篇)——Spark入门到精通:第八节 Spark SQL与DataFrame(一)
  12. pssh Oracle,服务器批量执行工具 PSSH
  13. easyui中动态使datebox、combobox为只读状态
  14. 一道『easy』等级的力扣题,我写了两个小时的笔记...
  15. 人工智能被拒绝,语音识别做不到给电视直播加字幕?
  16. 双眼融合训练一个月_视觉融合功能的四种训练方法
  17. 实名认证失败_身份证在国政通进行实名认证失败怎么办?
  18. 机房综合布线施工主要是几个方面
  19. 神马!看电子书,会让记忆力衰退!
  20. Error: [$injector:unpr] AngularJS 注入报错

热门文章

  1. 模电笔记 基本运算电路
  2. 个人开发者如何进行广告变现
  3. 引流脚本有用吗,日引流上千粉的引流脚本是怎么回事
  4. 在Linux下高仿win7桌面,在桌面系统领域 - Windows 7完全可以干掉Linux
  5. linux系统的开发版连接wifi密码,Linux操作系统下连接闪讯的方法(支持有线与无线)...
  6. struts2.x自定义类型转换
  7. 百年携手 砥砺创新 —— 绿色巨人西门子的科技创新与实践之路
  8. 激活工银亚洲账号(收到开通成功通知短信以后,汇款到“港元储蓄”子账号)
  9. jieba+wordcloud 分词+词频可视化 问题总结
  10. 读书笔记《Outlier Analysis》 第二章 异常检测的概率和统计模型