From fcd4612f70bb22e11bf776c76afc45b03a5b026c Mon Sep 17 00:00:00 2001 From: Vinit Deshpande Date: Thu, 11 Jun 2015 18:22:23 -0700 Subject: Fix access point list jumping around in WifiSettings This happens because the scan times are very aggressive (to save power); and we don't find all APs on each scan. So on each scan, some APs are considered lost and some other are considered found; resulting in reordering the list. This change fixes that by requiring 3 scans to confirm absence of an AP. Bug: 7263326 Change-Id: I04f61ec5e5aa1589f457645acbf538c7e275a4bf --- .../com/android/settingslib/wifi/AccessPoint.java | 291 ++++++++++++--------- .../com/android/settingslib/wifi/WifiTracker.java | 61 ++++- 2 files changed, 221 insertions(+), 131 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 4cef286..0180a30 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -46,6 +46,7 @@ import android.util.LruCache; import com.android.settingslib.R; +import java.util.ArrayList; import java.util.Map; @@ -79,10 +80,15 @@ public class AccessPoint implements Comparable { * For now this data is used only with Verbose Logging so as to show the band and number * of BSSIDs on which that network is seen. */ - public LruCache mScanResultCache; + public LruCache mScanResultCache = new LruCache(32); + private static final String KEY_NETWORKINFO = "key_networkinfo"; private static final String KEY_WIFIINFO = "key_wifiinfo"; private static final String KEY_SCANRESULT = "key_scanresult"; + private static final String KEY_SSID = "key_ssid"; + private static final String KEY_SECURITY = "key_security"; + private static final String KEY_PSKTYPE = "key_psktype"; + private static final String KEY_SCANRESULTCACHE = "key_scanresultcache"; private static final String KEY_CONFIG = "key_config"; /** @@ -108,7 +114,6 @@ public class AccessPoint implements Comparable { private int pskType = PSK_UNKNOWN; private WifiConfiguration mConfig; - private ScanResult mScanResult; private int mRssi = Integer.MAX_VALUE; private long mSeen = 0; @@ -125,20 +130,35 @@ public class AccessPoint implements Comparable { if (mConfig != null) { loadConfig(mConfig); } - mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT); - if (mScanResult != null) { - loadResult(mScanResult); + if (savedState.containsKey(KEY_SSID)) { + ssid = savedState.getString(KEY_SSID); + } + if (savedState.containsKey(KEY_SECURITY)) { + security = savedState.getInt(KEY_SECURITY); + } + if (savedState.containsKey(KEY_PSKTYPE)) { + pskType = savedState.getInt(KEY_PSKTYPE); } mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO); if (savedState.containsKey(KEY_NETWORKINFO)) { mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO); } + if (savedState.containsKey(KEY_SCANRESULTCACHE)) { + ArrayList scanResultArrayList = + savedState.getParcelableArrayList(KEY_SCANRESULTCACHE); + mScanResultCache.evictAll(); + for (ScanResult result : scanResultArrayList) { + mScanResultCache.put(result.BSSID, result); + } + } update(mInfo, mNetworkInfo); + mRssi = getRssi(); + mSeen = getSeen(); } AccessPoint(Context context, ScanResult result) { mContext = context; - loadResult(result); + initWithScanResult(result); } AccessPoint(Context context, WifiConfiguration config) { @@ -240,6 +260,28 @@ public class AccessPoint implements Comparable { return WifiManager.calculateSignalLevel(mRssi, 4); } + public int getRssi() { + int rssi = Integer.MIN_VALUE; + for (ScanResult result : mScanResultCache.snapshot().values()) { + if (result.level > rssi) { + rssi = result.level; + } + } + + return rssi; + } + + public long getSeen() { + long seen = 0; + for (ScanResult result : mScanResultCache.snapshot().values()) { + if (result.timestamp > seen) { + seen = result.timestamp; + } + } + + return seen; + } + public NetworkInfo getNetworkInfo() { return mNetworkInfo; } @@ -455,120 +497,109 @@ public class AccessPoint implements Comparable { visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate)); } - if (mScanResultCache != null) { - int rssi5 = WifiConfiguration.INVALID_RSSI; - int rssi24 = WifiConfiguration.INVALID_RSSI; - int num5 = 0; - int num24 = 0; - int numBlackListed = 0; - int n24 = 0; // Number scan results we included in the string - int n5 = 0; // Number scan results we included in the string - Map list = mScanResultCache.snapshot(); - // TODO: sort list by RSSI or age - for (ScanResult result : list.values()) { - if (result.seen == 0) - continue; - - if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++; - - if (result.frequency >= LOWER_FREQ_5GHZ - && result.frequency <= HIGHER_FREQ_5GHZ) { - // Strictly speaking: [4915, 5825] - // number of known BSSID on 5GHz band - num5 = num5 + 1; - } else if (result.frequency >= LOWER_FREQ_24GHZ - && result.frequency <= HIGHER_FREQ_24GHZ) { - // Strictly speaking: [2412, 2482] - // number of known BSSID on 2.4Ghz band - num24 = num24 + 1; - } + int rssi5 = WifiConfiguration.INVALID_RSSI; + int rssi24 = WifiConfiguration.INVALID_RSSI; + int num5 = 0; + int num24 = 0; + int numBlackListed = 0; + int n24 = 0; // Number scan results we included in the string + int n5 = 0; // Number scan results we included in the string + Map list = mScanResultCache.snapshot(); + // TODO: sort list by RSSI or age + for (ScanResult result : list.values()) { + if (result.seen == 0) + continue; + + if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++; + + if (result.frequency >= LOWER_FREQ_5GHZ + && result.frequency <= HIGHER_FREQ_5GHZ) { + // Strictly speaking: [4915, 5825] + // number of known BSSID on 5GHz band + num5 = num5 + 1; + } else if (result.frequency >= LOWER_FREQ_24GHZ + && result.frequency <= HIGHER_FREQ_24GHZ) { + // Strictly speaking: [2412, 2482] + // number of known BSSID on 2.4Ghz band + num24 = num24 + 1; + } - // Ignore results seen, older than 20 seconds - if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue; + // Ignore results seen, older than 20 seconds + if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue; - if (result.frequency >= LOWER_FREQ_5GHZ - && result.frequency <= HIGHER_FREQ_5GHZ) { - if (result.level > rssi5) { - rssi5 = result.level; - } - if (n5 < 4) { - if (scans5GHz == null) scans5GHz = new StringBuilder(); - scans5GHz.append(" \n{").append(result.BSSID); - if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*"); - scans5GHz.append("=").append(result.frequency); - scans5GHz.append(",").append(result.level); - if (result.autoJoinStatus != 0) { - scans5GHz.append(",st=").append(result.autoJoinStatus); - } - if (result.numIpConfigFailures != 0) { - scans5GHz.append(",ipf=").append(result.numIpConfigFailures); - } - scans5GHz.append("}"); - n5++; - } - } else if (result.frequency >= LOWER_FREQ_24GHZ - && result.frequency <= HIGHER_FREQ_24GHZ) { - if (result.level > rssi24) { - rssi24 = result.level; + if (result.frequency >= LOWER_FREQ_5GHZ + && result.frequency <= HIGHER_FREQ_5GHZ) { + if (result.level > rssi5) { + rssi5 = result.level; + } + if (n5 < 4) { + if (scans5GHz == null) scans5GHz = new StringBuilder(); + scans5GHz.append(" \n{").append(result.BSSID); + if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*"); + scans5GHz.append("=").append(result.frequency); + scans5GHz.append(",").append(result.level); + if (result.autoJoinStatus != 0) { + scans5GHz.append(",st=").append(result.autoJoinStatus); } - if (n24 < 4) { - if (scans24GHz == null) scans24GHz = new StringBuilder(); - scans24GHz.append(" \n{").append(result.BSSID); - if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*"); - scans24GHz.append("=").append(result.frequency); - scans24GHz.append(",").append(result.level); - if (result.autoJoinStatus != 0) { - scans24GHz.append(",st=").append(result.autoJoinStatus); - } - if (result.numIpConfigFailures != 0) { - scans24GHz.append(",ipf=").append(result.numIpConfigFailures); - } - scans24GHz.append("}"); - n24++; + if (result.numIpConfigFailures != 0) { + scans5GHz.append(",ipf=").append(result.numIpConfigFailures); } + scans5GHz.append("}"); + n5++; } - } - visibility.append(" ["); - if (num24 > 0) { - visibility.append("(").append(num24).append(")"); - if (n24 <= 4) { - if (scans24GHz != null) { - visibility.append(scans24GHz.toString()); + } else if (result.frequency >= LOWER_FREQ_24GHZ + && result.frequency <= HIGHER_FREQ_24GHZ) { + if (result.level > rssi24) { + rssi24 = result.level; + } + if (n24 < 4) { + if (scans24GHz == null) scans24GHz = new StringBuilder(); + scans24GHz.append(" \n{").append(result.BSSID); + if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*"); + scans24GHz.append("=").append(result.frequency); + scans24GHz.append(",").append(result.level); + if (result.autoJoinStatus != 0) { + scans24GHz.append(",st=").append(result.autoJoinStatus); } - } else { - visibility.append("max=").append(rssi24); - if (scans24GHz != null) { - visibility.append(",").append(scans24GHz.toString()); + if (result.numIpConfigFailures != 0) { + scans24GHz.append(",ipf=").append(result.numIpConfigFailures); } + scans24GHz.append("}"); + n24++; } } - visibility.append(";"); - if (num5 > 0) { - visibility.append("(").append(num5).append(")"); - if (n5 <= 4) { - if (scans5GHz != null) { - visibility.append(scans5GHz.toString()); - } - } else { - visibility.append("max=").append(rssi5); - if (scans5GHz != null) { - visibility.append(",").append(scans5GHz.toString()); - } + } + visibility.append(" ["); + if (num24 > 0) { + visibility.append("(").append(num24).append(")"); + if (n24 <= 4) { + if (scans24GHz != null) { + visibility.append(scans24GHz.toString()); + } + } else { + visibility.append("max=").append(rssi24); + if (scans24GHz != null) { + visibility.append(",").append(scans24GHz.toString()); } } - if (numBlackListed > 0) - visibility.append("!").append(numBlackListed); - visibility.append("]"); - } else { - if (mRssi != Integer.MAX_VALUE) { - visibility.append(" rssi="); - visibility.append(mRssi); - if (mScanResult != null) { - visibility.append(", f="); - visibility.append(mScanResult.frequency); + } + visibility.append(";"); + if (num5 > 0) { + visibility.append("(").append(num5).append(")"); + if (n5 <= 4) { + if (scans5GHz != null) { + visibility.append(scans5GHz.toString()); + } + } else { + visibility.append("max=").append(rssi5); + if (scans5GHz != null) { + visibility.append(",").append(scans5GHz.toString()); } } } + if (numBlackListed > 0) + visibility.append("!").append(numBlackListed); + visibility.append("]"); return visibility.toString(); } @@ -635,28 +666,29 @@ public class AccessPoint implements Comparable { ssid = config.providerFriendlyName; else ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID)); - + security = getSecurity(config); networkId = config.networkId; mConfig = config; } - private void loadResult(ScanResult result) { + private void initWithScanResult(ScanResult result) { ssid = result.SSID; security = getSecurity(result); if (security == SECURITY_PSK) pskType = getPskType(result); mRssi = result.level; - mScanResult = result; - if (result.seen > mSeen) { - mSeen = result.seen; - } + mSeen = result.timestamp; } public void saveWifiState(Bundle savedState) { - savedState.putParcelable(KEY_CONFIG, mConfig); - savedState.putParcelable(KEY_SCANRESULT, mScanResult); + if (ssid != null) savedState.putString(KEY_SSID, getSsidStr()); + savedState.putInt(KEY_SECURITY, security); + savedState.putInt(KEY_PSKTYPE, pskType); + if (mConfig != null) savedState.putParcelable(KEY_CONFIG, mConfig); savedState.putParcelable(KEY_WIFIINFO, mInfo); + savedState.putParcelableArrayList(KEY_SCANRESULTCACHE, + new ArrayList(mScanResultCache.snapshot().values())); if (mNetworkInfo != null) { savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo); } @@ -667,32 +699,31 @@ public class AccessPoint implements Comparable { } boolean update(ScanResult result) { - if (result.seen > mSeen) { - mSeen = result.seen; - } - if (WifiTracker.sVerboseLogging > 0) { - if (mScanResultCache == null) { - mScanResultCache = new LruCache(32); - } + if (ssid.equals(result.SSID) && security == getSecurity(result)) { + /* Update the LRU timestamp, if BSSID exists */ + mScanResultCache.get(result.BSSID); + + /* Add or update the scan result for the BSSID */ mScanResultCache.put(result.BSSID, result); - } - if (ssid.equals(result.SSID) && security == getSecurity(result)) { - if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) { - int oldLevel = getLevel(); - mRssi = result.level; - if (getLevel() != oldLevel && mAccessPointListener != null) { - mAccessPointListener.onLevelChanged(this); - } + int oldLevel = getLevel(); + int oldRssi = getRssi(); + mSeen = getSeen(); + mRssi = (getRssi() + oldRssi)/2; + int newLevel = getLevel(); + + if (newLevel > 0 && newLevel != oldLevel && mAccessPointListener != null) { + mAccessPointListener.onLevelChanged(this); } // This flag only comes from scans, is not easily saved in config if (security == SECURITY_PSK) { pskType = getPskType(result); } - mScanResult = result; + if (mAccessPointListener != null) { mAccessPointListener.onAccessPointChanged(this); } + return true; } return false; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 19be4a5..f4e4ea1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -28,6 +28,7 @@ import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.util.Log; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; @@ -35,9 +36,12 @@ import com.android.settingslib.R; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -45,6 +49,7 @@ import java.util.concurrent.atomic.AtomicBoolean; */ public class WifiTracker { private static final String TAG = "WifiTracker"; + private static final boolean DBG = false; /** verbose logging flag. this flag is set thru developer debugging options * and used so as to assist with in-the-field WiFi connectivity debugging */ @@ -70,6 +75,10 @@ public class WifiTracker { private boolean mSavedNetworksExist; private boolean mRegistered; private ArrayList mAccessPoints = new ArrayList<>(); + private HashMap mSeenBssids = new HashMap<>(); + private HashMap mScanResultCache = new HashMap<>(); + private Integer mScanId = 0; + private static final int NUM_SCANS_TO_CONFIRM_AP_LOSS = 3; private NetworkInfo mLastNetworkInfo; private WifiInfo mLastInfo; @@ -166,6 +175,11 @@ public class WifiTracker { if (mScanner == null) { mScanner = new Scanner(); } + + mScanResultCache.clear(); + mSeenBssids.clear(); + mScanId = 0; + if (mWifiManager.isWifiEnabled()) { mScanner.resume(); } @@ -237,6 +251,33 @@ public class WifiTracker { } } + private Collection fetchScanResults() { + mScanId++; + final List newResults = mWifiManager.getScanResults(); + for (ScanResult newResult : newResults) { + mScanResultCache.put(newResult.BSSID, newResult); + mSeenBssids.put(newResult.BSSID, mScanId); + } + + if (mScanId > NUM_SCANS_TO_CONFIRM_AP_LOSS) { + if (DBG) Log.d(TAG, "------ Dumping SSIDs that were expired on this scan ------"); + Integer threshold = mScanId - NUM_SCANS_TO_CONFIRM_AP_LOSS; + for (Iterator> it = mSeenBssids.entrySet().iterator(); + it.hasNext(); /* nothing */) { + Map.Entry e = it.next(); + if (e.getValue() < threshold) { + ScanResult result = mScanResultCache.get(e.getKey()); + if (DBG) Log.d(TAG, "Removing " + e.getKey() + ":(" + result.SSID + ")"); + mScanResultCache.remove(e.getKey()); + it.remove(); + } + } + if (DBG) Log.d(TAG, "---- Done Dumping SSIDs that were expired on this scan ----"); + } + + return mScanResultCache.values(); + } + private void updateAccessPoints() { // Swap the current access points into a cached list. List cachedAccessPoints = getAccessPoints(); @@ -283,7 +324,7 @@ public class WifiTracker { } } - final List results = mWifiManager.getScanResults(); + final Collection results = fetchScanResults(); if (results != null) { for (ScanResult result : results) { // Ignore hidden and ad-hoc networks. @@ -328,6 +369,24 @@ public class WifiTracker { // Pre-sort accessPoints to speed preference insertion Collections.sort(accessPoints); + + // Log accesspoints that were deleted + if (DBG) Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------"); + for (AccessPoint prevAccessPoint : mAccessPoints) { + if (prevAccessPoint.getSsid() == null) continue; + String prevSsid = prevAccessPoint.getSsidStr(); + boolean found = false; + for (AccessPoint newAccessPoint : accessPoints) { + if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid().equals(prevSsid)) { + found = true; + break; + } + } + if (!found) + if (DBG) Log.d(TAG, "Did not find " + prevSsid + " in this scan"); + } + if (DBG) Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----"); + mAccessPoints = accessPoints; mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED); } -- cgit v1.1