summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorDavid Su <dysu@google.com>2019-05-22 15:55:42 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-05-22 15:55:42 +0000
commitea1688cfc1965d9a61682173276cb9446ce101bb (patch)
tree7938d5dca8b07c3fa021b378b771774415fa4fdf /service
parent2e7b60ac0d7e6f45eaa4b2ee4d164dc6b718a22c (diff)
parent53648549ec4cc4a6aae5a70370b7e92ff5ebcb69 (diff)
Merge "Adjust link probe manager parameters using experiment results" into qt-dev
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/LinkProbeManager.java145
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java52
-rw-r--r--service/java/com/android/server/wifi/util/TimedQuotaManager.java85
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
+ + '}';
+ }
+}