blob: facab0a5414de8790bc02731b19aadff07a98967 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import android.content.Context;
import android.net.NetworkAgent;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import com.android.internal.R;
/**
* Class used to calculate scores for connected wifi networks and report it to the associated
* network agent.
*/
public class LegacyConnectedScore extends ConnectedScore {
private static final int STARTING_SCORE = 56;
private static final int SCAN_CACHE_VISIBILITY_MS = 12000;
private static final int HOME_VISIBLE_NETWORK_MAX_COUNT = 6;
private static final int SCAN_CACHE_COUNT_PENALTY = 2;
private static final int MAX_SUCCESS_RATE_OF_STUCK_LINK = 3; // proportional to packets per sec
private static final int MAX_STUCK_LINK_COUNT = 5;
private static final int MAX_BAD_RSSI_COUNT = 7;
private static final int BAD_RSSI_COUNT_PENALTY = 2;
private static final int MAX_LOW_RSSI_COUNT = 1;
private static final double MIN_TX_FAILURE_RATE_FOR_WORKING_LINK = 0.3;
private static final int MIN_SUSTAINED_LINK_STUCK_COUNT = 1;
private static final int LINK_STUCK_PENALTY = 2;
private static final int BAD_LINKSPEED_PENALTY = 4;
private static final int GOOD_LINKSPEED_BONUS = 4;
// Device configs. The values are examples.
private final int mThresholdMinimumRssi5; // -82
private final int mThresholdQualifiedRssi5; // -70
private final int mThresholdSaturatedRssi5; // -57
private final int mThresholdMinimumRssi24; // -85
private final int mThresholdQualifiedRssi24; // -73
private final int mThresholdSaturatedRssi24; // -60
private final int mBadLinkSpeed24; // 6 Mbps
private final int mBadLinkSpeed5; // 12 Mbps
private final int mGoodLinkSpeed24; // 24 Mbps
private final int mGoodLinkSpeed5; // 36 Mbps
private final WifiConfigManager mWifiConfigManager;
private boolean mVerboseLoggingEnabled = false;
private boolean mMultiBandScanResults;
private boolean mIsHomeNetwork;
private int mScore = 0;
LegacyConnectedScore(Context context, WifiConfigManager wifiConfigManager, Clock clock) {
super(clock);
// Fetch all the device configs.
mThresholdMinimumRssi5 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
mThresholdQualifiedRssi5 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
mThresholdSaturatedRssi5 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
mThresholdMinimumRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
mThresholdQualifiedRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
mThresholdSaturatedRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
mBadLinkSpeed24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_bad_link_speed_24);
mBadLinkSpeed5 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_bad_link_speed_5);
mGoodLinkSpeed24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_good_link_speed_24);
mGoodLinkSpeed5 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_good_link_speed_5);
mWifiConfigManager = wifiConfigManager;
}
@Override
public void updateUsingWifiInfo(WifiInfo wifiInfo, long millis) {
mMultiBandScanResults = multiBandScanResults(wifiInfo);
mIsHomeNetwork = isHomeNetwork(wifiInfo);
int rssiThreshBad = mThresholdMinimumRssi24;
int rssiThreshLow = mThresholdQualifiedRssi24;
if (wifiInfo.is5GHz() && !mMultiBandScanResults) {
rssiThreshBad = mThresholdMinimumRssi5;
rssiThreshLow = mThresholdQualifiedRssi5;
}
int rssi = wifiInfo.getRssi();
if (mIsHomeNetwork) {
rssi += WifiConfiguration.HOME_NETWORK_RSSI_BOOST;
}
if ((wifiInfo.txBadRate >= 1)
&& (wifiInfo.txSuccessRate < MAX_SUCCESS_RATE_OF_STUCK_LINK)
&& rssi < rssiThreshLow) {
// Link is stuck
if (wifiInfo.linkStuckCount < MAX_STUCK_LINK_COUNT) {
wifiInfo.linkStuckCount += 1;
}
} else if (wifiInfo.txBadRate < MIN_TX_FAILURE_RATE_FOR_WORKING_LINK) {
if (wifiInfo.linkStuckCount > 0) {
wifiInfo.linkStuckCount -= 1;
}
}
if (rssi < rssiThreshBad) {
if (wifiInfo.badRssiCount < MAX_BAD_RSSI_COUNT) {
wifiInfo.badRssiCount += 1;
}
} else if (rssi < rssiThreshLow) {
wifiInfo.lowRssiCount = MAX_LOW_RSSI_COUNT; // Dont increment the lowRssi count above 1
if (wifiInfo.badRssiCount > 0) {
// Decrement bad Rssi count
wifiInfo.badRssiCount -= 1;
}
} else {
wifiInfo.badRssiCount = 0;
wifiInfo.lowRssiCount = 0;
}
// Ugh, we need to finish the score calculation while we have wifiInfo
mScore = calculateScore(wifiInfo);
}
@Override
public void updateUsingRssi(int rssi, long millis, double standardDeviation) {
// This scorer needs more than just the RSSI. Just ignore.
}
@Override
public int generateScore() {
return mScore;
}
@Override
public void reset() {
mScore = 0;
}
/**
* Calculates a score based on the current state and wifiInfo
*/
private int calculateScore(WifiInfo wifiInfo) {
int score = STARTING_SCORE;
int rssiThreshSaturated = mThresholdSaturatedRssi24;
int linkspeedThreshBad = mBadLinkSpeed24;
int linkspeedThreshGood = mGoodLinkSpeed24;
if (wifiInfo.is5GHz()) {
if (!mMultiBandScanResults) {
rssiThreshSaturated = mThresholdSaturatedRssi5;
}
linkspeedThreshBad = mBadLinkSpeed5;
linkspeedThreshGood = mGoodLinkSpeed5;
}
int rssi = wifiInfo.getRssi();
if (mIsHomeNetwork) {
rssi += WifiConfiguration.HOME_NETWORK_RSSI_BOOST;
}
int linkSpeed = wifiInfo.getLinkSpeed();
if (wifiInfo.linkStuckCount > MIN_SUSTAINED_LINK_STUCK_COUNT) {
// Once link gets stuck for more than 3 seconds, start reducing the score
score = score - LINK_STUCK_PENALTY * (wifiInfo.linkStuckCount - 1);
}
if (linkSpeed < linkspeedThreshBad) {
score -= BAD_LINKSPEED_PENALTY;
} else if ((linkSpeed >= linkspeedThreshGood) && (wifiInfo.txSuccessRate > 5)) {
score += GOOD_LINKSPEED_BONUS; // So as bad rssi alone doesn't kill us
}
score -= wifiInfo.badRssiCount * BAD_RSSI_COUNT_PENALTY + wifiInfo.lowRssiCount;
if (rssi >= rssiThreshSaturated) score += 5;
if (score > NetworkAgent.WIFI_BASE_SCORE) score = NetworkAgent.WIFI_BASE_SCORE;
if (score < 0) score = 0;
return score;
}
/**
* Determines if we can see both 2.4GHz and 5GHz for current config
*/
private boolean multiBandScanResults(WifiInfo wifiInfo) {
WifiConfiguration currentConfiguration =
mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId());
if (currentConfiguration == null) return false;
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(wifiInfo.getNetworkId());
if (scanDetailCache == null) return false;
// Nasty that we change state here...
currentConfiguration.setVisibility(scanDetailCache.getVisibility(SCAN_CACHE_VISIBILITY_MS));
if (currentConfiguration.visibility == null) return false;
if (currentConfiguration.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) return false;
if (currentConfiguration.visibility.rssi5 == WifiConfiguration.INVALID_RSSI) return false;
// N.B. this does not do exactly what is claimed!
if (currentConfiguration.visibility.rssi24
>= currentConfiguration.visibility.rssi5 - SCAN_CACHE_COUNT_PENALTY) {
return true;
}
return false;
}
/**
* Decides whether the current network is a "home" network
*/
private boolean isHomeNetwork(WifiInfo wifiInfo) {
WifiConfiguration currentConfiguration =
mWifiConfigManager.getConfiguredNetwork(wifiInfo.getNetworkId());
if (currentConfiguration == null) return false;
// This seems like it will only return true for really old routers!
if (currentConfiguration.allowedKeyManagement.cardinality() != 1) return false;
if (!currentConfiguration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
return false;
}
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(wifiInfo.getNetworkId());
if (scanDetailCache == null) return false;
if (scanDetailCache.size() <= HOME_VISIBLE_NETWORK_MAX_COUNT) {
return true;
}
return false;
}
}