diff options
author | David Su <dysu@google.com> | 2019-05-22 15:55:42 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-05-22 15:55:42 +0000 |
commit | ea1688cfc1965d9a61682173276cb9446ce101bb (patch) | |
tree | 7938d5dca8b07c3fa021b378b771774415fa4fdf /service | |
parent | 2e7b60ac0d7e6f45eaa4b2ee4d164dc6b718a22c (diff) | |
parent | 53648549ec4cc4a6aae5a70370b7e92ff5ebcb69 (diff) |
Merge "Adjust link probe manager parameters using experiment results" into qt-dev
Diffstat (limited to 'service')
3 files changed, 210 insertions, 72 deletions
diff --git a/service/java/com/android/server/wifi/LinkProbeManager.java b/service/java/com/android/server/wifi/LinkProbeManager.java index b91ba67f4..89c84f76f 100644 --- a/service/java/com/android/server/wifi/LinkProbeManager.java +++ b/service/java/com/android/server/wifi/LinkProbeManager.java @@ -27,9 +27,11 @@ import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.wifi.util.TimedQuotaManager; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -43,15 +45,25 @@ public class LinkProbeManager { private static final int WIFI_LINK_PROBING_ENABLED_DEFAULT = 1; // 1 = enabled // TODO(112029045): Use constants from ScoringParams instead - @VisibleForTesting - static final int LINK_PROBE_RSSI_THRESHOLD = -70; - @VisibleForTesting - static final int LINK_PROBE_LINK_SPEED_THRESHOLD_MBPS = 15; // in megabits per second - @VisibleForTesting - static final long LINK_PROBE_INTERVAL_MS = 15 * 1000; - - @VisibleForTesting - static final int[] EXPERIMENT_DELAYS_MS = {3000, 6000, 9000, 12000, 15000}; + @VisibleForTesting static final int RSSI_THRESHOLD = -70; + @VisibleForTesting static final int LINK_SPEED_THRESHOLD_MBPS = 15; // in megabits per second + /** Minimum delay before probing after the last probe. */ + @VisibleForTesting static final long DELAY_BETWEEN_PROBES_MS = 6000; + /** Minimum delay before probing after screen turned on. */ + @VisibleForTesting static final long SCREEN_ON_DELAY_MS = 6000; + /** + * Minimum delay before probing after last increase of the Tx success counter (which indicates + * that a data frame (i.e. not counting management frame) was successfully transmitted). + */ + @VisibleForTesting static final long DELAY_AFTER_TX_SUCCESS_MS = 6000; + + @VisibleForTesting static final long MAX_PROBE_COUNT_IN_PERIOD = + WifiMetrics.MAX_LINK_PROBE_STA_EVENTS; + @VisibleForTesting static final long PERIOD_MILLIS = Duration.ofDays(1).toMillis(); + + @VisibleForTesting static final int[] EXPERIMENT_DELAYS_MS = {3000, 6000, 9000, 12000, 15000}; + @VisibleForTesting static final int[] EXPERIMENT_RSSIS = {-65, -70, -75}; + @VisibleForTesting static final int[] EXPERIMENT_LINK_SPEEDS = {10, 15, 20}; private List<Experiment> mExperiments = new ArrayList<>(); private final Clock mClock; @@ -65,16 +77,32 @@ public class LinkProbeManager { private boolean mVerboseLoggingEnabled = false; + /** + * Tracks the last timestamp when a link probe was triggered. Link probing only occurs when at + * least {@link #DELAY_BETWEEN_PROBES_MS} has passed since the last link probe. + */ private long mLastLinkProbeTimestampMs; /** - * Tracks the last timestamp when wifiInfo.txSuccess was increased i.e. the last time a Tx was - * successful. Link probing only occurs when at least {@link #LINK_PROBE_INTERVAL_MS} has passed - * since the last Tx success. - * This is also reset to the current time when {@link #reset()} is called, so that a link probe - * only occurs at least {@link #LINK_PROBE_INTERVAL_MS} after a new connection is made. + * Tracks the last timestamp when {@link WifiInfo#txSuccess} was increased i.e. the last time a + * Tx was successful. Link probing only occurs when at least {@link #DELAY_AFTER_TX_SUCCESS_MS} + * has passed since the last Tx success. + * This is also reset to the current time when {@link #resetOnNewConnection()} is called, so + * that a link probe only occurs at least {@link #DELAY_AFTER_TX_SUCCESS_MS} after a new + * connection is made. */ private long mLastTxSuccessIncreaseTimestampMs; + /** + * Stores the last value of {@link WifiInfo#txSuccess}. The current value of + * {@link WifiInfo#txSuccess} is compared against the last value to determine whether there was + * a successful Tx. + */ private long mLastTxSuccessCount; + /** + * Tracks the last timestamp when the screen turned on. Link probing only occurs when at least + * {@link #SCREEN_ON_DELAY_MS} has passed since the last time the screen was turned on. + */ + private long mLastScreenOnTimestampMs; + private final TimedQuotaManager mTimedQuotaManager; public LinkProbeManager(Clock clock, WifiNative wifiNative, WifiMetrics wifiMetrics, FrameworkFacade frameworkFacade, Looper looper, Context context) { @@ -85,6 +113,7 @@ public class LinkProbeManager { mContext = context; mLinkProbingSupported = mContext.getResources() .getBoolean(R.bool.config_wifi_link_probing_supported); + mTimedQuotaManager = new TimedQuotaManager(clock, MAX_PROBE_COUNT_IN_PERIOD, PERIOD_MILLIS); if (mLinkProbingSupported) { mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor( @@ -97,7 +126,8 @@ public class LinkProbeManager { }); updateLinkProbeSetting(); - reset(); + resetOnNewConnection(); + resetOnScreenTurnedOn(); } initExperiments(); @@ -124,9 +154,15 @@ public class LinkProbeManager { pw.println("LinkProbeManager - mLastTxSuccessIncreaseTimestampMs: " + mLastTxSuccessIncreaseTimestampMs); pw.println("LinkProbeManager - mLastTxSuccessCount: " + mLastTxSuccessCount); + pw.println("LinkProbeManager - mLastScreenOnTimestampMs: " + mLastScreenOnTimestampMs); + pw.println("LinkProbeManager - mTimedQuotaManager: " + mTimedQuotaManager); } - private void reset() { + /** + * When connecting to a new network, reset internal state. + */ + public void resetOnNewConnection() { + mExperiments.forEach(Experiment::resetOnNewConnection); if (!mLinkProbingSupported) return; long now = mClock.getElapsedSinceBootMillis(); @@ -136,20 +172,14 @@ public class LinkProbeManager { } /** - * When connecting to a new network, reset internal state. - */ - public void resetOnNewConnection() { - mExperiments.forEach(Experiment::resetOnNewConnection); - reset(); - } - - /** * When RSSI poll events are stopped and restarted (usually screen turned off then back on), * reset internal state. */ public void resetOnScreenTurnedOn() { mExperiments.forEach(Experiment::resetOnScreenTurnedOn); - reset(); + if (!mLinkProbingSupported) return; + + mLastScreenOnTimestampMs = mClock.getElapsedSinceBootMillis(); } /** @@ -172,23 +202,33 @@ public class LinkProbeManager { } mLastTxSuccessCount = wifiInfo.txSuccess; - // maximum 1 link probe every LINK_PROBE_INTERVAL_MS + // maximum 1 link probe every DELAY_BETWEEN_PROBES_MS long timeSinceLastLinkProbeMs = now - mLastLinkProbeTimestampMs; - if (timeSinceLastLinkProbeMs < LINK_PROBE_INTERVAL_MS) { + if (timeSinceLastLinkProbeMs < DELAY_BETWEEN_PROBES_MS) { return; } - // if tx succeeded at least once in the last LINK_PROBE_INTERVAL_MS, don't need to probe + // if tx succeeded at least once in the last DELAY_AFTER_TX_SUCCESS_MS, don't need to probe long timeSinceLastTxSuccessIncreaseMs = now - mLastTxSuccessIncreaseTimestampMs; - if (timeSinceLastTxSuccessIncreaseMs < LINK_PROBE_INTERVAL_MS) { + if (timeSinceLastTxSuccessIncreaseMs < DELAY_AFTER_TX_SUCCESS_MS) { + return; + } + + // if not enough time has passed since the screen last turned on, don't probe + long timeSinceLastScreenOnMs = now - mLastScreenOnTimestampMs; + if (timeSinceLastScreenOnMs < SCREEN_ON_DELAY_MS) { return; } // can skip probing if RSSI is valid and high and link speed is fast int rssi = wifiInfo.getRssi(); int linkSpeed = wifiInfo.getLinkSpeed(); - if (rssi != WifiInfo.INVALID_RSSI && rssi > LINK_PROBE_RSSI_THRESHOLD - && linkSpeed > LINK_PROBE_LINK_SPEED_THRESHOLD_MBPS) { + if (rssi != WifiInfo.INVALID_RSSI && rssi > RSSI_THRESHOLD + && linkSpeed > LINK_SPEED_THRESHOLD_MBPS) { + return; + } + + if (!mTimedQuotaManager.requestQuota()) { return; } @@ -201,8 +241,6 @@ public class LinkProbeManager { rssi, linkSpeed)); } - long wallClockTimestampMs = mClock.getWallClockMillis(); - // TODO(b/112029045): also report MCS rate to metrics when supported by driver mWifiNative.probeLink( interfaceName, @@ -214,7 +252,7 @@ public class LinkProbeManager { Log.d(TAG, "link probing success, elapsedTimeMs=" + elapsedTimeMs); } - mWifiMetrics.logLinkProbeSuccess(wallClockTimestampMs, + mWifiMetrics.logLinkProbeSuccess( timeSinceLastTxSuccessIncreaseMs, rssi, linkSpeed, elapsedTimeMs); } @@ -224,7 +262,7 @@ public class LinkProbeManager { if (mVerboseLoggingEnabled) { Log.d(TAG, "link probing failure, reason=" + reason); } - mWifiMetrics.logLinkProbeFailure(wallClockTimestampMs, + mWifiMetrics.logLinkProbeFailure( timeSinceLastTxSuccessIncreaseMs, rssi, linkSpeed, reason); } }, @@ -235,11 +273,11 @@ public class LinkProbeManager { } private void initExperiments() { - for (int screenOnDelayMs : EXPERIMENT_DELAYS_MS) { - for (int noTxDelayMs : EXPERIMENT_DELAYS_MS) { - for (int delayBetweenProbesMs : EXPERIMENT_DELAYS_MS) { + for (int delay : EXPERIMENT_DELAYS_MS) { + for (int rssiThreshold : EXPERIMENT_RSSIS) { + for (int linkSpeedThreshold: EXPERIMENT_LINK_SPEEDS) { Experiment experiment = new Experiment(mClock, mWifiMetrics, - screenOnDelayMs, noTxDelayMs, delayBetweenProbesMs); + delay, delay, delay, rssiThreshold, linkSpeedThreshold); mExperiments.add(experiment); } } @@ -254,29 +292,38 @@ public class LinkProbeManager { private final int mScreenOnDelayMs; private final int mNoTxDelayMs; private final int mDelayBetweenProbesMs; + private final int mRssiThreshold; + private final int mLinkSpeedThreshold; private final String mExperimentId; private long mLastLinkProbeTimestampMs; private long mLastTxSuccessIncreaseTimestampMs; private long mLastTxSuccessCount; + private long mLastScreenOnTimestampMs; Experiment(Clock clock, WifiMetrics wifiMetrics, - int screenOnDelayMs, int noTxDelayMs, int delayBetweenProbesMs) { + int screenOnDelayMs, int noTxDelayMs, int delayBetweenProbesMs, + int rssiThreshold, int linkSpeedThreshold) { mClock = clock; mWifiMetrics = wifiMetrics; mScreenOnDelayMs = screenOnDelayMs; mNoTxDelayMs = noTxDelayMs; mDelayBetweenProbesMs = delayBetweenProbesMs; + mRssiThreshold = rssiThreshold; + mLinkSpeedThreshold = linkSpeedThreshold; mExperimentId = getExperimentId(); resetOnNewConnection(); + resetOnScreenTurnedOn(); } private String getExperimentId() { return "[screenOnDelay=" + mScreenOnDelayMs + ',' + "noTxDelay=" + mNoTxDelayMs + ',' - + "delayBetweenProbes=" + mDelayBetweenProbesMs + ']'; + + "delayBetweenProbes=" + mDelayBetweenProbesMs + ',' + + "rssiThreshold=" + mRssiThreshold + ',' + + "linkSpeedThreshold=" + mLinkSpeedThreshold + ']'; } void resetOnNewConnection() { @@ -287,12 +334,7 @@ public class LinkProbeManager { } void resetOnScreenTurnedOn() { - long now = mClock.getElapsedSinceBootMillis(); - long firstPossibleLinkProbeAfterScreenOnTimestampMs = now + mScreenOnDelayMs; - mLastLinkProbeTimestampMs = Math.max(mLastLinkProbeTimestampMs, - firstPossibleLinkProbeAfterScreenOnTimestampMs - mDelayBetweenProbesMs); - // don't reset mLastTxSuccessIncreaseTimestampMs and mLastTxSuccessCount since no new - // connection was established + mLastScreenOnTimestampMs = mClock.getElapsedSinceBootMillis(); } void updateConnectionStats(WifiInfo wifiInfo) { @@ -314,11 +356,16 @@ public class LinkProbeManager { return; } + long timeSinceLastScreenOnMs = now - mLastScreenOnTimestampMs; + if (timeSinceLastScreenOnMs < SCREEN_ON_DELAY_MS) { + return; + } + // can skip probing if RSSI is valid and high and link speed is fast int rssi = wifiInfo.getRssi(); int linkSpeed = wifiInfo.getLinkSpeed(); - if (rssi != WifiInfo.INVALID_RSSI && rssi > LINK_PROBE_RSSI_THRESHOLD - && linkSpeed > LINK_PROBE_LINK_SPEED_THRESHOLD_MBPS) { + if (rssi != WifiInfo.INVALID_RSSI && rssi > mRssiThreshold + && linkSpeed > mLinkSpeedThreshold) { return; } diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 539fe3dee..a62ad379c 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -212,6 +212,13 @@ public class WifiMetrics { private int mProbeMcsRateSinceLastUpdate = -1; private long mScoreBreachLowTimeMillis = -1; + public static final int MAX_STA_EVENTS = 768; + private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<>(); + private int mLastPollRssi = -127; + private int mLastPollLinkSpeed = -1; + private int mLastPollFreq = -1; + private int mLastScore = -1; + /** Tracks if we should be logging WifiIsUnusableEvent */ private boolean mUnusableEventLogging = false; /** Tracks if we should be logging LinkSpeedCounts */ @@ -328,6 +335,8 @@ public class WifiMetrics { * experiment. */ private final ObjectCounter<String> mLinkProbeExperimentProbeCounts = new ObjectCounter<>(); + private int mLinkProbeStaEventCount = 0; + @VisibleForTesting static final int MAX_LINK_PROBE_STA_EVENTS = MAX_STA_EVENTS / 4; private final LinkedList<WifiUsabilityStatsEntry> mWifiUsabilityStatsEntriesList = new LinkedList<>(); @@ -2761,6 +2770,7 @@ public class WifiMetrics { pw.println("mNetworkSelectionExperimentPairNumChoicesCounts:" + mNetworkSelectionExperimentPairNumChoicesCounts); + pw.println("mLinkProbeStaEventCount:" + mLinkProbeStaEventCount); pw.println("mWifiNetworkRequestApiLog:\n" + mWifiNetworkRequestApiLog); pw.println("mWifiNetworkRequestApiMatchSizeHistogram:\n" @@ -3500,6 +3510,7 @@ public class WifiMetrics { mLinkProbeSuccessElapsedTimeMsHistogram.clear(); mLinkProbeFailureReasonCounts.clear(); mLinkProbeExperimentProbeCounts.clear(); + mLinkProbeStaEventCount = 0; mNetworkSelectionExperimentPairNumChoicesCounts.clear(); mWifiNetworkSuggestionApiLog.clear(); mWifiNetworkSuggestionApiLog.clear(); @@ -3935,13 +3946,6 @@ public class WifiMetrics { return sb.toString(); } - public static final int MAX_STA_EVENTS = 768; - private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<StaEventWithTime>(); - private int mLastPollRssi = -127; - private int mLastPollLinkSpeed = -1; - private int mLastPollFreq = -1; - private int mLastScore = -1; - /** * Converts the first 31 bits of a BitSet to a little endian int */ @@ -4684,7 +4688,6 @@ public class WifiMetrics { /** * Reports stats for a successful link probe. * - * @param startTimestampMs The wall clock time when the link probe was started, in ms. * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since * the last Tx success (according to * {@link WifiInfo#txSuccess}). @@ -4695,7 +4698,7 @@ public class WifiMetrics { * probe was ACKed. Note: this number should be correlated with the number * of retries that the driver attempted before the probe was ACKed. */ - public void logLinkProbeSuccess(long startTimestampMs, long timeSinceLastTxSuccessMs, + public void logLinkProbeSuccess(long timeSinceLastTxSuccessMs, int rssi, int linkSpeed, int elapsedTimeMs) { synchronized (mLock) { mProbeStatusSinceLastUpdate = @@ -4708,19 +4711,20 @@ public class WifiMetrics { mLinkProbeSuccessLinkSpeedCounts.increment(linkSpeed); mLinkProbeSuccessElapsedTimeMsHistogram.increment(elapsedTimeMs); - StaEvent event = new StaEvent(); - event.type = StaEvent.TYPE_LINK_PROBE; - event.linkProbeWasSuccess = true; - event.linkProbeSuccessElapsedTimeMs = elapsedTimeMs; - // TODO(129958996): Cap number of link probe StaEvents - addStaEvent(event); + if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) { + StaEvent event = new StaEvent(); + event.type = StaEvent.TYPE_LINK_PROBE; + event.linkProbeWasSuccess = true; + event.linkProbeSuccessElapsedTimeMs = elapsedTimeMs; + addStaEvent(event); + } + mLinkProbeStaEventCount++; } } /** * Reports stats for an unsuccessful link probe. * - * @param startTimestampMs The wall clock time when the link probe was started, in ms. * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since * the last Tx success (according to * {@link WifiInfo#txSuccess}). @@ -4728,7 +4732,7 @@ public class WifiMetrics { * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}. * @param reason The error code for the failure. See {@link WifiNative.SendMgmtFrameError}. */ - public void logLinkProbeFailure(long startTimestampMs, long timeSinceLastTxSuccessMs, + public void logLinkProbeFailure(long timeSinceLastTxSuccessMs, int rssi, int linkSpeed, @WifiNative.SendMgmtFrameError int reason) { synchronized (mLock) { mProbeStatusSinceLastUpdate = @@ -4741,12 +4745,14 @@ public class WifiMetrics { mLinkProbeFailureLinkSpeedCounts.increment(linkSpeed); mLinkProbeFailureReasonCounts.increment(reason); - StaEvent event = new StaEvent(); - event.type = StaEvent.TYPE_LINK_PROBE; - event.linkProbeWasSuccess = false; - event.linkProbeFailureReason = linkProbeFailureReasonToProto(reason); - // TODO(129958996): Cap number of link probe StaEvents - addStaEvent(event); + if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) { + StaEvent event = new StaEvent(); + event.type = StaEvent.TYPE_LINK_PROBE; + event.linkProbeWasSuccess = false; + event.linkProbeFailureReason = linkProbeFailureReasonToProto(reason); + addStaEvent(event); + } + mLinkProbeStaEventCount++; } } diff --git a/service/java/com/android/server/wifi/util/TimedQuotaManager.java b/service/java/com/android/server/wifi/util/TimedQuotaManager.java new file mode 100644 index 000000000..bf78e9bc8 --- /dev/null +++ b/service/java/com/android/server/wifi/util/TimedQuotaManager.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 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.util; + +import com.android.server.wifi.Clock; + +/** + * Manages a quota that is reset at the beginning of each new time period. + */ +public class TimedQuotaManager { + private final Clock mClock; + + private final long mQuota; + private final long mPeriodMillis; + private final long mStartTimeMillis; + + /** + * The number of elapsed periods between {@link #mStartTimeMillis} and the time of the last call + * to {@link #requestQuota()}. + */ + private long mLastPeriod; + /** How much quota has been consumed in the current period. */ + private long mConsumedQuota; + + /** + * Constructor. + * @param clock Clock instance. + * @param quota the maximum quota for a given period. + * @param periodMillis the quota will be reset at the beginning of each new period. + */ + public TimedQuotaManager(Clock clock, long quota, long periodMillis) { + mClock = clock; + mQuota = quota; + mPeriodMillis = periodMillis; + mStartTimeMillis = clock.getElapsedSinceBootMillis(); + mLastPeriod = 0; + mConsumedQuota = 0; + } + + /** + * Requests one quota. If there is sufficient remaining quota for the current period, + * returns true and consumes one quota. Otherwise, returns false. + */ + public boolean requestQuota() { + long currentPeriod = getCurrentPeriod(); + if (mLastPeriod < currentPeriod) { + mLastPeriod = currentPeriod; + mConsumedQuota = 0; + } + if (mConsumedQuota < mQuota) { + mConsumedQuota++; + return true; + } + return false; + } + + private long getCurrentPeriod() { + return (mClock.getElapsedSinceBootMillis() - mStartTimeMillis) / mPeriodMillis; + } + + @Override + public String toString() { + return "TimedQuotaManager{" + + "mQuota=" + mQuota + + ", mPeriodMillis=" + mPeriodMillis + + ", mStartTimeMillis=" + mStartTimeMillis + + ", mLastPeriod=" + mLastPeriod + + ", mConsumedQuota=" + mConsumedQuota + + '}'; + } +} |