summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/WifiScoreCard.java43
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java34
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
+ }
+
}