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
31namespace 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.
35enum 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.
56class BaseVariable {
57 public:
58  // Interface for observing changes on variable value.
59  class ObserverInterface {
60   public:
61    virtual ~ObserverInterface() {}
62
63    // Called when the value on the variable changes.
64    virtual void ValueChanged(BaseVariable* variable) = 0;
65  };
66
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.
77  const std::string& GetName() const {
78    return name_;
79  }
80
81  // Returns the variable mode.
82  VariableMode GetMode() const {
83    return mode_;
84  }
85
86  // For VariableModePoll variables, it returns the polling interval of this
87  // variable. In other case, it returns 0.
88  base::TimeDelta GetPollInterval() const {
89    return poll_interval_;
90  }
91
92  // Adds and removes observers for value changes on the variable. This only
93  // works for kVariableAsync variables since the other modes don't track value
94  // changes. Adding the same observer twice has no effect.
95  virtual void AddObserver(BaseVariable::ObserverInterface* observer) {
96    if (std::find(observer_list_.begin(), observer_list_.end(), observer) ==
97        observer_list_.end()) {
98      observer_list_.push_back(observer);
99    }
100  }
101
102  virtual void RemoveObserver(BaseVariable::ObserverInterface* observer) {
103    observer_list_.remove(observer);
104  }
105
106 protected:
107  // Creates a BaseVariable using the default polling interval (5 minutes).
108  BaseVariable(const std::string& name, VariableMode mode)
109      : BaseVariable(name, mode,
110                     base::TimeDelta::FromMinutes(kDefaultPollMinutes)) {}
111
112  // Creates a BaseVariable with mode kVariableModePoll and the provided
113  // polling interval.
114  BaseVariable(const std::string& name, base::TimeDelta poll_interval)
115      : BaseVariable(name, kVariableModePoll, poll_interval) {}
116
117  // Reset the poll interval on a polling variable to the given one.
118  void SetPollInterval(base::TimeDelta poll_interval) {
119    DCHECK_EQ(kVariableModePoll, mode_) << "Can't set the poll_interval on a "
120                                        << mode_ << " variable";
121    poll_interval_ = poll_interval;
122  }
123
124  // Calls ValueChanged on all the observers.
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
143  BaseVariable(const std::string& name, VariableMode mode,
144               base::TimeDelta poll_interval)
145    : name_(name), mode_(mode),
146      poll_interval_(mode == kVariableModePoll ?
147                     poll_interval : base::TimeDelta()) {}
148
149  void OnValueChangedNotification() {
150    // A ValueChanged() method can change the list of observers, for example
151    // removing itself and invalidating the iterator, so we create a snapshot
152    // of the observers first. Also, to support the case when *another* observer
153    // is removed, we check for them.
154    std::list<BaseVariable::ObserverInterface*> observer_list_copy(
155        observer_list_);
156
157    for (auto& observer : observer_list_copy) {
158      if (std::find(observer_list_.begin(), observer_list_.end(), observer) !=
159          observer_list_.end()) {
160        observer->ValueChanged(this);
161      }
162    }
163  }
164
165  // The default PollInterval in minutes.
166  static constexpr int kDefaultPollMinutes = 5;
167
168  // The variable's name as a string.
169  const std::string name_;
170
171  // The variable's mode.
172  const VariableMode mode_;
173
174  // The variable's polling interval for VariableModePoll variable and 0 for
175  // other modes.
176  base::TimeDelta poll_interval_;
177
178  // The list of value changes observers.
179  std::list<BaseVariable::ObserverInterface*> observer_list_;
180
181  DISALLOW_COPY_AND_ASSIGN(BaseVariable);
182};
183
184// Interface to an Update Manager variable of a given type. Implementation
185// internals are hidden as protected members, since policies should not be
186// using them directly.
187template<typename T>
188class Variable : public BaseVariable {
189 public:
190  ~Variable() override {}
191
192 protected:
193  // Only allow to get values through the EvaluationContext class and not
194  // directly from the variable.
195  friend class EvaluationContext;
196
197  // Needed to be able to verify variable contents during unit testing.
198  friend class UmTestUtils;
199  FRIEND_TEST(UmRealRandomProviderTest, GetRandomValues);
200
201  Variable(const std::string& name, VariableMode mode)
202      : BaseVariable(name, mode) {}
203
204  Variable(const std::string& name, const base::TimeDelta poll_interval)
205      : BaseVariable(name, poll_interval) {}
206
207  // Gets the current value of the variable. The current value is copied to a
208  // new object and returned. The caller of this method owns the object and
209  // should delete it.
210  //
211  // In case of and error getting the current value or the |timeout| timeout is
212  // exceeded, a null value is returned and the |errmsg| is set.
213  //
214  // The caller can pass a null value for |errmsg|, in which case the error
215  // message won't be set.
216  virtual const T* GetValue(base::TimeDelta timeout, std::string* errmsg) = 0;
217
218 private:
219  DISALLOW_COPY_AND_ASSIGN(Variable);
220};
221
222}  // namespace chromeos_update_manager
223
224#endif  // UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
225