From 7f1820cb857a69547aa49c77c5c26176d6e5c8cc Mon Sep 17 00:00:00 2001 From: Veena Arvind Date: Wed, 1 Nov 2023 01:13:53 +0000 Subject: Check that elasped realtime > frequency of reboot. This prevents devices that trigger the alarm by modifying the system clock (like tests) from rebooting. Also fix bug with checking reboot window + tests. Test: atest ConfigInfrastructureServiceUnitTests[com.google.android.configinfrastructure.apex] Bug: 297502146 Change-Id: I5314bdd5b0236eb5a6e5c2372f0a0ddd56c7f4f8 --- .../deviceconfig/UnattendedRebootManager.java | 21 ++++++++++- .../UnattendedRebootManagerInjector.java | 2 ++ .../deviceconfig/UnattendedRebootManagerTest.java | 42 ++++++++++++++++++++-- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/service/java/com/android/server/deviceconfig/UnattendedRebootManager.java b/service/java/com/android/server/deviceconfig/UnattendedRebootManager.java index e6ccf9f..8429d0a 100644 --- a/service/java/com/android/server/deviceconfig/UnattendedRebootManager.java +++ b/service/java/com/android/server/deviceconfig/UnattendedRebootManager.java @@ -16,12 +16,14 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.PowerManager; import android.os.RecoverySystem; +import android.os.SystemClock; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.util.concurrent.TimeUnit; /** * Reboot scheduler for applying aconfig flags. @@ -68,6 +70,11 @@ final class UnattendedRebootManager { return ZoneId.systemDefault(); } + @Override + public long elapsedRealtime() { + return SystemClock.elapsedRealtime(); + } + public int getRebootStartTime() { return DEFAULT_REBOOT_WINDOW_START_TIME_HOUR; } @@ -201,6 +208,17 @@ final class UnattendedRebootManager { void tryRebootOrSchedule() { Log.v(TAG, "Attempting unattended reboot"); + // Has enough time passed since reboot? + if (TimeUnit.MILLISECONDS.toDays(mInjector.elapsedRealtime()) + < mInjector.getRebootFrequency()) { + Log.v( + TAG, + "Device has already been rebooted in that last" + + mInjector.getRebootFrequency() + + " days."); + scheduleReboot(); + return; + } // Is RoR is supported? if (!isDeviceSecure(mContext)) { Log.v(TAG, "Device is not secure. Proceed with regular reboot"); @@ -228,7 +246,7 @@ final class UnattendedRebootManager { .toLocalDateTime() .getHour(); if (currentHour < mInjector.getRebootStartTime() - && currentHour >= mInjector.getRebootEndTime()) { + || currentHour >= mInjector.getRebootEndTime()) { Log.v(TAG, "Reboot requested outside of reboot window, reschedule."); prepareUnattendedReboot(); scheduleReboot(); @@ -236,6 +254,7 @@ final class UnattendedRebootManager { } // Proceed with RoR. + Log.v(TAG, "Rebooting device..."); try { int success = mInjector.rebootAndApply(mContext, REBOOT_REASON, /* slotSwitch= */ false); if (success != 0) { diff --git a/service/java/com/android/server/deviceconfig/UnattendedRebootManagerInjector.java b/service/java/com/android/server/deviceconfig/UnattendedRebootManagerInjector.java index e1e0909..5ca3e1e 100644 --- a/service/java/com/android/server/deviceconfig/UnattendedRebootManagerInjector.java +++ b/service/java/com/android/server/deviceconfig/UnattendedRebootManagerInjector.java @@ -20,6 +20,8 @@ interface UnattendedRebootManagerInjector { ZoneId zoneId(); + long elapsedRealtime(); + /** Reboot time injectors. */ int getRebootStartTime(); diff --git a/service/javatests/src/com/android/server/deviceconfig/UnattendedRebootManagerTest.java b/service/javatests/src/com/android/server/deviceconfig/UnattendedRebootManagerTest.java index 20494e5..7d822b6 100644 --- a/service/javatests/src/com/android/server/deviceconfig/UnattendedRebootManagerTest.java +++ b/service/javatests/src/com/android/server/deviceconfig/UnattendedRebootManagerTest.java @@ -43,7 +43,10 @@ public class UnattendedRebootManagerTest { private static final long CURRENT_TIME = 1696452549304L; // 2023-10-04T13:49:09.304 private static final long REBOOT_TIME = 1696496400000L; // 2023-10-05T02:00:00 private static final long RESCHEDULED_REBOOT_TIME = 1696582800000L; // 2023-10-06T02:00:00 - private static final long OUTSIDE_WINDOW_REBOOT_TIME = 1696583400000L; // 2023-10-06T03:10:00 + private static final long OUTSIDE_WINDOW_REBOOT_TIME = 1696587000000L; // 2023-10-06T03:10:00 + private static final long RESCHEDULED_OUTSIDE_WINDOW_REBOOT_TIME = + 1696669200000L; // 2023-10-07T02:00:00 + private static final long ELAPSED_REALTIME_1_DAY = 86400000L; private Context mContext; private KeyguardManager mKeyguardManager; @@ -83,6 +86,8 @@ public class UnattendedRebootManagerTest { }, new IntentFilter(ACTION_TRIGGER_REBOOT), Context.RECEIVER_EXPORTED); + + mFakeInjector.setElapsedRealtime(ELAPSED_REALTIME_1_DAY); } @Test @@ -175,6 +180,26 @@ public class UnattendedRebootManagerTest { assertTrue(mFakeInjector.isRequestedNetwork()); } + @Test + public void scheduleReboot_elapsedRealtimeLessThanFrequency() { + Log.i(TAG, "scheduleReboot_elapsedRealtimeLessThanFrequency"); + when(mKeyguardManager.isDeviceSecure()).thenReturn(true); + when(mConnectivityManager.getNetworkCapabilities(any())) + .thenReturn( + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .build()); + mFakeInjector.setElapsedRealtime(82800000); // 23 hours + + mRebootManager.prepareUnattendedReboot(); + mRebootManager.scheduleReboot(); + + assertFalse(mFakeInjector.isRebootAndApplied()); + assertFalse(mFakeInjector.isRegularRebooted()); + assertThat(mFakeInjector.getActualRebootTime()).isEqualTo(RESCHEDULED_REBOOT_TIME); + } + @Test public void tryRebootOrSchedule_outsideRebootWindow() { Log.i(TAG, "scheduleReboot_internetOutsideRebootWindow"); @@ -192,8 +217,10 @@ public class UnattendedRebootManagerTest { // reboot window. mRebootManager.tryRebootOrSchedule(); - assertFalse(mFakeInjector.isRebootAndApplied()); + assertTrue(mFakeInjector.isRebootAndApplied()); assertFalse(mFakeInjector.isRegularRebooted()); + assertThat(mFakeInjector.getActualRebootTime()) + .isEqualTo(RESCHEDULED_OUTSIDE_WINDOW_REBOOT_TIME); } static class FakeInjector implements UnattendedRebootManagerInjector { @@ -207,6 +234,8 @@ public class UnattendedRebootManagerTest { private long nowMillis; + private long elapsedRealtimeMillis; + FakeInjector() { nowMillis = CURRENT_TIME; } @@ -291,6 +320,15 @@ public class UnattendedRebootManagerTest { return ZoneId.of("America/Los_Angeles"); } + @Override + public long elapsedRealtime() { + return elapsedRealtimeMillis; + } + + public void setElapsedRealtime(long elapsedRealtimeMillis) { + this.elapsedRealtimeMillis = elapsedRealtimeMillis; + } + @Override public void regularReboot(Context context) { regularRebooted = true; -- cgit v1.2.3