Loading wifi/java/android/net/wifi/WifiNetworkScoreCache.java 0 → 100755 +196 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import android.Manifest.permission; import android.annotation.SystemApi; import android.content.Context; import android.net.INetworkScoreCache; import android.net.NetworkKey; import android.net.ScoredNetwork; import android.util.Log; 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. * * @hide */ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { private static final String TAG = "WifiNetworkScoreCache"; private static final boolean DBG = false; // A Network scorer returns a score in the range [-128, +127] // We treat the lowest possible score as though there were no score, effectively allowing the // scorer to provide an RSSI threshold below which a network should not be used. public static final int INVALID_NETWORK_SCORE = Byte.MIN_VALUE; private final Context mContext; // 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; public WifiNetworkScoreCache(Context context) { mContext = context; mNetworkCache = new HashMap<String, ScoredNetwork>(); } @Override public final void updateScores(List<ScoredNetwork> networks) { if (networks == null) { return; } Log.e(TAG, "updateScores list size=" + networks.size()); synchronized(mNetworkCache) { for (ScoredNetwork network : networks) { String networkKey = buildNetworkKey(network); if (networkKey == null) continue; mNetworkCache.put(networkKey, network); } } } @Override public final void clearScores() { synchronized (mNetworkCache) { mNetworkCache.clear(); } } /** * Returns whether there is any score info for the given ScanResult. * * This includes null-score info, so it should only be used when determining whether to request * scores from the network scorer. */ public boolean isScoredNetwork(ScanResult result) { return getScoredNetwork(result) != null; } /** * Returns whether there is a non-null score curve for the given ScanResult. * * A null score curve has special meaning - we should never connect to an ephemeral network if * the score curve is null. */ public boolean hasScoreCurve(ScanResult result) { ScoredNetwork network = getScoredNetwork(result); return network != null && network.rssiCurve != null; } public int getNetworkScore(ScanResult result) { int score = INVALID_NETWORK_SCORE; ScoredNetwork network = getScoredNetwork(result); if (network != null && network.rssiCurve != null) { score = network.rssiCurve.lookupScore(result.level); if (DBG) { Log.e(TAG, "getNetworkScore found scored network " + network.networkKey + " score " + Integer.toString(score) + " RSSI " + result.level); } } return score; } /** * Returns the ScoredNetwork metered hint for a given ScanResult. * * If there is no ScoredNetwork associated with the ScanResult then false will be returned. */ public boolean getMeteredHint(ScanResult result) { ScoredNetwork network = getScoredNetwork(result); return network != null && network.meteredHint; } public int getNetworkScore(ScanResult result, boolean isActiveNetwork) { int score = INVALID_NETWORK_SCORE; ScoredNetwork network = getScoredNetwork(result); if (network != null && network.rssiCurve != null) { score = network.rssiCurve.lookupScore(result.level, isActiveNetwork); if (DBG) { Log.e(TAG, "getNetworkScore found scored network " + network.networkKey + " score " + Integer.toString(score) + " RSSI " + result.level + " isActiveNetwork " + isActiveNetwork); } } return score; } private ScoredNetwork getScoredNetwork(ScanResult result) { String key = buildNetworkKey(result); if (key == null) return null; //find it synchronized(mNetworkCache) { ScoredNetwork network = mNetworkCache.get(key); return network; } } private String buildNetworkKey(ScoredNetwork network) { if (network == null || network.networkKey == null) return null; if (network.networkKey.wifiKey == null) return null; if (network.networkKey.type == NetworkKey.TYPE_WIFI) { String key = network.networkKey.wifiKey.ssid; if (key == null) return null; if (network.networkKey.wifiKey.bssid != null) { key = key + network.networkKey.wifiKey.bssid; } return key; } return null; } private String buildNetworkKey(ScanResult result) { if (result == null || result.SSID == null) { return null; } StringBuilder key = new StringBuilder("\""); key.append(result.SSID); key.append("\""); if (result.BSSID != null) { key.append(result.BSSID); } return key.toString(); } @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); writer.println("WifiNetworkScoreCache"); writer.println(" All score curves:"); for (Map.Entry<String, ScoredNetwork> entry : mNetworkCache.entrySet()) { ScoredNetwork scoredNetwork = entry.getValue(); writer.println(" " + entry.getKey() + ": " + scoredNetwork.rssiCurve + ", meteredHint=" + scoredNetwork.meteredHint); } writer.println(" Current network scores:"); WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); for (ScanResult scanResult : wifiManager.getScanResults()) { writer.println(" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult)); } } } wifi/tests/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ guava \ mockito-target-minus-junit4 \ frameworks-base-testutils \ Loading wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.net.wifi; import static org.junit.Assert.*; import static org.mockito.Mockito.when; import android.content.Context; import android.net.NetworkKey; import android.net.RssiCurve; import android.net.ScoredNetwork; import android.net.WifiKey; import android.support.test.filters.SmallTest; 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.Mock; import org.mockito.MockitoAnnotations; /** Unit tests for {@link WifiNetworkScoreCache}. */ @RunWith(AndroidJUnit4.class) @SmallTest public class WifiNetworkScoreCacheTest { @Mock public Context mockContext; // isn't used, can be null @Mock private RssiCurve mockRssiCurve; public static final String SSID = "ssid"; public static final String FORMATTED_SSID = "\"" + SSID + "\""; public static final String BSSID = "AA:AA:AA:AA:AA:AA"; public static final WifiKey VALID_KEY = new WifiKey(FORMATTED_SSID, BSSID); public static final ScanResult VALID_SCAN_RESULT = buildScanResult(SSID, BSSID); private ScoredNetwork mValidScoredNetwork; private WifiNetworkScoreCache mScoreCache = new WifiNetworkScoreCache(mockContext); private static ScanResult buildScanResult(String ssid, String bssid) { return new ScanResult( WifiSsid.createFromAsciiEncoded(ssid), bssid, "" /* caps */, 0 /* level */, 0 /* frequency */, 0 /* tsf */, 0 /* distCm */, 0 /* distSdCm*/); } private static ScoredNetwork buildScoredNetwork(WifiKey key, RssiCurve curve) { return new ScoredNetwork(new NetworkKey(key), curve); } // Called from setup private void initializeCacheWithValidScoredNetwork() { mScoreCache.updateScores(ImmutableList.of(mValidScoredNetwork)); } @Before public void setUp() { MockitoAnnotations.initMocks(this); mValidScoredNetwork = buildScoredNetwork(VALID_KEY, mockRssiCurve); mScoreCache = new WifiNetworkScoreCache(mockContext); initializeCacheWithValidScoredNetwork(); } @Test public void isScoredNetworkShouldReturnTrueAfterUpdateScoresIsCalled() { assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)); } @Test public void isScoredNetworkShouldReturnFalseAfterClearScoresIsCalled() { mScoreCache.clearScores(); assertFalse(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)); } @Test public void updateScoresShouldAddNewNetwork() { WifiKey key2 = new WifiKey("\"ssid2\"", BSSID); ScoredNetwork network2 = buildScoredNetwork(key2, mockRssiCurve); ScanResult result2 = buildScanResult("ssid2", BSSID); mScoreCache.updateScores(ImmutableList.of(network2)); assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)); assertTrue(mScoreCache.isScoredNetwork(result2)); } @Test public void hasScoreCurveShouldReturnTrue() { assertTrue(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)); } @Test public void hasScoreCurveShouldReturnFalseWhenNoCachedNetwork() { ScanResult unscored = buildScanResult("fake", BSSID); assertFalse(mScoreCache.hasScoreCurve(unscored)); } @Test public void hasScoreCurveShouldReturnFalseWhenScoredNetworkHasNoCurve() { ScoredNetwork noCurve = buildScoredNetwork(VALID_KEY, null /* rssiCurve */); mScoreCache.updateScores(ImmutableList.of(noCurve)); assertFalse(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)); } @Test public void getNetworkScoreShouldReturnScore() { final byte score = 50; final int rssi = -70; ScanResult result = new ScanResult(VALID_SCAN_RESULT); result.level = rssi; when(mockRssiCurve.lookupScore(rssi)).thenReturn(score); assertEquals(score, mScoreCache.getNetworkScore(result)); } @Test public void getMeteredHintShouldReturnFalse() { assertFalse(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)); } @Test public void getMeteredHintShouldReturnTrue() { ScoredNetwork network = new ScoredNetwork(new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */); mScoreCache.updateScores(ImmutableList.of(network)); assertTrue(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)); } } Loading
wifi/java/android/net/wifi/WifiNetworkScoreCache.java 0 → 100755 +196 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import android.Manifest.permission; import android.annotation.SystemApi; import android.content.Context; import android.net.INetworkScoreCache; import android.net.NetworkKey; import android.net.ScoredNetwork; import android.util.Log; 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. * * @hide */ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { private static final String TAG = "WifiNetworkScoreCache"; private static final boolean DBG = false; // A Network scorer returns a score in the range [-128, +127] // We treat the lowest possible score as though there were no score, effectively allowing the // scorer to provide an RSSI threshold below which a network should not be used. public static final int INVALID_NETWORK_SCORE = Byte.MIN_VALUE; private final Context mContext; // 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; public WifiNetworkScoreCache(Context context) { mContext = context; mNetworkCache = new HashMap<String, ScoredNetwork>(); } @Override public final void updateScores(List<ScoredNetwork> networks) { if (networks == null) { return; } Log.e(TAG, "updateScores list size=" + networks.size()); synchronized(mNetworkCache) { for (ScoredNetwork network : networks) { String networkKey = buildNetworkKey(network); if (networkKey == null) continue; mNetworkCache.put(networkKey, network); } } } @Override public final void clearScores() { synchronized (mNetworkCache) { mNetworkCache.clear(); } } /** * Returns whether there is any score info for the given ScanResult. * * This includes null-score info, so it should only be used when determining whether to request * scores from the network scorer. */ public boolean isScoredNetwork(ScanResult result) { return getScoredNetwork(result) != null; } /** * Returns whether there is a non-null score curve for the given ScanResult. * * A null score curve has special meaning - we should never connect to an ephemeral network if * the score curve is null. */ public boolean hasScoreCurve(ScanResult result) { ScoredNetwork network = getScoredNetwork(result); return network != null && network.rssiCurve != null; } public int getNetworkScore(ScanResult result) { int score = INVALID_NETWORK_SCORE; ScoredNetwork network = getScoredNetwork(result); if (network != null && network.rssiCurve != null) { score = network.rssiCurve.lookupScore(result.level); if (DBG) { Log.e(TAG, "getNetworkScore found scored network " + network.networkKey + " score " + Integer.toString(score) + " RSSI " + result.level); } } return score; } /** * Returns the ScoredNetwork metered hint for a given ScanResult. * * If there is no ScoredNetwork associated with the ScanResult then false will be returned. */ public boolean getMeteredHint(ScanResult result) { ScoredNetwork network = getScoredNetwork(result); return network != null && network.meteredHint; } public int getNetworkScore(ScanResult result, boolean isActiveNetwork) { int score = INVALID_NETWORK_SCORE; ScoredNetwork network = getScoredNetwork(result); if (network != null && network.rssiCurve != null) { score = network.rssiCurve.lookupScore(result.level, isActiveNetwork); if (DBG) { Log.e(TAG, "getNetworkScore found scored network " + network.networkKey + " score " + Integer.toString(score) + " RSSI " + result.level + " isActiveNetwork " + isActiveNetwork); } } return score; } private ScoredNetwork getScoredNetwork(ScanResult result) { String key = buildNetworkKey(result); if (key == null) return null; //find it synchronized(mNetworkCache) { ScoredNetwork network = mNetworkCache.get(key); return network; } } private String buildNetworkKey(ScoredNetwork network) { if (network == null || network.networkKey == null) return null; if (network.networkKey.wifiKey == null) return null; if (network.networkKey.type == NetworkKey.TYPE_WIFI) { String key = network.networkKey.wifiKey.ssid; if (key == null) return null; if (network.networkKey.wifiKey.bssid != null) { key = key + network.networkKey.wifiKey.bssid; } return key; } return null; } private String buildNetworkKey(ScanResult result) { if (result == null || result.SSID == null) { return null; } StringBuilder key = new StringBuilder("\""); key.append(result.SSID); key.append("\""); if (result.BSSID != null) { key.append(result.BSSID); } return key.toString(); } @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); writer.println("WifiNetworkScoreCache"); writer.println(" All score curves:"); for (Map.Entry<String, ScoredNetwork> entry : mNetworkCache.entrySet()) { ScoredNetwork scoredNetwork = entry.getValue(); writer.println(" " + entry.getKey() + ": " + scoredNetwork.rssiCurve + ", meteredHint=" + scoredNetwork.meteredHint); } writer.println(" Current network scores:"); WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); for (ScanResult scanResult : wifiManager.getScanResults()) { writer.println(" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult)); } } }
wifi/tests/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ guava \ mockito-target-minus-junit4 \ frameworks-base-testutils \ Loading
wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.net.wifi; import static org.junit.Assert.*; import static org.mockito.Mockito.when; import android.content.Context; import android.net.NetworkKey; import android.net.RssiCurve; import android.net.ScoredNetwork; import android.net.WifiKey; import android.support.test.filters.SmallTest; 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.Mock; import org.mockito.MockitoAnnotations; /** Unit tests for {@link WifiNetworkScoreCache}. */ @RunWith(AndroidJUnit4.class) @SmallTest public class WifiNetworkScoreCacheTest { @Mock public Context mockContext; // isn't used, can be null @Mock private RssiCurve mockRssiCurve; public static final String SSID = "ssid"; public static final String FORMATTED_SSID = "\"" + SSID + "\""; public static final String BSSID = "AA:AA:AA:AA:AA:AA"; public static final WifiKey VALID_KEY = new WifiKey(FORMATTED_SSID, BSSID); public static final ScanResult VALID_SCAN_RESULT = buildScanResult(SSID, BSSID); private ScoredNetwork mValidScoredNetwork; private WifiNetworkScoreCache mScoreCache = new WifiNetworkScoreCache(mockContext); private static ScanResult buildScanResult(String ssid, String bssid) { return new ScanResult( WifiSsid.createFromAsciiEncoded(ssid), bssid, "" /* caps */, 0 /* level */, 0 /* frequency */, 0 /* tsf */, 0 /* distCm */, 0 /* distSdCm*/); } private static ScoredNetwork buildScoredNetwork(WifiKey key, RssiCurve curve) { return new ScoredNetwork(new NetworkKey(key), curve); } // Called from setup private void initializeCacheWithValidScoredNetwork() { mScoreCache.updateScores(ImmutableList.of(mValidScoredNetwork)); } @Before public void setUp() { MockitoAnnotations.initMocks(this); mValidScoredNetwork = buildScoredNetwork(VALID_KEY, mockRssiCurve); mScoreCache = new WifiNetworkScoreCache(mockContext); initializeCacheWithValidScoredNetwork(); } @Test public void isScoredNetworkShouldReturnTrueAfterUpdateScoresIsCalled() { assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)); } @Test public void isScoredNetworkShouldReturnFalseAfterClearScoresIsCalled() { mScoreCache.clearScores(); assertFalse(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)); } @Test public void updateScoresShouldAddNewNetwork() { WifiKey key2 = new WifiKey("\"ssid2\"", BSSID); ScoredNetwork network2 = buildScoredNetwork(key2, mockRssiCurve); ScanResult result2 = buildScanResult("ssid2", BSSID); mScoreCache.updateScores(ImmutableList.of(network2)); assertTrue(mScoreCache.isScoredNetwork(VALID_SCAN_RESULT)); assertTrue(mScoreCache.isScoredNetwork(result2)); } @Test public void hasScoreCurveShouldReturnTrue() { assertTrue(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)); } @Test public void hasScoreCurveShouldReturnFalseWhenNoCachedNetwork() { ScanResult unscored = buildScanResult("fake", BSSID); assertFalse(mScoreCache.hasScoreCurve(unscored)); } @Test public void hasScoreCurveShouldReturnFalseWhenScoredNetworkHasNoCurve() { ScoredNetwork noCurve = buildScoredNetwork(VALID_KEY, null /* rssiCurve */); mScoreCache.updateScores(ImmutableList.of(noCurve)); assertFalse(mScoreCache.hasScoreCurve(VALID_SCAN_RESULT)); } @Test public void getNetworkScoreShouldReturnScore() { final byte score = 50; final int rssi = -70; ScanResult result = new ScanResult(VALID_SCAN_RESULT); result.level = rssi; when(mockRssiCurve.lookupScore(rssi)).thenReturn(score); assertEquals(score, mScoreCache.getNetworkScore(result)); } @Test public void getMeteredHintShouldReturnFalse() { assertFalse(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)); } @Test public void getMeteredHintShouldReturnTrue() { ScoredNetwork network = new ScoredNetwork(new NetworkKey(VALID_KEY), mockRssiCurve, true /* metered Hint */); mScoreCache.updateScores(ImmutableList.of(network)); assertTrue(mScoreCache.getMeteredHint(VALID_SCAN_RESULT)); } }