diff options
17 files changed, 592 insertions, 89 deletions
diff --git a/service/java/com/android/server/wifi/AggressiveConnectedScore.java b/service/java/com/android/server/wifi/AggressiveConnectedScore.java index a0de7731e..c8ad00d77 100644 --- a/service/java/com/android/server/wifi/AggressiveConnectedScore.java +++ b/service/java/com/android/server/wifi/AggressiveConnectedScore.java @@ -16,29 +16,21 @@ package com.android.server.wifi; -import android.content.Context; import android.net.wifi.WifiInfo; -import com.android.internal.R; - /** - * Experimental scorer, used when aggressive handover preference is set. + * Experimental scorer */ public class AggressiveConnectedScore extends ConnectedScore { - // Device configs. The values are examples. - private final int mThresholdQualifiedRssi5; // -70 - private final int mThresholdQualifiedRssi24; // -73 + private final ScoringParams mScoringParams; private int mFrequencyMHz = 5000; private int mRssi = 0; - public AggressiveConnectedScore(Context context, Clock clock) { + public AggressiveConnectedScore(ScoringParams scoringParams, Clock clock) { super(clock); - mThresholdQualifiedRssi5 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz); - mThresholdQualifiedRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz); + mScoringParams = scoringParams; } @Override @@ -59,8 +51,8 @@ public class AggressiveConnectedScore extends ConnectedScore { @Override public int generateScore() { - int badRssi = mFrequencyMHz >= 5000 ? mThresholdQualifiedRssi5 : mThresholdQualifiedRssi24; - int score = (mRssi - badRssi) + WIFI_TRANSITION_SCORE; + int threshRssi = mScoringParams.getSufficientRssi(mFrequencyMHz); + int score = (mRssi - threshRssi) + WIFI_TRANSITION_SCORE; return score; } } diff --git a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java index 97f6b6f09..4b600ed5e 100644 --- a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java +++ b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java @@ -44,11 +44,12 @@ public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluat private final int mBand5GHzAward; private final int mLastSelectionAward; private final int mSecurityAward; - private final int mThresholdSaturatedRssi24; - private final int mThresholdSaturatedRssi5; + private final ScoringParams mScoringParams; - SavedNetworkEvaluator(final Context context, WifiConfigManager configManager, Clock clock, + SavedNetworkEvaluator(final Context context, ScoringParams scoringParams, + WifiConfigManager configManager, Clock clock, LocalLog localLog, WifiConnectivityHelper connectivityHelper) { + mScoringParams = scoringParams; mWifiConfigManager = configManager; mClock = clock; mLocalLog = localLog; @@ -68,10 +69,6 @@ public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluat R.integer.config_wifi_framework_SECURITY_AWARD); mBand5GHzAward = context.getResources().getInteger( R.integer.config_wifi_framework_5GHz_preference_boost_factor); - mThresholdSaturatedRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz); - mThresholdSaturatedRssi5 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz); } private void localLog(String log) { @@ -162,7 +159,7 @@ public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluat sbuf.append("[ ").append(scanResult.SSID).append(" ").append(scanResult.BSSID) .append(" RSSI:").append(scanResult.level).append(" ] "); // Calculate the RSSI score. - int rssiSaturationThreshold = is5GHz ? mThresholdSaturatedRssi5 : mThresholdSaturatedRssi24; + int rssiSaturationThreshold = mScoringParams.getGoodRssi(scanResult.frequency); int rssi = scanResult.level < rssiSaturationThreshold ? scanResult.level : rssiSaturationThreshold; score += (rssi + mRssiScoreOffset) * mRssiScoreSlope; diff --git a/service/java/com/android/server/wifi/ScoringParams.java b/service/java/com/android/server/wifi/ScoringParams.java new file mode 100644 index 000000000..1fddd7688 --- /dev/null +++ b/service/java/com/android/server/wifi/ScoringParams.java @@ -0,0 +1,256 @@ +/* + * Copyright 2018 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 com.android.server.wifi; + +import android.annotation.NonNull; +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; +import android.util.KeyValueListParser; +import android.util.Log; + +import com.android.internal.R; + +/** + * Holds parameters used for scoring networks. + * + * Doing this in one place means that there's a better chance of consistency between + * connected score and network selection. + * + */ +public class ScoringParams { + private static final String TAG = "WifiScoringParams"; + private static final int EXIT = 0; + private static final int ENTRY = 1; + private static final int SUFFICIENT = 2; + private static final int GOOD = 3; + + /** + * Parameter values are stored in a separate container so that a new collection of values can + * be checked for consistency before activating them. + */ + private class Values { + public static final String KEY_RSSI2 = "rssi2"; + public static final String KEY_RSSI5 = "rssi5"; + public static final String KEY_HORIZON = "horizon"; // number of seconds for rssi forecast + + public final int[] rssi2 = {-83, -80, -73, -60}; + public final int[] rssi5 = {-80, -77, -70, -57}; + public int horizon = 15; + + Values() { + } + + Values(Values source) { + for (int i = 0; i < rssi2.length; i++) { + rssi2[i] = source.rssi2[i]; + } + for (int i = 0; i < rssi5.length; i++) { + rssi5[i] = source.rssi5[i]; + } + horizon = source.horizon; + } + + public void parseString(String kvList) throws IllegalArgumentException { + KeyValueListParser parser = new KeyValueListParser(','); + parser.setString(kvList); + updateIntArray(rssi2, parser, KEY_RSSI2); + updateIntArray(rssi5, parser, KEY_RSSI5); + horizon = updateInt(parser, KEY_HORIZON, horizon); + } + + private int updateInt(KeyValueListParser parser, String key, int defaultValue) + throws IllegalArgumentException { + String value = parser.getString(key, null); + if (value == null) return defaultValue; + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(); + } + } + + private void updateIntArray(final int[] dest, KeyValueListParser parser, String key) + throws IllegalArgumentException { + if (parser.getString(key, null) == null) return; + int[] ints = parser.getIntArray(key, null); + if (ints == null) throw new IllegalArgumentException(); + if (ints.length != dest.length) throw new IllegalArgumentException(); + for (int i = 0; i < dest.length; i++) { + dest[i] = ints[i]; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendKey(sb, KEY_RSSI2); + appendInts(sb, rssi2); + appendKey(sb, KEY_RSSI5); + appendInts(sb, rssi5); + appendKey(sb, KEY_HORIZON); + sb.append(horizon); + return sb.toString(); + } + + private void appendKey(StringBuilder sb, String key) { + if (sb.length() != 0) sb.append(","); + sb.append(key).append("="); + } + + private void appendInts(StringBuilder sb, final int[] a) { + final int n = a.length; + for (int i = 0; i < n; i++) { + if (i > 0) sb.append(":"); + sb.append(a[i]); + } + } + } + + @NonNull private Values mVal = new Values(); + + public ScoringParams() { + } + + public ScoringParams(Context context) { + loadResources(context); + } + + public ScoringParams(Context context, FrameworkFacade facade, Handler handler) { + loadResources(context); + setupContentObserver(context, facade, handler); + } + + private void loadResources(Context context) { + mVal.rssi2[EXIT] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz); + mVal.rssi2[ENTRY] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz); + mVal.rssi2[SUFFICIENT] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz); + mVal.rssi2[GOOD] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz); + mVal.rssi5[EXIT] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz); + mVal.rssi5[ENTRY] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz); + mVal.rssi5[SUFFICIENT] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz); + mVal.rssi5[GOOD] = context.getResources().getInteger( + R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz); + } + + private void setupContentObserver(Context context, FrameworkFacade facade, Handler handler) { + final ScoringParams self = this; + String defaults = self.toString(); + ContentObserver observer = new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange) { + String params = facade.getStringSetting( + context, Settings.Global.WIFI_SCORE_PARAMS); + if (params != null) { + self.update(defaults); + if (!self.update(params)) { + Log.e(TAG, "Error in " + Settings.Global.WIFI_SCORE_PARAMS + ": " + params); + } + } + Log.i(TAG, self.toString()); + } + }; + facade.registerContentObserver(context, + Settings.Global.getUriFor(Settings.Global.WIFI_SCORE_PARAMS), + true, + observer); + observer.onChange(false); + } + + /** + * Updates the parameters from the given parameter string. + * If any errors are detected, no change is made. + * @param kvList is a comma-separated key=value list. + * @return true for success + */ + public boolean update(String kvList) { + Values v = new Values(mVal); + try { + v.parseString(kvList); + mVal = v; + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + + /** Constant to denote someplace in the 2.4 GHz band */ + public static final int BAND2 = 2400; + + /** Constant to denote someplace in the 5 GHz band */ + public static final int BAND5 = 5000; + + /** + * Returns the RSSI value at which the connection is deemed to be unusable, + * in the absence of other indications. + */ + public int getExitRssi(int frequencyMegaHertz) { + return getRssiArray(frequencyMegaHertz)[EXIT]; + } + + /** + * Returns the minimum scan RSSI for making a connection attempt. + */ + public int getEntryRssi(int frequencyMegaHertz) { + return getRssiArray(frequencyMegaHertz)[ENTRY]; + } + + /** + * Returns a connected RSSI value that indicates the connection is + * good enough that we needn't scan for alternatives. + */ + public int getSufficientRssi(int frequencyMegaHertz) { + return getRssiArray(frequencyMegaHertz)[SUFFICIENT]; + } + + /** + * Returns a connected RSSI value that indicates a good connection. + */ + public int getGoodRssi(int frequencyMegaHertz) { + return getRssiArray(frequencyMegaHertz)[GOOD]; + } + + /** + * Returns the number of seconds to use for rssi forecast. + */ + public int getHorizonSeconds() { + return mVal.horizon; + } + + private static final int MINIMUM_5GHZ_BAND_FREQUENCY_IN_MEGAHERTZ = 5000; + + private int[] getRssiArray(int frequency) { + if (frequency < MINIMUM_5GHZ_BAND_FREQUENCY_IN_MEGAHERTZ) { + return mVal.rssi2; + } else { + return mVal.rssi5; + } + } + + @Override + public String toString() { + return mVal.toString(); + } +} diff --git a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java index bfc51f69e..cb47978df 100644 --- a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java +++ b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java @@ -16,10 +16,8 @@ package com.android.server.wifi; -import android.content.Context; import android.net.wifi.WifiInfo; -import com.android.internal.R; import com.android.server.wifi.util.KalmanFilter; import com.android.server.wifi.util.Matrix; @@ -29,23 +27,16 @@ import com.android.server.wifi.util.Matrix; */ public class VelocityBasedConnectedScore extends ConnectedScore { - // Device configs. The values are examples. - private final int mThresholdMinimumRssi5; // -82 - private final int mThresholdMinimumRssi24; // -85 + private final ScoringParams mScoringParams; - private int mFrequency = 5000; - private double mThresholdMinimumRssi; + private int mFrequency = ScoringParams.BAND5; private double mThresholdAdjustment; private final KalmanFilter mFilter; private long mLastMillis; - public VelocityBasedConnectedScore(Context context, Clock clock) { + public VelocityBasedConnectedScore(ScoringParams scoringParams, Clock clock) { super(clock); - mThresholdMinimumRssi5 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz); - mThresholdMinimumRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz); - mThresholdMinimumRssi = mThresholdMinimumRssi5; + mScoringParams = scoringParams; mFilter = new KalmanFilter(); mFilter.mH = new Matrix(2, new double[]{1.0, 0.0}); mFilter.mR = new Matrix(1, new double[]{1.0}); @@ -71,7 +62,6 @@ public class VelocityBasedConnectedScore extends ConnectedScore { @Override public void reset() { mLastMillis = 0; - mThresholdAdjustment = 0.0; } /** @@ -114,8 +104,6 @@ public class VelocityBasedConnectedScore extends ConnectedScore { // Consider resetting or partially resetting threshold adjustment // Consider checking bssid mFrequency = frequency; - mThresholdMinimumRssi = - mFrequency >= 5000 ? mThresholdMinimumRssi5 : mThresholdMinimumRssi24; } updateUsingRssi(wifiInfo.getRssi(), millis, mDefaultRssiStandardDeviation); adjustThreshold(wifiInfo); @@ -142,7 +130,7 @@ public class VelocityBasedConnectedScore extends ConnectedScore { * Returns the adjusted RSSI threshold */ public double getAdjustedRssiThreshold() { - return mThresholdMinimumRssi + mThresholdAdjustment; + return mScoringParams.getExitRssi(mFrequency) + mThresholdAdjustment; } private double mMinimumPpsForMeasuringSuccess = 2.0; @@ -178,7 +166,7 @@ public class VelocityBasedConnectedScore extends ConnectedScore { @Override public int generateScore() { double badRssi = getAdjustedRssiThreshold(); - double horizonSeconds = 15.0; + double horizonSeconds = mScoringParams.getHorizonSeconds(); Matrix x = new Matrix(mFilter.mx); double filteredRssi = x.get(0, 0); setDeltaTimeSeconds(horizonSeconds); diff --git a/service/java/com/android/server/wifi/WakeupEvaluator.java b/service/java/com/android/server/wifi/WakeupEvaluator.java index df9c43df6..b98a4fd23 100644 --- a/service/java/com/android/server/wifi/WakeupEvaluator.java +++ b/service/java/com/android/server/wifi/WakeupEvaluator.java @@ -19,7 +19,6 @@ package com.android.server.wifi; import android.content.Context; import android.net.wifi.ScanResult; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import java.util.Collection; @@ -36,11 +35,9 @@ public class WakeupEvaluator { * Constructs a {@link WakeupEvaluator} using the given context. */ public static WakeupEvaluator fromContext(Context context) { - int minimumRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz); - int minimumRssi5 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz); - return new WakeupEvaluator(minimumRssi24, minimumRssi5); + ScoringParams scoringParams = new ScoringParams(context); // TODO(b/74793980) - replumb + return new WakeupEvaluator(scoringParams.getEntryRssi(ScoringParams.BAND2), + scoringParams.getEntryRssi(ScoringParams.BAND5)); } @VisibleForTesting diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index 6594945ca..3b9d0ff21 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -143,6 +143,7 @@ public class WifiConnectivityManager { private final AlarmManager mAlarmManager; private final Handler mEventHandler; private final Clock mClock; + private final ScoringParams mScoringParams; private final LocalLog mLocalLog; private final LinkedList<Long> mConnectionAttemptTimeStamps; @@ -562,7 +563,8 @@ public class WifiConnectivityManager { /** * WifiConnectivityManager constructor */ - WifiConnectivityManager(Context context, WifiStateMachine stateMachine, + WifiConnectivityManager(Context context, ScoringParams scoringParams, + WifiStateMachine stateMachine, WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, WifiNetworkSelector networkSelector, WifiConnectivityHelper connectivityHelper, WifiLastResortWatchdog wifiLastResortWatchdog, OpenNetworkNotifier openNetworkNotifier, @@ -587,12 +589,12 @@ public class WifiConnectivityManager { mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mEventHandler = new Handler(looper); mClock = clock; + mScoringParams = scoringParams; mConnectionAttemptTimeStamps = new LinkedList<>(); - mMin5GHzRssi = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz); - mMin24GHzRssi = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz); + //TODO(b/74793980) - handle these more dynamically + mMin5GHzRssi = mScoringParams.getEntryRssi(ScoringParams.BAND5); + mMin24GHzRssi = mScoringParams.getEntryRssi(ScoringParams.BAND2); mBand5GHzBonus = context.getResources().getInteger( R.integer.config_wifi_framework_5GHz_preference_boost_factor); mCurrentConnectionBonus = context.getResources().getInteger( @@ -601,14 +603,12 @@ public class WifiConnectivityManager { R.integer.config_wifi_framework_SAME_BSSID_AWARD); mSecureBonus = context.getResources().getInteger( R.integer.config_wifi_framework_SECURITY_AWARD); - int thresholdSaturatedRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz); mEnableAutoJoinWhenAssociated = context.getResources().getBoolean( R.bool.config_wifi_framework_enable_associated_network_selection); - mInitialScoreMax = (context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz) - + context.getResources().getInteger( - R.integer.config_wifi_framework_RSSI_SCORE_OFFSET)) + mInitialScoreMax = (Math.max(mScoringParams.getGoodRssi(ScoringParams.BAND2), + mScoringParams.getGoodRssi(ScoringParams.BAND5)) + + context.getResources().getInteger( + R.integer.config_wifi_framework_RSSI_SCORE_OFFSET)) * context.getResources().getInteger( R.integer.config_wifi_framework_RSSI_SCORE_SLOPE); mFullScanMaxTxRate = context.getResources().getInteger( diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index b6beb6820..2e0591978 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -89,6 +89,7 @@ public class WifiInjector { private final SupplicantP2pIfaceHal mSupplicantP2pIfaceHal; private final HostapdHal mHostapdHal; private final WifiVendorHal mWifiVendorHal; + private final ScoringParams mScoringParams; private final WifiStateMachine mWifiStateMachine; private final WifiStateMachinePrime mWifiStateMachinePrime; private final WifiSettingsStore mSettingsStore; @@ -223,10 +224,13 @@ public class WifiInjector { mWifiMetrics.setWifiConfigManager(mWifiConfigManager); mWifiConnectivityHelper = new WifiConnectivityHelper(mWifiNative); mConnectivityLocalLog = new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 256 : 512); - mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiConfigManager, mClock, + mScoringParams = new ScoringParams(mContext, mFrameworkFacade, + new Handler(wifiStateMachineLooper)); + mWifiNetworkSelector = new WifiNetworkSelector(mContext, mScoringParams, + mWifiConfigManager, mClock, mConnectivityLocalLog); mWifiMetrics.setWifiNetworkSelector(mWifiNetworkSelector); - mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, + mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, mScoringParams, mWifiConfigManager, mClock, mConnectivityLocalLog, mWifiConnectivityHelper); mScoredNetworkEvaluator = new ScoredNetworkEvaluator(context, wifiStateMachineLooper, mFrameworkFacade, mNetworkScoreManager, mWifiConfigManager, mConnectivityLocalLog, @@ -413,6 +417,10 @@ public class WifiInjector { return mWakeupController; } + public ScoringParams getScoringParams() { + return mScoringParams; + } + public TelephonyManager makeTelephonyManager() { // may not be available when WiFi starts return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -507,7 +515,8 @@ public class WifiInjector { */ public WifiConnectivityManager makeWifiConnectivityManager(WifiInfo wifiInfo, boolean hasConnectionRequests) { - return new WifiConnectivityManager(mContext, mWifiStateMachine, getWifiScanner(), + return new WifiConnectivityManager(mContext, getScoringParams(), + mWifiStateMachine, getWifiScanner(), mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper, mWifiLastResortWatchdog, mOpenNetworkNotifier, mCarrierNetworkNotifier, mCarrierNetworkConfig, mWifiMetrics, mWifiStateMachineHandlerThread.getLooper(), diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java index dc854097b..97ef221e7 100644 --- a/service/java/com/android/server/wifi/WifiNetworkSelector.java +++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java @@ -57,10 +57,7 @@ public class WifiNetworkSelector { private volatile List<Pair<ScanDetail, WifiConfiguration>> mConnectableNetworks = new ArrayList<>(); private List<ScanDetail> mFilteredNetworks = new ArrayList<>(); - private final int mThresholdQualifiedRssi24; - private final int mThresholdQualifiedRssi5; - private final int mThresholdMinimumRssi24; - private final int mThresholdMinimumRssi5; + private final ScoringParams mScoringParams; private final int mStayOnNetworkMinimumTxRate; private final int mStayOnNetworkMinimumRxRate; private final boolean mEnableAutoJoinWhenAssociated; @@ -149,9 +146,8 @@ public class WifiNetworkSelector { } int currentRssi = wifiInfo.getRssi(); - boolean hasQualifiedRssi = - (wifiInfo.is24GHz() && (currentRssi > mThresholdQualifiedRssi24)) - || (wifiInfo.is5GHz() && (currentRssi > mThresholdQualifiedRssi5)); + boolean hasQualifiedRssi = currentRssi + > mScoringParams.getSufficientRssi(wifiInfo.getFrequency()); boolean hasActiveStream = (wifiInfo.txSuccessRate > mStayOnNetworkMinimumTxRate) || (wifiInfo.rxSuccessRate > mStayOnNetworkMinimumRxRate); if (hasQualifiedRssi && hasActiveStream) { @@ -262,8 +258,7 @@ public class WifiNetworkSelector { * Compares ScanResult level against the minimum threshold for its band, returns true if lower */ public boolean isSignalTooWeak(ScanResult scanResult) { - return ((scanResult.is24GHz() && scanResult.level < mThresholdMinimumRssi24) - || (scanResult.is5GHz() && scanResult.level < mThresholdMinimumRssi5)); + return (scanResult.level < mScoringParams.getEntryRssi(scanResult.frequency)); } private List<ScanDetail> filterScanResults(List<ScanDetail> scanDetails, @@ -597,20 +592,14 @@ public class WifiNetworkSelector { return true; } - WifiNetworkSelector(Context context, WifiConfigManager configManager, Clock clock, + WifiNetworkSelector(Context context, ScoringParams scoringParams, + WifiConfigManager configManager, Clock clock, LocalLog localLog) { mWifiConfigManager = configManager; mClock = clock; + mScoringParams = scoringParams; mLocalLog = localLog; - mThresholdQualifiedRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz); - mThresholdQualifiedRssi5 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz); - mThresholdMinimumRssi24 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz); - mThresholdMinimumRssi5 = context.getResources().getInteger( - R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz); mEnableAutoJoinWhenAssociated = context.getResources().getBoolean( R.bool.config_wifi_framework_enable_associated_network_selection); mStayOnNetworkMinimumTxRate = context.getResources().getInteger( diff --git a/service/java/com/android/server/wifi/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java index 162f627ae..3db76e8af 100644 --- a/service/java/com/android/server/wifi/WifiScoreReport.java +++ b/service/java/com/android/server/wifi/WifiScoreReport.java @@ -16,7 +16,6 @@ package com.android.server.wifi; -import android.content.Context; import android.net.NetworkAgent; import android.net.wifi.WifiInfo; import android.util.Log; @@ -50,10 +49,10 @@ public class WifiScoreReport { ConnectedScore mAggressiveConnectedScore; VelocityBasedConnectedScore mFancyConnectedScore; - WifiScoreReport(Context context, Clock clock) { + WifiScoreReport(ScoringParams scoringParams, Clock clock) { mClock = clock; - mAggressiveConnectedScore = new AggressiveConnectedScore(context, clock); - mFancyConnectedScore = new VelocityBasedConnectedScore(context, clock); + mAggressiveConnectedScore = new AggressiveConnectedScore(scoringParams, clock); + mFancyConnectedScore = new VelocityBasedConnectedScore(scoringParams, clock); } /** diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index c5d946a8c..d24bc7db9 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -900,7 +900,7 @@ public class WifiStateMachine extends StateMachine { mCountryCode = countryCode; - mWifiScoreReport = new WifiScoreReport(mContext, mClock); + mWifiScoreReport = new WifiScoreReport(mWifiInjector.getScoringParams(), mClock); mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); diff --git a/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java index e5a522e96..ff5fbe894 100644 --- a/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java @@ -72,7 +72,8 @@ public class SavedNetworkEvaluatorTest { mThresholdSaturatedRssi5G = mResource.getInteger( R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz); - mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, mWifiConfigManager, + mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, + new ScoringParams(mContext), mWifiConfigManager, mClock, mLocalLog, mWifiConnectivityHelper); } diff --git a/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java b/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java new file mode 100644 index 000000000..6b3b720e9 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/ScoringParamsTest.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2018 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 com.android.server.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; +import android.support.test.filters.SmallTest; + +import com.android.internal.R; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +/** + * Unit tests for {@link com.android.server.wifi.ScoringParams}. + */ +@SmallTest +public class ScoringParamsTest { + + ScoringParams mScoringParams; + + /** + * Sets up for unit test + */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + setUpResources(mResources); + when(mContext.getResources()).thenReturn(mResources); + mScoringParams = new ScoringParams(); + } + + /** + * Check that thresholds are properly ordered, and in range. + */ + private void checkThresholds(int frequency) { + assertTrue(-127 <= mScoringParams.getExitRssi(frequency)); + assertTrue(mScoringParams.getExitRssi(frequency) + <= mScoringParams.getEntryRssi(frequency)); + assertTrue(mScoringParams.getEntryRssi(frequency) + <= mScoringParams.getSufficientRssi(frequency)); + assertTrue(mScoringParams.getSufficientRssi(frequency) + <= mScoringParams.getGoodRssi(frequency)); + assertTrue(mScoringParams.getGoodRssi(frequency) < 0); + } + + /** + * Test basic constructor + */ + @Test + public void testBasicConstructor() throws Exception { + mScoringParams = new ScoringParams(); + checkThresholds(2412); + checkThresholds(5020); + assertEquals(15, mScoringParams.getHorizonSeconds()); + } + + /** + * Test toString + */ + @Test + public void testToString() throws Exception { + mScoringParams = new ScoringParams(); + String expect = "rssi2=-83:-80:-73:-60,rssi5=-80:-77:-70:-57,horizon=15"; + String actual = mScoringParams.toString(); + assertEquals(expect, actual); + } + + /** + * Test complete update + */ + @Test + public void testUpdateEverything() throws Exception { + mScoringParams = new ScoringParams(); + String params = "rssi2=-86:-84:-77:-10,rssi5=-88:-77:-66:-55,horizon=3"; + assertTrue(mScoringParams.update(params)); + assertEquals(params, mScoringParams.toString()); + } + + /** + * Test partial update + */ + @Test + public void testPartialUpdate() throws Exception { + mScoringParams = new ScoringParams(); + String before = mScoringParams.toString(); + String partial = "rssi5=-88:-77:-66:-55"; + assertFalse(before.contains(partial)); + assertTrue(mScoringParams.update(partial)); + String after = mScoringParams.toString(); + assertTrue(after + " should contain " + partial, after.contains(partial)); + } + + /** + * Test some failed updates + */ + @Test + public void testUpdateFail() throws Exception { + mScoringParams = new ScoringParams(); + String before = mScoringParams.toString(); + assertFalse(mScoringParams.update("word")); + assertFalse(mScoringParams.update("42")); + assertFalse(mScoringParams.update(" ")); + assertFalse(mScoringParams.update("horizon=flat")); + assertFalse(mScoringParams.update(",,,,,,,,,,,,,,,,,,")); + assertFalse(mScoringParams.update("rssi2=-86")); + assertFalse(mScoringParams.update("rssi2=-99:-88:-77:-66:-55")); + assertFalse(mScoringParams.update("rssi5=one:two:three:four")); + assertEquals(before, mScoringParams.toString()); + } + + /** + * Test that empty updates are OK + */ + @Test + public void testEmptyUpdate() throws Exception { + mScoringParams = new ScoringParams(); + String before = mScoringParams.toString(); + assertTrue(mScoringParams.update("")); + assertTrue(mScoringParams.update(null)); + assertEquals(before, mScoringParams.toString()); + } + + /** + * Tests for obtaining values from device configuration (config.xml) + */ + int mBad2GHz, mEntry2GHz, mSufficient2GHz, mGood2GHz; + int mBad5GHz, mEntry5GHz, mSufficient5GHz, mGood5GHz; + + @Mock Context mContext; + @Spy private MockResources mResources = new MockResources(); + + private int setupIntegerResource(int resourceName, int value) { + doReturn(value).when(mResources).getInteger(resourceName); + return value; + } + + /** + * Sets up resource values for testing + * + * See frameworks/base/core/res/res/values/config.xml + */ + private void setUpResources(Resources resources) { + mBad2GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz, -88); + mEntry2GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz, -77); + mSufficient2GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz, -66); + mGood2GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz, -55); + mBad5GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz, -80); + mEntry5GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz, -70); + mSufficient5GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz, -60); + mGood5GHz = setupIntegerResource( + R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz, -50); + } + + /** + * Check that we get the config.xml values, if that's what we want + */ + @Test + public void testContextConstructor() throws Exception { + mScoringParams = new ScoringParams(mContext); + + assertEquals(mBad2GHz, mScoringParams.getExitRssi(2412)); + assertEquals(mEntry2GHz, mScoringParams.getEntryRssi(2480)); + assertEquals(mSufficient2GHz, mScoringParams.getSufficientRssi(2400)); + assertEquals(mGood2GHz, mScoringParams.getGoodRssi(2499)); + assertEquals(mGood2GHz, mScoringParams.getGoodRssi(ScoringParams.BAND2)); + + assertEquals(mBad5GHz, mScoringParams.getExitRssi(5000)); + assertEquals(mEntry5GHz, mScoringParams.getEntryRssi(5010)); + assertEquals(mSufficient5GHz, mScoringParams.getSufficientRssi(5100)); + assertEquals(mGood5GHz, mScoringParams.getGoodRssi(5678)); + assertEquals(mGood5GHz, mScoringParams.getGoodRssi(ScoringParams.BAND5)); + } + + /** + * Additional mocks for handling Settings + */ + @Mock FrameworkFacade mFrameworkFacade; + @Mock Handler mHandler; + + /** + * Test getting updates from Settings + * + * Exercises the ContentObserver notification path + */ + @Test + public void testFullConstructorWithUpdatesFromSettings() throws Exception { + ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass(ContentObserver.class); + when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) + .thenReturn(null); + mScoringParams = new ScoringParams(mContext, mFrameworkFacade, mHandler); + verify(mFrameworkFacade) + .registerContentObserver(eq(mContext), any(), anyBoolean(), captor.capture()); + + String before = mScoringParams.toString(); + String changed = before.replace('8', '9'); + assertFalse(changed.equals(before)); + + when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) + .thenReturn(changed); + captor.getValue().onChange(/*selfChange*/ false); + assertEquals(changed, mScoringParams.toString()); + + when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) + .thenReturn(""); + captor.getValue().onChange(/*selfChange*/ false); + assertEquals(before, mScoringParams.toString()); + } + + @Test + public void testBadSettings() throws Exception { + ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass(ContentObserver.class); + when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) + .thenReturn(null); + mScoringParams = new ScoringParams(mContext, mFrameworkFacade, mHandler); + verify(mFrameworkFacade) + .registerContentObserver(eq(mContext), any(), anyBoolean(), captor.capture()); + + String before = mScoringParams.toString(); + String garbage = "what??"; + + when(mFrameworkFacade.getStringSetting(mContext, Settings.Global.WIFI_SCORE_PARAMS)) + .thenReturn(garbage); + captor.getValue().onChange(/*selfChange*/ false); + assertEquals(before, mScoringParams.toString()); + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java b/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java index 6a72522e0..949350332 100644 --- a/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java @@ -87,7 +87,8 @@ public class VelocityBasedConnectedScoreTest { mWifiInfo.setFrequency(2412); when(mContext.getResources()).thenReturn(mResources); mClock = new FakeClock(); - mVelocityBasedConnectedScore = new VelocityBasedConnectedScore(mContext, mClock); + mVelocityBasedConnectedScore = new VelocityBasedConnectedScore( + new ScoringParams(mContext), mClock); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java index 8b6c2fbe0..6eaf767d1 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java @@ -304,7 +304,9 @@ public class WifiConnectivityManagerTest { } WifiConnectivityManager createConnectivityManager() { - return new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner, + return new WifiConnectivityManager(mContext, + new ScoringParams(mContext), + mWifiStateMachine, mWifiScanner, mWifiConfigManager, mWifiInfo, mWifiNS, mWifiConnectivityHelper, mWifiLastResortWatchdog, mOpenNetworkNotifier, mCarrierNetworkNotifier, mCarrierNetworkConfig, mWifiMetrics, mLooper.getLooper(), mClock, mLocalLog, true, diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java index 1163b0772..6fab007b7 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java @@ -65,7 +65,9 @@ public class WifiNetworkSelectorTest { setupWifiInfo(); mLocalLog = new LocalLog(512); - mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiConfigManager, mClock, + mWifiNetworkSelector = new WifiNetworkSelector(mContext, + new ScoringParams(mContext), + mWifiConfigManager, mClock, mLocalLog); mWifiNetworkSelector.registerNetworkEvaluator(mDummyEvaluator, 1); mDummyEvaluator.setEvaluatorToSelectCandidate(true); @@ -179,6 +181,7 @@ public class WifiNetworkSelectorTest { // simulate a disconnected state when(mWifiInfo.is24GHz()).thenReturn(true); when(mWifiInfo.is5GHz()).thenReturn(false); + when(mWifiInfo.getFrequency()).thenReturn(2400); when(mWifiInfo.getRssi()).thenReturn(-70); when(mWifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID); when(mWifiInfo.getBSSID()).thenReturn(null); @@ -361,6 +364,7 @@ public class WifiNetworkSelectorTest { when(mWifiInfo.getBSSID()).thenReturn(bssids[0]); when(mWifiInfo.is24GHz()).thenReturn(false); when(mWifiInfo.is5GHz()).thenReturn(true); + when(mWifiInfo.getFrequency()).thenReturn(5000); when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000); @@ -407,6 +411,7 @@ public class WifiNetworkSelectorTest { when(mWifiInfo.getBSSID()).thenReturn(bssids[0]); when(mWifiInfo.is24GHz()).thenReturn(false); when(mWifiInfo.is5GHz()).thenReturn(true); + when(mWifiInfo.getFrequency()).thenReturn(5000); when(mWifiInfo.getRssi()).thenReturn(levels[0]); when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() @@ -483,6 +488,7 @@ public class WifiNetworkSelectorTest { when(mWifiInfo.getBSSID()).thenReturn(bssids[0]); when(mWifiInfo.is24GHz()).thenReturn(true); when(mWifiInfo.is5GHz()).thenReturn(false); + when(mWifiInfo.getFrequency()).thenReturn(2400); when(mWifiInfo.getRssi()).thenReturn(levels[0]); when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000); @@ -910,6 +916,7 @@ public class WifiNetworkSelectorTest { when(mWifiInfo.getBSSID()).thenReturn(bssids[0]); when(mWifiInfo.is24GHz()).thenReturn(!ScanResult.is5GHz(freqs[0])); when(mWifiInfo.is5GHz()).thenReturn(ScanResult.is5GHz(freqs[0])); + when(mWifiInfo.getFrequency()).thenReturn(freqs[0]); when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000); diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java index 1cef87a63..67c9a736b 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java @@ -123,7 +123,7 @@ public class WifiScoreReportTest { int trimSize = 5; when(mContext.getResources()).thenReturn(mResources); mClock = new FakeClock(); - mWifiScoreReport = new WifiScoreReport(mContext, mClock); + mWifiScoreReport = new WifiScoreReport(new ScoringParams(mContext), mClock); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java index 0907c77ee..5d5ef3d9f 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java @@ -416,7 +416,7 @@ public class WifiStateMachineTest { when(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper); when(mWifiInjector.getWakeupController()).thenReturn(mWakeupController); when(mWifiInjector.getScanRequestProxy()).thenReturn(mScanRequestProxy); - + when(mWifiInjector.getScoringParams()).thenReturn(new ScoringParams()); when(mWifiNative.setupInterfaceForClientMode(anyBoolean(), any())) .thenReturn(WIFI_IFACE_NAME); when(mWifiNative.initialize()).thenReturn(true); |