diff options
-rw-r--r-- | service/java/com/android/server/wifi/WifiScoreCard.java | 43 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java | 34 |
2 files changed, 77 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java index 86b72f6e9..af995fd62 100644 --- a/service/java/com/android/server/wifi/WifiScoreCard.java +++ b/service/java/com/android/server/wifi/WifiScoreCard.java @@ -46,6 +46,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -67,6 +68,8 @@ public class WifiScoreCard { private static final String TAG = "WifiScoreCard"; private static final boolean DBG = false; + private static final int TARGET_IN_MEMORY_ENTRIES = 50; + private final Clock mClock; private final String mL2KeySeed; private MemoryStore mMemoryStore; @@ -251,6 +254,7 @@ public class WifiScoreCard { if (mValidated) return; // Only once per connection update(Event.VALIDATION_SUCCESS, wifiInfo); mValidated = true; + doWrites(); } /** @@ -369,6 +373,8 @@ public class WifiScoreCard { public final String ssid; public final MacAddress bssid; public boolean changed; + public boolean referenced; + private SecurityType mSecurityType = null; private int mNetworkAgentId = Integer.MIN_VALUE; private int mNetworkConfigId = Integer.MIN_VALUE; @@ -381,6 +387,7 @@ public class WifiScoreCard { this.l2Key = l2KeyFromLong(hash); this.id = idFromLong(hash); this.changed = false; + this.referenced = false; } void updateEventStats(Event event, int frequency, int rssi, int linkspeed) { PerSignal perSignal = lookupSignal(event, frequency); @@ -513,6 +520,8 @@ public class WifiScoreCard { private final PerBssid mDummyPerBssid; private final Map<MacAddress, PerBssid> mApForBssid = new ArrayMap<>(); + private int mApForBssidTargetSize = TARGET_IN_MEMORY_ENTRIES; + private int mApForBssidReferenced = 0; // TODO should be private, but WifiCandidates needs it @NonNull PerBssid lookupBssid(String ssid, String bssid) { @@ -531,9 +540,15 @@ public class WifiScoreCard { PerBssid old = mApForBssid.put(mac, ans); if (old != null) { Log.i(TAG, "Discarding stats for score card (ssid changed) ID: " + old.id); + if (old.referenced) mApForBssidReferenced--; } requestReadForPerBssid(ans); } + if (!ans.referenced) { + ans.referenced = true; + mApForBssidReferenced++; + clean(); + } return ans; } @@ -580,6 +595,34 @@ public class WifiScoreCard { return count; } + /** + * Evicts older entries from memory. + * + * This uses an approximate least-recently-used method. When the number of + * referenced entries exceeds the target value, any items that have not been + * referenced since the last round are evicted, and the remaining entries + * are marked as unreferenced. The total count varies between the target + * value and twice the target value. + */ + private void clean() { + if (mMemoryStore == null) return; + if (mApForBssidReferenced >= mApForBssidTargetSize) { + doWrites(); // Do not want to evict changed items + // Evict the unreferenced ones, and clear all the referenced bits for the next round. + Iterator<Map.Entry<MacAddress, PerBssid>> it = mApForBssid.entrySet().iterator(); + while (it.hasNext()) { + PerBssid perBssid = it.next().getValue(); + if (perBssid.referenced) { + perBssid.referenced = false; + } else { + it.remove(); + if (DBG) Log.v(TAG, "Evict " + perBssid.id); + } + } + mApForBssidReferenced = 0; + } + } + private long computeHashLong(String ssid, MacAddress mac) { byte[][] parts = { // Our seed keeps the L2Keys specific to this device diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java index 577f5bc65..1afa42ad6 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java @@ -494,4 +494,38 @@ public class WifiScoreCardTest { assertEquals(0, leftovers.length); } + /** + * Test that older items are evicted from memory. + */ + @Test + public void testOlderItemsShouldBeEvicted() throws Exception { + mWifiInfo.setRssi(-55); + mWifiInfo.setFrequency(5805); + mWifiInfo.setLinkSpeed(384); + mWifiScoreCard.installMemoryStore(mMemoryStore); + for (int i = 0; i < 256; i++) { + MacAddress bssid = MacAddress.fromBytes(new byte[]{2, 2, 2, 2, 2, (byte) i}); + mWifiInfo.setBSSID(bssid.toString()); + mWifiScoreCard.noteSignalPoll(mWifiInfo); + } + + verify(mMemoryStore, times(256)).read(any(), any()); + verify(mMemoryStore, atLeastOnce()).write(any(), any()); // Assumes target size < 256 + reset(mMemoryStore); + + for (int i = 256 - 3; i < 256; i++) { + MacAddress bssid = MacAddress.fromBytes(new byte[]{2, 2, 2, 2, 2, (byte) i}); + mWifiInfo.setBSSID(bssid.toString()); + mWifiScoreCard.noteSignalPoll(mWifiInfo); + } + verify(mMemoryStore, never()).read(any(), any()); // Assumes target size >= 3 + + for (int i = 0; i < 3; i++) { + MacAddress bssid = MacAddress.fromBytes(new byte[]{2, 2, 2, 2, 2, (byte) i}); + mWifiInfo.setBSSID(bssid.toString()); + mWifiScoreCard.noteSignalPoll(mWifiInfo); + } + verify(mMemoryStore, times(3)).read(any(), any()); // Assumes target size < 253 + } + } |