merge in lmp-mr1-nova-release history after reset to lmp-mr1-release
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java
index 0dfa3fb..e30b1c7 100644
--- a/service/java/com/android/server/wifi/WifiAutoJoinController.java
+++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java
@@ -171,11 +171,23 @@
             // Fetch the previous instance for this result
             ScanResult sr = scanResultCache.get(result.BSSID);
             if (sr != null) {
+                if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0
+                        && result.level == 0
+                        && sr.level < -20) {
+                    // A 'zero' RSSI reading is most likely a chip problem which returns
+                    // an unknown RSSI, hence ignore it
+                    result.level = sr.level;
+                }
+
                 // If there was a previous cache result for this BSSID, average the RSSI values
                 result.averageRssi(sr.level, sr.seen, mScanResultMaximumAge);
 
                 // Remove the previous Scan Result - this is not necessary
                 scanResultCache.remove(result.BSSID);
+            } else if (mWifiConfigStore.scanResultRssiLevelPatchUp != 0 && result.level == 0) {
+                // A 'zero' RSSI reading is most likely a chip problem which returns
+                // an unknown RSSI, hence initialize it to a sane value
+                result.level = mWifiConfigStore.scanResultRssiLevelPatchUp;
             }
 
             if (!mNetworkScoreCache.isScoredNetwork(result)) {
@@ -572,30 +584,75 @@
         }
     }
 
+    int compareWifiConfigurationsFromVisibility(WifiConfiguration a, int aRssiBoost,
+             WifiConfiguration b, int bRssiBoost) {
 
-    int getScoreFromVisibility(WifiConfiguration.Visibility visibility, int rssiBoost, String dbg) {
-        int rssiBoost5 = 0;
-        int score = 0;
+        int aRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
+        int bRssiBoost5 = 0; // 5GHz RSSI boost to apply for purpose band selection (5GHz pref)
+
+        int aScore = 0;
+        int bScore = 0;
+
+        boolean aPrefers5GHz = false;
+        boolean bPrefers5GHz = false;
 
         /**
-         * Boost RSSI value of 5GHz bands iff the base value is better than threshold
+         * Calculate a boost to apply to RSSI value of configuration we want to join on 5GHz:
+         * Boost RSSI value of 5GHz bands iff the base value is better than threshold,
+         * penalize the RSSI value of 5GHz band iff the base value is lower than threshold
          * 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 typically
-         * at least 6-10 dB higher
          */
-        rssiBoost5 = rssiBoostFrom5GHzRssi(visibility.rssi5, dbg+"->");
+        aRssiBoost5 = rssiBoostFrom5GHzRssi(a.visibility.rssi5, a.configKey() + "->");
+        bRssiBoost5 = rssiBoostFrom5GHzRssi(b.visibility.rssi5, b.configKey() + "->");
 
-        // Select which band to use so as to score a
-        if (visibility.rssi5 + rssiBoost5 > visibility.rssi24) {
+        // Select which band to use for a
+        if (a.visibility.rssi5 + aRssiBoost5 > b.visibility.rssi24) {
             // Prefer a's 5GHz
-            score = visibility.rssi5 + rssiBoost5 + rssiBoost;
-        } else {
-            // Prefer a's 2.4GHz
-            score = visibility.rssi24 + rssiBoost;
+            aPrefers5GHz = true;
         }
 
-        return score;
+        // Select which band to use for b
+        if (b.visibility.rssi5 + bRssiBoost5 > b.visibility.rssi24) {
+            // Prefer b's 5GHz
+            bPrefers5GHz = true;
+        }
+
+        if (aPrefers5GHz) {
+            if (bPrefers5GHz) {
+                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
+                // one, but directly compare the RSSI values, this improves stability,
+                // since the 5GHz RSSI boost can introduce large fluctuations
+                aScore = a.visibility.rssi5 + aRssiBoost;
+            } else {
+                // If only a is on 5GHz, then apply the 5GHz preference boost to a
+                aScore = a.visibility.rssi5 + aRssiBoost + aRssiBoost5;
+            }
+        } else {
+            aScore = a.visibility.rssi24 + aRssiBoost;
+        }
+
+        if (bPrefers5GHz) {
+            if (aPrefers5GHz) {
+                // If both a and b are on 5GHz then we don't apply the 5GHz RSSI boost to either
+                // one, but directly compare the RSSI values, this improves stability,
+                // since the 5GHz RSSI boost can introduce large fluctuations
+                bScore = b.visibility.rssi5 + bRssiBoost;
+            } else {
+                // If only b is on 5GHz, then apply the 5GHz preference boost to b
+                bScore = b.visibility.rssi5 + bRssiBoost + bRssiBoost5;
+            }
+        } else {
+            bScore = b.visibility.rssi24 + bRssiBoost;
+        }
+        if (VDBG) {
+            logDbg("        " + a.configKey() + " is5=" + aPrefers5GHz + " score=" + aScore
+                    + b.configKey() + " is5=" + bPrefers5GHz + " score=" + bScore);
+        }
+        // Compare a and b
+        // If a score is higher then a > b and the order is descending (negative)
+        // If b score is higher then a < b and the order is ascending (positive)
+        return bScore - aScore;
     }
 
     // Compare WifiConfiguration by RSSI, and return a comparison value in the range [-50, +50]
@@ -646,13 +703,7 @@
             );
         }
 
-        scoreA = getScoreFromVisibility(astatus, aRssiBoost, a.configKey());
-        scoreB = getScoreFromVisibility(bstatus, bRssiBoost, b.configKey());
-
-        // Compare a and b
-        // If a score is higher then a > b and the order is descending (negative)
-        // If b score is higher then a < b and the order is ascending (positive)
-        order = scoreB - scoreA;
+        order = compareWifiConfigurationsFromVisibility(a, aRssiBoost, b, bRssiBoost);
 
         // Normalize the order to [-50, +50]
         if (order > 50) order = 50;
@@ -670,13 +721,11 @@
                     + "," + a.visibility.rssi5
                     + ") num=(" + a.visibility.num24
                     + "," + a.visibility.num5 + ")"
-                    + " scorea=" + scoreA
                     + prefer + b.configKey()
                     + " rssi=(" + b.visibility.rssi24
                     + "," + b.visibility.rssi5
                     + ") num=(" + b.visibility.num24
                     + "," + b.visibility.num5 + ")"
-                    + " scoreb=" + scoreB
                     + " -> " + order);
         }
 
@@ -883,8 +932,7 @@
             int boost = mWifiConfigStore.bandPreferenceBoostFactor5
                     *(rssi - mWifiConfigStore.bandPreferenceBoostThreshold5);
             if (boost > 50) {
-                // 50 dB boost is set so as to overcome the hysteresis of +20 plus a difference of
-                // 25 dB between 2.4 and 5GHz band. This allows jumping from 2.4 to 5GHz
+                // 50 dB boost allows jumping from 2.4 to 5GHz
                 // consistently
                 boost = 50;
             }
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index 028e2bb..ebdf40e 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -387,6 +387,9 @@
     public boolean enableWifiCellularHandoverUserTriggeredAdjustment = true;
 
     public int currentNetworkBoost = 25;
+    public int scanResultRssiLevelPatchUp = -85;
+
+    public static final int maxNumScanCacheEntries = 128;
 
     /**
      * Regex pattern for extracting a connect choice.
@@ -539,8 +542,12 @@
 
         enableAutoJoinWhenAssociated = mContext.getResources().getBoolean(
                 R.bool.config_wifi_framework_enable_associated_network_selection);
+
         currentNetworkBoost = mContext.getResources().getInteger(
                 R.integer.config_wifi_framework_current_network_boost);
+
+        scanResultRssiLevelPatchUp = mContext.getResources().getInteger(
+                R.integer.config_wifi_framework_scan_result_rssi_level_patchup_value);
     }
 
     void enableVerboseLogging(int verbose) {
@@ -1793,7 +1800,7 @@
     }
 
     public void setLastSelectedConfiguration(int netId) {
-        if (DBG) {
+        if (VDBG) {
             loge("setLastSelectedConfiguration " + Integer.toString(netId));
         }
         if (netId == WifiConfiguration.INVALID_NETWORK_ID) {
@@ -2098,7 +2105,6 @@
                         }
 
                         if (key.startsWith(BSSID_KEY_END)) {
-
                             if ((bssid != null) && (ssid != null)) {
 
                                 if (config.scanResultCache == null) {
@@ -3353,6 +3359,30 @@
                     scanResult.untrusted = true;
                 }
 
+                if (config.scanResultCache.size() > (maxNumScanCacheEntries + 64)) {
+                    long now_dbg = 0;
+                    if (VVDBG) {
+                        loge(" Will trim config " + config.configKey()
+                                + " size " + config.scanResultCache.size());
+
+                        for (ScanResult r : config.scanResultCache.values()) {
+                            loge("     " + result.BSSID + " " + result.seen);
+                        }
+                        now_dbg = SystemClock.elapsedRealtimeNanos();
+                    }
+                    // Trim the scan result cache to maxNumScanCacheEntries entries max
+                    // Since this operation is expensive, make sure it is not performed
+                    // until the cache has grown significantly above the trim treshold
+                    config.trimScanResultsCache(maxNumScanCacheEntries);
+                    if (VVDBG) {
+                        long diff = SystemClock.elapsedRealtimeNanos() - now_dbg;
+                        loge(" Finished trimming config, time(ns) " + diff);
+                        for (ScanResult r : config.scanResultCache.values()) {
+                            loge("     " + r.BSSID + " " + r.seen);
+                        }
+                    }
+                }
+
                 // Add the scan result to this WifiConfiguration
                 config.scanResultCache.put(scanResult.BSSID, scanResult);
                 // Since we added a scan result to this configuration, re-attempt linking
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index a1ff294..6944461 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -7014,6 +7014,14 @@
                                     + " -> obsolete");
                             return HANDLED;
                         }
+                        if (mP2pConnected.get()) {
+                            loge("WifiStateMachine L2Connected CMD_START_SCAN source "
+                                    + message.arg1
+                                    + " " + message.arg2 + ", " + mDelayedScanCounter
+                                    + " ignore because P2P is connected");
+                            messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
+                            return HANDLED;
+                        }
                         boolean tryFullBandScan = false;
                         boolean restrictChannelList = false;
                         long now_ms = System.currentTimeMillis();
@@ -7931,8 +7939,14 @@
                     if (message.arg1 == SCAN_ALARM_SOURCE) {
                         // Check if the CMD_START_SCAN message is obsolete (and thus if it should
                         // not be processed) and restart the scan
+                        int period =  mDisconnectedScanPeriodMs;
+                        if (mP2pConnected.get()) {
+                           period = (int)Settings.Global.getLong(mContext.getContentResolver(),
+                                    Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
+                                    mDisconnectedScanPeriodMs);
+                        }
                         if (!checkAndRestartDelayedScan(message.arg2,
-                                true, mDisconnectedScanPeriodMs, null, null)) {
+                                true, period, null, null)) {
                             messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE;
                             loge("WifiStateMachine Disconnected CMD_START_SCAN source "
                                     + message.arg1
@@ -7968,6 +7982,12 @@
                         if (DBG) log("Turn on scanning after p2p disconnected");
                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
+                    } else {
+                        // If P2P is not connected and there are saved networks, then restart
+                        // scanning at the normal period. This is necessary because scanning might
+                        // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
+                        // was set to zero.
+                        startDelayedScan(mDisconnectedScanPeriodMs, null, null);
                     }
                 case CMD_RECONNECT:
                 case CMD_REASSOCIATE: