From 1b2f37401818b04cf4908d5aa9017eab44fe5662 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Wed, 28 Mar 2018 14:54:08 +0100 Subject: [PATCH] Tweak SystemUpdatePolicy APIs * Introduce a FreezePeriod class that represents a single freeze period and is defined by two MonthDay instances. * Add ERROR_UNKNOWN to ValidationFailedException * Make SystemUpdatePolicy final * Document SystemUpdatePolicy.InstallationOption and add IntDef to getType() Test: runtest frameworks-services -c com.android.server.devicepolicy.SystemUpdatePolicyTest Test: cts-tradefed run cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testSystemUpdatePolicy Test: gts-tradefed run gts-dev --module GtsGmscoreHostTestCases --test com.google.android.gts.devicepolicy.DeviceOwnerTest#testSystemUpdatePolicy Bug: 74976911 Change-Id: I85cf636c3a98c97bd03b7b296c3130028051a791 --- api/current.txt | 23 ++-- api/system-current.txt | 2 +- ...{FreezeInterval.java => FreezePeriod.java} | 124 +++++++++++++----- .../android/app/admin/SystemUpdatePolicy.java | 105 +++++++++------ .../devicepolicy/SystemUpdatePolicyTest.java | 89 ++++++------- 5 files changed, 209 insertions(+), 134 deletions(-) rename core/java/android/app/admin/{FreezeInterval.java => FreezePeriod.java} (75%) diff --git a/api/current.txt b/api/current.txt index 607109d31228d..dbfd014a192ec 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6748,6 +6748,12 @@ package android.app.admin { field public static final android.os.Parcelable.Creator CREATOR; } + public class FreezePeriod { + ctor public FreezePeriod(java.time.MonthDay, java.time.MonthDay); + method public java.time.MonthDay getEnd(); + method public java.time.MonthDay getStart(); + } + public abstract class NetworkEvent implements android.os.Parcelable { method public int describeContents(); method public long getId(); @@ -6818,16 +6824,16 @@ package android.app.admin { field public static final int SECURITY_PATCH_STATE_UNKNOWN = 0; // 0x0 } - public class SystemUpdatePolicy implements android.os.Parcelable { + public final class SystemUpdatePolicy implements android.os.Parcelable { method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy(); method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy(); method public static android.app.admin.SystemUpdatePolicy createWindowedInstallPolicy(int, int); method public int describeContents(); - method public java.util.List> getFreezePeriods(); + method public java.util.List getFreezePeriods(); method public int getInstallWindowEnd(); method public int getInstallWindowStart(); method public int getPolicyType(); - method public android.app.admin.SystemUpdatePolicy setFreezePeriods(java.util.List>); + method public android.app.admin.SystemUpdatePolicy setFreezePeriods(java.util.List); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int TYPE_INSTALL_AUTOMATIC = 1; // 0x1 @@ -6840,11 +6846,12 @@ package android.app.admin { method public int getErrorCode(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 5; // 0x5 - field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 4; // 0x4 - field public static final int ERROR_DUPLICATE_OR_OVERLAP = 1; // 0x1 - field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 3; // 0x3 - field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 2; // 0x2 + field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 6; // 0x6 + field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 5; // 0x5 + field public static final int ERROR_DUPLICATE_OR_OVERLAP = 2; // 0x2 + field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 4; // 0x4 + field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 3; // 0x3 + field public static final int ERROR_UNKNOWN = 1; // 0x1 } } diff --git a/api/system-current.txt b/api/system-current.txt index 1322a39495a32..3bdcbed72d377 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -451,7 +451,7 @@ package android.app.admin { field public static final int STATE_USER_UNMANAGED = 0; // 0x0 } - public class SystemUpdatePolicy implements android.os.Parcelable { + public final class SystemUpdatePolicy implements android.os.Parcelable { method public int describeContents(); method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long); method public void writeToParcel(android.os.Parcel, int); diff --git a/core/java/android/app/admin/FreezeInterval.java b/core/java/android/app/admin/FreezePeriod.java similarity index 75% rename from core/java/android/app/admin/FreezeInterval.java rename to core/java/android/app/admin/FreezePeriod.java index de5e21ac75c41..657f0177097ea 100644 --- a/core/java/android/app/admin/FreezeInterval.java +++ b/core/java/android/app/admin/FreezePeriod.java @@ -20,49 +20,88 @@ import android.util.Log; import android.util.Pair; import java.time.LocalDate; +import java.time.MonthDay; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; /** - * An interval representing one freeze period which repeats annually. We use the number of days - * since the start of (non-leap) year to define the start and end dates of an interval, both - * inclusive. If the end date is smaller than the start date, the interval is considered wrapped - * around the year-end. As far as an interval is concerned, February 29th should be treated as - * if it were February 28th: so an interval starting or ending on February 28th are not - * distinguishable from an interval on February 29th. When calulating interval length or - * distance between two dates, February 29th is also disregarded. + * A class that represents one freeze period which repeats annually. A freeze period has + * two {@link java.time#MonthDay} values that define the start and end dates of the period, both + * inclusive. If the end date is earlier than the start date, the period is considered wrapped + * around the year-end. As far as freeze period is concerned, leap year is disregarded and February + * 29th should be treated as if it were February 28th: so a freeze starting or ending on February + * 28th is identical to a freeze starting or ending on February 29th. When calulating the length of + * a freeze or the distance bewteen two freee periods, February 29th is also ignored. * * @see SystemUpdatePolicy#setFreezePeriods - * @hide */ -public class FreezeInterval { - private static final String TAG = "FreezeInterval"; +public class FreezePeriod { + private static final String TAG = "FreezePeriod"; private static final int DUMMY_YEAR = 2001; static final int DAYS_IN_YEAR = 365; // 365 since DUMMY_YEAR is not a leap year - final int mStartDay; // [1,365] - final int mEndDay; // [1,365] + private final MonthDay mStart; + private final MonthDay mEnd; - FreezeInterval(int startDay, int endDay) { - if (startDay < 1 || startDay > 365 || endDay < 1 || endDay > 365) { - throw new RuntimeException("Bad dates for Interval: " + startDay + "," + endDay); - } - mStartDay = startDay; - mEndDay = endDay; + /* + * Start and end dates represented by number of days since the beginning of the year. + * They are internal representations of mStart and mEnd with normalized Leap year days + * (Feb 29 == Feb 28 == 59th day of year). All internal calclations are based on + * these two values so that leap year days are disregarded. + */ + private final int mStartDay; // [1, 365] + private final int mEndDay; // [1, 365] + + /** + * Creates a freeze period by its start and end dates. If the end date is earlier than the start + * date, the freeze period is considered wrapping year-end. + */ + public FreezePeriod(MonthDay start, MonthDay end) { + mStart = start; + mStartDay = mStart.atYear(DUMMY_YEAR).getDayOfYear(); + mEnd = end; + mEndDay = mEnd.atYear(DUMMY_YEAR).getDayOfYear(); } + /** + * Returns the start date (inclusive) of this freeze period. + */ + public MonthDay getStart() { + return mStart; + } + + /** + * Returns the end date (inclusive) of this freeze period. + */ + public MonthDay getEnd() { + return mEnd; + } + + /** + * @hide + */ + private FreezePeriod(int startDay, int endDay) { + mStartDay = startDay; + mStart = dayOfYearToMonthDay(startDay); + mEndDay = endDay; + mEnd = dayOfYearToMonthDay(endDay); + } + + /** @hide */ int getLength() { return getEffectiveEndDay() - mStartDay + 1; } + /** @hide */ boolean isWrapped() { return mEndDay < mStartDay; } /** * Returns the effective end day, taking wrapping around year-end into consideration + * @hide */ int getEffectiveEndDay() { if (!isWrapped()) { @@ -72,6 +111,7 @@ public class FreezeInterval { } } + /** @hide */ boolean contains(LocalDate localDate) { final int daysOfYear = dayOfYearDisregardLeapYear(localDate); if (!isWrapped()) { @@ -84,6 +124,7 @@ public class FreezeInterval { } } + /** @hide */ boolean after(LocalDate localDate) { return mStartDay > dayOfYearDisregardLeapYear(localDate); } @@ -95,6 +136,7 @@ public class FreezeInterval { * include now, the returned dates represents the next future interval. * The result will always have the same month and dayOfMonth value as the non-instantiated * interval itself. + * @hide */ Pair toCurrentOrFutureRealDates(LocalDate now) { final int nowDays = dayOfYearDisregardLeapYear(now); @@ -138,14 +180,24 @@ public class FreezeInterval { + LocalDate.ofYearDay(DUMMY_YEAR, mEndDay).format(formatter); } - // Treat the supplied date as in a non-leap year and return its day of year. - static int dayOfYearDisregardLeapYear(LocalDate date) { + /** @hide */ + private static MonthDay dayOfYearToMonthDay(int dayOfYear) { + LocalDate date = LocalDate.ofYearDay(DUMMY_YEAR, dayOfYear); + return MonthDay.of(date.getMonth(), date.getDayOfMonth()); + } + + /** + * Treat the supplied date as in a non-leap year and return its day of year. + * @hide + */ + private static int dayOfYearDisregardLeapYear(LocalDate date) { return date.withYear(DUMMY_YEAR).getDayOfYear(); } /** * Compute the number of days between first (inclusive) and second (exclusive), * treating all years in between as non-leap. + * @hide */ public static int distanceWithoutLeapYear(LocalDate first, LocalDate second) { return dayOfYearDisregardLeapYear(first) - dayOfYearDisregardLeapYear(second) @@ -165,16 +217,16 @@ public class FreezeInterval { * 3. At most one wrapped Interval remains, and it will be at the end of the list * @hide */ - protected static List canonicalizeIntervals(List intervals) { + static List canonicalizePeriods(List intervals) { boolean[] taken = new boolean[DAYS_IN_YEAR]; // First convert the intervals into flat array - for (FreezeInterval interval : intervals) { + for (FreezePeriod interval : intervals) { for (int i = interval.mStartDay; i <= interval.getEffectiveEndDay(); i++) { taken[(i - 1) % DAYS_IN_YEAR] = true; } } // Then reconstruct intervals from the array - List result = new ArrayList<>(); + List result = new ArrayList<>(); int i = 0; while (i < DAYS_IN_YEAR) { if (!taken[i]) { @@ -183,14 +235,14 @@ public class FreezeInterval { } final int intervalStart = i + 1; while (i < DAYS_IN_YEAR && taken[i]) i++; - result.add(new FreezeInterval(intervalStart, i)); + result.add(new FreezePeriod(intervalStart, i)); } // Check if the last entry can be merged to the first entry to become one single // wrapped interval final int lastIndex = result.size() - 1; if (lastIndex > 0 && result.get(lastIndex).mEndDay == DAYS_IN_YEAR && result.get(0).mStartDay == 1) { - FreezeInterval wrappedInterval = new FreezeInterval(result.get(lastIndex).mStartDay, + FreezePeriod wrappedInterval = new FreezePeriod(result.get(lastIndex).mStartDay, result.get(0).mEndDay); result.set(lastIndex, wrappedInterval); result.remove(0); @@ -207,18 +259,18 @@ public class FreezeInterval { * * @hide */ - protected static void validatePeriods(List periods) { - List allPeriods = FreezeInterval.canonicalizeIntervals(periods); + static void validatePeriods(List periods) { + List allPeriods = FreezePeriod.canonicalizePeriods(periods); if (allPeriods.size() != periods.size()) { throw SystemUpdatePolicy.ValidationFailedException.duplicateOrOverlapPeriods(); } for (int i = 0; i < allPeriods.size(); i++) { - FreezeInterval current = allPeriods.get(i); + FreezePeriod current = allPeriods.get(i); if (current.getLength() > SystemUpdatePolicy.FREEZE_PERIOD_MAX_LENGTH) { throw SystemUpdatePolicy.ValidationFailedException.freezePeriodTooLong("Freeze " + "period " + current + " is too long: " + current.getLength() + " days"); } - FreezeInterval previous = i > 0 ? allPeriods.get(i - 1) + FreezePeriod previous = i > 0 ? allPeriods.get(i - 1) : allPeriods.get(allPeriods.size() - 1); if (previous != current) { final int separation; @@ -247,7 +299,7 @@ public class FreezeInterval { * * @hide */ - protected static void validateAgainstPreviousFreezePeriod(List periods, + static void validateAgainstPreviousFreezePeriod(List periods, LocalDate prevPeriodStart, LocalDate prevPeriodEnd, LocalDate now) { if (periods.size() == 0 || prevPeriodStart == null || prevPeriodEnd == null) { return; @@ -258,14 +310,14 @@ public class FreezeInterval { // Clock was adjusted backwards. We can continue execution though, the separation // and length validation below still works under this condition. } - List allPeriods = FreezeInterval.canonicalizeIntervals(periods); + List allPeriods = FreezePeriod.canonicalizePeriods(periods); // Given current time now, find the freeze period that's either current, or the one // that's immediately afterwards. For the later case, it might be after the year-end, // but this can only happen if there is only one freeze period. - FreezeInterval curOrNextFreezePeriod = allPeriods.get(0); - for (FreezeInterval interval : allPeriods) { + FreezePeriod curOrNextFreezePeriod = allPeriods.get(0); + for (FreezePeriod interval : allPeriods) { if (interval.contains(now) - || interval.mStartDay > FreezeInterval.dayOfYearDisregardLeapYear(now)) { + || interval.mStartDay > FreezePeriod.dayOfYearDisregardLeapYear(now)) { curOrNextFreezePeriod = interval; break; } @@ -282,7 +334,7 @@ public class FreezeInterval { // Now validate [prevPeriodStart, prevPeriodEnd] against curOrNextFreezeDates final String periodsDescription = "Prev: " + prevPeriodStart + "," + prevPeriodEnd + "; cur: " + curOrNextFreezeDates.first + "," + curOrNextFreezeDates.second; - long separation = FreezeInterval.distanceWithoutLeapYear(curOrNextFreezeDates.first, + long separation = FreezePeriod.distanceWithoutLeapYear(curOrNextFreezeDates.first, prevPeriodEnd) - 1; if (separation > 0) { // Two intervals do not overlap, check separation @@ -292,7 +344,7 @@ public class FreezeInterval { } } else { // Two intervals overlap, check combined length - long length = FreezeInterval.distanceWithoutLeapYear(curOrNextFreezeDates.second, + long length = FreezePeriod.distanceWithoutLeapYear(curOrNextFreezeDates.second, prevPeriodStart) + 1; if (length > SystemUpdatePolicy.FREEZE_PERIOD_MAX_LENGTH) { throw ValidationFailedException.combinedPeriodTooLong("Combined freeze period " diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java index 47b3a81d0174c..20eef6cc01d83 100644 --- a/core/java/android/app/admin/SystemUpdatePolicy.java +++ b/core/java/android/app/admin/SystemUpdatePolicy.java @@ -38,9 +38,11 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.MonthDay; import java.time.ZoneId; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -51,7 +53,7 @@ import java.util.stream.Collectors; * @see DevicePolicyManager#setSystemUpdatePolicy * @see DevicePolicyManager#getSystemUpdatePolicy */ -public class SystemUpdatePolicy implements Parcelable { +public final class SystemUpdatePolicy implements Parcelable { private static final String TAG = "SystemUpdatePolicy"; /** @hide */ @@ -163,6 +165,7 @@ public class SystemUpdatePolicy implements Parcelable { ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE, ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG, ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE, + ERROR_UNKNOWN, }) @Retention(RetentionPolicy.SOURCE) @interface ValidationFailureType {} @@ -170,34 +173,39 @@ public class SystemUpdatePolicy implements Parcelable { /** @hide */ public static final int ERROR_NONE = 0; + /** + * Validation failed with unknown error. + */ + public static final int ERROR_UNKNOWN = 1; + /** * The freeze periods contains duplicates, periods that overlap with each * other or periods whose start and end joins. */ - public static final int ERROR_DUPLICATE_OR_OVERLAP = 1; + public static final int ERROR_DUPLICATE_OR_OVERLAP = 2; /** * There exists at least one freeze period whose length exceeds 90 days. */ - public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 2; + public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 3; /** * There exists some freeze period which starts within 60 days of the preceding period's * end time. */ - public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 3; + public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 4; /** * The device has been in a freeze period and when combining with the new freeze period * to be set, it will result in the total freeze period being longer than 90 days. */ - public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 4; + public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 5; /** * The device has been in a freeze period and some new freeze period to be set is less * than 60 days from the end of the last freeze period the device went through. */ - public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 5; + public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 6; @ValidationFailureType private final int mErrorCode; @@ -272,7 +280,7 @@ public class SystemUpdatePolicy implements Parcelable { private int mMaintenanceWindowStart; private int mMaintenanceWindowEnd; - private final ArrayList mFreezePeriods; + private final ArrayList mFreezePeriods; private SystemUpdatePolicy() { mPolicyType = TYPE_UNKNOWN; @@ -444,12 +452,10 @@ public class SystemUpdatePolicy implements Parcelable { * requirement set above * @return this instance */ - public SystemUpdatePolicy setFreezePeriods(List> freezePeriods) { - List newPeriods = freezePeriods.stream().map( - p -> new FreezeInterval(p.first, p.second)).collect(Collectors.toList()); - FreezeInterval.validatePeriods(newPeriods); + public SystemUpdatePolicy setFreezePeriods(List freezePeriods) { + FreezePeriod.validatePeriods(freezePeriods); mFreezePeriods.clear(); - mFreezePeriods.addAll(newPeriods); + mFreezePeriods.addAll(freezePeriods); return this; } @@ -458,12 +464,8 @@ public class SystemUpdatePolicy implements Parcelable { * * @return the list of freeze periods, or an empty list if none was set. */ - public List> getFreezePeriods() { - List> result = new ArrayList<>(mFreezePeriods.size()); - for (FreezeInterval interval : mFreezePeriods) { - result.add(new Pair<>(interval.mStartDay, interval.mEndDay)); - } - return result; + public List getFreezePeriods() { + return Collections.unmodifiableList(mFreezePeriods); } /** @@ -472,7 +474,7 @@ public class SystemUpdatePolicy implements Parcelable { * @hide */ public Pair getCurrentFreezePeriod(LocalDate now) { - for (FreezeInterval interval : mFreezePeriods) { + for (FreezePeriod interval : mFreezePeriods) { if (interval.contains(now)) { return interval.toCurrentOrFutureRealDates(now); } @@ -485,10 +487,10 @@ public class SystemUpdatePolicy implements Parcelable { * is not within a freeze period. */ private long timeUntilNextFreezePeriod(long now) { - List sortedPeriods = FreezeInterval.canonicalizeIntervals(mFreezePeriods); + List sortedPeriods = FreezePeriod.canonicalizePeriods(mFreezePeriods); LocalDate nowDate = millisToDate(now); LocalDate nextFreezeStart = null; - for (FreezeInterval interval : sortedPeriods) { + for (FreezePeriod interval : sortedPeriods) { if (interval.after(nowDate)) { nextFreezeStart = interval.toCurrentOrFutureRealDates(nowDate).first; break; @@ -506,13 +508,13 @@ public class SystemUpdatePolicy implements Parcelable { /** @hide */ public void validateFreezePeriods() { - FreezeInterval.validatePeriods(mFreezePeriods); + FreezePeriod.validatePeriods(mFreezePeriods); } /** @hide */ public void validateAgainstPreviousFreezePeriod(LocalDate prevPeriodStart, LocalDate prevPeriodEnd, LocalDate now) { - FreezeInterval.validateAgainstPreviousFreezePeriod(mFreezePeriods, prevPeriodStart, + FreezePeriod.validateAgainstPreviousFreezePeriod(mFreezePeriods, prevPeriodStart, prevPeriodEnd, now); } @@ -521,10 +523,10 @@ public class SystemUpdatePolicy implements Parcelable { * updates and how long this action is valid for, given the current system update policy. Its * action could be one of the following *
    - *
  • {@code TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and without - * user intervention as soon as they become available. - *
  • {@code TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days - *
  • {@code TYPE_PAUSE} system updates should be postponed indefinitely until further notice + *
  • {@link #TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and + * without user intervention as soon as they become available. + *
  • {@link #TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days + *
  • {@link #TYPE_PAUSE} system updates should be postponed indefinitely until further notice *
* * The effective time measures how long this installation option is valid for from the queried @@ -535,18 +537,38 @@ public class SystemUpdatePolicy implements Parcelable { */ @SystemApi public static class InstallationOption { + /** @hide */ + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_INSTALL_AUTOMATIC, + TYPE_PAUSE, + TYPE_POSTPONE + }) + @Retention(RetentionPolicy.SOURCE) + @interface InstallationOptionType {} + + @InstallationOptionType private final int mType; private long mEffectiveTime; - InstallationOption(int type, long effectiveTime) { + InstallationOption(@InstallationOptionType int type, long effectiveTime) { this.mType = type; this.mEffectiveTime = effectiveTime; } - public int getType() { + /** + * Returns the type of the current installation option, could be one of + * {@link #TYPE_INSTALL_AUTOMATIC}, {@link #TYPE_POSTPONE} and {@link #TYPE_PAUSE}. + * @return type of installation option. + */ + public @InstallationOptionType int getType() { return mType; } + /** + * Returns how long the current installation option in effective for, starting from the time + * of query. + * @return the effective time in milliseconds. + */ public long getEffectiveTime() { return mEffectiveTime; } @@ -667,9 +689,11 @@ public class SystemUpdatePolicy implements Parcelable { int freezeCount = mFreezePeriods.size(); dest.writeInt(freezeCount); for (int i = 0; i < freezeCount; i++) { - FreezeInterval interval = mFreezePeriods.get(i); - dest.writeInt(interval.mStartDay); - dest.writeInt(interval.mEndDay); + FreezePeriod interval = mFreezePeriods.get(i); + dest.writeInt(interval.getStart().getMonthValue()); + dest.writeInt(interval.getStart().getDayOfMonth()); + dest.writeInt(interval.getEnd().getMonthValue()); + dest.writeInt(interval.getEnd().getDayOfMonth()); } } @@ -686,8 +710,9 @@ public class SystemUpdatePolicy implements Parcelable { int freezeCount = source.readInt(); policy.mFreezePeriods.ensureCapacity(freezeCount); for (int i = 0; i < freezeCount; i++) { - policy.mFreezePeriods.add( - new FreezeInterval(source.readInt(), source.readInt())); + MonthDay start = MonthDay.of(source.readInt(), source.readInt()); + MonthDay end = MonthDay.of(source.readInt(), source.readInt()); + policy.mFreezePeriods.add(new FreezePeriod(start, end)); } return policy; } @@ -730,9 +755,9 @@ public class SystemUpdatePolicy implements Parcelable { if (!parser.getName().equals(KEY_FREEZE_TAG)) { continue; } - policy.mFreezePeriods.add(new FreezeInterval( - Integer.parseInt(parser.getAttributeValue(null, KEY_FREEZE_START)), - Integer.parseInt(parser.getAttributeValue(null, KEY_FREEZE_END)))); + policy.mFreezePeriods.add(new FreezePeriod( + MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_START)), + MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_END)))); } return policy; } @@ -751,10 +776,10 @@ public class SystemUpdatePolicy implements Parcelable { out.attribute(null, KEY_INSTALL_WINDOW_START, Integer.toString(mMaintenanceWindowStart)); out.attribute(null, KEY_INSTALL_WINDOW_END, Integer.toString(mMaintenanceWindowEnd)); for (int i = 0; i < mFreezePeriods.size(); i++) { - FreezeInterval interval = mFreezePeriods.get(i); + FreezePeriod interval = mFreezePeriods.get(i); out.startTag(null, KEY_FREEZE_TAG); - out.attribute(null, KEY_FREEZE_START, Integer.toString(interval.mStartDay)); - out.attribute(null, KEY_FREEZE_END, Integer.toString(interval.mEndDay)); + out.attribute(null, KEY_FREEZE_START, interval.getStart().toString()); + out.attribute(null, KEY_FREEZE_END, interval.getEnd().toString()); out.endTag(null, KEY_FREEZE_TAG); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java index f740654e436b3..e4e97012367a2 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java @@ -24,7 +24,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.app.admin.FreezeInterval; +import android.app.admin.FreezePeriod; import android.app.admin.SystemUpdatePolicy; import android.os.Parcel; import android.support.test.runner.AndroidJUnit4; @@ -42,15 +42,15 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; +import java.time.MonthDay; import java.time.ZoneId; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; + /** * Unit tests for {@link android.app.admin.SystemUpdatePolicy}. * Throughout this test, we use "MM-DD" format to denote dates without year. @@ -224,36 +224,36 @@ public final class SystemUpdatePolicyTest { @Test public void testDistanceWithoutLeapYear() { - assertEquals(364, FreezeInterval.distanceWithoutLeapYear( + assertEquals(364, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 12, 31), LocalDate.of(2016, 1, 1))); - assertEquals(365, FreezeInterval.distanceWithoutLeapYear( + assertEquals(365, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2017, 1, 1), LocalDate.of(2016, 1, 1))); - assertEquals(365, FreezeInterval.distanceWithoutLeapYear( + assertEquals(365, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2017, 2, 28), LocalDate.of(2016, 2, 29))); - assertEquals(-365, FreezeInterval.distanceWithoutLeapYear( + assertEquals(-365, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 1, 1), LocalDate.of(2017, 1, 1))); - assertEquals(1, FreezeInterval.distanceWithoutLeapYear( + assertEquals(1, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 29))); - assertEquals(1, FreezeInterval.distanceWithoutLeapYear( + assertEquals(1, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 28))); - assertEquals(0, FreezeInterval.distanceWithoutLeapYear( + assertEquals(0, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 2, 29), LocalDate.of(2016, 2, 28))); - assertEquals(0, FreezeInterval.distanceWithoutLeapYear( + assertEquals(0, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 2, 28), LocalDate.of(2016, 2, 28))); - assertEquals(59, FreezeInterval.distanceWithoutLeapYear( + assertEquals(59, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2016, 3, 1), LocalDate.of(2016, 1, 1))); - assertEquals(59, FreezeInterval.distanceWithoutLeapYear( + assertEquals(59, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2017, 3, 1), LocalDate.of(2017, 1, 1))); - assertEquals(365 * 40, FreezeInterval.distanceWithoutLeapYear( + assertEquals(365 * 40, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1))); - assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear( + assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2019, 3, 1), LocalDate.of(2017, 3, 1))); - assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear( + assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2018, 3, 1), LocalDate.of(2016, 3, 1))); - assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear( + assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear( LocalDate.of(2017, 3, 1), LocalDate.of(2015, 3, 1))); } @@ -386,10 +386,10 @@ public final class SystemUpdatePolicyTest { // Two freeze periods p = SystemUpdatePolicy.createAutomaticInstallPolicy(); - setFreezePeriods(p, "05-01", "06-01", "11-01", "01-29"); - // automatic policy for July, August, September and October + setFreezePeriods(p, "05-01", "06-01", "10-15", "01-10"); + // automatic policy for July, August, September and October until 15th assertInstallationOption( - SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(92), + SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(31 + 30 + 14), millis_2018_08_01, p); } @@ -435,18 +435,18 @@ public final class SystemUpdatePolicyTest { String... dates) throws Exception { SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); setFreezePeriods(p, dates); - p.validateAgainstPreviousFreezePeriod(parseDate(prevStart), parseDate(prevEnd), - parseDate(now)); + p.validateAgainstPreviousFreezePeriod(parseLocalDate(prevStart), + parseLocalDate(prevEnd), parseLocalDate(now)); } // "MM-DD" format for date private void setFreezePeriods(SystemUpdatePolicy policy, String... dates) throws Exception { - List> periods = new ArrayList<>(); - LocalDate lastDate = null; + List periods = new ArrayList<>(); + MonthDay lastDate = null; for (String date : dates) { - LocalDate currentDate = parseDate(date); + MonthDay currentDate = parseMonthDay(date); if (lastDate != null) { - periods.add(new Pair<>(lastDate.getDayOfYear(), currentDate.getDayOfYear())); + periods.add(new FreezePeriod(lastDate, currentDate)); lastDate = null; } else { lastDate = currentDate; @@ -457,7 +457,7 @@ public final class SystemUpdatePolicyTest { } private void testSerialization(SystemUpdatePolicy policy, - List> expectedPeriods) throws Exception { + List expectedPeriods) throws Exception { // Test parcel / unparcel Parcel parcel = Parcel.obtain(); policy.writeToParcel(parcel, 0); @@ -485,36 +485,27 @@ public final class SystemUpdatePolicyTest { } private void checkFreezePeriods(SystemUpdatePolicy policy, - List> expectedPeriods) { + List expectedPeriods) { int i = 0; - for (Pair period : policy.getFreezePeriods()) { - assertEquals(expectedPeriods.get(i).first, period.first); - assertEquals(expectedPeriods.get(i).second, period.second); + for (FreezePeriod period : policy.getFreezePeriods()) { + assertEquals(expectedPeriods.get(i).getStart(), period.getStart()); + assertEquals(expectedPeriods.get(i).getEnd(), period.getEnd()); i++; } } - private LocalDate parseDate(String date) { - // Use leap year when parsing date string to handle "02-29", but force round down - // to Feb 28th by overriding the year to non-leap year. - final int year; - boolean monthDateOnly = false; - if (date.length() == 5) { - year = 2000; - monthDateOnly = true; - } else { - year = Integer.parseInt(date.substring(0, 4)); - date = date.substring(5); - } - LocalDate result = LocalDate.of(year, Integer.parseInt(date.substring(0, 2)), + // MonthDay is of format MM-dd + private MonthDay parseMonthDay(String date) { + return MonthDay.of(Integer.parseInt(date.substring(0, 2)), Integer.parseInt(date.substring(3, 5))); - if (monthDateOnly) { - return result.withYear(2001); - } else { - return result; - } } + // LocalDat is of format YYYY-MM-dd + private LocalDate parseLocalDate(String date) { + return parseMonthDay(date.substring(5)).atYear(Integer.parseInt(date.substring(0, 4))); + } + + private long toMillis(int year, int month, int day) { return LocalDateTime.of(year, month, day, 0, 0, 0).atZone(ZoneId.systemDefault()) .toInstant().toEpochMilli();