欢迎大家一起学习探讨通信之WLAN。本节我们讨论关于Android设备的WiFi Background 扫描机制。通过使用WiFi设备的经验可知。WiFi设备连接上WiFi网络,必要条件是需要扫描到目标网络。我们在使用Android设备时,设备不处于WiFi设置界面时,移动到已保存的WiFi网络覆盖范围内,设备会自动连接上网络。细心的使用者,可能已发现,有时设备很短时间内就连接上已保存网络,有时设备需要过几分钟才能连接上已保存网络。当不处于WiFi设置界面时,WiFi自动连接功能主要依赖BG Scan机制。这里我们主要探讨下Android 9.0 WiFi BG Scan机制背后代码实现的故事。

好。我们先看下打开WiFi相关状态初始化流程。Android 框架中维护了一个WiFi状态机(WiFiStateMachine),当用户点击打开WiFi按钮后,状态机最终要停留到DisconnectedState状态。在状态转变期间,状态机需经过ConnectModeState节点,在该状态的enter()中,调用setupClientMode(),启动一些client mode相关服务和获取其相关状态。在setupClientMode()方法中初始化了WifiConnectivityManager对象,为WiFi BG Scan奠定了基础。

framework/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
class ConnectModeState extends State {public void enter() {setupClientMode();  //设置client Mode,即WiFi Station}
}
private void setupClientMode() {if (mWifiConnectivityManager == null) {synchronized (mWifiReqCountLock) {//创建注册WifiConnectivityManager对象mWifiConnectivityManager =mWifiInjector.makeWifiConnectivityManager(mWifiInfo,hasConnectionRequests());mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0);mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);}}
}framework/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java
public WifiConnectivityManager makeWifiConnectivityManager(WifiInfo wifiInfo,boolean hasConnectionRequests) {return new WifiConnectivityManager(mContext, getScoringParams(),mWifiStateMachine, getWifiScanner(),mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper,mWifiLastResortWatchdog, mOpenNetworkNotifier, mCarrierNetworkNotifier,mCarrierNetworkConfig, mWifiMetrics, mWifiStateMachineHandlerThread.getLooper(),mClock, mConnectivityLocalLog, hasConnectionRequests, mFrameworkFacade,mSavedNetworkEvaluator, mScoredNetworkEvaluator, mPasspointNetworkEvaluator);
}

经过状态机多次转移,终于来到了DisconnectedState状态。Android状态机有个特性:状态机要进入某个状态,必须先进入其enter();要退出某个状态,必须执行状态的exit()。在进入DisconnectedState状态时,触发了WiFi BG Scan 的流程。进入到WifiConnectivityManager这个类中,将BG Scan周期扫描逻辑的真正实现。

framework/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
class DisconnectedState extends State {@Override//DisconnectedState 状态中调用mWifiConnectivityManager通知WiFi状态变化。public void enter() {mWifiConnectivityManager.handleConnectionStateChanged(WifiConnectivityManager.WIFI_STATE_DISCONNECTED);}
}
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
public void handleConnectionStateChanged(int state) {if (mWifiState == WIFI_STATE_DISCONNECTED) {mLastConnectionAttemptBssid = null;scheduleWatchdogTimer();startConnectivityScan(SCAN_IMMEDIATELY);//开始WiFi扫描}
}
private void startConnectivityScan(boolean scanImmediately) {if (mScreenOn) {startPeriodicScan(scanImmediately);//亮屏下,执行正常WiFi扫描} else {if (mWifiState == WIFI_STATE_DISCONNECTED && !mPnoScanStarted) {startDisconnectedPnoScan();//熄屏下,执行正常PNO wifi扫描}}
}
private void startPeriodicScan(boolean scanImmediately) {mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;startPeriodicSingleScan(); //开始周期扫描,并赋值mPeriodicSingleScanInterval=20S。
}

到这里,WiFi BG Scan已经进入其机制具体实现中,详细学习下这块代码逻辑的实现,调用逻辑相对还是比较清晰简单。

framework/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
正常扫描,在亮屏状态下进行,从代码中可看到对mScreen的判断。
public static final int PERIODIC_SCAN_INTERVAL_MS = 20 * 1000; // 最小扫描间隔20s
public static final int MAX_PERIODIC_SCAN_INTERVAL_MS = 160 * 1000; //最大扫描间隔160s这里解释下,PNO扫描只扫描已保存的网络,在熄屏状态下执行的。
private static final int DISCONNECTED_PNO_SCAN_INTERVAL_MS = 20 * 1000; // 最小PNO扫描间隔20s
private static final int CONNECTED_PNO_SCAN_INTERVAL_MS = 160 * 1000; // 最大PNO扫描间隔160sprivate int mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;创建Alarm,时间到期执行periodicScanTimerHandler()方法。
private final AlarmManager.OnAlarmListener mPeriodicScanTimerListener =new AlarmManager.OnAlarmListener() {public void onAlarm() {periodicScanTimerHandler();}
};// 设置周期扫描Timer。并将周期扫描标志变量设置mPeriodicScanTimerSet=true。
private void schedulePeriodicScanTimer(int intervalMs) {mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,mClock.getElapsedSinceBootMillis() + intervalMs,PERIODIC_SCAN_TIMER_TAG,mPeriodicScanTimerListener, mEventHandler);mPeriodicScanTimerSet = true;}private void periodicScanTimerHandler() {localLog("periodicScanTimerHandler");//安排下一个定时器,如亮屏,则开始扫描。if (mScreenOn) {startPeriodicSingleScan();}}
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java// 启动扫描并设置下一次扫描的间隔。private void startPeriodicSingleScan() {long currentTimeStamp = mClock.getElapsedSinceBootMillis();如果距上次扫描时间小于20s,在重新设置到时扫描Timer.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) {//判断是否需要执行扫描,//如果为true。在执行扫描,并重新设置周期扫描Timer。//如果为false。则跳过本次扫描,重新设置周期扫描Timer同上次时长。mLastPeriodicSingleScanTimeStamp = currentTimeStamp;startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);schedulePeriodicScanTimer(mPeriodicSingleScanInterval);//以指数回退方式设置下一个扫描间隔。//mPeriodicSingleScanInterval = mPeriodicSingleScanInterval  * 2//单次执行Timer时间为:20S  40S  80S 160S。后续一直保存为160SmPeriodicSingleScanInterval *= 2; if (mPeriodicSingleScanInterval >  MAX_PERIODIC_SCAN_INTERVAL_MS) {mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;}} else {schedulePeriodicScanTimer(mPeriodicSingleScanInterval);}}
具体执行扫描实现如下。调用startSingleScan方法,将扫描动作传递到Scanner中。
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
// Start a single scan
private void startSingleScan(boolean isFullBandScan, WorkSource workSource) {mScanner.startScan(settings, singleScanListener, workSource);
}
./base/wifi/java/android/net/wifi/WifiScanner.java
public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {//通过AsyncChannel发送消息CMD_START_SINGLE_SCAN,给到扫描服务。mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}//扫描服务处理WifiScanner发送的消息
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
class DriverStartedState extends State {public boolean processMessage(Message msg) {case WifiScanner.CMD_START_SINGLE_SCAN:tryToStartNewScan();}
}
void tryToStartNewScan() {if (mScannerImpl.startSingleScan(settings, this)) {}
}framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
public abstract boolean startSingleScan(WifiNative.ScanSettings settings,WifiNative.ScanEventHandler eventHandler);framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
public boolean startSingleScan(WifiNative.ScanSettings settings,WifiNative.ScanEventHandler eventHandler) {success = mWifiNative.scan(mIfaceName, settings.scanType, freqs, hiddenNetworkSSIDSet);
}

WiFiNative下发扫描命令给到WiFiCond,在WiFiCond进程中将消息发送至kernel nl802.11中,最后发送至driver执行WiFi扫描动作。

framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.javapublic boolean scan(@NonNull String ifaceName, int scanType, Set<Integer> freqs,Set<String> hiddenNetworkSSIDs) {return mWificondControl.scan(ifaceName, scanType, freqs, hiddenNetworkSSIDs);}

到此,我们已经分析完了WiFi BG scan的代码实现流程。但WiFiNative->kernel->驱动执行还有比较复杂的调用关系,后续再进行分析梳理。

注:

对以上所述专业知识有修正意见或建议,可随时留言反馈。如感兴趣更多通信知识,可关注“通信之WLAN”微信公众号。

谢谢大家支持~!

Android 9.0 WiFi BG Scan机制相关推荐

  1. (一百九十六)Android Q 学习WiFi的评分机制(三)

    前言:之前在(一百九十六)Android Q 学习WiFi的评分机制(二)梳理了CS对WiFi score变化的处理,主要是rematchAllNetworksAndRequests方法中的处理,其中 ...

  2. Android 8.0 WiFi Ap 热点控制接口

    1. Android 7.0 及其以前的 WiFi 热点接口 /*** Gets the Wi-Fi enabled state.** @return One of {@link #WIFI_AP_S ...

  3. nexus+7+android+5.0++wifi+代理,谷歌Nexus5吃上安卓8.0:除了WiFi全不能正常工作

    原标题:谷歌Nexus5吃上安卓8.0:除了WiFi全不能正常工作 IT之家9月4日消息 谷歌Nexus5发布于2013年10月31日,初始搭载的系统为Android 4.4,2015年12月8日,谷 ...

  4. nexus+7+android+5.0++wifi+代理,二代Nexus 7获Android 5.0.2系统更新

    据外媒Android Police报道,谷歌日前已经正式开始推送Android 5.0.2更新,作为亲儿子的Nexus 7(2013)已经推送,Nexus 10的更新也即将到来 日前,据外媒Andro ...

  5. nexus+7+android+5.0++wifi+代理,谷歌亲儿子Nexus 7和9已尝鲜Android 5.1.1

    此前有消息称谷歌很可能在本周早些时候向Nexus设备推送Android 5.1 Lollipop系统更新,谷歌负责安卓平台的副总裁布尔科(DaveBurke)宣布了推送安卓5.1系统的消息.目前绝大多 ...

  6. android 5.0 wifi移植,android  wifi移植

    手动加载驱动 ####16th,Jul 驱动加载 modprobe libertas modprobe libertas_sdio 加载第二行时出错拉 # modprobe libertas_sdio ...

  7. android 12.0 wifi开关控制功能实现

    1.前言 在12.0的产品rom定制化开发中,在产品开发中,对于功能的开发的功能也是挺多的,而在对于wifi的功能定制需求,有要求需要通过系统属性来控制wifi开关是否可以打开 来控制是否可以连接wi ...

  8. android 11.0 wifi开关控制

    1.概述 在11.0的产品开发中,对于wifi的功能定制需求,有要求需要通过系统属性来控制wifi开关是否可以打开 来控制是否可以连接wifi,打开控制wifi的功能 2.wifi开关控制的核心代码 ...

  9. android 10.0 wifi开关控制

    1.概述 在10.0的系统产品开发中,产品需要对wifi模块进行管控,通过系统属性来控制wifi模块是否启用,所以需要在打开wifi的地方来通过系统属性来控制是否可以打开wifi 2.wifi开关控制 ...

最新文章

  1. KFold、StratifiedKFold、GroupKFold的区别
  2. 1041 Be Unique
  3. VTK:Rendering之Cone4
  4. Index of Oracle
  5. 在centos7上安装Jenkins
  6. 线程事件--day36
  7. 算法设计与分析——递归与分治——归并排序
  8. WPF 学习笔记 路由事件
  9. 制作第一个HTML网页,2制作第一个HTML网页.ppt
  10. yii2 batchInsert批量插入
  11. centos下yum安装lamp
  12. 庆祝自己通过系分考试,分发资料
  13. 关于IIS中Request.ServerVariables(SCRIPT_NAME)的bug
  14. 实习周记---20180519
  15. 手机版kali Linux教程(质量高)
  16. 帮你解决Kali Linux 外接无线网卡显示不出来的问题
  17. 敷衍没有出路,iPhone14同时被热捧和唾弃
  18. 【GDOUCTF2023】wp
  19. 荣耀v40和华为Nova8pro哪个好 华为Nova8pro和荣耀v40的区别
  20. Cluster vs Clustering

热门文章

  1. 全国-百度地图中心点坐标
  2. mybatis insert 插入字段为空解决办法
  3. 思科ccie网络工程师必看网络安全技术详解-ielab实验室
  4. 微信小程序路由的三种方法
  5. 用友u8计算机快捷键,用友软件常用快捷键
  6. 下列sql语句中哪条语句可为用户zhangsan分配数据库userdb表userinfo的查询和插入数据权限
  7. Linux软件太少了,LINUX挺好,可惜应用软件太少
  8. mips平台编译rtl8822cs驱动报错问题
  9. oracle输出查看,ORACLE关于如何是exp导出还是expdp并查看信息
  10. Excel一键导出当前工作表多个区域的所有图片