1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.net.wifi.ScanResult; 22 import android.net.wifi.WifiInfo; 23 import android.net.wifi.WifiNetworkSelectionConfig; 24 import android.os.Build; 25 import android.text.TextUtils; 26 import android.util.Log; 27 import android.util.SparseArray; 28 29 import androidx.annotation.RequiresApi; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.modules.utils.build.SdkLevel; 33 import com.android.server.wifi.util.KeyValueListParser; 34 import com.android.wifi.resources.R; 35 36 /** 37 * Holds parameters used for scoring networks. 38 * 39 * Doing this in one place means that there's a better chance of consistency between 40 * connected score and network selection. 41 * 42 */ 43 public class ScoringParams { 44 private final Context mContext; 45 46 private static final String TAG = "WifiScoringParams"; 47 private static final int EXIT = 0; 48 private static final int ENTRY = 1; 49 private static final int SUFFICIENT = 2; 50 private static final int GOOD = 3; 51 52 private static final int ACTIVE_TRAFFIC = 1; 53 private static final int HIGH_TRAFFIC = 2; 54 55 @VisibleForTesting 56 public static final int FREQUENCY_WEIGHT_LOW = -40; 57 @VisibleForTesting 58 public static final int FREQUENCY_WEIGHT_DEFAULT = 0; 59 @VisibleForTesting 60 public static final int FREQUENCY_WEIGHT_HIGH = 40; 61 62 SparseArray<Integer> mFrequencyWeights = new SparseArray<>(); 63 64 /** 65 * Parameter values are stored in a separate container so that a new collection of values can 66 * be checked for consistency before activating them. 67 */ 68 private class Values { 69 /** RSSI thresholds for 2.4 GHz band (dBm) */ 70 public static final String KEY_RSSI2 = "rssi2"; 71 public final int[] rssi2 = {-83, -80, -73, -60}; 72 73 /** RSSI thresholds for 5 GHz band (dBm) */ 74 public static final String KEY_RSSI5 = "rssi5"; 75 public final int[] rssi5 = {-80, -77, -70, -57}; 76 77 /** RSSI thresholds for 6 GHz band (dBm) */ 78 public static final String KEY_RSSI6 = "rssi6"; 79 public final int[] rssi6 = {-80, -77, -70, -57}; 80 81 /** Guidelines based on packet rates (packets/sec) */ 82 public static final String KEY_PPS = "pps"; 83 public final int[] pps = {0, 1, 100}; 84 85 /** Number of seconds for RSSI forecast */ 86 public static final String KEY_HORIZON = "horizon"; 87 public static final int MIN_HORIZON = -9; 88 public static final int MAX_HORIZON = 60; 89 public int horizon = 15; 90 91 /** Number 0-10 influencing requests for network unreachability detection */ 92 public static final String KEY_NUD = "nud"; 93 public static final int MIN_NUD = 0; 94 public static final int MAX_NUD = 10; 95 public int nud = 8; 96 97 /** Experiment identifier */ 98 public static final String KEY_EXPID = "expid"; 99 public static final int MIN_EXPID = 0; 100 public static final int MAX_EXPID = Integer.MAX_VALUE; 101 public int expid = 0; 102 103 /** CandidateScorer parameters */ 104 public int throughputBonusNumerator = 120; 105 public int throughputBonusDenominator = 433; 106 public int throughputBonusNumeratorAfter800Mbps = 1; 107 public int throughputBonusDenominatorAfter800Mbps = 16; 108 public boolean enable6GhzBeaconRssiBoost = true; 109 public int throughputBonusLimit = 320; 110 public int savedNetworkBonus = 500; 111 public int unmeteredNetworkBonus = 1000; 112 public int currentNetworkBonusMin = 16; 113 public int currentNetworkBonusPercent = 20; 114 public int secureNetworkBonus = 40; 115 public int band6GhzBonus = 0; 116 public int scoringBucketStepSize = 500; 117 public int lastUnmeteredSelectionMinutes = 480; 118 public int lastMeteredSelectionMinutes = 120; 119 public int estimateRssiErrorMargin = 5; 120 public static final int MIN_MINUTES = 1; 121 public static final int MAX_MINUTES = Integer.MAX_VALUE / (60 * 1000); 122 Values()123 Values() { 124 } 125 Values(Values source)126 Values(Values source) { 127 for (int i = 0; i < rssi2.length; i++) { 128 rssi2[i] = source.rssi2[i]; 129 } 130 for (int i = 0; i < rssi5.length; i++) { 131 rssi5[i] = source.rssi5[i]; 132 } 133 for (int i = 0; i < rssi6.length; i++) { 134 rssi6[i] = source.rssi6[i]; 135 } 136 for (int i = 0; i < pps.length; i++) { 137 pps[i] = source.pps[i]; 138 } 139 horizon = source.horizon; 140 nud = source.nud; 141 expid = source.expid; 142 } 143 validate()144 public void validate() throws IllegalArgumentException { 145 validateRssiArray(rssi2); 146 validateRssiArray(rssi5); 147 validateRssiArray(rssi6); 148 validateOrderedNonNegativeArray(pps); 149 validateRange(horizon, MIN_HORIZON, MAX_HORIZON); 150 validateRange(nud, MIN_NUD, MAX_NUD); 151 validateRange(expid, MIN_EXPID, MAX_EXPID); 152 validateRange(lastUnmeteredSelectionMinutes, MIN_MINUTES, MAX_MINUTES); 153 validateRange(lastMeteredSelectionMinutes, MIN_MINUTES, MAX_MINUTES); 154 } 155 validateRssiArray(int[] rssi)156 private void validateRssiArray(int[] rssi) throws IllegalArgumentException { 157 int low = WifiInfo.MIN_RSSI; 158 int high = Math.min(WifiInfo.MAX_RSSI, -1); // Stricter than Wifiinfo 159 for (int i = 0; i < rssi.length; i++) { 160 validateRange(rssi[i], low, high); 161 low = rssi[i]; 162 } 163 } 164 validateRange(int k, int low, int high)165 private void validateRange(int k, int low, int high) throws IllegalArgumentException { 166 if (k < low || k > high) { 167 throw new IllegalArgumentException(); 168 } 169 } 170 validateOrderedNonNegativeArray(int[] a)171 private void validateOrderedNonNegativeArray(int[] a) throws IllegalArgumentException { 172 int low = 0; 173 for (int i = 0; i < a.length; i++) { 174 if (a[i] < low) { 175 throw new IllegalArgumentException(); 176 } 177 low = a[i]; 178 } 179 } 180 parseString(String kvList)181 public void parseString(String kvList) throws IllegalArgumentException { 182 KeyValueListParser parser = new KeyValueListParser(','); 183 parser.setString(kvList); 184 if (parser.size() != ("" + kvList).split(",").length) { 185 throw new IllegalArgumentException("dup keys"); 186 } 187 updateIntArray(rssi2, parser, KEY_RSSI2); 188 updateIntArray(rssi5, parser, KEY_RSSI5); 189 updateIntArray(rssi6, parser, KEY_RSSI6); 190 updateIntArray(pps, parser, KEY_PPS); 191 horizon = updateInt(parser, KEY_HORIZON, horizon); 192 nud = updateInt(parser, KEY_NUD, nud); 193 expid = updateInt(parser, KEY_EXPID, expid); 194 } 195 updateInt(KeyValueListParser parser, String key, int defaultValue)196 private int updateInt(KeyValueListParser parser, String key, int defaultValue) 197 throws IllegalArgumentException { 198 String value = parser.getString(key, null); 199 if (value == null) return defaultValue; 200 try { 201 return Integer.parseInt(value); 202 } catch (NumberFormatException e) { 203 throw new IllegalArgumentException(); 204 } 205 } 206 updateIntArray(final int[] dest, KeyValueListParser parser, String key)207 private void updateIntArray(final int[] dest, KeyValueListParser parser, String key) 208 throws IllegalArgumentException { 209 if (parser.getString(key, null) == null) return; 210 int[] ints = parser.getIntArray(key, null); 211 if (ints == null) throw new IllegalArgumentException(); 212 if (ints.length != dest.length) throw new IllegalArgumentException(); 213 for (int i = 0; i < dest.length; i++) { 214 dest[i] = ints[i]; 215 } 216 } 217 218 @Override toString()219 public String toString() { 220 StringBuilder sb = new StringBuilder(); 221 appendKey(sb, KEY_RSSI2); 222 appendInts(sb, rssi2); 223 appendKey(sb, KEY_RSSI5); 224 appendInts(sb, rssi5); 225 appendKey(sb, KEY_RSSI6); 226 appendInts(sb, rssi6); 227 appendKey(sb, KEY_PPS); 228 appendInts(sb, pps); 229 appendKey(sb, KEY_HORIZON); 230 sb.append(horizon); 231 appendKey(sb, KEY_NUD); 232 sb.append(nud); 233 appendKey(sb, KEY_EXPID); 234 sb.append(expid); 235 return sb.toString(); 236 } 237 appendKey(StringBuilder sb, String key)238 private void appendKey(StringBuilder sb, String key) { 239 if (sb.length() != 0) sb.append(","); 240 sb.append(key).append("="); 241 } 242 appendInts(StringBuilder sb, final int[] a)243 private void appendInts(StringBuilder sb, final int[] a) { 244 final int n = a.length; 245 for (int i = 0; i < n; i++) { 246 if (i > 0) sb.append(":"); 247 sb.append(a[i]); 248 } 249 } 250 } 251 252 @NonNull private Values mVal = null; 253 254 @VisibleForTesting ScoringParams()255 public ScoringParams() { 256 mContext = null; 257 mVal = new Values(); 258 } 259 ScoringParams(Context context)260 public ScoringParams(Context context) { 261 mContext = context; 262 loadResources(mContext); 263 } 264 loadResources(Context context)265 private void loadResources(Context context) { 266 if (mVal != null) return; 267 mVal = new Values(); 268 mVal.rssi2[EXIT] = context.getResources().getInteger( 269 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz); 270 mVal.rssi2[ENTRY] = context.getResources().getInteger( 271 R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz); 272 mVal.rssi2[SUFFICIENT] = context.getResources().getInteger( 273 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz); 274 mVal.rssi2[GOOD] = context.getResources().getInteger( 275 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz); 276 mVal.rssi5[EXIT] = context.getResources().getInteger( 277 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz); 278 mVal.rssi5[ENTRY] = context.getResources().getInteger( 279 R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz); 280 mVal.rssi5[SUFFICIENT] = context.getResources().getInteger( 281 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz); 282 mVal.rssi5[GOOD] = context.getResources().getInteger( 283 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz); 284 mVal.rssi6[EXIT] = context.getResources().getInteger( 285 R.integer.config_wifiFrameworkScoreBadRssiThreshold6ghz); 286 mVal.rssi6[ENTRY] = context.getResources().getInteger( 287 R.integer.config_wifiFrameworkScoreEntryRssiThreshold6ghz); 288 mVal.rssi6[SUFFICIENT] = context.getResources().getInteger( 289 R.integer.config_wifiFrameworkScoreLowRssiThreshold6ghz); 290 mVal.rssi6[GOOD] = context.getResources().getInteger( 291 R.integer.config_wifiFrameworkScoreGoodRssiThreshold6ghz); 292 mVal.throughputBonusNumerator = context.getResources().getInteger( 293 R.integer.config_wifiFrameworkThroughputBonusNumerator); 294 mVal.throughputBonusDenominator = context.getResources().getInteger( 295 R.integer.config_wifiFrameworkThroughputBonusDenominator); 296 mVal.throughputBonusNumeratorAfter800Mbps = context.getResources().getInteger( 297 R.integer.config_wifiFrameworkThroughputBonusNumeratorAfter800Mbps); 298 mVal.throughputBonusDenominatorAfter800Mbps = context.getResources().getInteger( 299 R.integer.config_wifiFrameworkThroughputBonusDenominatorAfter800Mbps); 300 mVal.enable6GhzBeaconRssiBoost = context.getResources().getBoolean( 301 R.bool.config_wifiEnable6GhzBeaconRssiBoost); 302 mVal.throughputBonusLimit = context.getResources().getInteger( 303 R.integer.config_wifiFrameworkThroughputBonusLimit); 304 mVal.savedNetworkBonus = context.getResources().getInteger( 305 R.integer.config_wifiFrameworkSavedNetworkBonus); 306 mVal.unmeteredNetworkBonus = context.getResources().getInteger( 307 R.integer.config_wifiFrameworkUnmeteredNetworkBonus); 308 mVal.currentNetworkBonusMin = context.getResources().getInteger( 309 R.integer.config_wifiFrameworkCurrentNetworkBonusMin); 310 mVal.currentNetworkBonusPercent = context.getResources().getInteger( 311 R.integer.config_wifiFrameworkCurrentNetworkBonusPercent); 312 mVal.secureNetworkBonus = context.getResources().getInteger( 313 R.integer.config_wifiFrameworkSecureNetworkBonus); 314 mVal.band6GhzBonus = context.getResources().getInteger(R.integer.config_wifiBand6GhzBonus); 315 mVal.scoringBucketStepSize = context.getResources().getInteger( 316 R.integer.config_wifiScoringBucketStepSize); 317 mVal.lastUnmeteredSelectionMinutes = context.getResources().getInteger( 318 R.integer.config_wifiFrameworkLastSelectionMinutes); 319 mVal.lastMeteredSelectionMinutes = context.getResources().getInteger( 320 R.integer.config_wifiFrameworkLastMeteredSelectionMinutes); 321 mVal.estimateRssiErrorMargin = context.getResources().getInteger( 322 R.integer.config_wifiEstimateRssiErrorMarginDb); 323 mVal.pps[ACTIVE_TRAFFIC] = context.getResources().getInteger( 324 R.integer.config_wifiFrameworkMinPacketPerSecondActiveTraffic); 325 mVal.pps[HIGH_TRAFFIC] = context.getResources().getInteger( 326 R.integer.config_wifiFrameworkMinPacketPerSecondHighTraffic); 327 try { 328 mVal.validate(); 329 } catch (IllegalArgumentException e) { 330 Log.wtf(TAG, "Inconsistent config_wifi_framework_ resources: " + this, e); 331 } 332 } 333 334 private static final String COMMA_KEY_VAL_STAR = "^(,[A-Za-z_][A-Za-z0-9_]*=[0-9.:+-]+)*$"; 335 336 /** 337 * Updates the parameters from the given parameter string. 338 * If any errors are detected, no change is made. 339 * @param kvList is a comma-separated key=value list. 340 * @return true for success 341 */ 342 @VisibleForTesting update(String kvList)343 public boolean update(String kvList) { 344 if (TextUtils.isEmpty(kvList)) { 345 return true; 346 } 347 if (!("," + kvList).matches(COMMA_KEY_VAL_STAR)) { 348 return false; 349 } 350 Values v = new Values(mVal); 351 try { 352 v.parseString(kvList); 353 v.validate(); 354 mVal = v; 355 return true; 356 } catch (IllegalArgumentException e) { 357 return false; 358 } 359 } 360 361 /** 362 * Sanitize a string to make it safe for printing. 363 * @param params is the untrusted string 364 * @return string with questionable characters replaced with question marks 365 */ sanitize(String params)366 public String sanitize(String params) { 367 if (params == null) return ""; 368 String printable = params.replaceAll("[^A-Za-z_0-9=,:.+-]", "?"); 369 if (printable.length() > 100) { 370 printable = printable.substring(0, 98) + "..."; 371 } 372 return printable; 373 } 374 375 /** 376 * Returns the RSSI value at which the connection is deemed to be unusable, 377 * in the absence of other indications. 378 */ getExitRssi(int frequencyMegaHertz)379 public int getExitRssi(int frequencyMegaHertz) { 380 return getRssiArray(frequencyMegaHertz)[EXIT]; 381 } 382 383 /** 384 * Returns the minimum scan RSSI for making a connection attempt. 385 */ getEntryRssi(int frequencyMegaHertz)386 public int getEntryRssi(int frequencyMegaHertz) { 387 return getRssiArray(frequencyMegaHertz)[ENTRY]; 388 } 389 390 /** 391 * Returns a connected RSSI value that indicates the connection is 392 * good enough that we needn't scan for alternatives. 393 */ getSufficientRssi(int frequencyMegaHertz)394 public int getSufficientRssi(int frequencyMegaHertz) { 395 return getRssiArray(frequencyMegaHertz)[SUFFICIENT]; 396 } 397 398 /** 399 * Returns a connected RSSI value that indicates a good connection. 400 */ getGoodRssi(int frequencyMegaHertz)401 public int getGoodRssi(int frequencyMegaHertz) { 402 return getRssiArray(frequencyMegaHertz)[GOOD]; 403 } 404 405 /** 406 * Sets the RSSI thresholds for 2.4 GHz. 407 */ 408 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setRssi2Thresholds(int[] rssi2)409 public void setRssi2Thresholds(int[] rssi2) { 410 if (WifiNetworkSelectionConfig.isRssiThresholdResetArray(rssi2)) { 411 mVal.rssi2[EXIT] = mContext.getResources().getInteger( 412 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz); 413 mVal.rssi2[ENTRY] = mContext.getResources().getInteger( 414 R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz); 415 mVal.rssi2[SUFFICIENT] = mContext.getResources().getInteger( 416 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz); 417 mVal.rssi2[GOOD] = mContext.getResources().getInteger( 418 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz); 419 } else { 420 mVal.rssi2[EXIT] = rssi2[EXIT]; 421 mVal.rssi2[ENTRY] = rssi2[ENTRY]; 422 mVal.rssi2[SUFFICIENT] = rssi2[SUFFICIENT]; 423 mVal.rssi2[GOOD] = rssi2[GOOD]; 424 } 425 } 426 427 /** 428 * Sets the RSSI thresholds for 5 GHz. 429 */ 430 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setRssi5Thresholds(int[] rssi5)431 public void setRssi5Thresholds(int[] rssi5) { 432 if (WifiNetworkSelectionConfig.isRssiThresholdResetArray(rssi5)) { 433 mVal.rssi5[EXIT] = mContext.getResources().getInteger( 434 R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz); 435 mVal.rssi5[ENTRY] = mContext.getResources().getInteger( 436 R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz); 437 mVal.rssi5[SUFFICIENT] = mContext.getResources().getInteger( 438 R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz); 439 mVal.rssi5[GOOD] = mContext.getResources().getInteger( 440 R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz); 441 } else { 442 mVal.rssi5[EXIT] = rssi5[EXIT]; 443 mVal.rssi5[ENTRY] = rssi5[ENTRY]; 444 mVal.rssi5[SUFFICIENT] = rssi5[SUFFICIENT]; 445 mVal.rssi5[GOOD] = rssi5[GOOD]; 446 } 447 } 448 449 /** 450 * Sets the RSSI thresholds for 6 GHz. 451 */ 452 @RequiresApi(Build.VERSION_CODES.TIRAMISU) setRssi6Thresholds(int[] rssi6)453 public void setRssi6Thresholds(int[] rssi6) { 454 if (WifiNetworkSelectionConfig.isRssiThresholdResetArray(rssi6)) { 455 mVal.rssi6[EXIT] = mContext.getResources().getInteger( 456 R.integer.config_wifiFrameworkScoreBadRssiThreshold6ghz); 457 mVal.rssi6[ENTRY] = mContext.getResources().getInteger( 458 R.integer.config_wifiFrameworkScoreEntryRssiThreshold6ghz); 459 mVal.rssi6[SUFFICIENT] = mContext.getResources().getInteger( 460 R.integer.config_wifiFrameworkScoreLowRssiThreshold6ghz); 461 mVal.rssi6[GOOD] = mContext.getResources().getInteger( 462 R.integer.config_wifiFrameworkScoreGoodRssiThreshold6ghz); 463 } else { 464 mVal.rssi6[EXIT] = rssi6[EXIT]; 465 mVal.rssi6[ENTRY] = rssi6[ENTRY]; 466 mVal.rssi6[SUFFICIENT] = rssi6[SUFFICIENT]; 467 mVal.rssi6[GOOD] = rssi6[GOOD]; 468 } 469 } 470 471 /** 472 * Sets the frequency weights list 473 */ setFrequencyWeights(SparseArray<Integer> weights)474 public void setFrequencyWeights(SparseArray<Integer> weights) { 475 mFrequencyWeights = weights; 476 } 477 478 /** 479 * Returns the frequency weight score for the provided frequency 480 */ getFrequencyScore(int frequencyMegaHertz)481 public int getFrequencyScore(int frequencyMegaHertz) { 482 if (SdkLevel.isAtLeastT() && mFrequencyWeights.contains(frequencyMegaHertz)) { 483 switch(mFrequencyWeights.get(frequencyMegaHertz)) { 484 case WifiNetworkSelectionConfig.FREQUENCY_WEIGHT_LOW: 485 return FREQUENCY_WEIGHT_LOW; 486 case WifiNetworkSelectionConfig.FREQUENCY_WEIGHT_HIGH: 487 return FREQUENCY_WEIGHT_HIGH; 488 default: 489 // This should never happen because we've validated the frequency weights 490 // in WifiNetworkSectionConfig. 491 Log.wtf(TAG, "Invalid frequency weight type " 492 + mFrequencyWeights.get(frequencyMegaHertz)); 493 } 494 } 495 return FREQUENCY_WEIGHT_DEFAULT; 496 } 497 498 /** 499 * Returns the number of seconds to use for rssi forecast. 500 */ getHorizonSeconds()501 public int getHorizonSeconds() { 502 return mVal.horizon; 503 } 504 505 /** 506 * Returns a packet rate that should be considered acceptable for staying on wifi, 507 * no matter how bad the RSSI gets (packets per second). 508 */ getYippeeSkippyPacketsPerSecond()509 public int getYippeeSkippyPacketsPerSecond() { 510 return mVal.pps[HIGH_TRAFFIC]; 511 } 512 513 /** 514 * Returns a packet rate that should be considered acceptable to skip scan or network selection 515 */ getActiveTrafficPacketsPerSecond()516 public int getActiveTrafficPacketsPerSecond() { 517 return mVal.pps[ACTIVE_TRAFFIC]; 518 } 519 520 /** 521 * Returns a number between 0 and 10 inclusive that indicates 522 * how aggressive to be about asking for IP configuration checks 523 * (also known as Network Unreachabilty Detection, or NUD). 524 * 525 * 0 - no nud checks requested by scorer (framework still checks after roam) 526 * 1 - check when score becomes very low 527 * ... 528 * 10 - check when score first breaches threshold, and again as it gets worse 529 * 530 */ getNudKnob()531 public int getNudKnob() { 532 return mVal.nud; 533 } 534 535 /** 536 * Returns the estimate rssi error margin to account minor differences in the environment 537 * and the device's orientation. 538 * 539 */ getEstimateRssiErrorMargin()540 public int getEstimateRssiErrorMargin() { 541 return mVal.estimateRssiErrorMargin; 542 } 543 544 /** 545 */ getThroughputBonusNumerator()546 public int getThroughputBonusNumerator() { 547 return mVal.throughputBonusNumerator; 548 } 549 550 /** 551 */ getThroughputBonusDenominator()552 public int getThroughputBonusDenominator() { 553 return mVal.throughputBonusDenominator; 554 } 555 556 /** 557 * Getter for throughput numerator after 800Mbps. 558 */ getThroughputBonusNumeratorAfter800Mbps()559 public int getThroughputBonusNumeratorAfter800Mbps() { 560 return mVal.throughputBonusNumeratorAfter800Mbps; 561 } 562 563 /** 564 * Getter for throughput denominator after 800Mbps. 565 */ getThroughputBonusDenominatorAfter800Mbps()566 public int getThroughputBonusDenominatorAfter800Mbps() { 567 return mVal.throughputBonusDenominatorAfter800Mbps; 568 } 569 570 /** 571 * Feature flag for boosting 6Ghz RSSI based on channel width. 572 */ is6GhzBeaconRssiBoostEnabled()573 public boolean is6GhzBeaconRssiBoostEnabled() { 574 return mVal.enable6GhzBeaconRssiBoost; 575 } 576 577 /* 578 * Returns the maximum bonus for the network selection candidate score 579 * for the contribution of the selected score. 580 */ getThroughputBonusLimit()581 public int getThroughputBonusLimit() { 582 return mVal.throughputBonusLimit; 583 } 584 585 /* 586 * Returns the bonus for the network selection candidate score 587 * for a saved network (i.e., not a suggestion). 588 */ getSavedNetworkBonus()589 public int getSavedNetworkBonus() { 590 return mVal.savedNetworkBonus; 591 } 592 593 /* 594 * Returns the bonus for the network selection candidate score 595 * for an unmetered network. 596 */ getUnmeteredNetworkBonus()597 public int getUnmeteredNetworkBonus() { 598 return mVal.unmeteredNetworkBonus; 599 } 600 601 /* 602 * Returns the minimum bonus for the network selection candidate score 603 * for the currently connected network. 604 */ getCurrentNetworkBonusMin()605 public int getCurrentNetworkBonusMin() { 606 return mVal.currentNetworkBonusMin; 607 } 608 609 /* 610 * Returns the percentage bonus for the network selection candidate score 611 * for the currently connected network. The percent value is applied to rssi score and 612 * throughput score; 613 */ getCurrentNetworkBonusPercent()614 public int getCurrentNetworkBonusPercent() { 615 return mVal.currentNetworkBonusPercent; 616 } 617 618 /* 619 * Returns the bonus for the network selection candidate score 620 * for a secure network. 621 */ getSecureNetworkBonus()622 public int getSecureNetworkBonus() { 623 return mVal.secureNetworkBonus; 624 } 625 626 /** 627 * Returns the bonus given if the network belongs to the 6Ghz band. 628 */ getBand6GhzBonus()629 public int getBand6GhzBonus() { 630 return mVal.band6GhzBonus; 631 } 632 633 /** 634 * Returns the expected amount of score to reach the next tier during candidate scoring. This 635 * value should be configured according to the value of parameters that determine the 636 * scoring buckets such as {@code config_wifiFrameworkSavedNetworkBonus} and 637 * {@code config_wifiFrameworkUnmeteredNetworkBonus}. 638 */ getScoringBucketStepSize()639 public int getScoringBucketStepSize() { 640 return mVal.scoringBucketStepSize; 641 } 642 643 /* 644 * Returns the duration in minutes for a recently selected non-metered network 645 * to be strongly favored. 646 */ getLastUnmeteredSelectionMinutes()647 public int getLastUnmeteredSelectionMinutes() { 648 return mVal.lastUnmeteredSelectionMinutes; 649 } 650 651 /* 652 * Returns the duration in minutes for a recently selected metered network 653 * to be strongly favored. 654 */ getLastMeteredSelectionMinutes()655 public int getLastMeteredSelectionMinutes() { 656 return mVal.lastMeteredSelectionMinutes; 657 } 658 659 /** 660 * Returns the experiment identifier. 661 * 662 * This value may be used to tag a set of experimental settings. 663 */ getExperimentIdentifier()664 public int getExperimentIdentifier() { 665 return mVal.expid; 666 } 667 668 /** 669 * Returns the RSSI thresholds array for the input band. 670 */ getRssiArray(int frequency)671 public int[] getRssiArray(int frequency) { 672 if (ScanResult.is24GHz(frequency)) { 673 return mVal.rssi2; 674 } else if (ScanResult.is5GHz(frequency)) { 675 return mVal.rssi5; 676 } else if (ScanResult.is6GHz(frequency)) { 677 return mVal.rssi6; 678 } 679 // Invalid frequency use 680 Log.e(TAG, "Invalid frequency(" + frequency + "), using 5G as default rssi array"); 681 return mVal.rssi5; 682 } 683 684 @Override toString()685 public String toString() { 686 return mVal.toString(); 687 } 688 } 689