Merge "Use a LruCache in WifiNetworkScoreCache." into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-08-25 20:29:32 +00:00
committed by Android (Google) Code Review
3 changed files with 81 additions and 53 deletions

View File

@@ -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;
/**

View File

@@ -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

View File

@@ -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();
}
}