From 4dc6f3a322806b25d50039614cde1b94fe91ab17 Mon Sep 17 00:00:00 2001 From: vandwalle Date: Tue, 10 Jun 2014 20:47:51 -0700 Subject: auto-roam initial implementation Bug:15553951 Change-Id: I04ebca4a4f5a9b408893ce1e9874f08aeff50ba2 --- .../server/wifi/WifiAutoJoinController.java | 313 ++++++++++++---- .../com/android/server/wifi/WifiConfigStore.java | 69 +++- .../com/android/server/wifi/WifiStateMachine.java | 404 ++++++++++++++++++--- .../com/android/server/wifi/WifiTrafficPoller.java | 9 - 4 files changed, 653 insertions(+), 142 deletions(-) (limited to 'service/java/com/android/server') 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(); //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)); } @@ -676,8 +712,87 @@ public class WifiAutoJoinController { return order; } + /* 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); } } } diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index 495876c35..8dd7f3442 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -75,13 +75,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.text.SimpleDateFormat; import java.text.DateFormat; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * This class provides the API to manage configured @@ -1959,6 +1953,54 @@ public class WifiConfigStore extends IpConfigStore { return config; } + public Set makeChannelList(WifiConfiguration config, int age) { + if (config == null) + return null; + long now_ms = System.currentTimeMillis(); + + HashSet channels = new HashSet(); + + //get channels for this configuration, if there are at least 2 BSSIDs + if (config.scanResultCache == null && config.linkedConfigurations == null) { + return null; + } + + if (VDBG) { + StringBuilder dbg = new StringBuilder(); + dbg.append("makeChannelList for " + config.configKey()); + if (config.scanResultCache != null) { + dbg.append(" bssids=" + config.scanResultCache.size()); + } + if (config.linkedConfigurations != null) { + dbg.append(" linked=" + config.linkedConfigurations.size()); + } + loge(dbg.toString()); + } + if (config.scanResultCache != null && config.scanResultCache.size() > 0) { + for (ScanResult result : config.scanResultCache.values()) { + if ((now_ms - result.seen) < age) { + channels.add(result.frequency); + } + } + } + //get channels for linked configurations + if (config.linkedConfigurations != null) { + for (String key : config.linkedConfigurations.keySet()) { + WifiConfiguration linked = getWifiConfiguration(key); + if (linked == null) + continue; + if (linked.scanResultCache == null) { + return null; + } + for (ScanResult result : linked.scanResultCache.values()) { + if ((now_ms - result.seen) < age) { + channels.add(result.frequency); + } + } + } + } + return channels; + } public WifiConfiguration updateSavedNetworkHistory(ScanResult scanResult) { WifiConfiguration found = null; @@ -2551,6 +2593,8 @@ public class WifiConfigStore extends IpConfigStore { loge("SSID re-enabled for " + config.configKey() + " had autoJoinStatus=" + Integer.toString(config.autoJoinStatus) + " self added " + config.selfAdded + " ephemeral " + config.ephemeral); + //TODO: really I don't know if re-enabling is right but we should err on the side of trying to connect + //TODO: even if the attempt will fail if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); } @@ -2561,14 +2605,13 @@ public class WifiConfigStore extends IpConfigStore { if (message != null) { loge(" wpa_supplicant message=" + message); } - if (config.selfAdded) { - //this is a network we self added, so as auto-join can opportunistically try it - //the user did not create this network and entered its credentials, so we want + if (config.selfAdded && config.lastConnected == 0) { + //this is a network we self added, and we never succeeded, + //the user did not create this network and never entered its credentials, so we want //to be very aggressive in disabling it completely. disableNetwork(config.networkId, WifiConfiguration.DISABLED_AUTH_FAILURE); config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); config.disableReason = WifiConfiguration.DISABLED_AUTH_FAILURE; - } else { if (message != null) { if (message.contains("WRONG_KEY") @@ -2585,7 +2628,9 @@ public class WifiConfigStore extends IpConfigStore { //TODO: blacklisting hard if (config.autoJoinStatus <= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { - config.setAutoJoinStatus(3 + config.autoJoinStatus * 2); + //4 auth failure will reach 128 and disable permanently + //autoJoinStatus: 0 -> 4 -> 20 -> 84 -> 128 + config.setAutoJoinStatus(4 + config.autoJoinStatus * 4); if (config.autoJoinStatus > WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE); } diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 242bd0fac..03aa8d329 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -42,20 +42,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.ContentObserver; -import android.net.ConnectivityManager; -import android.net.DhcpResults; -import android.net.DhcpStateMachine; -import android.net.InterfaceConfiguration; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkCapabilities; -import android.net.NetworkFactory; -import android.net.NetworkInfo; +import android.net.*; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkRequest; -import android.net.NetworkUtils; -import android.net.RouteInfo; import android.net.wifi.BatchedScanResult; import android.net.wifi.BatchedScanSettings; import android.net.wifi.RssiPacketCountInfo; @@ -107,14 +95,9 @@ import com.android.server.wifi.passpoint.WifiPasspointStateMachine; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Queue; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Iterator; import java.util.regex.Pattern; import java.io.FileReader; import java.io.BufferedReader; @@ -212,6 +195,8 @@ public class WifiStateMachine extends StateMachine { private final Queue mBufferedScanMsg = new LinkedList(); private WorkSource mScanWorkSource = null; private static final int UNKNOWN_SCAN_SOURCE = -1; + private static final int SCAN_ALARM_SOURCE = -2; + private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; @@ -293,10 +278,21 @@ public class WifiStateMachine extends StateMachine { private DhcpStateMachine mDhcpStateMachine; private boolean mDhcpActive = false; - private boolean mWifiLinkLayerStatsSupported = true; + private int mWifiLinkLayerStatsSupported = 4; private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); + //whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress + private enum AutoRoaming { + IDLE, + ROAMING, + EXTENDED_ROAMING + }; + + AutoRoaming mAutoRoaming = AutoRoaming.IDLE; + + static private final int ONE_HOUR_MILLI = 1000 * 60 * 60; + private class InterfaceObserver extends BaseNetworkObserver { private WifiStateMachine mWifiStateMachine; @@ -513,6 +509,9 @@ public class WifiStateMachine extends StateMachine { static final int CMD_UNWANTED_NETWORK = BASE + 144; + static final int CMD_AUTO_ROAM = BASE + 145; + + /* Wifi state machine modes of operation */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ public static final int CONNECT_MODE = 1; @@ -595,9 +594,6 @@ public class WifiStateMachine extends StateMachine { // currently connected network), so we save the country code here to avoid redundency private String mLastSetCountryCode; - private static final int MIN_RSSI = -200; - private static final int MAX_RSSI = 256; - /* Default parent state */ private State mDefaultState = new DefaultState(); /* Temporary initial state */ @@ -633,6 +629,8 @@ public class WifiStateMachine extends StateMachine { private State mVerifyingLinkState = new VerifyingLinkState(); /* Connected with IP addr */ private State mConnectedState = new ConnectedState(); + /* Roaming */ + private State mRoamingState = new RoamingState(); /* disconnect issued, waiting for network disconnect confirmation */ private State mDisconnectingState = new DisconnectingState(); /* Network is not connected, supplicant assoc+auth is not complete */ @@ -821,7 +819,7 @@ public class WifiStateMachine extends StateMachine { new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - startScan(UNKNOWN_SCAN_SOURCE, null, null); + startScan(SCAN_ALARM_SOURCE, null, null); if (VDBG) loge("WiFiStateMachine SCAN ALARM"); } @@ -907,6 +905,7 @@ public class WifiStateMachine extends StateMachine { addState(mObtainingIpState, mL2ConnectedState); addState(mVerifyingLinkState, mL2ConnectedState); addState(mConnectedState, mL2ConnectedState); + addState(mRoamingState, mL2ConnectedState); addState(mDisconnectingState, mConnectModeState); addState(mDisconnectedState, mConnectModeState); addState(mWpsRunningState, mConnectModeState); @@ -1401,7 +1400,8 @@ public class WifiStateMachine extends StateMachine { loge(ts + " noteScanstart no scan source"); } } - if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) { + if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE && callingUid != SCAN_ALARM_SOURCE) + || workSource != null)) { mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); try { mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); @@ -2415,7 +2415,7 @@ public class WifiStateMachine extends StateMachine { + Integer.toString(newLinkSpeed)); } - if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values + if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { // screen out invalid values /* some implementations avoid negative values by adding 256 * so we need to adjust for that here. */ @@ -2437,7 +2437,7 @@ public class WifiStateMachine extends StateMachine { } mLastSignalLevel = newSignalLevel; } else { - mWifiInfo.setRssi(MIN_RSSI); + mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); } if (newLinkSpeed != -1) { @@ -2448,10 +2448,49 @@ public class WifiStateMachine extends StateMachine { } } + /* determine if we need to switch network: + * - the delta determine the urgency to switch and/or or the expected evilness of the disruption + * - match the uregncy of the switch versus the packet usage at the interface + */ + boolean shouldSwitchNetwork(int networkDelta) { + int delta; + if (networkDelta < 0) { + networkDelta = -1 * networkDelta; + } + delta = networkDelta; + if (mWifiInfo != null) { + //TODO: look at per AC packet count, do not switch if VO/VI traffic is present at the interface + //TODO: discriminate between ucast and mcast, since the rxSuccessRate include all the bonjour and Ipv6 + //TODO: broadcasts + if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { + delta -= 1000; + } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { + delta -= 6; + } + loge("WifiStateMachine shouldSwitchNetwork " + + " txSuccessRate=" + String.format( "%.2f", mWifiInfo.txSuccessRate) + + " rxSuccessRate=" +String.format( "%.2f", mWifiInfo.rxSuccessRate) + + " delta " + networkDelta + " -> " + delta); + } else { + loge("WifiStateMachine shouldSwitchNetwork " + + " delta " + networkDelta + " -> " + delta); + } + if (delta > 0) { + return true; + } + return false; + } private void calculateWifiScore(WifiLinkLayerStats stats) { - mWifiInfo.updatePacketRates(stats); + if (stats == null || mWifiLinkLayerStatsSupported <= 0) { + long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); + long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); + mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); + + } else { + mWifiInfo.updatePacketRates(stats); + } int score = 56; //starting score, temporarily hardcoded in between 50 and 60 boolean isBadLinkspeed = (mWifiInfo.is24GHz() && mWifiInfo.getLinkSpeed() <= 6) @@ -2496,10 +2535,7 @@ public class WifiStateMachine extends StateMachine { score += 4; //so as bad rssi alone dont kill us } - - if (isBadRSSI) { - if (mWifiInfo.badRssiCount < 7) mWifiInfo.badRssiCount += 1; } else if (isLowRSSI) { @@ -2762,7 +2798,13 @@ public class WifiStateMachine extends StateMachine { if (state != mNetworkInfo.getDetailedState()) { mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); - if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); + if (mNetworkAgent != null) { + if (mAutoRoaming == AutoRoaming.IDLE || + (state != DetailedState.DISCONNECTED && state != DetailedState.DISCONNECTING) ) { + //don't tell the Network agent if we are doing a disconnect-roam + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + } } } @@ -2799,7 +2841,11 @@ public class WifiStateMachine extends StateMachine { * using the interface, stopping DHCP & disabling interface */ private void handleNetworkDisconnect() { - if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP"); + if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" + + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() + +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() + +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() + +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); stopDhcp(); @@ -2811,16 +2857,7 @@ public class WifiStateMachine extends StateMachine { } /* Reset data structures */ - // TODO: use a WifiInfo.reset(), although it would require moving the - // MIN_RSSI to WifiInfo. - mWifiInfo.setInetAddress(null); - mWifiInfo.setBSSID(null); - mWifiInfo.setSSID(null); - mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); - mWifiInfo.setRssi(MIN_RSSI); - mWifiInfo.setLinkSpeed(-1); - mWifiInfo.setFrequency(-1); - mWifiInfo.setMeteredHint(false); + mWifiInfo.reset(); setNetworkDetailedState(DetailedState.DISCONNECTED); if (mNetworkAgent != null) { @@ -2836,6 +2873,7 @@ public class WifiStateMachine extends StateMachine { sendNetworkStateChangeBroadcast(mLastBssid); mLastBssid= null; + registerDisconnected(); mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; } @@ -2903,6 +2941,16 @@ public class WifiStateMachine extends StateMachine { mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); } + void renewDhcp() { + if (mDhcpStateMachine == null) { + mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( + mContext, WifiStateMachine.this, mInterfaceName); + + } + mDhcpStateMachine.registerForPreDhcpNotification(); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); + } + void stopDhcp() { if (mDhcpStateMachine != null) { /* In case we were in middle of DHCP operation restore back powermode */ @@ -2950,6 +2998,24 @@ public class WifiStateMachine extends StateMachine { if (addrs.hasNext()) { addr = addrs.next(); } + + if (mAutoRoaming != mAutoRoaming.IDLE) { + if (addr instanceof Inet4Address) { + int previousAddress = mWifiInfo.getIpAddress(); + int newAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); + if (previousAddress != newAddress) { + loge("handleSuccessfulIpConfiguration, roaming and address changed" + + mWifiInfo + " got: " + addr); + } else { + + } + } else { + loge("handleSuccessfulIpConfiguration, roaming and didnt get an IPv4 address" + + addr.toString()); + + + } + } mWifiInfo.setInetAddress(addr); mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); updateLinkProperties(); @@ -4161,6 +4227,9 @@ public class WifiStateMachine extends StateMachine { case CMD_AUTO_CONNECT: s = "CMD_AUTO_CONNECT"; break; + case CMD_AUTO_ROAM: + s = "CMD_AUTO_ROAM"; + break; case CMD_BOOT_COMPLETED: s = "CMD_BOOT_COMPLETED"; break; @@ -4312,6 +4381,28 @@ public class WifiStateMachine extends StateMachine { return s; } + void registerConnected() { + if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { + long now_ms = System.currentTimeMillis(); + //we are switching away from this configuration, hence record the time we were connected last + WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); + if (config != null) { + config.lastConnected = System.currentTimeMillis(); + } + } + } + + void registerDisconnected() { + if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { + long now_ms = System.currentTimeMillis(); + //we are switching away from this configuration, hence record the time we were connected last + WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); + if (config != null) { + config.lastDisconnected = System.currentTimeMillis(); + } + } + } + WifiConfiguration getCurrentWifiConfiguration() { if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { return null; @@ -4319,6 +4410,10 @@ public class WifiStateMachine extends StateMachine { return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); } + String getCurrentBSSID() { + return mLastBssid; + } + class ConnectModeState extends State { @Override public boolean processMessage(Message message) { @@ -4465,6 +4560,8 @@ public class WifiStateMachine extends StateMachine { mWifiNative.reconnect(); } break; + case CMD_AUTO_ROAM: + return HANDLED; case CMD_AUTO_CONNECT: /* Work Around: wpa_supplicant can get in a bad state where it returns a non * associated status thus the STATUS command but somehow-someplace still thinks @@ -4479,11 +4576,16 @@ public class WifiStateMachine extends StateMachine { /* connect command coming from auto-join */ config = (WifiConfiguration) message.obj; netId = message.arg1; + int roam = message.arg2; loge("CMD_AUTO_CONNECT sup state " + mSupplicantStateTracker.getSupplicantStateName() + " my state " + getCurrentState().getName() - + " nid=" + Integer.toString(netId)); + + " nid=" + Integer.toString(netId) + + " roam=" + Integer.toString(roam)); + + /* make sure we cancel any previous roam request */ + config.BSSID = "any"; /* Save the network config */ if (config != null) { @@ -4507,8 +4609,14 @@ public class WifiStateMachine extends StateMachine { /* The state tracker handles enabling networks upon completion/failure */ mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); //replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); - /* Expect a disconnection from the old connection */ - transitionTo(mDisconnectingState); + if (roam > 0) { + mAutoRoaming = AutoRoaming.EXTENDED_ROAMING; + } + if (mAutoRoaming != AutoRoaming.IDLE) { + transitionTo(mRoamingState); + } else { + transitionTo(mDisconnectingState); + } } else { loge("Failed to connect config: " + config + " netId: " + netId); replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, @@ -4539,6 +4647,8 @@ public class WifiStateMachine extends StateMachine { /* Save the network config */ if (config != null) { + /* make sure we don't lock the BSSID, TODO: allow it if it was not previously set by autojoin */ + config.BSSID = "any"; NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); netId = result.getNetworkId(); } @@ -4740,8 +4850,54 @@ public class WifiStateMachine extends StateMachine { deferMessage(message); break; case CMD_START_SCAN: - /* Do not attempt to connect when we are already connected */ - handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + if (DBG) { + loge("WifiStateMachine CMD_START_SCAN source " + message.arg1); + } + if (message.arg1 == SCAN_ALARM_SOURCE) { + if (mWifiInfo != null) { + //don't scan if lots of packets are being sent + //TODO add stats from TrafficPoller + if (mWifiInfo.txSuccessRate > 25 || mWifiInfo.rxSuccessRate > 80) { + if (DBG) { + loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 + + " and ignore scans " + + "tx=" + String.format( "%.2f", mWifiInfo.txSuccessRate) + + "rx=" + String.format( "%.2f", mWifiInfo.rxSuccessRate)); + } + return HANDLED; + } + } + WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); + if (currentConfiguration != null) { + Set channels = mWifiConfigStore.makeChannelList(currentConfiguration, + ONE_HOUR_MILLI); + if (channels != null && channels.size() != 0) { + StringBuilder freqs = new StringBuilder(); + boolean first = true; + for (Integer channel : channels) { + if (!first) + freqs.append(","); + freqs.append(channel.toString()); + first = false; + } + if (DBG) { + loge("WifiStateMachine starting scan with " + freqs); + } + // call wifi native to start the scan + if (startScanNative(SCAN_ONLY_MODE, freqs.toString())) { + // only count battery consumption if scan request is accepted + noteScanStart(SCAN_ALARM_SOURCE, null); + } + } else { + if (DBG) { + loge("WifiStateMachine starting scan, did not find channels"); + } + handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + } + } + } else { + handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); + } break; /* Ignore connection to same network */ case WifiManager.CONNECT_NETWORK: @@ -4804,8 +4960,13 @@ public class WifiStateMachine extends StateMachine { case CMD_RSSI_POLL: if (message.arg1 == mRssiPollToken) { WifiLinkLayerStats stats = null; - if (mWifiLinkLayerStatsSupported) { + //try a reading L2 stats a couple of time, allow for a few failures + //in case the HAL/drivers are not completely initialized once we get there + if (mWifiLinkLayerStatsSupported > 0) { stats = mWifiNative.getWifiLinkLayerStats(); + if (stats == null && mWifiLinkLayerStatsSupported > 0) { + mWifiLinkLayerStatsSupported -= 1; + } } // Get Info and continue polling fetchRssiLinkSpeedAndFrequencyNative(); @@ -4855,7 +5016,11 @@ public class WifiStateMachine extends StateMachine { if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { // TODO: If we're switching between static IP configuration and DHCP, remove the // static configuration first. - startDhcp(); + if (mAutoRoaming != AutoRoaming.IDLE) { + renewDhcp(); + } else { + startDhcp(); + } } else { // stop any running dhcp before assigning static IP stopDhcp(); @@ -4922,6 +5087,7 @@ public class WifiStateMachine extends StateMachine { setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); sendNetworkStateChangeBroadcast(mLastBssid); + mAutoRoaming = AutoRoaming.IDLE; } @Override public boolean processMessage(Message message) { @@ -4968,6 +5134,70 @@ public class WifiStateMachine extends StateMachine { } } + class RoamingState extends State { + @Override + public void enter() { + if (DBG) { + log("RoamingState Enter" + + " mScreenOn=" + mScreenOn ); + } + setScanAlarm(false); + } + @Override + public boolean processMessage(Message message) { + logStateAndMessage(message, getClass().getSimpleName()); + + switch (message.what) { + case WifiWatchdogStateMachine.POOR_LINK_DETECTED: + if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); + return HANDLED; + case CMD_UNWANTED_NETWORK: + if (DBG) log("Roaming and CS doesnt want the network -> ignore"); + return HANDLED; + case CMD_SET_OPERATIONAL_MODE: + if (message.arg1 != CONNECT_MODE) { + deferMessage(message); + } + break; + case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: + /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT + * we have missed the network disconnection, transition to mDisconnectedState + * and handle the rest of the events there + */ + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); + break; + case WifiMonitor.NETWORK_CONNECTION_EVENT: + if (DBG) log("roaming and Network connection established"); + mLastNetworkId = message.arg1; + mLastBssid = (String) message.obj; + + mWifiInfo.setBSSID(mLastBssid); + mWifiInfo.setNetworkId(mLastNetworkId); + /* send event to CM & network change broadcast */ + setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); + sendNetworkStateChangeBroadcast(mLastBssid); + transitionTo(mObtainingIpState); + break; + case WifiMonitor.NETWORK_DISCONNECTION_EVENT: + //throw away but only if it correspond to the network we're roaming from , so, how to do that? + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + + @Override + public void exit() { + loge("WifiStateMachine: Leaving Roaming state"); + + /* Request a CS wakelock during transition to mobile */ + //checkAndSetConnectivityInstance(); + //mCm.requestNetworkTransitionWakelock(getName()); + } + } + class ConnectedState extends State { @Override public void enter() { @@ -4984,13 +5214,14 @@ public class WifiStateMachine extends StateMachine { } else { mCurrentScanAlarmMs = 0; } + registerConnected(); } @Override public boolean processMessage(Message message) { logStateAndMessage(message, getClass().getSimpleName()); switch (message.what) { - case WifiWatchdogStateMachine.POOR_LINK_DETECTED: + case WifiWatchdogStateMachine.POOR_LINK_DETECTED: if (DBG) log("Watchdog reports poor link"); try { mNwService.disableIpv6(mInterfaceName); @@ -5014,6 +5245,64 @@ public class WifiStateMachine extends StateMachine { //low wifi score threshold sendMessage(CMD_DISCONNECT); return HANDLED; + case CMD_AUTO_ROAM: + /* this will happen similarly to an Auto_CONNECT, except we specify the BSSID */ + /* Work Around: wpa_supplicant can get in a bad state where it returns a non + * associated status thus the STATUS command but somehow-someplace still thinks + * it is associated and thus will ignore select/reconnect command with + * following message: + * "Already associated with the selected network - do nothing" + * + * Hence, sends a disconnect to supplicant first. + */ + mWifiNative.disconnect(); + + /* connect command coming from auto-join */ + String bssid = (String) message.obj; + int netId = mLastNetworkId; + int roam = message.arg2; + WifiConfiguration config = getCurrentWifiConfiguration(); + + loge("CMD_AUTO_ROAM sup state " + + mSupplicantStateTracker.getSupplicantStateName() + + " my state " + getCurrentState().getName() + + " nid=" + Integer.toString(netId) + + " roam=" + Integer.toString(roam) + + bssid); + + /* save the BSSID so as to lock it @ firmware */ + config.BSSID = bssid; + /* Save the network config */ + if (config != null) { + loge("CMD_AUTO_ROAM will save config -> " + config.SSID + + " nid=" + Integer.toString(netId)); + NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); + netId = result.getNetworkId(); + loge("CMD_AUTO_ROAM did save config -> " + + " nid=" + Integer.toString(netId)); + } + + if (mWifiConfigStore.selectNetwork(netId) && + mWifiNative.reconnect()) { + // we selected a better config, maybe because we could not see the last user + // selection, then forget it. We will remember the selection + // only if it was persisted. + // mWifiConfigStore. + // setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); + + /* The state tracker handles enabling networks upon completion/failure */ + mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); + //replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); + mAutoRoaming = AutoRoaming.ROAMING; + transitionTo(mRoamingState); + + } else { + loge("Failed to connect config: " + config + " netId: " + netId); + replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, + WifiManager.ERROR); + break; + } + break; default: return NOT_HANDLED; } @@ -5028,6 +5317,8 @@ public class WifiStateMachine extends StateMachine { /* Request a CS wakelock during transition to mobile */ checkAndSetConnectivityInstance(); mCm.requestNetworkTransitionWakelock(getName()); + loge("WifiStateMachine: Left Connected state"); + } } @@ -5107,11 +5398,20 @@ public class WifiStateMachine extends StateMachine { } if (PDBG) { + String roamstr = ""; + if (mAutoRoaming==AutoRoaming.EXTENDED_ROAMING) + roamstr = "Extended-Roaming"; + if (mAutoRoaming==AutoRoaming.ROAMING) + roamstr = "Roaming"; loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs + " mEnableBackgroundScan= " + mEnableBackgroundScan - + " screenOn=" + mScreenOn); + + " screenOn=" + mScreenOn + + roamstr); } + /** clear the roaming state, if we were roaming, we failed */ + mAutoRoaming = AutoRoaming.IDLE; + /* * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, * otherwise we initiate an infrequent scan that wakes up the device to ensure diff --git a/service/java/com/android/server/wifi/WifiTrafficPoller.java b/service/java/com/android/server/wifi/WifiTrafficPoller.java index 5da7ffa28..20e7221ad 100644 --- a/service/java/com/android/server/wifi/WifiTrafficPoller.java +++ b/service/java/com/android/server/wifi/WifiTrafficPoller.java @@ -104,15 +104,6 @@ final class WifiTrafficPoller { Message.obtain(mTrafficHandler, REMOVE_CLIENT, client).sendToTarget(); } - boolean shouldSwitchNetwork(int networkDelta) { - if (networkDelta > 100) - return true; - - - - return false; - } - void enableVerboseLogging(int verbose) { if (verbose > 0 ) { DBG = true; -- cgit v1.2.3