diff options
Diffstat (limited to 'service/java/com/android/server/wifi/WifiAutoJoinController.java')
-rw-r--r-- | service/java/com/android/server/wifi/WifiAutoJoinController.java | 313 |
1 files changed, 244 insertions, 69 deletions
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java index 3d8bbfe3f..95dfbbb45 100644 --- a/service/java/com/android/server/wifi/WifiAutoJoinController.java +++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java @@ -64,10 +64,9 @@ public class WifiAutoJoinController { new HashMap<String, ScanResult>(); //lose the non-auth failure blacklisting after 8 hours - private final static long loseBlackListHardMilly = 1000 * 60 * 60 * 8; + private final static long loseBlackListHardMilli = 1000 * 60 * 60 * 8; //lose some temporary blacklisting after 30 minutes - private final static long loseBlackListSoftMilly = 1000 * 60 * 30; - + private final static long loseBlackListSoftMilli = 1000 * 60 * 30; WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s, WifiTrafficPoller t, WifiNative n) { @@ -454,6 +453,7 @@ public class WifiAutoJoinController { } } } + } return found; } @@ -461,7 +461,6 @@ public class WifiAutoJoinController { int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b) { int order = 0; int boost5 = 25; - WifiConfiguration.Visibility astatus = a.visibility; WifiConfiguration.Visibility bstatus = b.visibility; if (astatus == null || bstatus == null) { @@ -470,12 +469,12 @@ public class WifiAutoJoinController { return 0; } if ((astatus.rssi5 > -70) && (bstatus.rssi5 == WifiConfiguration.INVALID_RSSI) - && ((astatus.rssi5+boost5) > (bstatus.rssi24))) { + && ((astatus.rssi5 + boost5) > (bstatus.rssi24))) { //a is seen on 5GHz with good RSSI, greater rssi than b //a is of higher priority - descending order = -1; } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 == WifiConfiguration.INVALID_RSSI) - && ((bstatus.rssi5+boost5) > (bstatus.rssi24))) { + && ((bstatus.rssi5 + boost5) > (bstatus.rssi24))) { //b is seen on 5GHz with good RSSI, greater rssi than a //a is of lower priority - ascending order = 1; @@ -483,6 +482,7 @@ public class WifiAutoJoinController { return order; } + int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) { int order = 0; String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration(); @@ -512,7 +512,8 @@ public class WifiAutoJoinController { return -1; //a is of higher priority - descending } - int boost5 = 25; + int aRssiBoost5 = 0; + int bRssiBoost5 = 0; //apply Hysteresis: boost the RSSI value of the currently connected configuration int aRssiBoost = 0; int bRssiBoost = 0; @@ -524,6 +525,8 @@ public class WifiAutoJoinController { } } if (linked) { + int ascore; + int bscore; // then we try prefer 5GHz, and try to ignore user's choice WifiConfiguration.Visibility astatus = a.visibility; WifiConfiguration.Visibility bstatus = b.visibility; @@ -540,38 +543,65 @@ public class WifiAutoJoinController { + Integer.toString(bstatus.rssi24)); } - if ((astatus.rssi5 > -70) && (bstatus.rssi5 <= WifiConfiguration.INVALID_RSSI) - && (astatus.rssi5+boost5+aRssiBoost) > (bstatus.rssi24+bRssiBoost)) { - //in this case: a has 5GHz and b doesn't have 5GHz - //compare a's 5GHz RSSI to b's 5GHz RSSI - - //a is seen on 5GHz with good RSSI, greater rssi than b - //a is of higher priority - descending - order = -10; + //Boost RSSI value of 5GHz bands iff the base value is better than -65 + //This implements band preference where we prefer 5GHz if RSSI5 is good enough, whereas + //we prefer 2.4GHz otherwise. + //Note that 2.4GHz doesn't need a boost since at equal power the RSSI is 6-10 dB higher + if ((astatus.rssi5+aRssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) { + aRssiBoost5 = 25; + } + if ((bstatus.rssi5+bRssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) { + bRssiBoost5 = 25; + } + if (astatus.rssi5+aRssiBoost5 > astatus.rssi24) { + //prefer a's 5GHz + ascore = astatus.rssi5 + aRssiBoost5 + aRssiBoost; + } else { + //prefer a's 2.4GHz + ascore = astatus.rssi24 + aRssiBoost; + } + if (bstatus.rssi5+bRssiBoost5 > bstatus.rssi24) { + //prefer b's 5GHz + bscore = bstatus.rssi5 + bRssiBoost5 + bRssiBoost; + } else { + //prefer b's 2.4GHz + bscore = bstatus.rssi24 + bRssiBoost; + } + if (ascore > bscore) { + //a is seen on 5GHz with good RSSI, greater rssi than b + //a is of higher priority - descending + order = -10; if (VDBG) { logDbg("compareWifiConfigurations linked and prefers " + a.configKey() + + " rssi=(" + a.visibility.rssi24 + + "," + a.visibility.rssi5 + + ") num=(" + a.visibility.num24 + + "," + a.visibility.num5 + ")" + " over " + b.configKey() - + " due to 5GHz RSSI " + Integer.toString(astatus.rssi5) - + " over: 5=" + Integer.toString(bstatus.rssi5) - + ", 2.4=" + Integer.toString(bstatus.rssi5)); + + " rssi=(" + b.visibility.rssi24 + + "," + b.visibility.rssi5 + + ") num=(" + b.visibility.num24 + + "," + b.visibility.num5 + ")" + + " due to RSSI"); } - } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 <= WifiConfiguration.INVALID_RSSI) - && ((bstatus.rssi5+boost5+bRssiBoost) > (astatus.rssi24+aRssiBoost))) { - //in this case: b has 5GHz and a doesn't have 5GHz - - //b is seen on 5GHz with good RSSI, greater rssi than a - //a is of lower priority - ascending - if (VDBG) { + } else if (bscore > ascore) { + //b is seen on 5GHz with good RSSI, greater rssi than a + //a is of lower priority - ascending + order = 10; + if (VDBG) { logDbg("compareWifiConfigurations linked and prefers " + b.configKey() - + " over " + a.configKey() + " due to 5GHz RSSI " - + Integer.toString(astatus.rssi5) + " over: 5=" - + Integer.toString(bstatus.rssi5) + ", 2.4=" - + Integer.toString(bstatus.rssi5)); + + " rssi=(" + b.visibility.rssi24 + + "," + b.visibility.rssi5 + + ") num=(" + b.visibility.num24 + + "," + b.visibility.num5 + ")" + + " over " + a.configKey() + + " rssi=(" + a.visibility.rssi24 + + "," + a.visibility.rssi5 + + ") num=(" + a.visibility.num24 + + "," + a.visibility.num5 + ")" + + " due to RSSI"); } - order = 10; - } else { - //TODO: handle cases where configurations are dual band } } @@ -612,21 +642,27 @@ public class WifiAutoJoinController { if ((lastSelectedConfiguration != null) && a.configKey().equals(lastSelectedConfiguration)) { - // a is the last selected configuration, so keep it above connect choices - //by giving a -4 (whereas connect choice preference gives +2) - order = order - 4; + // a is the last selected configuration, so keep it above connect choices (+/-2) and + // above RSSI based selection of linked configuration (+/- 11) + // by giving a -11 + // Additional other factors like BAD RSSI (still to do) and ASSOC_REJECTION high counts will then still + // tip the auto-join to roam + order = order - 11; if (VDBG) { - logDbg("compareWifiConfigurations prefers -4 " + a.configKey() + logDbg("compareWifiConfigurations prefers -11 " + a.configKey() + " over " + b.configKey() + " because a is the last selected -> " + Integer.toString(order)); } } else if ((lastSelectedConfiguration != null) && b.configKey().equals(lastSelectedConfiguration)) { - // b is the last selected configuration, so keep it above connect choices - //by giving a +4 (whereas connect choice preference gives -2) - order = order + 4; + // b is the last selected configuration, so keep it above connect choices (+/-2) and + // above RSSI based selection of linked configuration (+/- 11) + // by giving a +11 + // Additional other factors like BAD RSSI (still to do) and ASSOC_REJECTION high counts will then still + // tip the auto-join to roam + order = order + 11; if (VDBG) { - logDbg("compareWifiConfigurations prefers +4 " + a.configKey() + logDbg("compareWifiConfigurations prefers +11 " + a.configKey() + " over " + b.configKey() + " because b is the last selected -> " + Integer.toString(order)); } @@ -677,7 +713,86 @@ public class WifiAutoJoinController { } /* attemptAutoJoin function implement the core of the a network switching algorithm */ + ScanResult attemptRoam(WifiConfiguration candidate, int age) { + ScanResult a = null; + String currentBSSID = mWifiStateMachine.getCurrentBSSID(); + if (candidate == null) { + return null; + } + if (candidate.scanResultCache == null) { + return null; + } + if (candidate.scanResultCache.size() > 4) { + //implement same SSID roaming only for configuration that have less than 4 BSSIDs + return null; + } + if (candidate.visibility.num5 == 0) { + //implement same SSID roaming only for configuration that have 5GHz BSSIDs + return null; + } + + //determine which BSSID we want to associate to, taking account relative strength of 5 and 2.4 GHz BSSIDs + long now_ms = System.currentTimeMillis(); + int bRssiBoost5 = 0; + int aRssiBoost5 = 0; + int bRssiBoost = 0; + int aRssiBoost = 0; + for (ScanResult b : candidate.scanResultCache.values()) { + + if (b.seen == 0) + continue; + + if (b.BSSID == null) + continue; + + if ((now_ms - b.seen) > age) continue; + + //pick first one + if (a == null) { + a = b; + continue; + } + + if (currentBSSID != null && currentBSSID.equals(b.BSSID)) { + bRssiBoost = +10; + } + if (currentBSSID != null && currentBSSID.equals(a.BSSID)) { + aRssiBoost = +10; + } + if (b.is5GHz() && (b.level+bRssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) { + bRssiBoost5 = 25; + } + if (a.is5GHz() && (a.level+aRssiBoost) > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) { + aRssiBoost5 = 25; + } + if (b.level + bRssiBoost + bRssiBoost5 > a.level +aRssiBoost + aRssiBoost5) { + //b is the better BSSID + a = b; + } + + if (VDBG) { + logDbg("attemptRoam: " + + b.BSSID + "rssi=" + b.level + " freq=" + b.frequency + " versus " + + a.BSSID + "rssi=" + a.level + " freq=" + a.frequency + ); + } + } + if (VDBG) { + logDbg("attemptRoam: Found " + + a.BSSID + "rssi=" + a.level + " freq=" + a.frequency + + " Current: " + currentBSSID); + } + if (currentBSSID!= null && currentBSSID.equals(a.BSSID)) { + return null; + } else { + return a; + } + } + + /* attemptAutoJoin function implement the core of the a network switching algorithm */ void attemptAutoJoin() { + int isRoaming = 0; + String lastSelectedConfiguration = mWifiConfigStore.getLastSelectedConfiguration(); // reset the currentConfiguration Key, and set it only if WifiStateMachine and @@ -740,7 +855,9 @@ public class WifiAutoJoinController { } } - /* select Best Network candidate from known WifiConfigurations */ + /* run thru all visible configurations without looking at the one we are currently associated to + * select Best Network candidate from known WifiConfigurations + * */ for (WifiConfiguration config : list) { if ((config.status == WifiConfiguration.Status.DISABLED) && (config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE)) { @@ -758,7 +875,7 @@ public class WifiAutoJoinController { if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { //avoid temporarily disabled networks altogether - //TODO: implement a better logic which will reenable the network after some time + //TODO: implement a better logic which will re-enable the network after some time if (DBG) { logDbg("attemptAutoJoin skip candidate due to auto join status " + Integer.toString(config.autoJoinStatus) + " key " @@ -776,10 +893,10 @@ public class WifiAutoJoinController { //this event should be rare enough so that we still want to lose the black list config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); } else { - if ((now - config.blackListTimestamp) > loseBlackListHardMilly) { + if ((now - config.blackListTimestamp) > loseBlackListHardMilli) { //reenable it after 18 hours, i.e. next day config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); - } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilly) { + } else if ((now - config.blackListTimestamp) > loseBlackListSoftMilli) { //lose blacklisting due to bad link config.setAutoJoinStatus(config.autoJoinStatus - 8); } @@ -791,12 +908,12 @@ public class WifiAutoJoinController { && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_SOFT) { if (DBG) { logDbg("attemptAutoJoin skip candidate due to auto join status " - + Integer.toString(config.autoJoinStatus) + " key " - + config.configKey(true) - + " rssi=" + config.visibility.rssi24 - + ", " + config.visibility.rssi5 - + " num=" + config.visibility.num24 - + ", " + config.visibility.num5); + + config.autoJoinStatus + + " key " + config.configKey(true) + + " rssi=(" + config.visibility.rssi24 + + "," + config.visibility.rssi5 + + ") num=(" + config.visibility.num24 + + "," + config.visibility.num5 + ")"); } } else if (config.visibility.rssi5 < WifiConfiguration.UNBLACKLIST_THRESHOLD_5_HARD && config.visibility.rssi24 < WifiConfiguration.UNBLACKLIST_THRESHOLD_24_HARD) { @@ -806,24 +923,34 @@ public class WifiAutoJoinController { if (DBG) { logDbg("attemptAutoJoin good candidate seen, bumped soft -> status=" + config.autoJoinStatus - + ", " + config.visibility.rssi5 - + " num=" + config.visibility.num24 - + ", " + config.visibility.num5); + + " key " + config.configKey(true) + " rssi=(" + + config.visibility.rssi24 + "," + config.visibility.rssi5 + + ") num=(" + config.visibility.num24 + + "," + config.visibility.num5 + ")"); } } else { config.setAutoJoinStatus(config.autoJoinStatus - 2); if (DBG) { logDbg("attemptAutoJoin good candidate seen, bumped hard -> status=" + config.autoJoinStatus - + ", " + config.visibility.rssi5 - + " num=" + config.visibility.num24 - + ", " + config.visibility.num5); + + " key " + config.configKey(true) + " rssi=(" + + config.visibility.rssi24 + "," + config.visibility.rssi5 + + ") num=(" + config.visibility.num24 + + "," + config.visibility.num5 + ")"); } } if (config.autoJoinStatus >= WifiConfiguration.AUTO_JOIN_TEMPORARY_DISABLED) { //network is blacklisted, skip + if (DBG) { + logDbg("attemptAutoJoin skip blacklisted -> status=" + + config.autoJoinStatus + + " key " + config.configKey(true) + " rssi=(" + + config.visibility.rssi24 + "," + config.visibility.rssi5 + + ") num=(" + config.visibility.num24 + + "," + config.visibility.num5 + ")"); + } continue; } if (config.networkId == currentNetId) { @@ -843,13 +970,22 @@ public class WifiAutoJoinController { } if (config.visibility.rssi5 < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 && config.visibility.rssi24 < WifiConfiguration.INITIAL_AUTO_JOIN_ATTEMPT_MIN_24) { + if (DBG) { + logDbg("attemptAutoJoin gskip due to low visibility -> status=" + + config.autoJoinStatus + + " key " + config.configKey(true) + " rssi=" + + config.visibility.rssi24 + ", " + config.visibility.rssi5 + + " num=" + config.visibility.num24 + + ", " + config.visibility.num5); + } continue; } } if (DBG) { logDbg("attemptAutoJoin trying candidate id=" + config.networkId + " " - + config.SSID + " key " + config.configKey(true)); + + config.SSID + " key " + config.configKey(true) + + " status=" + config.autoJoinStatus); } if (candidate == null) { @@ -857,7 +993,7 @@ public class WifiAutoJoinController { } else { if (VDBG) { logDbg("attemptAutoJoin will compare candidate " + candidate.configKey() - + " with " + config.configKey() + " key " + config.configKey(true)); + + " with " + config.configKey()); } int order = compareWifiConfigurations(candidate, config); @@ -889,7 +1025,7 @@ public class WifiAutoJoinController { if (score > 0) { // try any arbitrary formula for now, adding apple and oranges, // i.e. adding network score and "dBm over noise" - if (result.frequency < 4000) { + if (result.is24GHz()) { if ((result.level + score) > (rssi24 -40)) { // force it as open, TBD should we otherwise verify that this // BSSID only supports open?? @@ -918,29 +1054,68 @@ public class WifiAutoJoinController { } } if (candidate != null) { - /* if candidate is found, check the state of the connection so as - to decide if we should be acting on this candidate and switching over */ + ScanResult roamCandidate = null; + /* if candidate is found, check the state of the connection so as + to decide if we should be acting on this candidate and switching over */ + if (currentConfiguration != null && currentConfiguration.isLinked(candidate)) { + isRoaming = 2; + } int networkDelta = compareNetwork(candidate); if (DBG && (networkDelta > 0)) { + String roam = ""; + if (isRoaming == 1) + roam = "roaming"; + if (isRoaming == 2) + roam = "extended-roaming"; logDbg("attemptAutoJoin did find candidate " + candidate.configKey() - + " for delta " + Integer.toString(networkDelta)); + + " for delta " + Integer.toString(networkDelta) + + roam); } + + if (networkDelta <= 0) { + roamCandidate = attemptRoam(currentConfiguration, 3000); + if (roamCandidate != null) + networkDelta = 10; //TODO: adjust this based on RSSI difference? + } + /* ASK traffic poller permission to switch: for instance, if user is currently streaming voice traffic, then don’t switch regardless of the delta */ - if (mWifiTrafficPoller.shouldSwitchNetwork(networkDelta)) { + if (mWifiStateMachine.shouldSwitchNetwork(networkDelta)) { if (mStaStaSupported) { logDbg("mStaStaSupported --> error do nothing now "); } else { - if (DBG) { - logDbg("AutoJoin auto connect with netId " - + Integer.toString(candidate.networkId) - + " to " + candidate.configKey()); + if (roamCandidate != null) { + if (DBG) { + logDbg("AutoJoin auto roam with netId " + + Integer.toString(currentConfiguration.networkId) + + " " + candidate.configKey() + " to BSSID=" + + roamCandidate.BSSID + " freq=" + roamCandidate.frequency + + " RSSI=" + roamCandidate.frequency); + } + if (roamCandidate.is5GHz()) { + mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM, + candidate.networkId, 2, roamCandidate.BSSID); + } else { + //if we want to autoroam to 2.4GHz then force reassociate without locking the + //BSSID, the wifi chipset should normally select a 2.4GHz BSSID as RSSI will be stronger, + //or otherwise fall back normally thru the firmware roam. + //Hence, roaming between 2.4GHz BSSIDs will be handled by firmware + //whereas roaming onto 5GHz BSSIDs will be handled by framework + mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_ROAM, + candidate.networkId, 2, "any"); + } + } else { + if (DBG) { + logDbg("AutoJoin auto connect with netId " + + Integer.toString(candidate.networkId) + + " to " + candidate.configKey()); + } + mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT, + candidate.networkId, isRoaming, candidate); } - mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT, - candidate.networkId); } } } |