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