update_engine: UM: Add check for monotonic time elapsed.
This forks the former EvaluationStatus::IsTimeGreaterThan() into two
separate variants, checking either the wallclock or monotonic current
time against a corresponding timestamp. This is needed for policies that
require resilience against wallclock time volatility.
BUG=chromium:394778
TEST=Unit tests.
Change-Id: I9ecd20cc87a3a520e119f157e55ae4f54104a506
Reviewed-on: https://chromium-review.googlesource.com/209487
Commit-Queue: Gilad Arnold <[email protected]>
Tested-by: Gilad Arnold <[email protected]>
Reviewed-by: Gilad Arnold <[email protected]>
diff --git a/update_manager/evaluation_context.cc b/update_manager/evaluation_context.cc
index 2f827c1..2d5d705 100644
--- a/update_manager/evaluation_context.cc
+++ b/update_manager/evaluation_context.cc
@@ -20,6 +20,31 @@
using chromeos_update_engine::ClockInterface;
using std::string;
+namespace {
+
+// Returns whether |curr_time| surpassed |ref_time|; if not, also checks whether
+// |ref_time| is sooner than the current value of |*reeval_time|, in which case
+// the latter is updated to the former.
+bool IsTimeGreaterThanHelper(base::Time ref_time, base::Time curr_time,
+ base::Time* reeval_time) {
+ if (curr_time > ref_time)
+ return true;
+ // Remember the nearest reference we've checked against in this evaluation.
+ if (*reeval_time > ref_time)
+ *reeval_time = ref_time;
+ return false;
+}
+
+// If |expires| never happens (maximal value), returns the maximal interval;
+// otherwise, returns the difference between |expires| and |curr|.
+TimeDelta GetTimeout(base::Time curr, base::Time expires) {
+ if (expires.is_max())
+ return TimeDelta::Max();
+ return expires - curr;
+}
+
+} // namespace
+
namespace chromeos_update_manager {
EvaluationContext::EvaluationContext(ClockInterface* clock,
@@ -80,23 +105,22 @@
callback->Run();
}
-bool EvaluationContext::IsTimeGreaterThan(base::Time timestamp) {
- if (evaluation_start_ > timestamp)
- return true;
- // We need to keep track of these calls to trigger a reevaluation.
- if (reevaluation_time_ > timestamp)
- reevaluation_time_ = timestamp;
- return false;
+bool EvaluationContext::IsWallclockTimeGreaterThan(base::Time timestamp) {
+ return IsTimeGreaterThanHelper(timestamp, evaluation_start_wallclock_,
+ &reevaluation_time_wallclock_);
+}
+
+bool EvaluationContext::IsMonotonicTimeGreaterThan(base::Time timestamp) {
+ return IsTimeGreaterThanHelper(timestamp, evaluation_start_monotonic_,
+ &reevaluation_time_monotonic_);
}
void EvaluationContext::ResetEvaluation() {
- // It is not important if these two values are not in sync. The first value is
- // a reference in time when the evaluation started, to device time-based
- // values for the current evaluation. The second is a deadline for the
- // evaluation which required a monotonic source of time.
- evaluation_start_ = clock_->GetWallclockTime();
+ evaluation_start_wallclock_ = clock_->GetWallclockTime();
+ evaluation_start_monotonic_ = clock_->GetMonotonicTime();
+ reevaluation_time_wallclock_ = Time::Max();
+ reevaluation_time_monotonic_ = Time::Max();
evaluation_monotonic_deadline_ = MonotonicDeadline(evaluation_timeout_);
- reevaluation_time_ = Time::Max();
// Remove the cached values of non-const variables
for (auto it = value_cache_.begin(); it != value_cache_.end(); ) {
@@ -121,14 +145,15 @@
return false;
}
- TimeDelta timeout(TimeDelta::Max());
- bool waiting_for_value_change = false;
-
- // Handle reevaluation due to a IsTimeGreaterThan() call.
- if (!reevaluation_time_.is_max())
- timeout = reevaluation_time_ - evaluation_start_;
+ // Handle reevaluation due to a Is{Wallclock,Monotonic}TimeGreaterThan(). We
+ // choose the smaller of the differences between evaluation start time and
+ // reevaluation time among the wallclock and monotonic scales.
+ TimeDelta timeout = std::min(
+ GetTimeout(evaluation_start_wallclock_, reevaluation_time_wallclock_),
+ GetTimeout(evaluation_start_monotonic_, reevaluation_time_monotonic_));
// Handle reevaluation due to async or poll variables.
+ bool waiting_for_value_change = false;
for (auto& it : value_cache_) {
switch (it.first->GetMode()) {
case kVariableModeAsync:
@@ -180,8 +205,12 @@
base::DictionaryValue value;
value.Set("variables", variables); // Adopts |variables|.
- value.SetString("evaluation_start",
- chromeos_update_engine::utils::ToString(evaluation_start_));
+ value.SetString(
+ "evaluation_start_wallclock",
+ chromeos_update_engine::utils::ToString(evaluation_start_wallclock_));
+ value.SetString(
+ "evaluation_start_monotonic",
+ chromeos_update_engine::utils::ToString(evaluation_start_monotonic_));
string json_str;
base::JSONWriter::WriteWithOptions(&value,