summaryrefslogtreecommitdiffstats
path: root/service
diff options
context:
space:
mode:
authorJeff Davidson <jpd@google.com>2014-12-05 10:55:23 -0800
committerJeff Davidson <jpd@google.com>2014-12-16 14:40:08 -0800
commit16fdf07021858fd116d96a5fb00ddb3c166d5ae6 (patch)
treefca9ba64851c97136ba392d66c5b003cff5122c5 /service
parent6a0c6896aa7f72744f8b3d65b3dcc7ea0c063bc7 (diff)
downloadandroid_frameworks_opt_net_wifi-16fdf07021858fd116d96a5fb00ddb3c166d5ae6.tar.gz
android_frameworks_opt_net_wifi-16fdf07021858fd116d96a5fb00ddb3c166d5ae6.tar.bz2
android_frameworks_opt_net_wifi-16fdf07021858fd116d96a5fb00ddb3c166d5ae6.zip
Stabilize ephemeral connections in the face of new BSSIDs.
Currently we only check whether the most recently seen BSSID has a score before deciding to disconnect an ephemeral network. This causes unnecessary flapping - if multiple BSSIDs are in visible range, and the scorer likes one of them but has no score for the other (or is still looking up the score), we will drop the connection. Instead, as long as we've recently seen a scored BSSID (in the last minute), we keep the connection alive. A scorer can still initiate an immediate disconnect from an unwanted network by nulling scores for all BSSIDs. The timeout (and whether we use this new behavior at all) is controlled by a Settings.Global flag. Bug: 18637384 Change-Id: I6bde3c9eef12caf2cc51c449abffc1c69f60c17f
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiAutoJoinController.java59
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkScoreCache.java74
2 files changed, 96 insertions, 37 deletions
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java
index e30b1c789..d2ae76a43 100644
--- a/service/java/com/android/server/wifi/WifiAutoJoinController.java
+++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java
@@ -22,6 +22,8 @@ import android.net.NetworkScoreManager;
import android.net.WifiKey;
import android.net.wifi.*;
import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.SystemClock;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -75,6 +77,9 @@ public class WifiAutoJoinController {
// Lose some temporary blacklisting after 30 minutes
private final static long loseBlackListSoftMilli = 1000 * 60 * 30;
+ /** @see android.provider.Settings.Global#WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS */
+ private static final long DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS = 1000 * 60; // 1 minute
+
public static final int AUTO_JOIN_IDLE = 0;
public static final int AUTO_JOIN_ROAMING = 1;
public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
@@ -1169,6 +1174,53 @@ public class WifiAutoJoinController {
!result.capabilities.contains("EAP");
}
+ private boolean haveRecentlySeenScoredBssid(WifiConfiguration config) {
+ long ephemeralOutOfRangeTimeoutMs = Settings.Global.getLong(
+ mContext.getContentResolver(),
+ Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
+ DEFAULT_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
+
+ // Check whether the currently selected network has a score curve. If
+ // ephemeralOutOfRangeTimeoutMs is <= 0, then this is all we check, and we stop here.
+ // Otherwise, we stop here if the currently selected network has a score. If it doesn't, we
+ // keep going - it could be that another BSSID is in range (has been seen recently) which
+ // has a score, even if the one we're immediately connected to doesn't.
+ ScanResult currentScanResult = mWifiStateMachine.getCurrentScanResult();
+ boolean currentNetworkHasScoreCurve = mNetworkScoreCache.hasScoreCurve(currentScanResult);
+ if (ephemeralOutOfRangeTimeoutMs <= 0 || currentNetworkHasScoreCurve) {
+ if (DBG) {
+ if (currentNetworkHasScoreCurve) {
+ logDbg("Current network has a score curve, keeping network: "
+ + currentScanResult);
+ } else {
+ logDbg("Current network has no score curve, giving up: " + config.SSID);
+ }
+ }
+ return currentNetworkHasScoreCurve;
+ }
+
+ if (config.scanResultCache == null || config.scanResultCache.isEmpty()) {
+ return false;
+ }
+
+ long currentTimeMs = System.currentTimeMillis();
+ for (ScanResult result : config.scanResultCache.values()) {
+ if (currentTimeMs > result.seen
+ && currentTimeMs - result.seen < ephemeralOutOfRangeTimeoutMs
+ && mNetworkScoreCache.hasScoreCurve(result)) {
+ if (DBG) {
+ logDbg("Found scored BSSID, keeping network: " + result.BSSID);
+ }
+ return true;
+ }
+ }
+
+ if (DBG) {
+ logDbg("No recently scored BSSID found, giving up connection: " + config.SSID);
+ }
+ return false;
+ }
+
/**
* attemptAutoJoin() function implements the core of the a network switching algorithm
* Return false if no acceptable networks were found.
@@ -1277,10 +1329,11 @@ public class WifiAutoJoinController {
mWifiStateMachine.disconnectCommand();
return false;
} else if (currentConfiguration.ephemeral && (!mAllowUntrustedConnections ||
- !mNetworkScoreCache.isScoredNetwork(currentConfiguration.lastSeen()))) {
+ !haveRecentlySeenScoredBssid(currentConfiguration))) {
// The current connection is untrusted (the framework added it), but we're either
- // no longer allowed to connect to such networks, or the score has been nullified
- // since we connected. Drop the current connection and perform the rest of autojoin.
+ // no longer allowed to connect to such networks, the score has been nullified
+ // since we connected, or the scored BSSID has gone out of range.
+ // Drop the current connection and perform the rest of autojoin.
logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
mWifiStateMachine.disconnectCommand();
return false;
diff --git a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
index 0a6852788..0a7df0b0e 100644
--- a/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
+++ b/service/java/com/android/server/wifi/WifiNetworkScoreCache.java
@@ -73,37 +73,38 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
}
}
+ /**
+ * Returns whether there is any score info for the given ScanResult.
+ *
+ * This includes null-score info, so it should only be used when determining whether to request
+ * scores from the network scorer.
+ */
public boolean isScoredNetwork(ScanResult result) {
- String key = buildNetworkKey(result);
- if (key == null) return false;
+ return getScoredNetwork(result) != null;
+ }
- //find it
- synchronized(mNetworkCache) {
- ScoredNetwork network = mNetworkCache.get(key);
- if (network != null) {
- return true;
- }
- }
- return false;
+ /**
+ * Returns whether there is a non-null score curve for the given ScanResult.
+ *
+ * A null score curve has special meaning - we should never connect to an ephemeral network if
+ * the score curve is null.
+ */
+ public boolean hasScoreCurve(ScanResult result) {
+ ScoredNetwork network = getScoredNetwork(result);
+ return network != null && network.rssiCurve != null;
}
public int getNetworkScore(ScanResult result) {
int score = INVALID_NETWORK_SCORE;
- String key = buildNetworkKey(result);
- if (key == null) return score;
-
- //find it
- synchronized(mNetworkCache) {
- ScoredNetwork network = mNetworkCache.get(key);
- if (network != null && network.rssiCurve != null) {
- score = network.rssiCurve.lookupScore(result.level);
- if (DBG) {
- Log.e(TAG, "getNetworkScore found scored network " + key
- + " score " + Integer.toString(score)
- + " RSSI " + result.level);
- }
+ ScoredNetwork network = getScoredNetwork(result);
+ if (network != null && network.rssiCurve != null) {
+ score = network.rssiCurve.lookupScore(result.level);
+ if (DBG) {
+ Log.e(TAG, "getNetworkScore found scored network " + network.networkKey
+ + " score " + Integer.toString(score)
+ + " RSSI " + result.level);
}
}
return score;
@@ -113,23 +114,28 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
int score = INVALID_NETWORK_SCORE;
+ ScoredNetwork network = getScoredNetwork(result);
+ if (network != null && network.rssiCurve != null) {
+ score = network.rssiCurve.lookupScore(result.level, isActiveNetwork);
+ if (DBG) {
+ Log.e(TAG, "getNetworkScore found scored network " + network.networkKey
+ + " score " + Integer.toString(score)
+ + " RSSI " + result.level
+ + " isActiveNetwork " + isActiveNetwork);
+ }
+ }
+ return score;
+ }
+
+ private ScoredNetwork getScoredNetwork(ScanResult result) {
String key = buildNetworkKey(result);
- if (key == null) return score;
+ if (key == null) return null;
//find it
synchronized(mNetworkCache) {
ScoredNetwork network = mNetworkCache.get(key);
- if (network != null && network.rssiCurve != null) {
- score = network.rssiCurve.lookupScore(result.level, isActiveNetwork);
- if (DBG) {
- Log.e(TAG, "getNetworkScore found scored network " + key
- + " score " + Integer.toString(score)
- + " RSSI " + result.level
- + " isActiveNetwork " + isActiveNetwork);
- }
- }
+ return network;
}
- return score;
}
private String buildNetworkKey(ScoredNetwork network) {