Loading wifi/java/android/net/wifi/WifiNetworkScoreCache.java +34 −29 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 */); Loading @@ -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) { Loading @@ -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) { Loading @@ -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); } Loading @@ -111,8 +116,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } @Override public final void clearScores() { synchronized (mNetworkCache) { mNetworkCache.clear(); synchronized (mLock) { mCache.evictAll(); } } Loading @@ -138,7 +143,6 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } public int getNetworkScore(ScanResult result) { int score = INVALID_NETWORK_SCORE; ScoredNetwork network = getScoredNetwork(result); Loading @@ -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); Loading @@ -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; } } Loading @@ -201,8 +204,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } return null; } synchronized (mNetworkCache) { return mNetworkCache.get(key); synchronized (mLock) { return mCache.get(key); } } Loading Loading @@ -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()) { synchronized (mLock) { for (ScoredNetwork score : mCache.snapshot().values()) { writer.println(" " + score); } writer.println(" Current network scores:"); 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)); 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; /** Loading wifi/tests/Android.mk +7 −6 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ guava \ mockito-target-minus-junit4 \ frameworks-base-testutils \ truth-prebuilt \ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ Loading wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java +40 −18 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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(); } } Loading
wifi/java/android/net/wifi/WifiNetworkScoreCache.java +34 −29 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 */); Loading @@ -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) { Loading @@ -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) { Loading @@ -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); } Loading @@ -111,8 +116,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } @Override public final void clearScores() { synchronized (mNetworkCache) { mNetworkCache.clear(); synchronized (mLock) { mCache.evictAll(); } } Loading @@ -138,7 +143,6 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } public int getNetworkScore(ScanResult result) { int score = INVALID_NETWORK_SCORE; ScoredNetwork network = getScoredNetwork(result); Loading @@ -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); Loading @@ -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; } } Loading @@ -201,8 +204,8 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } return null; } synchronized (mNetworkCache) { return mNetworkCache.get(key); synchronized (mLock) { return mCache.get(key); } } Loading Loading @@ -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()) { synchronized (mLock) { for (ScoredNetwork score : mCache.snapshot().values()) { writer.println(" " + score); } writer.println(" Current network scores:"); 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)); 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; /** Loading
wifi/tests/Android.mk +7 −6 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ guava \ mockito-target-minus-junit4 \ frameworks-base-testutils \ truth-prebuilt \ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ Loading
wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java +40 −18 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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(); } }