CHROMIUM: Allow larger continuity time jumps

Clock continuity is checked by maintaining a delta between
what is read from CLOCK_REALTIME and CLOCK_MONOTONIC_RAW.
This is very effective for a continuously powered machine.
For machines that are suspended and resumed, time jumps
occur frequently and will be the length of time that the
system was suspended.

The recently added CLOCK_BOOTTIME is meant to help applications
keep track of the time since boot, inclusive of suspend, but the
calculations that go into CLOCK_BOOTTIME may be subject to being
corrupted by RTC misbehavior, such as corruption upon return from
resume.

To limit the impact of time jumps from clock corruption upon resumption
without requiring a re-sync after every suspend, we set a more
reasonable upper limit.

To avoid expected time jumps from triggering simultaneous queries in
homogeneous environments, a jitter is introduced whenever the time
is being reset because of a desynchronization during an event.
(The jitter should match the maximum time of a check_continuity event.)

BUG=chromium:314679
TEST=doesn't immediately re-sync when returning from suspend (x86-alex)
     after time sync, date -s "5 hours", suspend, resume, see it note the de-sync.

Change-Id: I2d04fd46a63c420c4cd9a1e9ab5f09f148a1b027
Reviewed-on: https://chromium-review.googlesource.com/175431
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Commit-Queue: Will Drewry <wad@chromium.org>
Tested-by: Will Drewry <wad@chromium.org>
diff --git a/src/events/check_continuity.c b/src/events/check_continuity.c
index a19a278..9340fa1 100644
--- a/src/events/check_continuity.c
+++ b/src/events/check_continuity.c
@@ -21,9 +21,16 @@
  * Old delta is in |delta|. |delta| is overwritten
  * if >= 0 is returned.
  *
- * Desynchronization between MONOTONIC_RAW and REALTIME
- * will occur any time a system suspends and the real-time
- * clock is not maintained.
+ * This event catches any sort of real-time clock jump.  A jump is observed
+ * when settimeofday() or adjtimex() is called, or if the RTC misbehaves on
+ * return from suspend.  If a jump is detected between a cycle-oriented clock
+ * (MONOTONIC_RAW) and a potentially RTC managed clock (REALTIME), then a
+ * network resynchronization will be required.  To avoid requiring this on
+ * every resume-from-suspend, a larger delta represents the largest time jump
+ * allowed before needing a resync.
+ *
+ * Note, CLOCK_BOOTTIME does not resolve this on platforms without a persistent
+ * clock because the RTC still determines the time considered "suspend time".
  */
 int
 check_continuity (time_t *delta)
@@ -37,7 +44,9 @@
   new_delta = real.tv_sec - monotonic.tv_sec;
   if (*delta)
     {
-      if (new_delta < *delta - 10 || new_delta > *delta + 10)
+      /* The allowed delta matches the interval for now. */
+      static const time_t kDelta = CONTINUITY_INTERVAL;
+      if (new_delta < *delta - kDelta || new_delta > *delta + kDelta)
         {
           *delta = new_delta;
           return  1;
diff --git a/src/events/kickoff_time_sync.c b/src/events/kickoff_time_sync.c
index d56a967..228a37f 100644
--- a/src/events/kickoff_time_sync.c
+++ b/src/events/kickoff_time_sync.c
@@ -93,14 +93,17 @@
   struct state *state = arg;
   debug ("[event:%s] fired", __func__);
   time_t delta = state->clock_delta;
+  int jitter = 0;
   if (check_continuity (&delta) > 0)
     {
       info ("[event:%s] clock delta desync detected (%d != %d)", __func__,
             state->clock_delta, delta);
+      /* Add jitter iff we had network synchronization once before. */
+      if (state->clock_delta)
+        jitter = add_jitter (30, 30); /* TODO(wad) make configurable */
       /* Forget the old delta until we have time again. */
       state->clock_delta = 0;
       invalidate_time (state);
-      /* Don't bother saving here */
     }
   if (state->last_sync_type == SYNC_TYPE_NET)
     {
@@ -127,7 +130,7 @@
     }
   if (!state->events[E_RESOLVER])
     {
-      trigger_event (state, E_TLSDATE, 0);
+      trigger_event (state, E_TLSDATE, jitter);
       return;
     }
   /* If the resolver relies on an external response, then make sure that a
@@ -135,6 +138,6 @@
    * if this fires, it won't stop eventual handling of the resolver since it
    * doesn't event_del() E_RESOLVER.
    */
-  trigger_event (state, E_TLSDATE, RESOLVER_TIMEOUT);
-  trigger_event (state, E_RESOLVER, 0);
+  trigger_event (state, E_TLSDATE, jitter + RESOLVER_TIMEOUT);
+  trigger_event (state, E_RESOLVER, jitter);
 }
diff --git a/src/tlsdate.h b/src/tlsdate.h
index 3862756..9a836c1 100644
--- a/src/tlsdate.h
+++ b/src/tlsdate.h
@@ -41,8 +41,8 @@
 #define RESOLVER_TIMEOUT 30
 /* Invalidate the network sync once per day. */
 #define STEADY_STATE_INTERVAL (60*60*24)
-/* Check if the clock has drifted once an hour */
-#define CONTINUITY_INTERVAL (60*60)
+/* Check if the clock has jumped every four hours. */
+#define CONTINUITY_INTERVAL (60*60*4)
 #define DEFAULT_SYNC_HWCLOCK 1
 #define DEFAULT_LOAD_FROM_DISK 1
 #define DEFAULT_SAVE_TO_DISK 1