Home | History | Annotate | Download | only in update_manager
      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:
     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.
    187 template<typename T>
    188 class 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