blob: a24bf2301cb7dd5e3834ef3c678145da5808a626 [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
Alex Deymo63784a52014-05-28 10:46:14 -07005#include "update_engine/update_manager/evaluation_context.h"
Alex Deymo23949d42014-02-05 15:20:59 -08006
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
Alex Deymo63784a52014-05-28 10:46:14 -070021namespace chromeos_update_manager {
Alex Deymo23949d42014-02-05 15:20:59 -080022
Gilad Arnoldb2271992014-06-19 12:35:24 -070023EvaluationContext::EvaluationContext(ClockInterface* clock,
24 TimeDelta evaluation_timeout)
Alex Deymo41a75a72014-04-15 15:36:22 -070025 : clock_(clock),
Gilad Arnoldb2271992014-06-19 12:35:24 -070026 evaluation_timeout_(evaluation_timeout),
Alex Deymo41a75a72014-04-15 15:36:22 -070027 weak_ptr_factory_(this) {
28 ResetEvaluation();
29}
30
Alex Deymo53556ec2014-03-17 10:05:57 -070031EvaluationContext::~EvaluationContext() {
32 RemoveObserversAndTimeout();
33}
34
35void EvaluationContext::RemoveObserversAndTimeout() {
36 for (auto& it : value_cache_) {
37 if (it.first->GetMode() == kVariableModeAsync)
38 it.first->RemoveObserver(this);
39 }
40 CancelMainLoopEvent(poll_timeout_event_);
41 poll_timeout_event_ = kEventIdNull;
42}
43
Alex Deymo23949d42014-02-05 15:20:59 -080044TimeDelta EvaluationContext::RemainingTime() const {
Alex Deymo41a75a72014-04-15 15:36:22 -070045 return evaluation_monotonic_deadline_ - clock_->GetMonotonicTime();
Alex Deymo23949d42014-02-05 15:20:59 -080046}
47
Alex Deymo53556ec2014-03-17 10:05:57 -070048void EvaluationContext::ValueChanged(BaseVariable* var) {
49 DLOG(INFO) << "ValueChanged for variable " << var->GetName();
50 OnValueChangedOrPollTimeout();
51}
52
53void EvaluationContext::OnPollTimeout() {
54 DLOG(INFO) << "OnPollTimeout() called.";
55 poll_timeout_event_ = kEventIdNull;
56 OnValueChangedOrPollTimeout();
57}
58
59void EvaluationContext::OnValueChangedOrPollTimeout() {
60 RemoveObserversAndTimeout();
Alex Deymo41a75a72014-04-15 15:36:22 -070061
62 if (value_changed_callback_.get() != NULL) {
63 value_changed_callback_->Run();
64 value_changed_callback_.reset();
65 }
66}
67
68bool EvaluationContext::IsTimeGreaterThan(base::Time timestamp) {
69 if (evaluation_start_ > timestamp)
70 return true;
71 // We need to keep track of these calls to trigger a reevaluation.
72 if (reevaluation_time_ > timestamp)
73 reevaluation_time_ = timestamp;
74 return false;
75}
76
77void EvaluationContext::ResetEvaluation() {
78 // It is not important if these two values are not in sync. The first value is
79 // a reference in time when the evaluation started, to device time-based
80 // values for the current evaluation. The second is a deadline for the
81 // evaluation which required a monotonic source of time.
82 evaluation_start_ = clock_->GetWallclockTime();
83 evaluation_monotonic_deadline_ =
84 clock_->GetMonotonicTime() + evaluation_timeout_;
85 reevaluation_time_ = Time::Max();
86
Alex Deymo53556ec2014-03-17 10:05:57 -070087 // Remove the cached values of non-const variables
88 for (auto it = value_cache_.begin(); it != value_cache_.end(); ) {
89 if (it->first->GetMode() == kVariableModeConst) {
90 ++it;
91 } else {
92 it = value_cache_.erase(it);
93 }
94 }
Alex Deymo53556ec2014-03-17 10:05:57 -070095}
96
97bool EvaluationContext::RunOnValueChangeOrTimeout(Closure callback) {
98 TimeDelta reeval_timeout;
99 bool reeval_timeout_set = false;
100 bool waiting_for_value_change = false;
101
Alex Deymo41a75a72014-04-15 15:36:22 -0700102 // Check if a reevaluation should be triggered due to a IsTimeGreaterThan()
103 // call.
104 if (reevaluation_time_ != Time::Max()) {
105 reeval_timeout = reevaluation_time_ - evaluation_start_;
106 reeval_timeout_set = true;
107 }
108
Alex Deymo53556ec2014-03-17 10:05:57 -0700109 if (value_changed_callback_.get() != NULL) {
110 LOG(ERROR) << "RunOnValueChangeOrTimeout called more than once.";
111 return false;
112 }
113
114 for (auto& it : value_cache_) {
115 switch (it.first->GetMode()) {
116 case kVariableModeAsync:
117 waiting_for_value_change = true;
118 DLOG(INFO) << "Waiting for value on " << it.first->GetName();
119 it.first->AddObserver(this);
120 break;
121 case kVariableModePoll:
122 if (!reeval_timeout_set || reeval_timeout > it.first->GetPollInterval())
123 reeval_timeout = it.first->GetPollInterval();
124 reeval_timeout_set = true;
125 break;
126 case kVariableModeConst:
127 // Ignored.
128 break;
129 }
130 }
131 // Check if the re-evaluation is actually being scheduled. If there are no
132 // events waited for, this function should return false.
133 if (!waiting_for_value_change && !reeval_timeout_set)
134 return false;
135 if (reeval_timeout_set) {
136 poll_timeout_event_ = RunFromMainLoopAfterTimeout(
Alex Deymodb799532014-03-21 13:00:00 -0700137 base::Bind(&EvaluationContext::OnPollTimeout,
138 weak_ptr_factory_.GetWeakPtr()),
Alex Deymo53556ec2014-03-17 10:05:57 -0700139 reeval_timeout);
140 }
141
142 value_changed_callback_.reset(new Closure(callback));
143 return true;
144}
145
David Zeuthenc1490282014-04-29 16:25:03 -0700146string EvaluationContext::DumpContext() const {
147 base::DictionaryValue* variables = new base::DictionaryValue();
148 for (auto& it : value_cache_) {
149 variables->SetString(it.first->GetName(), it.second.ToString());
150 }
151
152 base::DictionaryValue value;
153 value.Set("variables", variables); // Adopts |variables|.
154 value.SetString("evaluation_start",
155 chromeos_update_engine::utils::ToString(evaluation_start_));
156
157 string json_str;
158 base::JSONWriter::WriteWithOptions(&value,
159 base::JSONWriter::OPTIONS_PRETTY_PRINT,
160 &json_str);
161
162 return json_str;
163}
164
Alex Deymo63784a52014-05-28 10:46:14 -0700165} // namespace chromeos_update_manager