blob: 03238cf8ded910793d9cf97ad4e03eb8ef9eb231 [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
Alex Deymo53556ec2014-03-17 10:05:57 -07007#include <base/bind.h>
8
9using base::Closure;
Alex Deymo41a75a72014-04-15 15:36:22 -070010using base::Time;
Alex Deymo23949d42014-02-05 15:20:59 -080011using base::TimeDelta;
Alex Deymo41a75a72014-04-15 15:36:22 -070012using chromeos_update_engine::ClockInterface;
Alex Deymo23949d42014-02-05 15:20:59 -080013
14namespace chromeos_policy_manager {
15
Alex Deymo41a75a72014-04-15 15:36:22 -070016EvaluationContext::EvaluationContext(ClockInterface* clock)
17 : clock_(clock),
18 weak_ptr_factory_(this) {
19 ResetEvaluation();
20}
21
Alex Deymo53556ec2014-03-17 10:05:57 -070022EvaluationContext::~EvaluationContext() {
23 RemoveObserversAndTimeout();
24}
25
26void EvaluationContext::RemoveObserversAndTimeout() {
27 for (auto& it : value_cache_) {
28 if (it.first->GetMode() == kVariableModeAsync)
29 it.first->RemoveObserver(this);
30 }
31 CancelMainLoopEvent(poll_timeout_event_);
32 poll_timeout_event_ = kEventIdNull;
33}
34
Alex Deymo23949d42014-02-05 15:20:59 -080035TimeDelta EvaluationContext::RemainingTime() const {
Alex Deymo41a75a72014-04-15 15:36:22 -070036 return evaluation_monotonic_deadline_ - clock_->GetMonotonicTime();
Alex Deymo23949d42014-02-05 15:20:59 -080037}
38
Alex Deymo53556ec2014-03-17 10:05:57 -070039void EvaluationContext::ValueChanged(BaseVariable* var) {
40 DLOG(INFO) << "ValueChanged for variable " << var->GetName();
41 OnValueChangedOrPollTimeout();
42}
43
44void EvaluationContext::OnPollTimeout() {
45 DLOG(INFO) << "OnPollTimeout() called.";
46 poll_timeout_event_ = kEventIdNull;
47 OnValueChangedOrPollTimeout();
48}
49
50void EvaluationContext::OnValueChangedOrPollTimeout() {
51 RemoveObserversAndTimeout();
Alex Deymo41a75a72014-04-15 15:36:22 -070052
53 if (value_changed_callback_.get() != NULL) {
54 value_changed_callback_->Run();
55 value_changed_callback_.reset();
56 }
57}
58
59bool EvaluationContext::IsTimeGreaterThan(base::Time timestamp) {
60 if (evaluation_start_ > timestamp)
61 return true;
62 // We need to keep track of these calls to trigger a reevaluation.
63 if (reevaluation_time_ > timestamp)
64 reevaluation_time_ = timestamp;
65 return false;
66}
67
68void EvaluationContext::ResetEvaluation() {
69 // It is not important if these two values are not in sync. The first value is
70 // a reference in time when the evaluation started, to device time-based
71 // values for the current evaluation. The second is a deadline for the
72 // evaluation which required a monotonic source of time.
73 evaluation_start_ = clock_->GetWallclockTime();
74 evaluation_monotonic_deadline_ =
75 clock_->GetMonotonicTime() + evaluation_timeout_;
76 reevaluation_time_ = Time::Max();
77
Alex Deymo53556ec2014-03-17 10:05:57 -070078 // Remove the cached values of non-const variables
79 for (auto it = value_cache_.begin(); it != value_cache_.end(); ) {
80 if (it->first->GetMode() == kVariableModeConst) {
81 ++it;
82 } else {
83 it = value_cache_.erase(it);
84 }
85 }
Alex Deymo53556ec2014-03-17 10:05:57 -070086}
87
88bool EvaluationContext::RunOnValueChangeOrTimeout(Closure callback) {
89 TimeDelta reeval_timeout;
90 bool reeval_timeout_set = false;
91 bool waiting_for_value_change = false;
92
Alex Deymo41a75a72014-04-15 15:36:22 -070093 // Check if a reevaluation should be triggered due to a IsTimeGreaterThan()
94 // call.
95 if (reevaluation_time_ != Time::Max()) {
96 reeval_timeout = reevaluation_time_ - evaluation_start_;
97 reeval_timeout_set = true;
98 }
99
Alex Deymo53556ec2014-03-17 10:05:57 -0700100 if (value_changed_callback_.get() != NULL) {
101 LOG(ERROR) << "RunOnValueChangeOrTimeout called more than once.";
102 return false;
103 }
104
105 for (auto& it : value_cache_) {
106 switch (it.first->GetMode()) {
107 case kVariableModeAsync:
108 waiting_for_value_change = true;
109 DLOG(INFO) << "Waiting for value on " << it.first->GetName();
110 it.first->AddObserver(this);
111 break;
112 case kVariableModePoll:
113 if (!reeval_timeout_set || reeval_timeout > it.first->GetPollInterval())
114 reeval_timeout = it.first->GetPollInterval();
115 reeval_timeout_set = true;
116 break;
117 case kVariableModeConst:
118 // Ignored.
119 break;
120 }
121 }
122 // Check if the re-evaluation is actually being scheduled. If there are no
123 // events waited for, this function should return false.
124 if (!waiting_for_value_change && !reeval_timeout_set)
125 return false;
126 if (reeval_timeout_set) {
127 poll_timeout_event_ = RunFromMainLoopAfterTimeout(
Alex Deymodb799532014-03-21 13:00:00 -0700128 base::Bind(&EvaluationContext::OnPollTimeout,
129 weak_ptr_factory_.GetWeakPtr()),
Alex Deymo53556ec2014-03-17 10:05:57 -0700130 reeval_timeout);
131 }
132
133 value_changed_callback_.reset(new Closure(callback));
134 return true;
135}
136
Alex Deymo23949d42014-02-05 15:20:59 -0800137} // namespace chromeos_policy_manager