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_INL_H_ 18 #define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ 19 20 #include <memory> 21 #include <string> 22 23 #include <base/bind.h> 24 #include <base/location.h> 25 #include <brillo/message_loops/message_loop.h> 26 27 #include "update_engine/update_manager/evaluation_context.h" 28 29 namespace chromeos_update_manager { 30 31 template <typename R, typename... Args> 32 EvalStatus UpdateManager::EvaluatePolicy( 33 EvaluationContext* ec, 34 EvalStatus (Policy::*policy_method)( 35 EvaluationContext*, State*, std::string*, R*, Args...) const, 36 R* result, 37 Args... args) { 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 } 47 48 // Reset the evaluation context. 49 ec->ResetEvaluation(); 50 51 const std::string policy_name = policy_->PolicyRequestName(policy_method); 52 LOG(INFO) << policy_name << ": START"; 53 54 // First try calling the actual policy. 55 std::string error; 56 EvalStatus status = (policy_.get()->*policy_method)( 57 ec, state_.get(), &error, result, args...); 58 // If evaluating the main policy failed, defer to the default policy. 59 if (status == EvalStatus::kFailed) { 60 LOG(WARNING) << "Evaluating policy failed: " << error 61 << "\nEvaluation context: " << ec->DumpContext(); 62 error.clear(); 63 status = (default_policy_.*policy_method)( 64 ec, state_.get(), &error, result, args...); 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."; 70 status = EvalStatus::kFailed; 71 } 72 } 73 74 LOG(INFO) << policy_name << ": END"; 75 76 return status; 77 } 78 79 template <typename R, typename... Args> 80 void UpdateManager::OnPolicyReadyToEvaluate( 81 scoped_refptr<EvaluationContext> ec, 82 base::Callback<void(EvalStatus status, const R& result)> callback, 83 EvalStatus (Policy::*policy_method)( 84 EvaluationContext*, State*, std::string*, R*, Args...) const, 85 Args... args) { 86 // Evaluate the policy. 87 R result; 88 EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...); 89 90 if (status != EvalStatus::kAskMeAgainLater) { 91 // AsyncPolicyRequest finished. 92 callback.Run(status, result); 93 return; 94 } 95 96 // Re-schedule the policy request based on used variables. 97 base::Closure reeval_callback = 98 base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, Args...>, 99 base::Unretained(this), 100 ec, 101 callback, 102 policy_method, 103 args...); 104 if (ec->RunOnValueChangeOrTimeout(reeval_callback)) 105 return; // Reevaluation scheduled successfully. 106 107 // Scheduling a reevaluation can fail because policy method didn't use any 108 // non-const variable nor there's any time-based event that will change the 109 // status of evaluation. Alternatively, this may indicate an error in the use 110 // of the scheduling interface. 111 LOG(ERROR) << "Failed to schedule a reevaluation of policy " 112 << policy_->PolicyRequestName(policy_method) << "; this is a bug."; 113 callback.Run(status, result); 114 } 115 116 template <typename R, typename... ActualArgs, typename... ExpectedArgs> 117 EvalStatus UpdateManager::PolicyRequest( 118 EvalStatus (Policy::*policy_method)( 119 EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const, 120 R* result, 121 ActualArgs... args) { 122 scoped_refptr<EvaluationContext> ec( 123 new EvaluationContext(clock_, evaluation_timeout_)); 124 // A PolicyRequest always consists on a single evaluation on a new 125 // EvaluationContext. 126 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we 127 // explicitly instantiate EvaluatePolicy with the latter in lieu of the 128 // former. 129 EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>( 130 ec.get(), policy_method, result, args...); 131 // Sync policy requests must not block, if they do then this is an error. 132 DCHECK(EvalStatus::kAskMeAgainLater != ret); 133 LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret) 134 << "Sync request used with an async policy; this is a bug"; 135 return ret; 136 } 137 138 template <typename R, typename... ActualArgs, typename... ExpectedArgs> 139 void UpdateManager::AsyncPolicyRequest( 140 base::Callback<void(EvalStatus, const R& result)> callback, 141 EvalStatus (Policy::*policy_method)( 142 EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const, 143 ActualArgs... args) { 144 scoped_refptr<EvaluationContext> ec = new EvaluationContext( 145 clock_, 146 evaluation_timeout_, 147 expiration_timeout_, 148 std::unique_ptr<base::Callback<void(EvaluationContext*)>>( 149 new base::Callback<void(EvaluationContext*)>( 150 base::Bind(&UpdateManager::UnregisterEvalContext, 151 weak_ptr_factory_.GetWeakPtr())))); 152 if (!ec_repo_.insert(ec.get()).second) { 153 LOG(ERROR) << "Failed to register evaluation context; this is a bug."; 154 } 155 156 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we 157 // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the 158 // latter in lieu of the former. 159 base::Closure eval_callback = 160 base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>, 161 base::Unretained(this), 162 ec, 163 callback, 164 policy_method, 165 args...); 166 brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback); 167 } 168 169 } // namespace chromeos_update_manager 170 171 #endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ 172