今天了解了一下Wifi自动连接时的评分机制,总结如下: WifiConnectivityManager的初始化: /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
class SupplicantStartedState extends State {
if (mWifiScanner == null) {
mWifiScanner = mWifiInjector.getWifiScanner();
synchronized (mWifiReqCountLock) {
mWifiConnectivityManager =
mWifiInjector.makeWifiConnectivityManager(mWifiInfo,
hasConnectionRequests());
mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0);
mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);
}
}
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java
public WifiConnectivityManager makeWifiConnectivityManager(WifiInfo wifiInfo,
boolean hasConnectionRequests) {
return new WifiConnectivityManager(mContext, mWifiStateMachine, getWifiScanner(),
mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper,
mWifiLastResortWatchdog, mOpenNetworkNotifier, mWifiMetrics,
mWifiStateMachineHandlerThread.getLooper(), mClock, mConnectivityLocalLog,
hasConnectionRequests, mFrameworkFacade, mSavedNetworkEvaluator,
mScoredNetworkEvaluator, mPasspointNetworkEvaluator);
}
WifiConnectivityManager中会注册三个Evaluator。 /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConnectivityManager.java
mNetworkSelector.registerNetworkEvaluator(savedNetworkEvaluator,
SAVED_NETWORK_EVALUATOR_PRIORITY);
if (hs2Enabled) {
mNetworkSelector.registerNetworkEvaluator(passpointNetworkEvaluator,
PASSPOINT_NETWORK_EVALUATOR_PRIORITY);
}
mNetworkSelector.registerNetworkEvaluator(scoredNetworkEvaluator,
SCORED_NETWORK_EVALUATOR_PRIORITY);
继续看下注册方法,其实就是初始化一个NetworkEvaluator数组,大小为6,即优先级从高到低0-5。 /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNetworkSelector.java
public static final int EVALUATOR_MIN_PRIORITY = 6;
private final NetworkEvaluator[] mEvaluators = new NetworkEvaluator[MAX_NUM_EVALUATORS];
public boolean registerNetworkEvaluator(NetworkEvaluator evaluator, int priority) {
if (priority < 0 || priority >= EVALUATOR_MIN_PRIORITY) {
localLog("Invalid network evaluator priority: " + priority);
return false;
}
if (mEvaluators[priority] != null) {
localLog("Priority " + priority + " is already registered by "
+ mEvaluators[priority].getName());
return false;
}
mEvaluators[priority] = evaluator;
return true;
}
WifiConnectivityManager的网络评估
private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {
if (mSupportCMCC && mWifiManagerEx.isAutoConnect() == false) {
Log.i(TAG, "WifiManagerEx isAutoConnect false, " + mWifiManagerEx.isAutoConnect());
return false;
}
if (!mP2pWifiCoexistSupported && WifiP2pServiceImpl.mP2pConnectingOrConnected) {
Log.i(TAG, "Do not auto connect when wifi and p2p should not coexsit");
return false;
}
refreshBssidBlacklist();
if (mStateMachine.isLinkDebouncing() || mStateMachine.isSupplicantTransientState()) {
localLog(listenerName + " onResults: No network selection because linkDebouncing is "
+ mStateMachine.isLinkDebouncing() + " and supplicantTransient is "
+ mStateMachine.isSupplicantTransientState());
return false;
}
localLog(listenerName + " onResults: start network selection");
WifiConfiguration candidate =
mNetworkSelector.selectNetwork(scanDetails, buildBssidBlacklist(), mWifiInfo,
mStateMachine.isConnected(), mStateMachine.isDisconnected(),
mUntrustedConnectionAllowed);
mWifiLastResortWatchdog.updateAvailableNetworks(
mNetworkSelector.getConnectableScanDetails());
mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {
localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED) {
mOpenNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
}
return false;
}
}
如api注释所述,对周期性、单次和pno扫描的结果进行潜在网络候选者的选择,如果有合适的网络,则进行连接
看下candiate是如何产生的:
public WifiConfiguration selectNetwork(List<ScanDetail> scanDetails,
HashSet<String> bssidBlacklist, WifiInfo wifiInfo,
boolean connected, boolean disconnected, boolean untrustedNetworkAllowed)
mFilteredNetworks.clear();
mConnectableNetworks.clear();
if (scanDetails.size() == 0) {
localLog("Empty connectivity scan result");
return null;
WifiConfiguration currentNetwork =
mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId());
String currentBssid = wifiInfo.getBSSID();
if (!isNetworkSelectionNeeded(scanDetails, wifiInfo, connected, disconnected)) {
return null;
}
for (NetworkEvaluator registeredEvaluator : mEvaluators) {
if (registeredEvaluator != null) {
registeredEvaluator.update(scanDetails);
}
}
mFilteredNetworks = filterScanResults(scanDetails, bssidBlacklist,
connected, currentBssid);
if (mFilteredNetworks.size() == 0) {
return null;
}
WifiConfiguration selectedNetwork = null;
for (NetworkEvaluator registeredEvaluator : mEvaluators) {
if (registeredEvaluator != null) {
localLog("About to run " + registeredEvaluator.getName() + " :");
selectedNetwork = registeredEvaluator.evaluateNetworks(
new ArrayList<>(mFilteredNetworks), currentNetwork, currentBssid, connected,
untrustedNetworkAllowed, mConnectableNetworks);
if (selectedNetwork != null) {
localLog(registeredEvaluator.getName() + " selects "
+ WifiNetworkSelector.toNetworkString(selectedNetwork) + " : "
+ selectedNetwork.getNetworkSelectionStatus().getCandidate().BSSID);
break;
}
if (selectedNetwork != null) {
selectedNetwork = overrideCandidateWithUserConnectChoice(selectedNetwork);
mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
}
return selectedNetwork;
}
看下是否可以进行网络选择: 1、 当前网络无效时 2、 当前没有连接网络时
private boolean isNetworkSelectionNeeded(List<ScanDetail> scanDetails, WifiInfo wifiInfo,
boolean connected, boolean disconnected) {
if (scanDetails.size() == 0) {
localLog("Empty connectivity scan results. Skip network selection.");
return false;
}
if (connected) {
if (isCurrentNetworkSufficient(wifiInfo, scanDetails)) {
localLog("Current connected network already sufficient. Skip network selection.");
return false;
} else {
localLog("Current connected network is not sufficient.");
return true;
}
} else if (disconnected) {
return true;
} else {
判断网络是否有效,主要是看以下几点要素: 1、rssi(区分2.4G还是5G) 2、packet rate 3、ephemeral(短暂的) 4、open network 5、5G优先级>2.4G
private boolean isCurrentNetworkSufficient(WifiInfo wifiInfo, List<ScanDetail> scanDetails) {
WifiConfiguration network =
mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId());
int currentRssi = wifiInfo.getRssi();
boolean hasQualifiedRssi =
(wifiInfo.is24GHz() && (currentRssi > mThresholdQualifiedRssi24))
|| (wifiInfo.is5GHz() && (currentRssi > mThresholdQualifiedRssi5));
boolean hasActiveStream = (wifiInfo.getTxSuccessRatePps() > mStayOnNetworkMinimumTxRate)
|| (wifiInfo.getRxSuccessRatePps() > mStayOnNetworkMinimumRxRate);
if (hasQualifiedRssi && hasActiveStream) {
localLog("Stay on current network because of good RSSI and ongoing traffic");
return true;
}
if (network.ephemeral) {
localLog("Current network is an ephemeral one.");
return false;
}
if (WifiConfigurationUtil.isConfigForOpenNetwork(network)) {
localLog("Current network is a open one.");
return false;
}
if (wifiInfo.is24GHz()) {
if (is5GHzNetworkAvailable(scanDetails)) {
localLog("Current network is 2.4GHz. 5GHz networks available.");
return false;
}
}
if (!hasQualifiedRssi) {
localLog("Current network RSSI[" + currentRssi + "]-acceptable but not qualified.");
return false;
}
return true;
}
SavedNetworkEvaluator的筛选 首先遍历扫描结果:
for (ScanDetail scanDetail : scanDetails) {
ScanResult scanResult = scanDetail.getScanResult();
int highestScoreOfScanResult = Integer.MIN_VALUE;
int candidateIdOfScanResult = WifiConfiguration.INVALID_NETWORK_ID;
过滤passpoint和ephemeral,如api所述这类网络交由PasspointNetworkEvaluator和ScoredNetworkEvaluator进行评估
if (network.isPasspoint() || network.isEphemeral()) {
continue;
}
接着过滤没有enabled的,scan bssid和config对不上的和eap-sim之类的网络但是没插卡的。
if (!status.isNetworkEnabled()) {
continue;
} else if (network.BSSID != null && !network.BSSID.equals("any")
&& !network.BSSID.equals(scanResult.BSSID)) {
localLog("Network " + WifiNetworkSelector.toNetworkString(network)+ " has specified BSSID " + network.BSSID + ". Skip " + scanResult.BSSID);
continue;
} else if (TelephonyUtil.isSimConfig(network)
&& !mWifiConfigManager.isSimPresent()) {
localLog("isSimPresent");
continue;
}
网络评分的关键:计算BSSID的分数,评分几大要素如下: 1、 RSSI 2、 5G 3、 lastUserSelectedNetworkId 4、 currentNetwork 5、 isFirmwareRoamingSupported 6、 isConfigForOpenNetwork
private int calculateBssidScore(ScanResult scanResult, WifiConfiguration network,
WifiConfiguration currentNetwork, String currentBssid,
StringBuffer sbuf) {
int score = 0;
boolean is5GHz = scanResult.is5GHz();
sbuf.append("[ ").append(scanResult.SSID).append(" ").append(scanResult.BSSID)
.append(" RSSI:").append(scanResult.level).append(" ] ");
int rssiSaturationThreshold = is5GHz ? mThresholdSaturatedRssi5 : mThresholdSaturatedRssi24;
int rssi = scanResult.level < rssiSaturationThreshold ? scanResult.level
: rssiSaturationThreshold;
score += (rssi + mRssiScoreOffset) * mRssiScoreSlope;
sbuf.append(" RSSI score: ").append(score).append(",");
如果是5G频段,会有奖励。
if (is5GHz) {
score += mBand5GHzAward;
sbuf.append(" 5GHz bonus: ").append(mBand5GHzAward).append(",");
}
之前连接过也有奖励
int lastUserSelectedNetworkId = mWifiConfigManager.getLastSelectedNetwork();
if (lastUserSelectedNetworkId != WifiConfiguration.INVALID_NETWORK_ID
&& lastUserSelectedNetworkId == network.networkId) {
long timeDifference = mClock.getElapsedSinceBootMillis()
- mWifiConfigManager.getLastSelectedTimeStamp();
if (timeDifference > 0) {
int bonus = mLastSelectionAward - (int) (timeDifference / 1000 / 60);
score += bonus > 0 ? bonus : 0;
sbuf.append(" User selection ").append(timeDifference / 1000 / 60)
.append(" minutes ago, bonus: ").append(bonus).append(",");
}
}
如果是当前正在连接的网络,也会加分
if (currentNetwork != null
&& (network.networkId == currentNetwork.networkId
/* || network.isLinked(currentNetwork) */)) {
score += mSameNetworkAward;
sbuf.append(" Same network bonus: ").append(mSameNetworkAward).append(",");
支持漫游也会有奖励
if (mConnectivityHelper.isFirmwareRoamingSupported()
&& currentBssid != null && !currentBssid.equals(scanResult.BSSID)) {
score += mSameBssidAward;
sbuf.append(" Equivalent BSSID bonus: ").append(mSameBssidAward).append(",");
}
}
BSSID相同也会有奖励
if (currentBssid != null && currentBssid.equals(scanResult.BSSID)) {
score += mSameBssidAward;
sbuf.append(" Same BSSID bonus: ").append(mSameBssidAward).append(",");
}
不是开放的网络,也会有奖励
if (!WifiConfigurationUtil.isConfigForOpenNetwork(network)) {
score += mSecurityAward;
sbuf.append(" Secure network bonus: ").append(mSecurityAward).append(",");
sbuf.append(" ## Total score: ").append(score).append("\n");
return score;
}