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  // Calls ValueChanged on all the observers.
118  void NotifyValueChanged() {
119    // Fire all the observer methods from the main loop as single call. In order
120    // to avoid scheduling these callbacks when it is not needed, we check
121    // first the list of observers.
122    if (!observer_list_.empty()) {
123      brillo::MessageLoop::current()->PostTask(
124          FROM_HERE,
125          base::Bind(&BaseVariable::OnValueChangedNotification,
126                     base::Unretained(this)));
127    }
128  }
129
130 private:
131  friend class UmEvaluationContextTest;
132  FRIEND_TEST(UmBaseVariableTest, RepeatedObserverTest);
133  FRIEND_TEST(UmBaseVariableTest, NotifyValueChangedTest);
134  FRIEND_TEST(UmBaseVariableTest, NotifyValueRemovesObserversTest);
135
136  BaseVariable(const std::string& name, VariableMode mode,
137               base::TimeDelta poll_interval)
138    : name_(name), mode_(mode),
139      poll_interval_(mode == kVariableModePoll ?
140                     poll_interval : base::TimeDelta()) {}
141
142  void OnValueChangedNotification() {
143    // A ValueChanged() method can change the list of observers, for example
144    // removing itself and invalidating the iterator, so we create a snapshot
145    // of the observers first. Also, to support the case when *another* observer
146    // is removed, we check for them.
147    std::list<BaseVariable::ObserverInterface*> observer_list_copy(
148        observer_list_);
149
150    for (auto& observer : observer_list_copy) {
151      if (std::find(observer_list_.begin(), observer_list_.end(), observer) !=
152          observer_list_.end()) {
153        observer->ValueChanged(this);
154      }
155    }
156  }
157
158  // The default PollInterval in minutes.
159  static constexpr int kDefaultPollMinutes = 5;
160
161  // The variable's name as a string.
162  const std::string name_;
163
164  // The variable's mode.
165  const VariableMode mode_;
166
167  // The variable's polling interval for VariableModePoll variable and 0 for
168  // other modes.
169  const base::TimeDelta poll_interval_;
170
171  // The list of value changes observers.
172  std::list<BaseVariable::ObserverInterface*> observer_list_;
173
174  DISALLOW_COPY_AND_ASSIGN(BaseVariable);
175};
176
177// Interface to an Update Manager variable of a given type. Implementation
178// internals are hidden as protected members, since policies should not be
179// using them directly.
180template<typename T>
181class Variable : public BaseVariable {
182 public:
183  ~Variable() override {}
184
185 protected:
186  // Only allow to get values through the EvaluationContext class and not
187  // directly from the variable.
188  friend class EvaluationContext;
189
190  // Needed to be able to verify variable contents during unit testing.
191  friend class UmTestUtils;
192  FRIEND_TEST(UmRealRandomProviderTest, GetRandomValues);
193
194  Variable(const std::string& name, VariableMode mode)
195      : BaseVariable(name, mode) {}
196
197  Variable(const std::string& name, const base::TimeDelta poll_interval)
198      : BaseVariable(name, poll_interval) {}
199
200  // Gets the current value of the variable. The current value is copied to a
201  // new object and returned. The caller of this method owns the object and
202  // should delete it.
203  //
204  // In case of and error getting the current value or the |timeout| timeout is
205  // exceeded, a null value is returned and the |errmsg| is set.
206  //
207  // The caller can pass a null value for |errmsg|, in which case the error
208  // message won't be set.
209  virtual const T* GetValue(base::TimeDelta timeout, std::string* errmsg) = 0;
210
211 private:
212  DISALLOW_COPY_AND_ASSIGN(Variable);
213};
214
215}  // namespace chromeos_update_manager
216
217#endif  // UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
218