系列文章目录
【安卓Framework学习】Wifi框架学习之核心类
【安卓Framework学习】Wifi框架学习之wifi状态机
【安卓Framework学习】Wifi框架学习之连接与断开流程
【安卓Framework学习】Wifi框架学习之扫描模式及扫描流程.
【安卓Framework学习】Wifi框架学习之开启与关闭流程.
【安卓Framework学习】安卓连接管理(ConnectivityService)之wifi连接及注册.
文章目录
前言
之前分析过wifi框架中的连接断开、开启关闭以及扫描相关的流程,本篇将继续分析wifi框架中隐藏较深的一个机制——热点的评分机制。在安卓wifi框架中,这一套机制实现了对设备周围的热点在一定规则下进行打分,然后根据分数高低决定是否需要连接。由于此机制中包含的规则较多,如有不正确之处望大家及时指出。文中出现的代码大部分基于android11源码。
一、如何触发评分机制
1、回调注册源码分析
接【安卓Framework学习】Wifi框架学习之开启与关闭流程.中wifi开启后ClientModeImpl
会进入到ConnectModeState
中,看看ConnectModeState.enter()
做了啥。
public void enter() {
/*省略部分代码*/
mWifiConnectivityManager.setWifiEnabled(true);
mNetworkFactory.setWifiState(true);
/*省略部分代码*/
}
进入状态的方法中调用了WifiConnectivityManager.setWifiEnabled()
方法,在看其中实现了什么内容。
public void setWifiEnabled(boolean enable) {
/*省略部分代码*/
mWifiEnabled = enable;
updateRunningState();
}
会调用到内部私有方法updateRunningState()
中,这个方法内部较为简单,这里假定是已经设置了需要自动连接的情况下,会继续进入到start()
方法中,如下。
private void start() {
if (mRunning) return;
retrieveWifiScanner();
/*省略部分代码*/
}
在retrieveWifiScanner()
方法中,想服务端注册了回调类WifiConnectivityManager.AllSingleScanListener
。
WifiConnectivityManager.java
private void retrieveWifiScanner() {
/*省略部分代码*/
mScanner.registerScanListener(new HandlerExecutor(mEventHandler), mAllSingleScanListener);
}
WifiScanner.java
public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
@NonNull ScanListener listener) {
/*省略部分代码*/
int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
}
调用了WifiScanner.registerScanListener()
方法,在WifiScanner
中又通过异步通信将回调注册到WifiScanningServiceImpl中
,回调注册就到这结束了。更详细的回调注册和调用在【安卓Framework学习】Wifi框架学习之扫描模式及扫描流程中已经详细说明了,后面开始自动评分也是从回调方法中开始。
2、回调注册流程图
二、wifi评分机制流程
1、评分机制源码分析
由上小结可以看出,在扫描结束后会通过调用注册的AllSingleScanListener
回调类的onResults()
方法,将扫描结果往上传给应用层,AllSingleScanListener.onResults()
方法如下。
public void onResults(WifiScanner.ScanData[] results) {
if (!mWifiEnabled || !mAutoJoinEnabled) {
clearScanDetails();
mWaitForFullBandScanResults = false;
return;
}
/*省略部分代码*/
boolean wasConnectAttempted = handleScanResults(mScanDetails,
ALL_SINGLE_SCAN_LISTENER, isFullBandScanResults);
clearScanDetails();
/*省略部分代码*/
}
在调用回调方法时,首先会去判断是否已经打开wifi和是否支持自动连接,如果其中一个条件不满足都不会进行接下来的自动连接操作。这里认定开启了wifi并且支持自动连接,那么接下来将会调用handleScanResults()
方法。
private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName,
boolean isFullScan) {
/*省略部分代码*/
/*热点筛选*/
List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan(
scanDetails, bssidBlocklist, mWifiInfo, mStateMachine.isConnected(),
mStateMachine.isDisconnected(), mUntrustedConnectionAllowed);
mLatestCandidates = candidates;
mLatestCandidatesTimestampMs = mClock.getElapsedSinceBootMillis();
if (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT
&& mContext.getResources().getBoolean(
R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled)) {
candidates = filterCandidatesHighMovement(candidates, listenerName, isFullScan);
}
/*热点评分优选*/
WifiConfiguration candidate = mNetworkSelector.selectNetwork(candidates);
mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
mWifiLastResortWatchdog.updateAvailableNetworks(
mNetworkSelector.getConnectableScanDetails());
mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {
/*热点连接*/
localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
/*省略部分代码*/
}
}
此方法包含了热点筛选、热点评分以及连接优选出来的热点等核心过程。其中热点筛选主要是通过wifi网络选择器WifiNetworkSelector
中的getCandidatesFromScan()
方法选择出候选热点列表。
public List<WifiCandidates.Candidate> getCandidatesFromScan(
List<ScanDetail> scanDetails, Set<String> bssidBlacklist, WifiInfo wifiInfo,
boolean connected, boolean disconnected, boolean untrustedNetworkAllowed)