我是靠谱客的博主 炙热台灯,这篇文章主要介绍Android 9.0 WiFi BG Scan机制,现在分享给大家,希望可以做个参考。

        欢迎大家一起学习探讨通信之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奠定了基础。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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周期扫描逻辑的真正实现。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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已经进入其机制具体实现中,详细学习下这块代码逻辑的实现,调用逻辑相对还是比较清晰简单。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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扫描间隔160s private 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(); } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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。后续一直保存为160S mPeriodicSingleScanInterval *= 2; if (mPeriodicSingleScanInterval > MAX_PERIODIC_SCAN_INTERVAL_MS) { mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS; } } else { schedulePeriodicScanTimer(mPeriodicSingleScanInterval); } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
具体执行扫描实现如下。调用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扫描动作。

复制代码
1
2
3
4
5
6
7
8
9
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java public 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机制的全部内容,更多相关Android内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部