diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index 00d7a7b9e0cb5..7b573da482e3e 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -384,7 +384,7 @@ public class NotificationUsageStats { noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_"); quietImportance = new ImportanceHistogram(context, "note_imp_quiet_"); finalImportance = new ImportanceHistogram(context, "note_importance_"); - enqueueRate = new RateEstimator(mCreated); + enqueueRate = new RateEstimator(); } public AggregatedStats getPrevious() { diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/services/core/java/com/android/server/notification/RateEstimator.java index 4dc30a4c98bdd..c17db4acf3cd7 100644 --- a/services/core/java/com/android/server/notification/RateEstimator.java +++ b/services/core/java/com/android/server/notification/RateEstimator.java @@ -25,30 +25,43 @@ package com.android.server.notification; public class RateEstimator { private static final double RATE_ALPHA = 0.8; private static final double MINIMUM_DT = 0.0005; - private long mLastEventTime; - private float mInterarrivalTime; + private Long mLastEventTime; + private Float mInterarrivalTime; - public RateEstimator(long now) { - mLastEventTime = now; - } + public RateEstimator() {} - /** Update the estimate to account for an event that jsut happened. */ + /** Update the estimate to account for an event that just happened. */ public float update(long now) { - mInterarrivalTime = (float) getInterarrivalEstimate(now); + float rate; + if (mLastEventTime == null) { + // No last event time, rate is zero. + rate = 0f; + } else { + // Calculate the new inter-arrival time based on last event time. + mInterarrivalTime = (float) getInterarrivalEstimate(now); + rate = (float) (1.0 / mInterarrivalTime); + } mLastEventTime = now; - return (float) (1.0 / mInterarrivalTime); + return rate; } /** @return the estimated rate if there were a new event right now. */ public float getRate(long now) { + if (mLastEventTime == null) { + return 0f; + } return (float) (1.0 / getInterarrivalEstimate(now)); } /** @return the average inter-arrival time if there were a new event right now. */ private double getInterarrivalEstimate(long now) { - // a*iat_old + (1-a)*(t_now-t_last) double dt = ((double) (now - mLastEventTime)) / 1000.0; dt = Math.max(dt, MINIMUM_DT); + if (mInterarrivalTime == null) { + // No last inter-arrival time, return the new value directly. + return dt; + } + // a*iat_old + (1-a)*(t_now-t_last) return (RATE_ALPHA * mInterarrivalTime + (1.0 - RATE_ALPHA) * dt); } } diff --git a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java index cc0920f506a8a..b5698d5bd40bb 100644 --- a/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java +++ b/services/tests/servicestests/src/com/android/server/notification/RateEstimatorTest.java @@ -26,18 +26,18 @@ public class RateEstimatorTest extends AndroidTestCase { @Override public void setUp() { mTestStartTime = 1225731600000L; - mEstimator = new RateEstimator(mTestStartTime); + mEstimator = new RateEstimator(); } @SmallTest public void testRunningTimeBackwardDoesntExplodeUpdate() throws Exception { - final float rate = mEstimator.update(mTestStartTime - 1000L); - assertFalse(Float.isInfinite(rate)); - assertFalse(Float.isNaN(rate)); + assertUpdateTime(mTestStartTime); + assertUpdateTime(mTestStartTime - 1000L); } @SmallTest public void testRunningTimeBackwardDoesntExplodeGet() throws Exception { + assertUpdateTime(mTestStartTime); final float rate = mEstimator.getRate(mTestStartTime - 1000L); assertFalse(Float.isInfinite(rate)); assertFalse(Float.isNaN(rate)); @@ -45,13 +45,14 @@ public class RateEstimatorTest extends AndroidTestCase { @SmallTest public void testInstantaneousEventsDontExplodeUpdate() throws Exception { - final float rate = mEstimator.update(mTestStartTime); - assertFalse(Float.isInfinite(rate)); - assertFalse(Float.isNaN(rate)); + assertUpdateTime(mTestStartTime); + assertUpdateTime(mTestStartTime); } @SmallTest public void testInstantaneousEventsDontExplodeGet() throws Exception { + assertUpdateTime(mTestStartTime); + assertUpdateTime(mTestStartTime); final float rate = mEstimator.getRate(mTestStartTime); assertFalse(Float.isInfinite(rate)); assertFalse(Float.isNaN(rate)); @@ -59,6 +60,7 @@ public class RateEstimatorTest extends AndroidTestCase { @SmallTest public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception { + assertUpdateTime(mTestStartTime); long eventStart = mTestStartTime + 1000; // start event a long time after initialization long nextEventTime = postEvents(eventStart, 1, 5); // five events at 1000Hz final float rate = mEstimator.getRate(nextEventTime); @@ -67,6 +69,7 @@ public class RateEstimatorTest extends AndroidTestCase { @SmallTest public void testSustained1000HzBurstIsEstimatedOverNinetyPercent() throws Exception { + assertUpdateTime(mTestStartTime); long eventStart = mTestStartTime + 1000; // start event a long time after initialization long nextEventTime = postEvents(eventStart, 1, 100); // one hundred events at 1000Hz final float rate = mEstimator.getRate(nextEventTime); @@ -75,6 +78,7 @@ public class RateEstimatorTest extends AndroidTestCase { @SmallTest public void testSustained100HzBurstIsEstimatedOverNinetyPercent() throws Exception { + assertUpdateTime(mTestStartTime); long eventStart = mTestStartTime + 1000; // start event a long time after initialization long nextEventTime = postEvents(eventStart, 10, 100); // one hundred events at 100Hz final float rate = mEstimator.getRate(nextEventTime); @@ -84,6 +88,7 @@ public class RateEstimatorTest extends AndroidTestCase { @SmallTest public void testRecoverQuicklyAfterSustainedBurst() throws Exception { + assertUpdateTime(mTestStartTime); long eventStart = mTestStartTime + 1000; // start event a long time after initialization long nextEventTime = postEvents(eventStart, 10, 1000); // one hundred events at 100Hz final float rate = mEstimator.getRate(nextEventTime + 5000L); // two seconds later @@ -92,12 +97,19 @@ public class RateEstimatorTest extends AndroidTestCase { @SmallTest public void testEstimateShouldNotOvershoot() throws Exception { + assertUpdateTime(mTestStartTime); long eventStart = mTestStartTime + 1000; // start event a long time after initialization long nextEventTime = postEvents(eventStart, 1, 1000); // one thousand events at 1000Hz final float rate = mEstimator.getRate(nextEventTime); assertLessThan("Rate", rate, 1000f); } + @SmallTest + public void testGetRateWithoutUpdate() throws Exception { + final float rate = mEstimator.getRate(mTestStartTime); + assertLessThan("Rate", rate, 0.1f); + } + private void assertLessThan(String label, float a, float b) { assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a < b); } @@ -115,4 +127,10 @@ public class RateEstimatorTest extends AndroidTestCase { } return time; } + + private void assertUpdateTime(long time) { + final float rate = mEstimator.update(time); + assertFalse(Float.isInfinite(rate)); + assertFalse(Float.isNaN(rate)); + } }