evaluation_context.h revision 83ffddaa3b09ceb4361e5c01ba300d57ab697a7e
1// 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#ifndef UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_ 6#define UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_ 7 8#include <map> 9#include <string> 10 11#include <base/bind.h> 12#include <base/callback.h> 13#include <base/memory/ref_counted.h> 14#include <base/memory/scoped_ptr.h> 15#include <base/memory/weak_ptr.h> 16#include <base/time/time.h> 17 18#include "update_engine/clock_interface.h" 19#include "update_engine/update_manager/boxed_value.h" 20#include "update_engine/update_manager/event_loop.h" 21#include "update_engine/update_manager/variable.h" 22 23namespace chromeos_update_manager { 24 25// The EvaluationContext class is the interface between a policy implementation 26// and the state. The EvaluationContext tracks the variables used by a policy 27// request and caches the returned values, owning those cached values. 28// The same EvaluationContext should be re-used for all the evaluations of the 29// same policy request (an AsyncPolicyRequest might involve several 30// re-evaluations). Each evaluation of the EvaluationContext is run at a given 31// point in time, which is used as a reference for the evaluation timeout and 32// the time based queries of the policy, such as 33// Is{Wallclock,Monotonic}TimeGreaterThan(). 34// 35// Example: 36// 37// scoped_refptr<EvaluationContext> ec = new EvaluationContext(...); 38// 39// ... 40// // The following call to ResetEvaluation() is optional. Use it to reset the 41// // evaluation time if the EvaluationContext isn't used right after its 42// // construction. 43// ec->ResetEvaluation(); 44// EvalStatus status = policy->SomeMethod(ec, state, &result, args...); 45// 46// ... 47// // Run a closure when any of the used async variables changes its value or 48// // the timeout for re-query the values happens again. 49// ec->RunOnValueChangeOrTimeout(closure); 50// // If the provided |closure| wants to re-evaluate the policy, it should 51// // call ec->ResetEvaluation() to start a new evaluation. 52// 53class EvaluationContext : public base::RefCounted<EvaluationContext>, 54 private BaseVariable::ObserverInterface { 55 public: 56 EvaluationContext( 57 chromeos_update_engine::ClockInterface* clock, 58 base::TimeDelta evaluation_timeout, 59 base::TimeDelta expiration_timeout, 60 scoped_ptr<base::Callback<void(EvaluationContext*)>> unregister_cb); 61 EvaluationContext(chromeos_update_engine::ClockInterface* clock, 62 base::TimeDelta evaluation_timeout) 63 : EvaluationContext( 64 clock, evaluation_timeout, base::TimeDelta::Max(), 65 scoped_ptr<base::Callback<void(EvaluationContext*)>>()) {} 66 ~EvaluationContext(); 67 68 // Returns a pointer to the value returned by the passed variable |var|. The 69 // EvaluationContext instance keeps the ownership of the returned object. The 70 // returned object is valid during the life of the evaluation, even if the 71 // passed Variable changes it. 72 // 73 // In case of error, a NULL value is returned. 74 template<typename T> 75 const T* GetValue(Variable<T>* var); 76 77 // Returns whether the evaluation time has surpassed |timestamp|, on either 78 // the ClockInterface::GetWallclockTime() or 79 // ClockInterface::GetMonotonicTime() scales, respectively. 80 bool IsWallclockTimeGreaterThan(base::Time timestamp); 81 bool IsMonotonicTimeGreaterThan(base::Time timestamp); 82 83 // Returns whether the evaluation context has expired. 84 bool is_expired() const { return is_expired_; } 85 86 // TODO(deymo): Move the following methods to an interface only visible by the 87 // UpdateManager class and not the policy implementations. 88 89 // Resets the EvaluationContext to its initial state removing all the 90 // non-const cached variables and re-setting the evaluation time. This should 91 // be called right before any new evaluation starts. 92 void ResetEvaluation(); 93 94 // Clears the expiration status of the EvaluationContext and resets its 95 // expiration timeout based on |expiration_timeout_|. This should be called if 96 // expiration occurred, prior to re-evaluating the policy. 97 void ResetExpiration(); 98 99 // Schedules the passed |callback| closure to be called when a cached 100 // variable changes its value, a polling interval passes, or the context 101 // expiration occurs. If none of these events can happen, for example if 102 // there's no cached variable, this method returns false. 103 // 104 // Right before the passed closure is called the EvaluationContext is 105 // reseted, removing all the non-const cached values. 106 bool RunOnValueChangeOrTimeout(base::Closure callback); 107 108 // Returns a textual representation of the evaluation context, 109 // including the variables and their values. This is intended only 110 // to help with debugging and the format may change in the future. 111 std::string DumpContext() const; 112 113 // Removes all the Observers callbacks and timeout events scheduled by 114 // RunOnValueChangeOrTimeout(). Also releases and returns the closure 115 // associated with these events. This method is idempotent. 116 scoped_ptr<base::Closure> RemoveObserversAndTimeout(); 117 118 private: 119 friend class UmEvaluationContextTest; 120 121 // BaseVariable::ObserverInterface override. 122 void ValueChanged(BaseVariable* var); 123 124 // Called from the main loop when a scheduled timeout has passed. 125 void OnTimeout(); 126 127 // Removes the observers from the used Variables and cancels the timeout, 128 // then executes the scheduled callback. 129 void OnValueChangedOrTimeout(); 130 131 // If |monotonic_deadline| is not Time::Max(), returns the remaining time 132 // until it is reached, or zero if it has passed. Otherwise, returns 133 // TimeDelta::Max(). 134 base::TimeDelta RemainingTime(base::Time monotonic_deadline) const; 135 136 // Returns a monotonic clock timestamp at which |timeout| will have elapsed 137 // since the current time. 138 base::Time MonotonicDeadline(base::TimeDelta timeout); 139 140 // A map to hold the cached values for every variable. 141 typedef std::map<BaseVariable*, BoxedValue> ValueCacheMap; 142 143 // The cached values of the called Variables. 144 ValueCacheMap value_cache_; 145 146 // A callback used for triggering re-evaluation upon a value change or poll 147 // timeout, or notifying about the evaluation context expiration. It is up to 148 // the caller to determine whether or not expiration occurred via 149 // is_expired(). 150 scoped_ptr<base::Closure> callback_; 151 152 // The EventId returned by the event loop identifying the timeout callback. 153 // Used for canceling the timeout callback. 154 EventId timeout_event_ = kEventIdNull; 155 156 // Whether a timeout event firing marks the expiration of the evaluation 157 // context. 158 bool timeout_marks_expiration_; 159 160 // Whether the evaluation context has indeed expired. 161 bool is_expired_ = false; 162 163 // Pointer to the mockable clock interface; 164 chromeos_update_engine::ClockInterface* const clock_; 165 166 // The timestamps when the evaluation of this EvaluationContext started, 167 // corresponding to ClockInterface::GetWallclockTime() and 168 // ClockInterface::GetMonotonicTime(), respectively. These values are reset 169 // every time ResetEvaluation() is called. 170 base::Time evaluation_start_wallclock_; 171 base::Time evaluation_start_monotonic_; 172 173 // The timestamps when a reevaluation should be triggered due to various 174 // expected value changes, corresponding to ClockInterface::GetWallclockTime() 175 // and ClockInterface::GetMonotonicTIme(), respectively. These timestamps are 176 // greater or equal to corresponding |evaluation_start_{wallclock,monotonic}_| 177 // counterparts since they are in the future; however, they may be smaller 178 // than the current corresponding times during the course of evaluation. 179 base::Time reevaluation_time_wallclock_; 180 base::Time reevaluation_time_monotonic_; 181 182 // The timeout of an evaluation. 183 const base::TimeDelta evaluation_timeout_; 184 185 // The timestamp in the ClockInterface::GetMonotonicTime() scale at which the 186 // current evaluation should finish. 187 base::Time evaluation_monotonic_deadline_; 188 189 // The expiration timeout of the evaluation context. 190 const base::TimeDelta expiration_timeout_; 191 192 // The monotonic clock deadline at which expiration occurs. 193 base::Time expiration_monotonic_deadline_; 194 195 // A callback for unregistering the context upon destruction. 196 scoped_ptr<base::Callback<void(EvaluationContext*)>> unregister_cb_; 197 198 base::WeakPtrFactory<EvaluationContext> weak_ptr_factory_; 199 200 DISALLOW_COPY_AND_ASSIGN(EvaluationContext); 201}; 202 203} // namespace chromeos_update_manager 204 205// Include the implementation of the template methods. 206#include "update_engine/update_manager/evaluation_context-inl.h" 207 208#endif // UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_ 209