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_UPDATE_MANAGER_H_
18 #define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
19 
20 #include <memory>
21 #include <set>
22 #include <string>
23 
24 #include <base/callback.h>
25 #include <base/time/time.h>
26 
27 #include "update_engine/common/clock_interface.h"
28 #include "update_engine/update_manager/default_policy.h"
29 #include "update_engine/update_manager/evaluation_context.h"
30 #include "update_engine/update_manager/policy.h"
31 #include "update_engine/update_manager/state.h"
32 
33 namespace chromeos_update_manager {
34 
35 // Please do not move this class into a new file for simplicity.
36 // This pure virtual class is purely created for purpose of testing. The reason
37 // was that |UpdateManager|'s member functions are templatized, which does not
38 // play nicely when testing (mocking + faking). Whenever a specialized member of
39 // |UpdateManager| must be tested, please add a specialized template member
40 // function within this class for testing.
41 class SpecializedPolicyRequestInterface {
42  public:
43   virtual ~SpecializedPolicyRequestInterface() = default;
44 
45   virtual void AsyncPolicyRequestUpdateCheckAllowed(
46       base::Callback<void(EvalStatus, const UpdateCheckParams& result)>
47           callback,
48       EvalStatus (Policy::*policy_method)(EvaluationContext*,
49                                           State*,
50                                           std::string*,
51                                           UpdateCheckParams*) const) = 0;
52 };
53 
54 // The main Update Manager singleton class.
55 class UpdateManager : public SpecializedPolicyRequestInterface {
56  public:
57   // Creates the UpdateManager instance, assuming ownership on the provided
58   // |state|.
59   UpdateManager(chromeos_update_engine::ClockInterface* clock,
60                 base::TimeDelta evaluation_timeout,
61                 base::TimeDelta expiration_timeout,
62                 State* state);
63 
64   virtual ~UpdateManager();
65 
66   // PolicyRequest() evaluates the given policy with the provided arguments and
67   // returns the result. The |policy_method| is the pointer-to-method of the
68   // Policy class for the policy request to call. The UpdateManager will call
69   // this method on the right policy. The pointer |result| must not be null
70   // and the remaining |args| depend on the arguments required by the passed
71   // |policy_method|.
72   //
73   // When the policy request succeeds, the |result| is set and the method
74   // returns EvalStatus::kSucceeded, otherwise, the |result| may not be set.  A
75   // policy called with this method should not block (i.e. return
76   // EvalStatus::kAskMeAgainLater), which is considered a programming error. On
77   // failure, EvalStatus::kFailed is returned.
78   //
79   // An example call to this method is:
80   //   um.PolicyRequest(&Policy::SomePolicyMethod, &bool_result, arg1, arg2);
81   template <typename R, typename... ActualArgs, typename... ExpectedArgs>
82   EvalStatus PolicyRequest(
83       EvalStatus (Policy::*policy_method)(
84           EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
85       R* result,
86       ActualArgs...);
87 
88   // Evaluates the given |policy_method| policy with the provided |args|
89   // arguments and calls the |callback| callback with the result when done.
90   //
91   // If the policy implementation should block, returning a
92   // EvalStatus::kAskMeAgainLater status the Update Manager will re-evaluate the
93   // policy until another status is returned. If the policy implementation based
94   // its return value solely on const variables, the callback will be called
95   // with the EvalStatus::kAskMeAgainLater status (which indicates an error).
96   template <typename R, typename... ActualArgs, typename... ExpectedArgs>
97   void AsyncPolicyRequest(
98       base::Callback<void(EvalStatus, const R& result)> callback,
99       EvalStatus (Policy::*policy_method)(
100           EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
101       ActualArgs... args);
102 
103   void AsyncPolicyRequestUpdateCheckAllowed(
104       base::Callback<void(EvalStatus, const UpdateCheckParams& result)>
105           callback,
106       EvalStatus (Policy::*policy_method)(EvaluationContext*,
107                                           State*,
108                                           std::string*,
109                                           UpdateCheckParams*) const) override;
110 
111  protected:
112   // The UpdateManager receives ownership of the passed Policy instance.
set_policy(const Policy * policy)113   void set_policy(const Policy* policy) { policy_.reset(policy); }
114 
115   // State getter used for testing.
state()116   State* state() { return state_.get(); }
117 
118  private:
119   FRIEND_TEST(UmUpdateManagerTest, PolicyRequestCallsPolicy);
120   FRIEND_TEST(UmUpdateManagerTest, PolicyRequestCallsDefaultOnError);
121   FRIEND_TEST(UmUpdateManagerTest, PolicyRequestDoesntBlockDeathTest);
122   FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestDelaysEvaluation);
123   FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestTimeoutDoesNotFire);
124   FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestTimesOut);
125 
126   // EvaluatePolicy() evaluates the passed |policy_method| method on the current
127   // policy with the given |args| arguments. If the method fails, the default
128   // policy is used instead.
129   template <typename R, typename... Args>
130   EvalStatus EvaluatePolicy(
131       EvaluationContext* ec,
132       EvalStatus (Policy::*policy_method)(
133           EvaluationContext*, State*, std::string*, R*, Args...) const,
134       R* result,
135       Args... args);
136 
137   // OnPolicyReadyToEvaluate() is called by the main loop when the evaluation
138   // of the given |policy_method| should be executed. If the evaluation finishes
139   // the |callback| callback is called passing the |result| and the |status|
140   // returned by the policy. If the evaluation returns an
141   // EvalStatus::kAskMeAgainLater state, the |callback| will NOT be called and
142   // the evaluation will be re-scheduled to be called later.
143   template <typename R, typename... Args>
144   void OnPolicyReadyToEvaluate(
145       std::shared_ptr<EvaluationContext> ec,
146       base::Callback<void(EvalStatus status, const R& result)> callback,
147       EvalStatus (Policy::*policy_method)(
148           EvaluationContext*, State*, std::string*, R*, Args...) const,
149       Args... args);
150 
151   // Unregisters (removes from repo) a previously created EvaluationContext.
152   void UnregisterEvalContext(EvaluationContext* ec);
153 
154   // The policy used by the UpdateManager. Note that since it is a const Policy,
155   // policy implementations are not allowed to persist state on this class.
156   std::unique_ptr<const Policy> policy_;
157 
158   // A safe default value to the current policy. This policy is used whenever
159   // a policy implementation fails with EvalStatus::kFailed.
160   const DefaultPolicy default_policy_;
161 
162   // State Providers.
163   std::unique_ptr<State> state_;
164 
165   // Pointer to the mockable clock interface;
166   chromeos_update_engine::ClockInterface* clock_;
167 
168   // Timeout for a policy evaluation.
169   const base::TimeDelta evaluation_timeout_;
170 
171   // Timeout for expiration of the evaluation context, used for async requests.
172   const base::TimeDelta expiration_timeout_;
173 
174   // Repository of previously created EvaluationContext objects. These are being
175   // unregistered (and the reference released) when the context is being
176   // destructed; alternatively, when the UpdateManager instance is destroyed, it
177   // will remove all pending events associated with all outstanding contexts
178   // (which should, in turn, trigger their destruction).
179   std::set<std::shared_ptr<EvaluationContext>> ec_repo_;
180 
181   base::WeakPtrFactory<UpdateManager> weak_ptr_factory_;
182 
183   DISALLOW_COPY_AND_ASSIGN(UpdateManager);
184 };
185 
186 }  // namespace chromeos_update_manager
187 
188 // Include the implementation of the template methods.
189 #include "update_engine/update_manager/update_manager-inl.h"
190 
191 #endif  // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
192