blob: 3a37618d4f2894a7e1091dc97bba51b824f82f4c [file] [log] [blame]
Alex Deymo23949d42014-02-05 15:20:59 -08001// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/policy_manager/evaluation_context.h"
6
David Zeuthenc1490282014-04-29 16:25:03 -07007#include <string>
8
Alex Deymo53556ec2014-03-17 10:05:57 -07009#include <base/bind.h>
David Zeuthenc1490282014-04-29 16:25:03 -070010#include <base/json/json_writer.h>
11#include <base/values.h>
12
13#include "update_engine/utils.h"
Alex Deymo53556ec2014-03-17 10:05:57 -070014
15using base::Closure;
Alex Deymo41a75a72014-04-15 15:36:22 -070016using base::Time;
Alex Deymo23949d42014-02-05 15:20:59 -080017using base::TimeDelta;
Alex Deymo41a75a72014-04-15 15:36:22 -070018using chromeos_update_engine::ClockInterface;
David Zeuthenc1490282014-04-29 16:25:03 -070019using std::string;
Alex Deymo23949d42014-02-05 15:20:59 -080020
21namespace chromeos_policy_manager {
22
Alex Deymo41a75a72014-04-15 15:36:22 -070023EvaluationContext::EvaluationContext(ClockInterface* clock)
24 : clock_(clock),
25 weak_ptr_factory_(this) {
26 ResetEvaluation();
27}
28
Alex Deymo53556ec2014-03-17 10:05:57 -070029EvaluationContext::~EvaluationContext() {
30 RemoveObserversAndTimeout();
31}
32
33void EvaluationContext::RemoveObserversAndTimeout() {
34 for (auto& it : value_cache_) {
35 if (it.first->GetMode() == kVariableModeAsync)
36 it.first->RemoveObserver(this);
37 }
38 CancelMainLoopEvent(poll_timeout_event_);
39 poll_timeout_event_ = kEventIdNull;
40}
41
Alex Deymo23949d42014-02-05 15:20:59 -080042TimeDelta EvaluationContext::RemainingTime() const {
Alex Deymo41a75a72014-04-15 15:36:22 -070043 return evaluation_monotonic_deadline_ - clock_->GetMonotonicTime();
Alex Deymo23949d42014-02-05 15:20:59 -080044}
45
Alex Deymo53556ec2014-03-17 10:05:57 -070046void EvaluationContext::ValueChanged(BaseVariable* var) {
47 DLOG(INFO) << "ValueChanged for variable " << var->GetName();
48 OnValueChangedOrPollTimeout();
49}
50
51void EvaluationContext::OnPollTimeout() {
52 DLOG(INFO) << "OnPollTimeout() called.";
53 poll_timeout_event_ = kEventIdNull;
54 OnValueChangedOrPollTimeout();
55}
56
57void EvaluationContext::OnValueChangedOrPollTimeout() {
58 RemoveObserversAndTimeout();
Alex Deymo41a75a72014-04-15 15:36:22 -070059
60 if (value_changed_callback_.get() != NULL) {
61 value_changed_callback_->Run();
62 value_changed_callback_.reset();
63 }
64}
65
66bool EvaluationContext::IsTimeGreaterThan(base::Time timestamp) {
67 if (evaluation_start_ > timestamp)
68 return true;
69 // We need to keep track of these calls to trigger a reevaluation.
70 if (reevaluation_time_ > timestamp)
71 reevaluation_time_ = timestamp;
72 return false;
73}
74
75void EvaluationContext::ResetEvaluation() {
76 // It is not important if these two values are not in sync. The first value is
77 // a reference in time when the evaluation started, to device time-based
78 // values for the current evaluation. The second is a deadline for the
79 // evaluation which required a monotonic source of time.
80 evaluation_start_ = clock_->GetWallclockTime();
81 evaluation_monotonic_deadline_ =
82 clock_->GetMonotonicTime() + evaluation_timeout_;
83 reevaluation_time_ = Time::Max();
84
Alex Deymo53556ec2014-03-17 10:05:57 -070085 // Remove the cached values of non-const variables
86 for (auto it = value_cache_.begin(); it != value_cache_.end(); ) {
87 if (it->first->GetMode() == kVariableModeConst) {
88 ++it;
89 } else {
90 it = value_cache_.erase(it);
91 }
92 }
Alex Deymo53556ec2014-03-17 10:05:57 -070093}
94
95bool EvaluationContext::RunOnValueChangeOrTimeout(Closure callback) {
96 TimeDelta reeval_timeout;
97 bool reeval_timeout_set = false;
98 bool waiting_for_value_change = false;
99
Alex Deymo41a75a72014-04-15 15:36:22 -0700100 // Check if a reevaluation should be triggered due to a IsTimeGreaterThan()
101 // call.
102 if (reevaluation_time_ != Time::Max()) {
103 reeval_timeout = reevaluation_time_ - evaluation_start_;
104 reeval_timeout_set = true;
105 }
106
Alex Deymo53556ec2014-03-17 10:05:57 -0700107 if (value_changed_callback_.get() != NULL) {
108 LOG(ERROR) << "RunOnValueChangeOrTimeout called more than once.";
109 return false;
110 }
111
112 for (auto& it : value_cache_) {
113 switch (it.first->GetMode()) {
114 case kVariableModeAsync:
115 waiting_for_value_change = true;
116 DLOG(INFO) << "Waiting for value on " << it.first->GetName();
117 it.first->AddObserver(this);
118 break;
119 case kVariableModePoll:
120 if (!reeval_timeout_set || reeval_timeout > it.first->GetPollInterval())
121 reeval_timeout = it.first->GetPollInterval();
122 reeval_timeout_set = true;
123 break;
124 case kVariableModeConst:
125 // Ignored.
126 break;
127 }
128 }
129 // Check if the re-evaluation is actually being scheduled. If there are no
130 // events waited for, this function should return false.
131 if (!waiting_for_value_change && !reeval_timeout_set)
132 return false;
133 if (reeval_timeout_set) {
134 poll_timeout_event_ = RunFromMainLoopAfterTimeout(
Alex Deymodb799532014-03-21 13:00:00 -0700135 base::Bind(&EvaluationContext::OnPollTimeout,
136 weak_ptr_factory_.GetWeakPtr()),
Alex Deymo53556ec2014-03-17 10:05:57 -0700137 reeval_timeout);
138 }
139
140 value_changed_callback_.reset(new Closure(callback));
141 return true;
142}
143
David Zeuthenc1490282014-04-29 16:25:03 -0700144string EvaluationContext::DumpContext() const {
145 base::DictionaryValue* variables = new base::DictionaryValue();
146 for (auto& it : value_cache_) {
147 variables->SetString(it.first->GetName(), it.second.ToString());
148 }
149
150 base::DictionaryValue value;
151 value.Set("variables", variables); // Adopts |variables|.
152 value.SetString("evaluation_start",
153 chromeos_update_engine::utils::ToString(evaluation_start_));
154
155 string json_str;
156 base::JSONWriter::WriteWithOptions(&value,
157 base::JSONWriter::OPTIONS_PRETTY_PRINT,
158 &json_str);
159
160 return json_str;
161}
162
Alex Deymo23949d42014-02-05 15:20:59 -0800163} // namespace chromeos_policy_manager