Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6830c7b authored by Stephen Chen's avatar Stephen Chen Committed by android-build-merger
Browse files

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

am: c9ae7df5

Change-Id: Ib3b7933a7ba6dd17513e1da13099fd4c2bd4f5a2
parents 0402f86a c9ae7df5
Loading
Loading
Loading
Loading
+34 −29
Original line number Diff line number Diff line
@@ -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()) {
        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;

        /**
+7 −6
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    guava \
    mockito-target-minus-junit4 \
    frameworks-base-testutils \
    truth-prebuilt \

LOCAL_JAVA_LIBRARIES := \
    android.test.runner \
+40 −18
Original line number Diff line number Diff line
@@ -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();
    }
}