• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2014 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #ifndef UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
18 #define UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
19 
20 #include <algorithm>
21 #include <list>
22 #include <string>
23 
24 #include <base/bind.h>
25 #include <base/location.h>
26 #include <base/logging.h>
27 #include <base/time/time.h>
28 #include <brillo/message_loops/message_loop.h>
29 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
30 
31 namespace chromeos_update_manager {
32 
33 // The VariableMode specifies important behavior of the variable in terms of
34 // whether, how and when the value of the variable changes.
35 enum VariableMode {
36   // Const variables never changes during the life of a policy request, so the
37   // EvaluationContext caches the value even between different evaluations of
38   // the same policy request.
39   kVariableModeConst,
40 
41   // Poll variables, or synchronous variables, represent a variable with a value
42   // that can be queried at any time, but it is not known when the value
43   // changes on the source of information. In order to detect if the value of
44   // the variable changes, it has to be queried again.
45   kVariableModePoll,
46 
47   // Async variables are able to produce a signal or callback whenever the
48   // value changes. This means that it's not required to poll the value to
49   // detect when it changes, instead, you should register an observer to get
50   // a notification when that happens.
51   kVariableModeAsync,
52 };
53 
54 // This class is a base class with the common functionality that doesn't
55 // depend on the variable's type, implemented by all the variables.
56 class BaseVariable {
57  public:
58   // Interface for observing changes on variable value.
59   class ObserverInterface {
60    public:
~ObserverInterface()61     virtual ~ObserverInterface() {}
62 
63     // Called when the value on the variable changes.
64     virtual void ValueChanged(BaseVariable* variable) = 0;
65   };
66 
~BaseVariable()67   virtual ~BaseVariable() {
68     if (!observer_list_.empty()) {
69       LOG(WARNING) << "Variable " << name_ << " deleted with "
70                    << observer_list_.size() << " observers.";
71     }
72     DCHECK(observer_list_.empty()) << "Don't destroy the variable without "
73                                       "removing the observers.";
74   }
75 
76   // Returns the variable name as a string.
GetName()77   const std::string& GetName() const { return name_; }
78 
79   // Returns the variable mode.
GetMode()80   VariableMode GetMode() const { return mode_; }
81 
82   // For VariableModePoll variables, it returns the polling interval of this
83   // variable. In other case, it returns 0.
GetPollInterval()84   base::TimeDelta GetPollInterval() const { return poll_interval_; }
85 
86   // Returns true, if the value for this variable is expected to be missing
87   // sometimes so we can avoid printing confusing error logs.
IsMissingOk()88   bool IsMissingOk() const { return missing_ok_; }
89 
90   // Adds and removes observers for value changes on the variable. This only
91   // works for kVariableAsync variables since the other modes don't track value
92   // changes. Adding the same observer twice has no effect.
AddObserver(BaseVariable::ObserverInterface * observer)93   virtual void AddObserver(BaseVariable::ObserverInterface* observer) {
94     if (std::find(observer_list_.begin(), observer_list_.end(), observer) ==
95         observer_list_.end()) {
96       observer_list_.push_back(observer);
97     }
98   }
99 
RemoveObserver(BaseVariable::ObserverInterface * observer)100   virtual void RemoveObserver(BaseVariable::ObserverInterface* observer) {
101     observer_list_.remove(observer);
102   }
103 
104  protected:
105   // Creates a BaseVariable using the default polling interval (5 minutes).
BaseVariable(const std::string & name,VariableMode mode)106   BaseVariable(const std::string& name, VariableMode mode)
107       : BaseVariable(
108             name, mode, base::TimeDelta::FromMinutes(kDefaultPollMinutes)) {}
109 
110   // Creates a BaseVariable with mode kVariableModePoll and the provided
111   // polling interval.
BaseVariable(const std::string & name,base::TimeDelta poll_interval)112   BaseVariable(const std::string& name, base::TimeDelta poll_interval)
113       : BaseVariable(name, kVariableModePoll, poll_interval) {}
114 
115   // Reset the poll interval on a polling variable to the given one.
SetPollInterval(base::TimeDelta poll_interval)116   void SetPollInterval(base::TimeDelta poll_interval) {
117     DCHECK_EQ(kVariableModePoll, mode_)
118         << "Can't set the poll_interval on a " << mode_ << " variable";
119     poll_interval_ = poll_interval;
120   }
121 
SetMissingOk()122   void SetMissingOk() { missing_ok_ = true; }
123 
124   // Calls ValueChanged on all the observers.
NotifyValueChanged()125   void NotifyValueChanged() {
126     // Fire all the observer methods from the main loop as single call. In order
127     // to avoid scheduling these callbacks when it is not needed, we check
128     // first the list of observers.
129     if (!observer_list_.empty()) {
130       brillo::MessageLoop::current()->PostTask(
131           FROM_HERE,
132           base::Bind(&BaseVariable::OnValueChangedNotification,
133                      base::Unretained(this)));
134     }
135   }
136 
137  private:
138   friend class UmEvaluationContextTest;
139   FRIEND_TEST(UmBaseVariableTest, RepeatedObserverTest);
140   FRIEND_TEST(UmBaseVariableTest, NotifyValueChangedTest);
141   FRIEND_TEST(UmBaseVariableTest, NotifyValueRemovesObserversTest);
142 
BaseVariable(const std::string & name,VariableMode mode,base::TimeDelta poll_interval)143   BaseVariable(const std::string& name,
144                VariableMode mode,
145                base::TimeDelta poll_interval)
146       : name_(name),
147         mode_(mode),
148         poll_interval_(mode == kVariableModePoll ? poll_interval
149                                                  : base::TimeDelta()),
150         missing_ok_(false) {}
151 
OnValueChangedNotification()152   void OnValueChangedNotification() {
153     // A ValueChanged() method can change the list of observers, for example
154     // removing itself and invalidating the iterator, so we create a snapshot
155     // of the observers first. Also, to support the case when *another* observer
156     // is removed, we check for them.
157     std::list<BaseVariable::ObserverInterface*> observer_list_copy(
158         observer_list_);
159 
160     for (auto& observer : observer_list_copy) {
161       if (std::find(observer_list_.begin(), observer_list_.end(), observer) !=
162           observer_list_.end()) {
163         observer->ValueChanged(this);
164       }
165     }
166   }
167 
168   // The default PollInterval in minutes.
169   static constexpr int kDefaultPollMinutes = 5;
170 
171   // The variable's name as a string.
172   const std::string name_;
173 
174   // The variable's mode.
175   const VariableMode mode_;
176 
177   // The variable's polling interval for VariableModePoll variable and 0 for
178   // other modes.
179   base::TimeDelta poll_interval_;
180 
181   // The list of value changes observers.
182   std::list<BaseVariable::ObserverInterface*> observer_list_;
183 
184   // Defines whether this variable is expected to have no value.
185   bool missing_ok_;
186 
187   DISALLOW_COPY_AND_ASSIGN(BaseVariable);
188 };
189 
190 // Interface to an Update Manager variable of a given type. Implementation
191 // internals are hidden as protected members, since policies should not be
192 // using them directly.
193 template <typename T>
194 class Variable : public BaseVariable {
195  public:
~Variable()196   ~Variable() override {}
197 
198  protected:
199   // Only allow to get values through the EvaluationContext class and not
200   // directly from the variable.
201   friend class EvaluationContext;
202 
203   // Needed to be able to verify variable contents during unit testing.
204   friend class UmTestUtils;
205   FRIEND_TEST(UmRealRandomProviderTest, GetRandomValues);
206 
Variable(const std::string & name,VariableMode mode)207   Variable(const std::string& name, VariableMode mode)
208       : BaseVariable(name, mode) {}
209 
Variable(const std::string & name,const base::TimeDelta poll_interval)210   Variable(const std::string& name, const base::TimeDelta poll_interval)
211       : BaseVariable(name, poll_interval) {}
212 
213   // Gets the current value of the variable. The current value is copied to a
214   // new object and returned. The caller of this method owns the object and
215   // should delete it.
216   //
217   // In case of and error getting the current value or the |timeout| timeout is
218   // exceeded, a null value is returned and the |errmsg| is set.
219   //
220   // The caller can pass a null value for |errmsg|, in which case the error
221   // message won't be set.
222   virtual const T* GetValue(base::TimeDelta timeout, std::string* errmsg) = 0;
223 
224  private:
225   DISALLOW_COPY_AND_ASSIGN(Variable);
226 };
227 
228 }  // namespace chromeos_update_manager
229 
230 #endif  // UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
231