Loading api/system-current.txt +13 −0 Original line number Diff line number Diff line Loading @@ -437,6 +437,19 @@ package android.app.admin { field public static final int STATE_USER_UNMANAGED = 0; // 0x0 } public 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); field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy> CREATOR; field public static final int TYPE_PAUSE = 4; // 0x4 } public static class SystemUpdatePolicy.InstallationOption { method public long getEffectiveTime(); method public int getType(); } } package android.app.backup { Loading core/java/android/app/admin/FreezeInterval.java +5 −1 Original line number Diff line number Diff line Loading @@ -84,6 +84,10 @@ public class FreezeInterval { } } boolean after(LocalDate localDate) { return mStartDay > dayOfYearDisregardLeapYear(localDate); } /** * Instantiate the current interval to real calendar dates, given a calendar date * {@code now}. If the interval contains now, the returned calendar dates should be the Loading Loading @@ -161,7 +165,7 @@ public class FreezeInterval { * 3. At most one wrapped Interval remains, and it will be at the end of the list * @hide */ private static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) { protected static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) { boolean[] taken = new boolean[DAYS_IN_YEAR]; // First convert the intervals into flat array for (FreezeInterval interval : intervals) { Loading core/java/android/app/admin/SystemUpdatePolicy.java +175 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.TEXT; import android.annotation.IntDef; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; Loading @@ -33,9 +34,15 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** Loading Loading @@ -103,6 +110,19 @@ public class SystemUpdatePolicy implements Parcelable { */ public static final int TYPE_POSTPONE = 3; /** * Incoming system updates (including security updates) should be blocked. This flag is not * exposed to third-party apps (and any attempt to set it will raise exceptions). This is used * to represent the current installation option type to the privileged system update clients, * for example to indicate OTA freeze is currently in place or when system is outside a daily * maintenance window. * * @see InstallationOption * @hide */ @SystemApi public static final int TYPE_PAUSE = 4; private static final String KEY_POLICY_TYPE = "policy_type"; private static final String KEY_INSTALL_WINDOW_START = "install_window_start"; private static final String KEY_INSTALL_WINDOW_END = "install_window_end"; Loading Loading @@ -460,6 +480,30 @@ public class SystemUpdatePolicy implements Parcelable { return null; } /** * Returns time (in milliseconds) until the start of the next freeze period, assuming now * is not within a freeze period. */ private long timeUntilNextFreezePeriod(long now) { List<FreezeInterval> sortedPeriods = FreezeInterval.canonicalizeIntervals(mFreezePeriods); LocalDate nowDate = millisToDate(now); LocalDate nextFreezeStart = null; for (FreezeInterval interval : sortedPeriods) { if (interval.after(nowDate)) { nextFreezeStart = interval.toCurrentOrFutureRealDates(nowDate).first; break; } else if (interval.contains(nowDate)) { throw new IllegalArgumentException("Given date is inside a freeze period"); } } if (nextFreezeStart == null) { // If no interval is after now, then it must be the one that starts at the beginning // of next year nextFreezeStart = sortedPeriods.get(0).toCurrentOrFutureRealDates(nowDate).first; } return dateToMillis(nextFreezeStart) - now; } /** @hide */ public void validateFreezePeriods() { FreezeInterval.validatePeriods(mFreezePeriods); Loading @@ -472,6 +516,134 @@ public class SystemUpdatePolicy implements Parcelable { prevPeriodEnd, now); } /** * An installation option represents how system update clients should act on incoming system * updates and how long this action is valid for, given the current system update policy. Its * action could be one of the following * <ul> * <li> {@code TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and without * user intervention as soon as they become available. * <li> {@code TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days * <li> {@code TYPE_PAUSE} system updates should be postponed indefinitely until further notice * </ul> * * The effective time measures how long this installation option is valid for from the queried * time, in milliseconds. * * This is an internal API for system update clients. * @hide */ @SystemApi public static class InstallationOption { private final int mType; private long mEffectiveTime; InstallationOption(int type, long effectiveTime) { this.mType = type; this.mEffectiveTime = effectiveTime; } public int getType() { return mType; } public long getEffectiveTime() { return mEffectiveTime; } /** @hide */ protected void limitEffectiveTime(long otherTime) { mEffectiveTime = Long.min(mEffectiveTime, otherTime); } } /** * Returns the installation option at the specified time, under the current * {@code SystemUpdatePolicy} object. This is a convenience method for system update clients * so they can instantiate this policy at any given time and find out what to do with incoming * system updates, without the need of examining the overall policy structure. * * Normally the system update clients will query the current installation option by calling this * method with the current timestamp, and act on the returned option until its effective time * lapses. It can then query the latest option using a new timestamp. It should also listen * for {@code DevicePolicyManager#ACTION_SYSTEM_UPDATE_POLICY_CHANGED} broadcast, in case the * whole policy is updated. * * @param when At what time the intallation option is being queried, specified in number of milliseonds since the epoch. * @see InstallationOption * @hide */ @SystemApi public InstallationOption getInstallationOptionAt(long when) { LocalDate whenDate = millisToDate(when); Pair<LocalDate, LocalDate> current = getCurrentFreezePeriod(whenDate); if (current != null) { return new InstallationOption(TYPE_PAUSE, dateToMillis(roundUpLeapDay(current.second).plusDays(1)) - when); } // We are not within a freeze period, query the underlying policy. // But also consider the start of the next freeze period, which might // reduce the effective time of the current installation option InstallationOption option = getInstallationOptionRegardlessFreezeAt(when); if (mFreezePeriods.size() > 0) { option.limitEffectiveTime(timeUntilNextFreezePeriod(when)); } return option; } private InstallationOption getInstallationOptionRegardlessFreezeAt(long when) { if (mPolicyType == TYPE_INSTALL_AUTOMATIC || mPolicyType == TYPE_POSTPONE) { return new InstallationOption(mPolicyType, Long.MAX_VALUE); } else if (mPolicyType == TYPE_INSTALL_WINDOWED) { Calendar query = Calendar.getInstance(); query.setTimeInMillis(when); // Calculate the number of milliseconds since midnight of the time specified by when long whenMillis = TimeUnit.HOURS.toMillis(query.get(Calendar.HOUR_OF_DAY)) + TimeUnit.MINUTES.toMillis(query.get(Calendar.MINUTE)) + TimeUnit.SECONDS.toMillis(query.get(Calendar.SECOND)) + query.get(Calendar.MILLISECOND); long windowStartMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowStart); long windowEndMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowEnd); final long dayInMillis = TimeUnit.DAYS.toMillis(1); if ((windowStartMillis <= whenMillis && whenMillis <= windowEndMillis) || ((windowStartMillis > windowEndMillis) && (windowStartMillis <= whenMillis || whenMillis <= windowEndMillis))) { return new InstallationOption(TYPE_INSTALL_AUTOMATIC, (windowEndMillis - whenMillis + dayInMillis) % dayInMillis); } else { return new InstallationOption(TYPE_PAUSE, (windowStartMillis - whenMillis + dayInMillis) % dayInMillis); } } else { throw new RuntimeException("Unknown policy type"); } } private static LocalDate roundUpLeapDay(LocalDate date) { if (date.isLeapYear() && date.getMonthValue() == 2 && date.getDayOfMonth() == 28) { return date.plusDays(1); } else { return date; } } /** Convert a timestamp since epoch to a LocalDate using default timezone, truncating * the hour/min/seconds part. */ private static LocalDate millisToDate(long when) { return Instant.ofEpochMilli(when).atZone(ZoneId.systemDefault()).toLocalDate(); } /** * Returns the timestamp since epoch of a LocalDate, assuming the time is 00:00:00. */ private static long dateToMillis(LocalDate when) { return LocalDateTime.of(when, LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant() .toEpochMilli(); } @Override public String toString() { return String.format("SystemUpdatePolicy (type: %d, windowStart: %d, windowEnd: %d, " Loading @@ -480,11 +652,13 @@ public class SystemUpdatePolicy implements Parcelable { mFreezePeriods.stream().map(n -> n.toString()).collect(Collectors.joining(","))); } @SystemApi @Override public int describeContents() { return 0; } @SystemApi @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mPolicyType); Loading @@ -499,6 +673,7 @@ public class SystemUpdatePolicy implements Parcelable { } } @SystemApi public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR = new Parcelable.Creator<SystemUpdatePolicy>() { Loading services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java +142 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; /** * Unit tests for {@link android.app.admin.SystemUpdatePolicy}. Loading Loading @@ -253,6 +254,147 @@ public final class SystemUpdatePolicyTest { } @Test public void testInstallationOptionWithoutFreeze() { // Also duplicated at com.google.android.gts.deviceowner.SystemUpdatePolicyTest final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800); SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy(); assertInstallationOption(SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, Long.MAX_VALUE, millis_2018_01_01, p); p = SystemUpdatePolicy.createPostponeInstallPolicy(); assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, Long.MAX_VALUE, millis_2018_01_01, p); p = SystemUpdatePolicy.createWindowedInstallPolicy(120, 180); // 2:00 - 3:00 // 00:00 is two hours before the next window assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(2), millis_2018_01_01, p); // 02:00 is within the current maintenance window, and one hour until the window ends assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), millis_2018_01_01 + TimeUnit.HOURS.toMillis(2), p); // 04:00 is 22 hours from the window next day assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22), millis_2018_01_01 + TimeUnit.HOURS.toMillis(4), p); p = SystemUpdatePolicy.createWindowedInstallPolicy(22 * 60, 2 * 60); // 22:00 - 2:00 // 21:00 is one hour from the next window assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(1), millis_2018_01_01 + TimeUnit.HOURS.toMillis(21), p); // 00:00 is two hours from the end of current window assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(2), millis_2018_01_01, p); // 03:00 is 22 hours from the window today assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19), millis_2018_01_01 + TimeUnit.HOURS.toMillis(3), p); } @Test public void testInstallationOptionWithFreeze() throws Exception { final long millis_2016_02_29 = TimeUnit.SECONDS.toMillis(1456704000); final long millis_2017_01_31 = TimeUnit.SECONDS.toMillis(1485820800); final long millis_2017_02_28 = TimeUnit.SECONDS.toMillis(1488240000); final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800); final long millis_2018_08_01 = TimeUnit.SECONDS.toMillis(1533081600); SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "01-01", "01-31"); // Inside a freeze period assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(31), millis_2018_01_01, p); // Device is outside freeze between 2/28 to 12/31 inclusive assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(307), millis_2017_02_28, p); // Freeze period contains leap day Feb 29 p = SystemUpdatePolicy.createPostponeInstallPolicy(); setFreezePeriods(p, "02-01", "03-15"); // Freezed until 3/31, note 2016 is a leap year assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2016_02_29, p); // Freezed until 3/31, note 2017 is not a leap year assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2017_02_28, p); // Next freeze is 2018/2/1 assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, TimeUnit.DAYS.toMillis(31), millis_2018_01_01, p); // Freeze period start on or right after leap day p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "03-01", "03-31"); assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1), millis_2017_02_28, p); setFreezePeriods(p, "02-28", "03-15"); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2017_02_28, p); // Freeze period end on or right after leap day p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "02-01", "02-28"); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1), millis_2017_02_28, p); p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "02-01", "03-01"); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2), millis_2017_02_28, p); // Freeze period with maintenance window p = SystemUpdatePolicy.createWindowedInstallPolicy(23 * 60, 1 * 60); // 23:00 - 1:00 setFreezePeriods(p, "02-01", "02-28"); // 00:00 is within the current window, outside freeze period assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), millis_2018_01_01, p); // Last day of feeze period, which ends in 22 hours assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22), millis_2017_02_28 + TimeUnit.HOURS.toMillis(2), p); // Last day before the next freeze, and within window assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), millis_2017_01_31, p); // Last day before the next freeze, and there is still a partial maintenance window before // the freeze. assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19), millis_2017_01_31 + TimeUnit.HOURS.toMillis(4), p); // Two freeze periods p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "05-01", "06-01", "12-01", "01-31"); // automatic policy for August, September, November and December assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(122), millis_2018_08_01, p); } private void assertInstallationOption(int expectedType, long expectedTime, long now, SystemUpdatePolicy p) { assertEquals(expectedType, p.getInstallationOptionAt(now).getType()); assertEquals(expectedTime, p.getInstallationOptionAt(now).getEffectiveTime()); } private void testFreezePeriodsSucceeds(String...dates) throws Exception { SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); setFreezePeriods(p, dates); Loading Loading
api/system-current.txt +13 −0 Original line number Diff line number Diff line Loading @@ -437,6 +437,19 @@ package android.app.admin { field public static final int STATE_USER_UNMANAGED = 0; // 0x0 } public 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); field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy> CREATOR; field public static final int TYPE_PAUSE = 4; // 0x4 } public static class SystemUpdatePolicy.InstallationOption { method public long getEffectiveTime(); method public int getType(); } } package android.app.backup { Loading
core/java/android/app/admin/FreezeInterval.java +5 −1 Original line number Diff line number Diff line Loading @@ -84,6 +84,10 @@ public class FreezeInterval { } } boolean after(LocalDate localDate) { return mStartDay > dayOfYearDisregardLeapYear(localDate); } /** * Instantiate the current interval to real calendar dates, given a calendar date * {@code now}. If the interval contains now, the returned calendar dates should be the Loading Loading @@ -161,7 +165,7 @@ public class FreezeInterval { * 3. At most one wrapped Interval remains, and it will be at the end of the list * @hide */ private static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) { protected static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) { boolean[] taken = new boolean[DAYS_IN_YEAR]; // First convert the intervals into flat array for (FreezeInterval interval : intervals) { Loading
core/java/android/app/admin/SystemUpdatePolicy.java +175 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.TEXT; import android.annotation.IntDef; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; Loading @@ -33,9 +34,15 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** Loading Loading @@ -103,6 +110,19 @@ public class SystemUpdatePolicy implements Parcelable { */ public static final int TYPE_POSTPONE = 3; /** * Incoming system updates (including security updates) should be blocked. This flag is not * exposed to third-party apps (and any attempt to set it will raise exceptions). This is used * to represent the current installation option type to the privileged system update clients, * for example to indicate OTA freeze is currently in place or when system is outside a daily * maintenance window. * * @see InstallationOption * @hide */ @SystemApi public static final int TYPE_PAUSE = 4; private static final String KEY_POLICY_TYPE = "policy_type"; private static final String KEY_INSTALL_WINDOW_START = "install_window_start"; private static final String KEY_INSTALL_WINDOW_END = "install_window_end"; Loading Loading @@ -460,6 +480,30 @@ public class SystemUpdatePolicy implements Parcelable { return null; } /** * Returns time (in milliseconds) until the start of the next freeze period, assuming now * is not within a freeze period. */ private long timeUntilNextFreezePeriod(long now) { List<FreezeInterval> sortedPeriods = FreezeInterval.canonicalizeIntervals(mFreezePeriods); LocalDate nowDate = millisToDate(now); LocalDate nextFreezeStart = null; for (FreezeInterval interval : sortedPeriods) { if (interval.after(nowDate)) { nextFreezeStart = interval.toCurrentOrFutureRealDates(nowDate).first; break; } else if (interval.contains(nowDate)) { throw new IllegalArgumentException("Given date is inside a freeze period"); } } if (nextFreezeStart == null) { // If no interval is after now, then it must be the one that starts at the beginning // of next year nextFreezeStart = sortedPeriods.get(0).toCurrentOrFutureRealDates(nowDate).first; } return dateToMillis(nextFreezeStart) - now; } /** @hide */ public void validateFreezePeriods() { FreezeInterval.validatePeriods(mFreezePeriods); Loading @@ -472,6 +516,134 @@ public class SystemUpdatePolicy implements Parcelable { prevPeriodEnd, now); } /** * An installation option represents how system update clients should act on incoming system * updates and how long this action is valid for, given the current system update policy. Its * action could be one of the following * <ul> * <li> {@code TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and without * user intervention as soon as they become available. * <li> {@code TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days * <li> {@code TYPE_PAUSE} system updates should be postponed indefinitely until further notice * </ul> * * The effective time measures how long this installation option is valid for from the queried * time, in milliseconds. * * This is an internal API for system update clients. * @hide */ @SystemApi public static class InstallationOption { private final int mType; private long mEffectiveTime; InstallationOption(int type, long effectiveTime) { this.mType = type; this.mEffectiveTime = effectiveTime; } public int getType() { return mType; } public long getEffectiveTime() { return mEffectiveTime; } /** @hide */ protected void limitEffectiveTime(long otherTime) { mEffectiveTime = Long.min(mEffectiveTime, otherTime); } } /** * Returns the installation option at the specified time, under the current * {@code SystemUpdatePolicy} object. This is a convenience method for system update clients * so they can instantiate this policy at any given time and find out what to do with incoming * system updates, without the need of examining the overall policy structure. * * Normally the system update clients will query the current installation option by calling this * method with the current timestamp, and act on the returned option until its effective time * lapses. It can then query the latest option using a new timestamp. It should also listen * for {@code DevicePolicyManager#ACTION_SYSTEM_UPDATE_POLICY_CHANGED} broadcast, in case the * whole policy is updated. * * @param when At what time the intallation option is being queried, specified in number of milliseonds since the epoch. * @see InstallationOption * @hide */ @SystemApi public InstallationOption getInstallationOptionAt(long when) { LocalDate whenDate = millisToDate(when); Pair<LocalDate, LocalDate> current = getCurrentFreezePeriod(whenDate); if (current != null) { return new InstallationOption(TYPE_PAUSE, dateToMillis(roundUpLeapDay(current.second).plusDays(1)) - when); } // We are not within a freeze period, query the underlying policy. // But also consider the start of the next freeze period, which might // reduce the effective time of the current installation option InstallationOption option = getInstallationOptionRegardlessFreezeAt(when); if (mFreezePeriods.size() > 0) { option.limitEffectiveTime(timeUntilNextFreezePeriod(when)); } return option; } private InstallationOption getInstallationOptionRegardlessFreezeAt(long when) { if (mPolicyType == TYPE_INSTALL_AUTOMATIC || mPolicyType == TYPE_POSTPONE) { return new InstallationOption(mPolicyType, Long.MAX_VALUE); } else if (mPolicyType == TYPE_INSTALL_WINDOWED) { Calendar query = Calendar.getInstance(); query.setTimeInMillis(when); // Calculate the number of milliseconds since midnight of the time specified by when long whenMillis = TimeUnit.HOURS.toMillis(query.get(Calendar.HOUR_OF_DAY)) + TimeUnit.MINUTES.toMillis(query.get(Calendar.MINUTE)) + TimeUnit.SECONDS.toMillis(query.get(Calendar.SECOND)) + query.get(Calendar.MILLISECOND); long windowStartMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowStart); long windowEndMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowEnd); final long dayInMillis = TimeUnit.DAYS.toMillis(1); if ((windowStartMillis <= whenMillis && whenMillis <= windowEndMillis) || ((windowStartMillis > windowEndMillis) && (windowStartMillis <= whenMillis || whenMillis <= windowEndMillis))) { return new InstallationOption(TYPE_INSTALL_AUTOMATIC, (windowEndMillis - whenMillis + dayInMillis) % dayInMillis); } else { return new InstallationOption(TYPE_PAUSE, (windowStartMillis - whenMillis + dayInMillis) % dayInMillis); } } else { throw new RuntimeException("Unknown policy type"); } } private static LocalDate roundUpLeapDay(LocalDate date) { if (date.isLeapYear() && date.getMonthValue() == 2 && date.getDayOfMonth() == 28) { return date.plusDays(1); } else { return date; } } /** Convert a timestamp since epoch to a LocalDate using default timezone, truncating * the hour/min/seconds part. */ private static LocalDate millisToDate(long when) { return Instant.ofEpochMilli(when).atZone(ZoneId.systemDefault()).toLocalDate(); } /** * Returns the timestamp since epoch of a LocalDate, assuming the time is 00:00:00. */ private static long dateToMillis(LocalDate when) { return LocalDateTime.of(when, LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant() .toEpochMilli(); } @Override public String toString() { return String.format("SystemUpdatePolicy (type: %d, windowStart: %d, windowEnd: %d, " Loading @@ -480,11 +652,13 @@ public class SystemUpdatePolicy implements Parcelable { mFreezePeriods.stream().map(n -> n.toString()).collect(Collectors.joining(","))); } @SystemApi @Override public int describeContents() { return 0; } @SystemApi @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mPolicyType); Loading @@ -499,6 +673,7 @@ public class SystemUpdatePolicy implements Parcelable { } } @SystemApi public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR = new Parcelable.Creator<SystemUpdatePolicy>() { Loading
services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java +142 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; /** * Unit tests for {@link android.app.admin.SystemUpdatePolicy}. Loading Loading @@ -253,6 +254,147 @@ public final class SystemUpdatePolicyTest { } @Test public void testInstallationOptionWithoutFreeze() { // Also duplicated at com.google.android.gts.deviceowner.SystemUpdatePolicyTest final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800); SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy(); assertInstallationOption(SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, Long.MAX_VALUE, millis_2018_01_01, p); p = SystemUpdatePolicy.createPostponeInstallPolicy(); assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, Long.MAX_VALUE, millis_2018_01_01, p); p = SystemUpdatePolicy.createWindowedInstallPolicy(120, 180); // 2:00 - 3:00 // 00:00 is two hours before the next window assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(2), millis_2018_01_01, p); // 02:00 is within the current maintenance window, and one hour until the window ends assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), millis_2018_01_01 + TimeUnit.HOURS.toMillis(2), p); // 04:00 is 22 hours from the window next day assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22), millis_2018_01_01 + TimeUnit.HOURS.toMillis(4), p); p = SystemUpdatePolicy.createWindowedInstallPolicy(22 * 60, 2 * 60); // 22:00 - 2:00 // 21:00 is one hour from the next window assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(1), millis_2018_01_01 + TimeUnit.HOURS.toMillis(21), p); // 00:00 is two hours from the end of current window assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(2), millis_2018_01_01, p); // 03:00 is 22 hours from the window today assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19), millis_2018_01_01 + TimeUnit.HOURS.toMillis(3), p); } @Test public void testInstallationOptionWithFreeze() throws Exception { final long millis_2016_02_29 = TimeUnit.SECONDS.toMillis(1456704000); final long millis_2017_01_31 = TimeUnit.SECONDS.toMillis(1485820800); final long millis_2017_02_28 = TimeUnit.SECONDS.toMillis(1488240000); final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800); final long millis_2018_08_01 = TimeUnit.SECONDS.toMillis(1533081600); SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "01-01", "01-31"); // Inside a freeze period assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(31), millis_2018_01_01, p); // Device is outside freeze between 2/28 to 12/31 inclusive assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(307), millis_2017_02_28, p); // Freeze period contains leap day Feb 29 p = SystemUpdatePolicy.createPostponeInstallPolicy(); setFreezePeriods(p, "02-01", "03-15"); // Freezed until 3/31, note 2016 is a leap year assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2016_02_29, p); // Freezed until 3/31, note 2017 is not a leap year assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2017_02_28, p); // Next freeze is 2018/2/1 assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, TimeUnit.DAYS.toMillis(31), millis_2018_01_01, p); // Freeze period start on or right after leap day p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "03-01", "03-31"); assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1), millis_2017_02_28, p); setFreezePeriods(p, "02-28", "03-15"); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16), millis_2017_02_28, p); // Freeze period end on or right after leap day p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "02-01", "02-28"); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1), millis_2017_02_28, p); p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "02-01", "03-01"); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2), millis_2016_02_29, p); assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2), millis_2017_02_28, p); // Freeze period with maintenance window p = SystemUpdatePolicy.createWindowedInstallPolicy(23 * 60, 1 * 60); // 23:00 - 1:00 setFreezePeriods(p, "02-01", "02-28"); // 00:00 is within the current window, outside freeze period assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), millis_2018_01_01, p); // Last day of feeze period, which ends in 22 hours assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22), millis_2017_02_28 + TimeUnit.HOURS.toMillis(2), p); // Last day before the next freeze, and within window assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1), millis_2017_01_31, p); // Last day before the next freeze, and there is still a partial maintenance window before // the freeze. assertInstallationOption( SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19), millis_2017_01_31 + TimeUnit.HOURS.toMillis(4), p); // Two freeze periods p = SystemUpdatePolicy.createAutomaticInstallPolicy(); setFreezePeriods(p, "05-01", "06-01", "12-01", "01-31"); // automatic policy for August, September, November and December assertInstallationOption( SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(122), millis_2018_08_01, p); } private void assertInstallationOption(int expectedType, long expectedTime, long now, SystemUpdatePolicy p) { assertEquals(expectedType, p.getInstallationOptionAt(now).getType()); assertEquals(expectedTime, p.getInstallationOptionAt(now).getEffectiveTime()); } private void testFreezePeriodsSucceeds(String...dates) throws Exception { SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy(); setFreezePeriods(p, dates); Loading