| Alex Deymo | aea4c1c | 2015-08-19 20:24:43 -0700 | [diff] [blame] | 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 | // | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 16 |  | 
| Gilad Arnold | 48415f1 | 2014-06-27 07:10:58 -0700 | [diff] [blame] | 17 | #ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ | 
 | 18 | #define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 19 |  | 
| Ben Chan | 02f7c1d | 2014-10-18 15:18:02 -0700 | [diff] [blame] | 20 | #include <memory> | 
| Alex Deymo | 53556ec | 2014-03-17 10:05:57 -0700 | [diff] [blame] | 21 | #include <string> | 
 | 22 |  | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 23 | #include <base/bind.h> | 
| Alex Deymo | 0bb2341 | 2015-06-19 00:04:46 -0700 | [diff] [blame] | 24 | #include <base/location.h> | 
| Alex Vakulenko | 3f39d5c | 2015-10-13 09:27:13 -0700 | [diff] [blame] | 25 | #include <brillo/message_loops/message_loop.h> | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 26 |  | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 27 | #include "update_engine/update_manager/evaluation_context.h" | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 28 |  | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 29 | namespace chromeos_update_manager { | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 30 |  | 
| Alex Deymo | e75e025 | 2014-04-08 14:00:11 -0700 | [diff] [blame] | 31 | template<typename R, typename... Args> | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 32 | EvalStatus UpdateManager::EvaluatePolicy( | 
| Alex Deymo | e75e025 | 2014-04-08 14:00:11 -0700 | [diff] [blame] | 33 |     EvaluationContext* ec, | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 34 |     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
 | 35 |                                         std::string*, R*, | 
 | 36 |                                         Args...) const, | 
| Alex Deymo | e75e025 | 2014-04-08 14:00:11 -0700 | [diff] [blame] | 37 |     R* result, Args... args) { | 
| Gilad Arnold | fd45a73 | 2014-08-07 15:53:46 -0700 | [diff] [blame] | 38 |   // If expiration timeout fired, dump the context and reset expiration. | 
 | 39 |   // IMPORTANT: We must still proceed with evaluation of the policy in this | 
 | 40 |   // case, so that the evaluation time (and corresponding reevaluation timeouts) | 
 | 41 |   // are readjusted. | 
 | 42 |   if (ec->is_expired()) { | 
 | 43 |     LOG(WARNING) << "Request timed out, evaluation context: " | 
 | 44 |                  << ec->DumpContext(); | 
 | 45 |     ec->ResetExpiration(); | 
 | 46 |   } | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 47 |  | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 48 |   // Reset the evaluation context. | 
 | 49 |   ec->ResetEvaluation(); | 
 | 50 |  | 
| Gilad Arnold | fd45a73 | 2014-08-07 15:53:46 -0700 | [diff] [blame] | 51 |   const std::string policy_name = policy_->PolicyRequestName(policy_method); | 
 | 52 |   LOG(INFO) << policy_name << ": START"; | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 53 |  | 
| Gilad Arnold | fd45a73 | 2014-08-07 15:53:46 -0700 | [diff] [blame] | 54 |   // First try calling the actual policy. | 
 | 55 |   std::string error; | 
 | 56 |   EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error, | 
 | 57 |                                                       result, args...); | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 58 |   // If evaluating the main policy failed, defer to the default policy. | 
| Alex Deymo | e636c3c | 2014-03-11 19:02:08 -0700 | [diff] [blame] | 59 |   if (status == EvalStatus::kFailed) { | 
| Gilad Arnold | fd45a73 | 2014-08-07 15:53:46 -0700 | [diff] [blame] | 60 |     LOG(WARNING) << "Evaluating policy failed: " << error | 
 | 61 |                  << "\nEvaluation context: " << ec->DumpContext(); | 
 | 62 |     error.clear(); | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 63 |     status = (default_policy_.*policy_method)(ec, state_.get(), &error, result, | 
 | 64 |                                               args...); | 
| Gilad Arnold | fd45a73 | 2014-08-07 15:53:46 -0700 | [diff] [blame] | 65 |     if (status == EvalStatus::kFailed) { | 
 | 66 |       LOG(WARNING) << "Evaluating default policy failed: " << error; | 
 | 67 |     } else if (status == EvalStatus::kAskMeAgainLater) { | 
 | 68 |       LOG(ERROR) | 
 | 69 |           << "Default policy would block; this is a bug, forcing failure."; | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 70 |       status = EvalStatus::kFailed; | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 71 |     } | 
 | 72 |   } | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 73 |  | 
| Gilad Arnold | fd45a73 | 2014-08-07 15:53:46 -0700 | [diff] [blame] | 74 |   LOG(INFO) << policy_name << ": END"; | 
| Gilad Arnold | b3b0544 | 2014-05-30 14:25:05 -0700 | [diff] [blame] | 75 |  | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 76 |   return status; | 
 | 77 | } | 
 | 78 |  | 
| Alex Deymo | e75e025 | 2014-04-08 14:00:11 -0700 | [diff] [blame] | 79 | template<typename R, typename... Args> | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 80 | void UpdateManager::OnPolicyReadyToEvaluate( | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 81 |     scoped_refptr<EvaluationContext> ec, | 
 | 82 |     base::Callback<void(EvalStatus status, const R& result)> callback, | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 83 |     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
 | 84 |                                         std::string*, R*, | 
 | 85 |                                         Args...) const, | 
| Alex Deymo | e75e025 | 2014-04-08 14:00:11 -0700 | [diff] [blame] | 86 |     Args... args) { | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 87 |   // Evaluate the policy. | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 88 |   R result; | 
| Alex Vakulenko | 9c155d2 | 2014-12-10 12:52:31 -0800 | [diff] [blame] | 89 |   EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...); | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 90 |  | 
 | 91 |   if (status != EvalStatus::kAskMeAgainLater) { | 
 | 92 |     // AsyncPolicyRequest finished. | 
 | 93 |     callback.Run(status, result); | 
 | 94 |     return; | 
 | 95 |   } | 
| Alex Deymo | 53556ec | 2014-03-17 10:05:57 -0700 | [diff] [blame] | 96 |  | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 97 |   // Re-schedule the policy request based on used variables. | 
 | 98 |   base::Closure reeval_callback = base::Bind( | 
 | 99 |       &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>, | 
 | 100 |       base::Unretained(this), ec, callback, | 
 | 101 |       policy_method, args...); | 
 | 102 |   if (ec->RunOnValueChangeOrTimeout(reeval_callback)) | 
 | 103 |     return;  // Reevaluation scheduled successfully. | 
 | 104 |  | 
 | 105 |   // Scheduling a reevaluation can fail because policy method didn't use any | 
 | 106 |   // non-const variable nor there's any time-based event that will change the | 
 | 107 |   // status of evaluation.  Alternatively, this may indicate an error in the use | 
 | 108 |   // of the scheduling interface. | 
 | 109 |   LOG(ERROR) << "Failed to schedule a reevaluation of policy " | 
 | 110 |              << policy_->PolicyRequestName(policy_method) << "; this is a bug."; | 
 | 111 |   callback.Run(status, result); | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 112 | } | 
 | 113 |  | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 114 | template<typename R, typename... ActualArgs, typename... ExpectedArgs> | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 115 | EvalStatus UpdateManager::PolicyRequest( | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 116 |     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
 | 117 |                                         std::string*, R*, | 
 | 118 |                                         ExpectedArgs...) const, | 
 | 119 |     R* result, ActualArgs... args) { | 
| Gilad Arnold | b227199 | 2014-06-19 12:35:24 -0700 | [diff] [blame] | 120 |   scoped_refptr<EvaluationContext> ec( | 
 | 121 |       new EvaluationContext(clock_, evaluation_timeout_)); | 
| Alex Vakulenko | 072359c | 2014-07-18 11:41:07 -0700 | [diff] [blame] | 122 |   // A PolicyRequest always consists on a single evaluation on a new | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 123 |   // EvaluationContext. | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 124 |   // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we | 
 | 125 |   // explicitly instantiate EvaluatePolicy with the latter in lieu of the | 
 | 126 |   // former. | 
| Alex Vakulenko | 9c155d2 | 2014-12-10 12:52:31 -0800 | [diff] [blame] | 127 |   EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method, | 
 | 128 |                                                       result, args...); | 
| Gilad Arnold | 897b5e5 | 2014-05-21 09:37:18 -0700 | [diff] [blame] | 129 |   // Sync policy requests must not block, if they do then this is an error. | 
 | 130 |   DCHECK(EvalStatus::kAskMeAgainLater != ret); | 
 | 131 |   LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret) | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 132 |       << "Sync request used with an async policy; this is a bug"; | 
| Gilad Arnold | 897b5e5 | 2014-05-21 09:37:18 -0700 | [diff] [blame] | 133 |   return ret; | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 134 | } | 
 | 135 |  | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 136 | template<typename R, typename... ActualArgs, typename... ExpectedArgs> | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 137 | void UpdateManager::AsyncPolicyRequest( | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 138 |     base::Callback<void(EvalStatus, const R& result)> callback, | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 139 |     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
 | 140 |                                         std::string*, R*, | 
 | 141 |                                         ExpectedArgs...) const, | 
 | 142 |     ActualArgs... args) { | 
| Gilad Arnold | b227199 | 2014-06-19 12:35:24 -0700 | [diff] [blame] | 143 |   scoped_refptr<EvaluationContext> ec = | 
| Gilad Arnold | 83ffdda | 2014-08-08 13:30:31 -0700 | [diff] [blame] | 144 |       new EvaluationContext( | 
 | 145 |           clock_, evaluation_timeout_, expiration_timeout_, | 
| Ben Chan | 02f7c1d | 2014-10-18 15:18:02 -0700 | [diff] [blame] | 146 |           std::unique_ptr<base::Callback<void(EvaluationContext*)>>( | 
| Gilad Arnold | 83ffdda | 2014-08-08 13:30:31 -0700 | [diff] [blame] | 147 |               new base::Callback<void(EvaluationContext*)>( | 
 | 148 |                   base::Bind(&UpdateManager::UnregisterEvalContext, | 
 | 149 |                              weak_ptr_factory_.GetWeakPtr())))); | 
 | 150 |   if (!ec_repo_.insert(ec.get()).second) { | 
 | 151 |     LOG(ERROR) << "Failed to register evaluation context; this is a bug."; | 
 | 152 |   } | 
 | 153 |  | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 154 |   // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 155 |   // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the | 
| Gilad Arnold | 13a8243 | 2014-05-19 12:52:44 -0700 | [diff] [blame] | 156 |   // latter in lieu of the former. | 
| Gilad Arnold | f9f85d6 | 2014-06-19 18:07:01 -0700 | [diff] [blame] | 157 |   base::Closure eval_callback = base::Bind( | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 158 |       &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>, | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 159 |       base::Unretained(this), ec, callback, policy_method, args...); | 
| Alex Vakulenko | 3f39d5c | 2015-10-13 09:27:13 -0700 | [diff] [blame] | 160 |   brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback); | 
| Alex Deymo | 7b948f0 | 2014-03-10 17:01:10 -0700 | [diff] [blame] | 161 | } | 
 | 162 |  | 
| Alex Deymo | 63784a5 | 2014-05-28 10:46:14 -0700 | [diff] [blame] | 163 | }  // namespace chromeos_update_manager | 
| Alex Deymo | c705cc8 | 2014-02-19 11:15:00 -0800 | [diff] [blame] | 164 |  | 
| Gilad Arnold | 48415f1 | 2014-06-27 07:10:58 -0700 | [diff] [blame] | 165 | #endif  // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ |