Merge "Use a LruCache in WifiNetworkScoreCache." into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c9ae7df52a
@@ -26,15 +26,14 @@ import android.net.ScoredNetwork;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link INetworkScoreCache} implementation for Wifi Networks.
|
||||
@@ -50,18 +49,21 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
// scorer to provide an RSSI threshold below which a network should not be used.
|
||||
public static final int INVALID_NETWORK_SCORE = Byte.MIN_VALUE;
|
||||
|
||||
/** Default number entries to be stored in the {@link LruCache}. */
|
||||
private static final int DEFAULT_MAX_CACHE_SIZE = 100;
|
||||
|
||||
// See {@link #CacheListener}.
|
||||
@Nullable
|
||||
@GuardedBy("mCacheLock")
|
||||
@GuardedBy("mLock")
|
||||
private CacheListener mListener;
|
||||
|
||||
private final Context mContext;
|
||||
private final Object mCacheLock = new Object();
|
||||
private final Object mLock = new Object();
|
||||
|
||||
// The key is of the form "<ssid>"<bssid>
|
||||
// TODO: What about SSIDs that can't be encoded as UTF-8?
|
||||
private final Map<String, ScoredNetwork> mNetworkCache;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final LruCache<String, ScoredNetwork> mCache;
|
||||
|
||||
public WifiNetworkScoreCache(Context context) {
|
||||
this(context, null /* listener */);
|
||||
@@ -74,9 +76,14 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
* @param listener CacheListener for cache updates
|
||||
*/
|
||||
public WifiNetworkScoreCache(Context context, @Nullable CacheListener listener) {
|
||||
this(context, listener, DEFAULT_MAX_CACHE_SIZE);
|
||||
}
|
||||
|
||||
public WifiNetworkScoreCache(
|
||||
Context context, @Nullable CacheListener listener, int maxCacheSize) {
|
||||
mContext = context.getApplicationContext();
|
||||
mListener = listener;
|
||||
mNetworkCache = new HashMap<>();
|
||||
mCache = new LruCache<>(maxCacheSize);
|
||||
}
|
||||
|
||||
@Override public final void updateScores(List<ScoredNetwork> networks) {
|
||||
@@ -89,7 +96,7 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
synchronized(mNetworkCache) {
|
||||
synchronized(mLock) {
|
||||
for (ScoredNetwork network : networks) {
|
||||
String networkKey = buildNetworkKey(network);
|
||||
if (networkKey == null) {
|
||||
@@ -98,12 +105,10 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
mNetworkCache.put(networkKey, network);
|
||||
mCache.put(networkKey, network);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mCacheLock) {
|
||||
if (mListener != null && changed) {
|
||||
mListener.post(networks);
|
||||
}
|
||||
@@ -111,8 +116,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
}
|
||||
|
||||
@Override public final void clearScores() {
|
||||
synchronized (mNetworkCache) {
|
||||
mNetworkCache.clear();
|
||||
synchronized (mLock) {
|
||||
mCache.evictAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +143,6 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
}
|
||||
|
||||
public int getNetworkScore(ScanResult result) {
|
||||
|
||||
int score = INVALID_NETWORK_SCORE;
|
||||
|
||||
ScoredNetwork network = getScoredNetwork(result);
|
||||
@@ -164,7 +168,6 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
}
|
||||
|
||||
public int getNetworkScore(ScanResult result, boolean isActiveNetwork) {
|
||||
|
||||
int score = INVALID_NETWORK_SCORE;
|
||||
|
||||
ScoredNetwork network = getScoredNetwork(result);
|
||||
@@ -185,8 +188,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
String key = buildNetworkKey(result);
|
||||
if (key == null) return null;
|
||||
|
||||
synchronized(mNetworkCache) {
|
||||
ScoredNetwork network = mNetworkCache.get(key);
|
||||
synchronized(mLock) {
|
||||
ScoredNetwork network = mCache.get(key);
|
||||
return network;
|
||||
}
|
||||
}
|
||||
@@ -201,8 +204,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
synchronized (mNetworkCache) {
|
||||
return mNetworkCache.get(key);
|
||||
synchronized (mLock) {
|
||||
return mCache.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,33 +251,35 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
|
||||
mContext.getPackageName(), Process.myUid());
|
||||
writer.println(header);
|
||||
writer.println(" All score curves:");
|
||||
for (ScoredNetwork score : mNetworkCache.values()) {
|
||||
writer.println(" " + score);
|
||||
}
|
||||
writer.println(" Current network scores:");
|
||||
WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||
for (ScanResult scanResult : wifiManager.getScanResults()) {
|
||||
writer.println(" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
|
||||
synchronized (mLock) {
|
||||
for (ScoredNetwork score : mCache.snapshot().values()) {
|
||||
writer.println(" " + score);
|
||||
}
|
||||
writer.println(" Network scores for latest ScanResults:");
|
||||
WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||
for (ScanResult scanResult : wifiManager.getScanResults()) {
|
||||
writer.println(
|
||||
" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Registers a CacheListener instance, replacing the previous listener if it existed. */
|
||||
public void registerListener(CacheListener listener) {
|
||||
synchronized (mCacheLock) {
|
||||
synchronized (mLock) {
|
||||
mListener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the registered CacheListener. */
|
||||
public void unregisterListener() {
|
||||
synchronized (mCacheLock) {
|
||||
synchronized (mLock) {
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Listener for updates to the cache inside WifiNetworkScoreCache. */
|
||||
public abstract static class CacheListener {
|
||||
|
||||
private Handler mHandler;
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,14 +49,15 @@ LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
|
||||
LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
android-support-test \
|
||||
core-test-rules \
|
||||
guava \
|
||||
mockito-target-minus-junit4 \
|
||||
frameworks-base-testutils \
|
||||
android-support-test \
|
||||
core-test-rules \
|
||||
guava \
|
||||
mockito-target-minus-junit4 \
|
||||
frameworks-base-testutils \
|
||||
truth-prebuilt \
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := \
|
||||
android.test.runner \
|
||||
android.test.runner \
|
||||
|
||||
LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
|
||||
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package android.net.wifi;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -34,12 +34,9 @@ import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -54,7 +51,11 @@ import java.util.concurrent.TimeUnit;
|
||||
public class WifiNetworkScoreCacheTest {
|
||||
|
||||
public static final String SSID = "ssid";
|
||||
public static final String SSID2 = "ssid2";
|
||||
public static final String SSID3 = "ssid3";
|
||||
public static final String FORMATTED_SSID = "\"" + SSID + "\"";
|
||||
public static final String FORMATTED_SSID2 = "\"" + SSID2 + "\"";
|
||||
public static final String FORMATTED_SSID3 = "\"" + SSID3 + "\"";
|
||||
public static final String BSSID = "AA:AA:AA:AA:AA:AA";
|
||||
|
||||
public static final WifiKey VALID_KEY = new WifiKey(FORMATTED_SSID, BSSID);
|
||||
@@ -120,13 +121,13 @@ public class WifiNetworkScoreCacheTest {
|
||||
|
||||
@Test
|
||||
public void isScoredNetworkShouldReturnTrueAfterUpdateScoresIsCalled() {
|
||||
assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT));
|
||||
assertThat(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isScoredNetworkShouldReturnFalseAfterClearScoresIsCalled() {
|
||||
mScoreCache.clearScores();
|
||||
assertFalse(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT));
|
||||
assertThat(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,19 +138,19 @@ public class WifiNetworkScoreCacheTest {
|
||||
|
||||
mScoreCache.updateScores(ImmutableList.of(network2));
|
||||
|
||||
assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT));
|
||||
assertTrue(mScoreCache.isScoredNetwork(result2));
|
||||
assertThat(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)).isTrue();
|
||||
assertThat(mScoreCache.isScoredNetwork(result2)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasScoreCurveShouldReturnTrue() {
|
||||
assertTrue(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT));
|
||||
assertThat(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasScoreCurveShouldReturnFalseWhenNoCachedNetwork() {
|
||||
ScanResult unscored = buildScanResult("fake", BSSID);
|
||||
assertFalse(mScoreCache.hasScoreCurve(unscored));
|
||||
assertThat(mScoreCache.hasScoreCurve(unscored)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -157,7 +158,7 @@ public class WifiNetworkScoreCacheTest {
|
||||
ScoredNetwork noCurve = buildScoredNetwork(VALID_KEY, null /* rssiCurve */);
|
||||
mScoreCache.updateScores(ImmutableList.of(noCurve));
|
||||
|
||||
assertFalse(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT));
|
||||
assertThat(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -169,12 +170,12 @@ public class WifiNetworkScoreCacheTest {
|
||||
|
||||
when(mockRssiCurve.lookupScore(rssi)).thenReturn(score);
|
||||
|
||||
assertEquals(score, mScoreCache.getNetworkScore(result));
|
||||
assertThat(mScoreCache.getNetworkScore(result)).isEqualTo(score);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMeteredHintShouldReturnFalse() {
|
||||
assertFalse(mScoreCache.getMeteredHint(VALID_SCAN_RESULT));
|
||||
assertThat(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -184,7 +185,7 @@ public class WifiNetworkScoreCacheTest {
|
||||
new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */);
|
||||
mScoreCache.updateScores(ImmutableList.of(network));
|
||||
|
||||
assertTrue(mScoreCache.getMeteredHint(VALID_SCAN_RESULT));
|
||||
assertThat(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -197,7 +198,28 @@ public class WifiNetworkScoreCacheTest {
|
||||
} catch (InterruptedException e) {
|
||||
fail("Interrupted Exception while waiting for listener to be invoked.");
|
||||
}
|
||||
assertEquals("One network should be updated", 1, mUpdatedNetworksCaptor.size());
|
||||
assertEquals(mValidScoredNetwork, mUpdatedNetworksCaptor.get(0));
|
||||
// One network should be updated.
|
||||
assertThat(mUpdatedNetworksCaptor.size()).isEqualTo(1);
|
||||
assertThat(mUpdatedNetworksCaptor.get(0)).isEqualTo(mValidScoredNetwork);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void leastRecentlyUsedScore_shouldBeEvictedFromCache() {
|
||||
mScoreCache = new WifiNetworkScoreCache(mockContext, mCacheListener, 2 /* maxCacheSize */);
|
||||
|
||||
ScoredNetwork network1 = mValidScoredNetwork;
|
||||
ScoredNetwork network2 = buildScoredNetwork(
|
||||
new WifiKey(FORMATTED_SSID2, BSSID), mockRssiCurve);
|
||||
ScoredNetwork network3 = buildScoredNetwork(
|
||||
new WifiKey(FORMATTED_SSID3, BSSID), mockRssiCurve);
|
||||
mScoreCache.updateScores(ImmutableList.of(network1));
|
||||
mScoreCache.updateScores(ImmutableList.of(network2));
|
||||
|
||||
// First score should be evicted because max cache size has been reached.
|
||||
mScoreCache.updateScores(ImmutableList.of(network3));
|
||||
|
||||
assertThat(mScoreCache.hasScoreCurve(buildScanResult(SSID2, BSSID))).isTrue();
|
||||
assertThat(mScoreCache.hasScoreCurve(buildScanResult(SSID3, BSSID))).isTrue();
|
||||
assertThat(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user