From af82ea2abf53b6825fbbce23434419527d8e8b5c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 4 Aug 2011 15:38:48 -0700 Subject: [PATCH] Data cycle ends on last second of month. When data cycle resets on a day invalid in given month, snap the cycle to last second of month. Previous behavior was to bump fully into next month, but that causes cycle loops. Includes tests to verify. Bug: 4623124 Change-Id: I2f233091f6f1df33a2814284519cbc04532874e9 --- .../android/net/NetworkPolicyManager.java | 3 +- .../NetworkPolicyManagerServiceTest.java | 71 +++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 1e9d81319297b..9d253c73614cb 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -189,9 +189,10 @@ public class NetworkPolicyManager { */ public static void snapToCycleDay(Time time, int cycleDay) { if (cycleDay > time.getActualMaximum(MONTH_DAY)) { - // cycle day isn't valid this month; snap to 1st of next month + // cycle day isn't valid this month; snap to last second of month time.month += 1; time.monthDay = 1; + time.second = -1; } else { time.monthDay = cycleDay; } diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 91fef22fbd213..09f8ff39c97e1 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -20,14 +20,18 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; +import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; +import static android.net.NetworkPolicyManager.computeNextCycleBoundary; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT; import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED; @@ -79,6 +83,7 @@ import org.easymock.EasyMock; import org.easymock.IAnswer; import java.io.File; +import java.util.LinkedHashSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -402,7 +407,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER); final long actualCycle = computeLastCycleBoundary(currentTime, policy); - assertEquals(expectedCycle, actualCycle); + assertTimeEquals(expectedCycle, actualCycle); } public void testLastCycleBoundaryLastMonth() throws Exception { @@ -413,7 +418,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER); final long actualCycle = computeLastCycleBoundary(currentTime, policy); - assertEquals(expectedCycle, actualCycle); + assertTimeEquals(expectedCycle, actualCycle); } public void testLastCycleBoundaryThisMonthFebruary() throws Exception { @@ -424,18 +429,48 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER); final long actualCycle = computeLastCycleBoundary(currentTime, policy); - assertEquals(expectedCycle, actualCycle); + assertTimeEquals(expectedCycle, actualCycle); } public void testLastCycleBoundaryLastMonthFebruary() throws Exception { // assume cycle day of "30th" in february, which should clamp final long currentTime = parseTime("2007-03-14T00:00:00.000Z"); - final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z"); + final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z"); final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER); final long actualCycle = computeLastCycleBoundary(currentTime, policy); - assertEquals(expectedCycle, actualCycle); + assertTimeEquals(expectedCycle, actualCycle); + } + + public void testNextCycleSane() throws Exception { + final NetworkPolicy policy = new NetworkPolicy( + sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER); + final LinkedHashSet seen = new LinkedHashSet(); + + // walk forwards, ensuring that cycle boundaries don't get stuck + long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy); + for (int i = 0; i < 128; i++) { + long nextCycle = computeNextCycleBoundary(currentCycle, policy); + assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3); + assertUnique(seen, nextCycle); + currentCycle = nextCycle; + } + } + + public void testLastCycleSane() throws Exception { + final NetworkPolicy policy = new NetworkPolicy( + sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER); + final LinkedHashSet seen = new LinkedHashSet(); + + // walk backwards, ensuring that cycle boundaries look sane + long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy); + for (int i = 0; i < 128; i++) { + long lastCycle = computeLastCycleBoundary(currentCycle, policy); + assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3); + assertUnique(seen, lastCycle); + currentCycle = lastCycle; + } } public void testNetworkPolicyAppliedCycleLastMonth() throws Exception { @@ -734,6 +769,32 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } } + private static void assertTimeEquals(long expected, long actual) { + if (expected != actual) { + fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual)); + } + } + + private static String formatTime(long millis) { + final Time time = new Time(Time.TIMEZONE_UTC); + time.set(millis); + return time.format3339(false); + } + + private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) { + final long low = expected - fuzzy; + final long high = expected + fuzzy; + if (actual < low || actual > high) { + fail("value " + actual + " is outside [" + low + "," + high + "]"); + } + } + + private static void assertUnique(LinkedHashSet seen, Long value) { + if (!seen.add(value)) { + fail("found duplicate time " + value + " in series " + seen.toString()); + } + } + private static void assertNotificationType(int expected, String actualTag) { assertEquals( Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));