handle supplicant disconnected state change in roaming state + make roaming less erratic

bug: 16753407
bug: 16823537

Change-Id: I47f1073b3775880d261ec2a963732c35454173cf
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java
index 354e39a..d93c8b8 100644
--- a/service/java/com/android/server/wifi/WifiAutoJoinController.java
+++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java
@@ -80,6 +80,8 @@
     public static final int AUTO_JOIN_EXTENDED_ROAMING = 2;
     public static final int AUTO_JOIN_OUT_OF_NETWORK_ROAMING = 3;
 
+    public static final int HIGH_THRESHOLD_MODIFIER = 5;
+
     WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s,
                            WifiConnectionStatistics st, WifiNative n) {
         mContext = c;
@@ -814,12 +816,12 @@
         // Determine which BSSID we want to associate to, taking account
         // relative strength of 5 and 2.4 GHz BSSIDs
         long nowMs = System.currentTimeMillis();
-        int bRssiBoost5 = 0;
-        int aRssiBoost5 = 0;
-        int bRssiBoost = 0;
-        int aRssiBoost = 0;
-        for (ScanResult b : current.scanResultCache.values()) {
 
+        for (ScanResult b : current.scanResultCache.values()) {
+            int bRssiBoost5 = 0;
+            int aRssiBoost5 = 0;
+            int bRssiBoost = 0;
+            int aRssiBoost = 0;
             if ((b.seen == 0) || (b.BSSID == null)
                     || (nowMs - b.seen) > age ) {
                     // TODO: do not apply blacklisting right now so as to leave this
@@ -839,35 +841,61 @@
             if (currentBSSID != null && currentBSSID.equals(b.BSSID)) {
                 // Reduce the benefit of hysteresis if RSSI <= -75
                 if (b.level <= WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
-                    bRssiBoost = +6;
+                    bRssiBoost = +8;
                 } else {
-                    bRssiBoost = +10;
+                    bRssiBoost = +14;
                 }
             }
             if (currentBSSID != null && currentBSSID.equals(a.BSSID)) {
                 if (a.level <= WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
                     // Reduce the benefit of hysteresis if RSSI <= -75
-                    aRssiBoost = +6;
+                    aRssiBoost = +8;
                 } else {
-                    aRssiBoost = +10;
+                    aRssiBoost = +14;
                 }
             }
 
-            // Favor 5GHz: give a boost to 5GHz BSSIDs
+            // Favor 5GHz: give a boost to 5GHz BSSIDs, with a slightly progressive curve
             //   Boost the BSSID if it is on 5GHz, above a threshold
             //   But penalize it if it is on 5GHz and below threshold
+            //
+            //   With he current threshold values, 5GHz network with RSSI above -55
+            //   Are given a boost of 30DB which is enough to overcome the current BSSID
+            //   hysteresis (+14) plus 2.4/5 GHz signal strength difference on most cases
             if (b.is5GHz() && (b.level+bRssiBoost)
+                    > (WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD
+                    + HIGH_THRESHOLD_MODIFIER) ) {
+                // boost by 30 if > -50
+                bRssiBoost5 = 30;
+            } else if (b.is5GHz() && (b.level+bRssiBoost)
                     > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
+                // boost by 20 if > -55
                 bRssiBoost5 = 20;
             } else if (b.is5GHz() && (b.level+bRssiBoost)
+                    > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW) {
+                // boost by 10 if > -65
+                bRssiBoost5 = 10;
+            } else if (b.is5GHz() && (b.level+bRssiBoost)
                     < WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
+                // penalize by 10 if < -75
                 bRssiBoost5 = -10;
             }
             if (a.is5GHz() && (a.level+aRssiBoost)
+                    > (WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD
+                    + HIGH_THRESHOLD_MODIFIER) ) {
+                // boost by 30 if > -50
+                aRssiBoost5 = 30;
+            } else if (a.is5GHz() && (a.level+aRssiBoost)
                     > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD) {
+                // boost by 20 if -55
                 aRssiBoost5 = 20;
             } else if (a.is5GHz() && (a.level+aRssiBoost)
+                    > WifiConfiguration.A_BAND_PREFERENCE_RSSI_THRESHOLD_LOW) {
+                // boost by 10 if > -65
+                aRssiBoost5 = 10;
+            } else if (a.is5GHz() && (a.level+aRssiBoost)
                     < WifiConfiguration.G_BAND_PREFERENCE_RSSI_THRESHOLD) {
+                // penalize by 10 if -75
                 aRssiBoost5 = -10;
             }
 
@@ -878,7 +906,8 @@
                 }
                 logDbg("attemptRoam: "
                         + b.BSSID + " rssi=" + b.level + " boost=" + Integer.toString(bRssiBoost)
-                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency + comp
+                        + "/" + Integer.toString(bRssiBoost5) + " freq=" + b.frequency
+                        + comp
                         + a.BSSID + " rssi=" + a.level + " boost=" + Integer.toString(aRssiBoost)
                         + "/" + Integer.toString(aRssiBoost5) + " freq=" + a.frequency);
             }
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index d0dafae..00c7fc7 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -307,7 +307,7 @@
 
     public void autoRoamSetBSSID(WifiConfiguration config, String bssid) {
         mTargetRoamBSSID = "any";
-        if (config == null)
+        if (config == null || bssid == null)
             return;
         if (config.bssidOwnerUid == 0 || config.bssidOwnerUid == Process.WIFI_UID) {
             if (VDBG) {
@@ -6115,22 +6115,31 @@
                     break;
                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
                     /**
-                     *  If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT
+                     * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT
+                     * before NETWORK_DISCONNECTION_EVENT
+                     * And there is an associated BSSID corresponding to our target BSSID, then
                      * we have missed the network disconnection, transition to mDisconnectedState
-                     * and handle the rest of the events there
+                     * and handle the rest of the events there.
                      */
                     StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
+                    if (stateChangeResult.state == SupplicantState.DISCONNECTED
+                            || stateChangeResult.state == SupplicantState.INACTIVE
+                            || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) {
+                        if (DBG) {
+                            log("STATE_CHANGE_EVENT in roaming state "
+                                    + stateChangeResult.toString() );
+                        }
+                        if (stateChangeResult.BSSID != null
+                                && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) {
+                            setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
+                            handleNetworkDisconnect();
+                        }
+                    }
                     break;
                case WifiMonitor.NETWORK_CONNECTION_EVENT:
                    if (DBG) log("roaming and Network connection established");
                    mLastNetworkId = message.arg1;
                    mLastBssid = (String) message.obj;
-                   /**
-                    * We already have an IP address, we are going to the ObtainingIpAddress
-                    * state to renew it. Other parts of the system interpret an
-                    * ObtainingIpState change as not having IP address anymore,
-                    * hence, don't tell it there. */
                    mWifiInfo.setBSSID(mLastBssid);
                    mWifiInfo.setNetworkId(mLastNetworkId);
                    mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true);
@@ -6138,7 +6147,7 @@
                     * We already have an IP address, we are going to the ObtainingIpAddress
                     * state to renew it. Other parts of the system interpret an
                     * ObtainingIpState change as not having IP address anymore,
-                    * hence, don't tell it there. */
+                    * hence, don't send the state change there. */
                    // setNetworkDetailedState(DetailedState.OBTAINING_IPADDR);
                    // sendNetworkStateChangeBroadcast(mLastBssid);
                    transitionTo(mObtainingIpState);