|  | // | 
|  | // Copyright (C) 2014 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | // | 
|  |  | 
|  | #ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ | 
|  | #define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  |  | 
|  | #include <base/bind.h> | 
|  | #include <base/location.h> | 
|  | #include <brillo/message_loops/message_loop.h> | 
|  |  | 
|  | #include "update_engine/update_manager/evaluation_context.h" | 
|  |  | 
|  | namespace chromeos_update_manager { | 
|  |  | 
|  | template<typename R, typename... Args> | 
|  | EvalStatus UpdateManager::EvaluatePolicy( | 
|  | EvaluationContext* ec, | 
|  | EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
|  | std::string*, R*, | 
|  | Args...) const, | 
|  | R* result, Args... args) { | 
|  | // If expiration timeout fired, dump the context and reset expiration. | 
|  | // IMPORTANT: We must still proceed with evaluation of the policy in this | 
|  | // case, so that the evaluation time (and corresponding reevaluation timeouts) | 
|  | // are readjusted. | 
|  | if (ec->is_expired()) { | 
|  | LOG(WARNING) << "Request timed out, evaluation context: " | 
|  | << ec->DumpContext(); | 
|  | ec->ResetExpiration(); | 
|  | } | 
|  |  | 
|  | // Reset the evaluation context. | 
|  | ec->ResetEvaluation(); | 
|  |  | 
|  | const std::string policy_name = policy_->PolicyRequestName(policy_method); | 
|  | LOG(INFO) << policy_name << ": START"; | 
|  |  | 
|  | // First try calling the actual policy. | 
|  | std::string error; | 
|  | EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error, | 
|  | result, args...); | 
|  | // If evaluating the main policy failed, defer to the default policy. | 
|  | if (status == EvalStatus::kFailed) { | 
|  | LOG(WARNING) << "Evaluating policy failed: " << error | 
|  | << "\nEvaluation context: " << ec->DumpContext(); | 
|  | error.clear(); | 
|  | status = (default_policy_.*policy_method)(ec, state_.get(), &error, result, | 
|  | args...); | 
|  | if (status == EvalStatus::kFailed) { | 
|  | LOG(WARNING) << "Evaluating default policy failed: " << error; | 
|  | } else if (status == EvalStatus::kAskMeAgainLater) { | 
|  | LOG(ERROR) | 
|  | << "Default policy would block; this is a bug, forcing failure."; | 
|  | status = EvalStatus::kFailed; | 
|  | } | 
|  | } | 
|  |  | 
|  | LOG(INFO) << policy_name << ": END"; | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | template<typename R, typename... Args> | 
|  | void UpdateManager::OnPolicyReadyToEvaluate( | 
|  | scoped_refptr<EvaluationContext> ec, | 
|  | base::Callback<void(EvalStatus status, const R& result)> callback, | 
|  | EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
|  | std::string*, R*, | 
|  | Args...) const, | 
|  | Args... args) { | 
|  | // Evaluate the policy. | 
|  | R result; | 
|  | EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...); | 
|  |  | 
|  | if (status != EvalStatus::kAskMeAgainLater) { | 
|  | // AsyncPolicyRequest finished. | 
|  | callback.Run(status, result); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Re-schedule the policy request based on used variables. | 
|  | base::Closure reeval_callback = base::Bind( | 
|  | &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>, | 
|  | base::Unretained(this), ec, callback, | 
|  | policy_method, args...); | 
|  | if (ec->RunOnValueChangeOrTimeout(reeval_callback)) | 
|  | return;  // Reevaluation scheduled successfully. | 
|  |  | 
|  | // Scheduling a reevaluation can fail because policy method didn't use any | 
|  | // non-const variable nor there's any time-based event that will change the | 
|  | // status of evaluation.  Alternatively, this may indicate an error in the use | 
|  | // of the scheduling interface. | 
|  | LOG(ERROR) << "Failed to schedule a reevaluation of policy " | 
|  | << policy_->PolicyRequestName(policy_method) << "; this is a bug."; | 
|  | callback.Run(status, result); | 
|  | } | 
|  |  | 
|  | template<typename R, typename... ActualArgs, typename... ExpectedArgs> | 
|  | EvalStatus UpdateManager::PolicyRequest( | 
|  | EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
|  | std::string*, R*, | 
|  | ExpectedArgs...) const, | 
|  | R* result, ActualArgs... args) { | 
|  | scoped_refptr<EvaluationContext> ec( | 
|  | new EvaluationContext(clock_, evaluation_timeout_)); | 
|  | // A PolicyRequest always consists on a single evaluation on a new | 
|  | // EvaluationContext. | 
|  | // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we | 
|  | // explicitly instantiate EvaluatePolicy with the latter in lieu of the | 
|  | // former. | 
|  | EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method, | 
|  | result, args...); | 
|  | // Sync policy requests must not block, if they do then this is an error. | 
|  | DCHECK(EvalStatus::kAskMeAgainLater != ret); | 
|  | LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret) | 
|  | << "Sync request used with an async policy; this is a bug"; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | template<typename R, typename... ActualArgs, typename... ExpectedArgs> | 
|  | void UpdateManager::AsyncPolicyRequest( | 
|  | base::Callback<void(EvalStatus, const R& result)> callback, | 
|  | EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, | 
|  | std::string*, R*, | 
|  | ExpectedArgs...) const, | 
|  | ActualArgs... args) { | 
|  | scoped_refptr<EvaluationContext> ec = | 
|  | new EvaluationContext( | 
|  | clock_, evaluation_timeout_, expiration_timeout_, | 
|  | std::unique_ptr<base::Callback<void(EvaluationContext*)>>( | 
|  | new base::Callback<void(EvaluationContext*)>( | 
|  | base::Bind(&UpdateManager::UnregisterEvalContext, | 
|  | weak_ptr_factory_.GetWeakPtr())))); | 
|  | if (!ec_repo_.insert(ec.get()).second) { | 
|  | LOG(ERROR) << "Failed to register evaluation context; this is a bug."; | 
|  | } | 
|  |  | 
|  | // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we | 
|  | // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the | 
|  | // latter in lieu of the former. | 
|  | base::Closure eval_callback = base::Bind( | 
|  | &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>, | 
|  | base::Unretained(this), ec, callback, policy_method, args...); | 
|  | brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback); | 
|  | } | 
|  |  | 
|  | }  // namespace chromeos_update_manager | 
|  |  | 
|  | #endif  // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ |