Skip to content

Commit 9bf3150

Browse files
committed
Save timezone when setting data cycle reset date.
Instead of cycle reset at midnight UTC, use midnight of timezone active when user last set cycle reset date. Tests to verify, and also to test leap year behavior. Bug: 5938567 Change-Id: Ie06f7f0fa242d23110f9586a3f4f7037af87b31b
1 parent 92d291e commit 9bf3150

File tree

4 files changed

+95
-34
lines changed

4 files changed

+95
-34
lines changed

core/java/android/net/NetworkPolicy.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
3636

3737
public final NetworkTemplate template;
3838
public int cycleDay;
39+
public String cycleTimezone;
3940
public long warningBytes;
4041
public long limitBytes;
4142
public long lastWarningSnooze;
@@ -44,15 +45,18 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
4445

4546
private static final long DEFAULT_MTU = 1500;
4647

47-
public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
48-
long limitBytes, boolean metered) {
49-
this(template, cycleDay, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered);
48+
public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
49+
long warningBytes, long limitBytes, boolean metered) {
50+
this(template, cycleDay, cycleTimezone, warningBytes, limitBytes, SNOOZE_NEVER,
51+
SNOOZE_NEVER, metered);
5052
}
5153

52-
public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
53-
long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered) {
54+
public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
55+
long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze,
56+
boolean metered) {
5457
this.template = checkNotNull(template, "missing NetworkTemplate");
5558
this.cycleDay = cycleDay;
59+
this.cycleTimezone = checkNotNull(cycleTimezone, "missing cycleTimezone");
5660
this.warningBytes = warningBytes;
5761
this.limitBytes = limitBytes;
5862
this.lastWarningSnooze = lastWarningSnooze;
@@ -63,25 +67,27 @@ public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
6367
public NetworkPolicy(Parcel in) {
6468
template = in.readParcelable(null);
6569
cycleDay = in.readInt();
70+
cycleTimezone = in.readString();
6671
warningBytes = in.readLong();
6772
limitBytes = in.readLong();
6873
lastWarningSnooze = in.readLong();
6974
lastLimitSnooze = in.readLong();
7075
metered = in.readInt() != 0;
7176
}
7277

73-
/** {@inheritDoc} */
78+
@Override
7479
public void writeToParcel(Parcel dest, int flags) {
7580
dest.writeParcelable(template, flags);
7681
dest.writeInt(cycleDay);
82+
dest.writeString(cycleTimezone);
7783
dest.writeLong(warningBytes);
7884
dest.writeLong(limitBytes);
7985
dest.writeLong(lastWarningSnooze);
8086
dest.writeLong(lastLimitSnooze);
8187
dest.writeInt(metered ? 1 : 0);
8288
}
8389

84-
/** {@inheritDoc} */
90+
@Override
8591
public int describeContents() {
8692
return 0;
8793
}
@@ -112,7 +118,7 @@ public void clearSnooze() {
112118
lastLimitSnooze = SNOOZE_NEVER;
113119
}
114120

115-
/** {@inheritDoc} */
121+
@Override
116122
public int compareTo(NetworkPolicy another) {
117123
if (another == null || another.limitBytes == LIMIT_DISABLED) {
118124
// other value is missing or disabled; we win
@@ -127,8 +133,8 @@ public int compareTo(NetworkPolicy another) {
127133

128134
@Override
129135
public int hashCode() {
130-
return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastWarningSnooze,
131-
lastLimitSnooze, metered);
136+
return Objects.hashCode(template, cycleDay, cycleTimezone, warningBytes, limitBytes,
137+
lastWarningSnooze, lastLimitSnooze, metered);
132138
}
133139

134140
@Override
@@ -139,24 +145,27 @@ public boolean equals(Object obj) {
139145
&& limitBytes == other.limitBytes
140146
&& lastWarningSnooze == other.lastWarningSnooze
141147
&& lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
148+
&& Objects.equal(cycleTimezone, other.cycleTimezone)
142149
&& Objects.equal(template, other.template);
143150
}
144151
return false;
145152
}
146153

147154
@Override
148155
public String toString() {
149-
return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
150-
+ warningBytes + ", limitBytes=" + limitBytes + ", lastWarningSnooze="
151-
+ lastWarningSnooze + ", lastLimitSnooze=" + lastLimitSnooze + ", metered="
152-
+ metered;
156+
return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", cycleTimezone="
157+
+ cycleTimezone + ", warningBytes=" + warningBytes + ", limitBytes=" + limitBytes
158+
+ ", lastWarningSnooze=" + lastWarningSnooze + ", lastLimitSnooze="
159+
+ lastLimitSnooze + ", metered=" + metered;
153160
}
154161

155162
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
163+
@Override
156164
public NetworkPolicy createFromParcel(Parcel in) {
157165
return new NetworkPolicy(in);
158166
}
159167

168+
@Override
160169
public NetworkPolicy[] newArray(int size) {
161170
return new NetworkPolicy[size];
162171
}

core/java/android/net/NetworkPolicyManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public void unregisterListener(INetworkPolicyListener listener) {
131131
* @hide
132132
*/
133133
public static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
134-
final Time now = new Time(Time.TIMEZONE_UTC);
134+
final Time now = new Time(policy.cycleTimezone);
135135
now.set(currentTime);
136136

137137
// first, find cycle boundary for current month
@@ -157,7 +157,7 @@ public static long computeLastCycleBoundary(long currentTime, NetworkPolicy poli
157157

158158
/** {@hide} */
159159
public static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
160-
final Time now = new Time(Time.TIMEZONE_UTC);
160+
final Time now = new Time(policy.cycleTimezone);
161161
now.set(currentTime);
162162

163163
// first, find cycle boundary for current month
@@ -183,7 +183,7 @@ public static long computeNextCycleBoundary(long currentTime, NetworkPolicy poli
183183

184184
/**
185185
* Snap to the cycle day for the current month given; when cycle day doesn't
186-
* exist, it snaps to 1st of following month.
186+
* exist, it snaps to last second of current month.
187187
*
188188
* @hide
189189
*/

services/java/com/android/server/net/NetworkPolicyManagerService.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
156156
private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
157157
private static final int VERSION_ADDED_METERED = 4;
158158
private static final int VERSION_SPLIT_SNOOZE = 5;
159+
private static final int VERSION_ADDED_TIMEZONE = 6;
159160

160161
// @VisibleForTesting
161162
public static final int TYPE_WARNING = 0x1;
@@ -171,6 +172,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
171172
private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
172173
private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
173174
private static final String ATTR_CYCLE_DAY = "cycleDay";
175+
private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone";
174176
private static final String ATTR_WARNING_BYTES = "warningBytes";
175177
private static final String ATTR_LIMIT_BYTES = "limitBytes";
176178
private static final String ATTR_LAST_SNOOZE = "lastSnooze";
@@ -922,13 +924,15 @@ private void ensureActiveMobilePolicyLocked() {
922924
com.android.internal.R.integer.config_networkPolicyDefaultWarning)
923925
* MB_IN_BYTES;
924926

925-
final Time time = new Time(Time.TIMEZONE_UTC);
927+
final Time time = new Time();
926928
time.setToNow();
929+
927930
final int cycleDay = time.monthDay;
931+
final String cycleTimezone = time.timezone;
928932

929933
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
930-
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, warningBytes,
931-
LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true));
934+
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone,
935+
warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true));
932936
writePolicyLocked();
933937
}
934938
}
@@ -964,6 +968,12 @@ private void readPolicyLocked() {
964968
final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
965969
final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
966970
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
971+
final String cycleTimezone;
972+
if (version >= VERSION_ADDED_TIMEZONE) {
973+
cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE);
974+
} else {
975+
cycleTimezone = Time.TIMEZONE_UTC;
976+
}
967977
final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
968978
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
969979
final long lastLimitSnooze;
@@ -998,8 +1008,8 @@ private void readPolicyLocked() {
9981008
final NetworkTemplate template = new NetworkTemplate(
9991009
networkTemplate, subscriberId);
10001010
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
1001-
warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
1002-
metered));
1011+
cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
1012+
lastLimitSnooze, metered));
10031013

10041014
} else if (TAG_UID_POLICY.equals(tag)) {
10051015
final int uid = readIntAttribute(in, ATTR_UID);
@@ -1054,7 +1064,7 @@ private void writePolicyLocked() {
10541064
out.startDocument(null, true);
10551065

10561066
out.startTag(null, TAG_POLICY_LIST);
1057-
writeIntAttribute(out, ATTR_VERSION, VERSION_SPLIT_SNOOZE);
1067+
writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_TIMEZONE);
10581068
writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
10591069

10601070
// write all known network policies
@@ -1068,6 +1078,7 @@ private void writePolicyLocked() {
10681078
out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
10691079
}
10701080
writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
1081+
out.attribute(null, ATTR_CYCLE_TIMEZONE, policy.cycleTimezone);
10711082
writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
10721083
writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
10731084
writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);

services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import static android.net.TrafficStats.MB_IN_BYTES;
3333
import static android.text.format.DateUtils.DAY_IN_MILLIS;
3434
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
35+
import static android.text.format.Time.TIMEZONE_UTC;
3536
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
3637
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
3738
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
@@ -439,7 +440,7 @@ public void testLastCycleBoundaryThisMonth() throws Exception {
439440
final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
440441

441442
final NetworkPolicy policy = new NetworkPolicy(
442-
sTemplateWifi, 5, 1024L, 1024L, false);
443+
sTemplateWifi, 5, TIMEZONE_UTC, 1024L, 1024L, false);
443444
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
444445
assertTimeEquals(expectedCycle, actualCycle);
445446
}
@@ -450,7 +451,7 @@ public void testLastCycleBoundaryLastMonth() throws Exception {
450451
final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
451452

452453
final NetworkPolicy policy = new NetworkPolicy(
453-
sTemplateWifi, 20, 1024L, 1024L, false);
454+
sTemplateWifi, 20, TIMEZONE_UTC, 1024L, 1024L, false);
454455
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
455456
assertTimeEquals(expectedCycle, actualCycle);
456457
}
@@ -461,7 +462,7 @@ public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
461462
final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
462463

463464
final NetworkPolicy policy = new NetworkPolicy(
464-
sTemplateWifi, 30, 1024L, 1024L, false);
465+
sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
465466
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
466467
assertTimeEquals(expectedCycle, actualCycle);
467468
}
@@ -472,14 +473,53 @@ public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
472473
final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
473474

474475
final NetworkPolicy policy = new NetworkPolicy(
475-
sTemplateWifi, 30, 1024L, 1024L, false);
476+
sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
476477
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
477478
assertTimeEquals(expectedCycle, actualCycle);
478479
}
479480

481+
public void testCycleBoundaryLeapYear() throws Exception {
482+
final NetworkPolicy policy = new NetworkPolicy(
483+
sTemplateWifi, 29, TIMEZONE_UTC, 1024L, 1024L, false);
484+
485+
assertTimeEquals(parseTime("2012-01-29T00:00:00.000Z"),
486+
computeNextCycleBoundary(parseTime("2012-01-14T00:00:00.000Z"), policy));
487+
assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
488+
computeNextCycleBoundary(parseTime("2012-02-14T00:00:00.000Z"), policy));
489+
assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
490+
computeLastCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
491+
assertTimeEquals(parseTime("2012-03-29T00:00:00.000Z"),
492+
computeNextCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
493+
494+
assertTimeEquals(parseTime("2007-01-29T00:00:00.000Z"),
495+
computeNextCycleBoundary(parseTime("2007-01-14T00:00:00.000Z"), policy));
496+
assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
497+
computeNextCycleBoundary(parseTime("2007-02-14T00:00:00.000Z"), policy));
498+
assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
499+
computeLastCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
500+
assertTimeEquals(parseTime("2007-03-29T00:00:00.000Z"),
501+
computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
502+
}
503+
504+
public void testNextCycleTimezoneAfterUtc() throws Exception {
505+
// US/Central is UTC-6
506+
final NetworkPolicy policy = new NetworkPolicy(
507+
sTemplateWifi, 10, "US/Central", 1024L, 1024L, false);
508+
assertTimeEquals(parseTime("2012-01-10T06:00:00.000Z"),
509+
computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
510+
}
511+
512+
public void testNextCycleTimezoneBeforeUtc() throws Exception {
513+
// Israel is UTC+2
514+
final NetworkPolicy policy = new NetworkPolicy(
515+
sTemplateWifi, 10, "Israel", 1024L, 1024L, false);
516+
assertTimeEquals(parseTime("2012-01-09T22:00:00.000Z"),
517+
computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
518+
}
519+
480520
public void testNextCycleSane() throws Exception {
481521
final NetworkPolicy policy = new NetworkPolicy(
482-
sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
522+
sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
483523
final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
484524

485525
// walk forwards, ensuring that cycle boundaries don't get stuck
@@ -494,7 +534,7 @@ public void testNextCycleSane() throws Exception {
494534

495535
public void testLastCycleSane() throws Exception {
496536
final NetworkPolicy policy = new NetworkPolicy(
497-
sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
537+
sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
498538
final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
499539

500540
// walk backwards, ensuring that cycle boundaries look sane
@@ -552,7 +592,7 @@ public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
552592

553593
replay();
554594
setNetworkPolicies(new NetworkPolicy(
555-
sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
595+
sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
556596
future.get();
557597
verifyAndReset();
558598
}
@@ -609,8 +649,8 @@ public void testOverWarningLimitNotification() throws Exception {
609649
future = expectMeteredIfacesChanged();
610650

611651
replay();
612-
setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES,
613-
2 * MB_IN_BYTES, false));
652+
setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1
653+
* MB_IN_BYTES, 2 * MB_IN_BYTES, false));
614654
future.get();
615655
verifyAndReset();
616656
}
@@ -740,8 +780,9 @@ public void testMeteredNetworkWithoutLimit() throws Exception {
740780
future = expectMeteredIfacesChanged(TEST_IFACE);
741781

742782
replay();
743-
setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED,
744-
LIMIT_DISABLED, true));
783+
setNetworkPolicies(new NetworkPolicy(
784+
sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED,
785+
true));
745786
future.get();
746787
verifyAndReset();
747788
}

0 commit comments

Comments
 (0)