1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2014 The Android Open Source Project 3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License"); 5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License. 6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at 7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// http://www.apache.org/licenses/LICENSE-2.0 9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software 11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS, 12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and 14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License. 15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 16c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 1748415f1f6c6c356bfa9ac85b76d8ebcf053f7157Gilad Arnold#ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ 1848415f1f6c6c356bfa9ac85b76d8ebcf053f7157Gilad Arnold#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ 19c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 2002f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan#include <memory> 2153556eccd206bacd5c9c8bb6605bcceb1bcb6190Alex Deymo#include <string> 2253556eccd206bacd5c9c8bb6605bcceb1bcb6190Alex Deymo 237b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo#include <base/bind.h> 240bb234147ea8f0247b733375fcf1685eaf329aacAlex Deymo#include <base/location.h> 253f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/message_loops/message_loop.h> 267b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo 2763784a578dd26880454d70797519358a2326291bAlex Deymo#include "update_engine/update_manager/evaluation_context.h" 28c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 2963784a578dd26880454d70797519358a2326291bAlex Deymonamespace chromeos_update_manager { 30c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 31e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymotemplate<typename R, typename... Args> 3263784a578dd26880454d70797519358a2326291bAlex DeymoEvalStatus UpdateManager::EvaluatePolicy( 33e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymo EvaluationContext* ec, 3413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, 3513a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold std::string*, R*, 3613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold Args...) const, 37e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymo R* result, Args... args) { 38fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold // If expiration timeout fired, dump the context and reset expiration. 39fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold // IMPORTANT: We must still proceed with evaluation of the policy in this 40fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold // case, so that the evaluation time (and corresponding reevaluation timeouts) 41fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold // are readjusted. 42fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold if (ec->is_expired()) { 43fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold LOG(WARNING) << "Request timed out, evaluation context: " 44fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold << ec->DumpContext(); 45fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold ec->ResetExpiration(); 46fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold } 47f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold 48f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // Reset the evaluation context. 49f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold ec->ResetEvaluation(); 50c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 51fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold const std::string policy_name = policy_->PolicyRequestName(policy_method); 52fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold LOG(INFO) << policy_name << ": START"; 53c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 54fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold // First try calling the actual policy. 55fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold std::string error; 56fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error, 57fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold result, args...); 58f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // If evaluating the main policy failed, defer to the default policy. 59f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold if (status == EvalStatus::kFailed) { 60fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold LOG(WARNING) << "Evaluating policy failed: " << error 61fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold << "\nEvaluation context: " << ec->DumpContext(); 62fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold error.clear(); 63f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold status = (default_policy_.*policy_method)(ec, state_.get(), &error, result, 64f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold args...); 65fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold if (status == EvalStatus::kFailed) { 66fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold LOG(WARNING) << "Evaluating default policy failed: " << error; 67fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold } else if (status == EvalStatus::kAskMeAgainLater) { 68fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold LOG(ERROR) 69fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold << "Default policy would block; this is a bug, forcing failure."; 70f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold status = EvalStatus::kFailed; 71c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo } 72c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo } 73f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold 74fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold LOG(INFO) << policy_name << ": END"; 75b3b05446d3ef9620c90084e11cd1ae4eca20f4a2Gilad Arnold 76c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo return status; 77c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo} 78c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 79e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymotemplate<typename R, typename... Args> 8063784a578dd26880454d70797519358a2326291bAlex Deymovoid UpdateManager::OnPolicyReadyToEvaluate( 817b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo scoped_refptr<EvaluationContext> ec, 827b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo base::Callback<void(EvalStatus status, const R& result)> callback, 8313a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, 8413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold std::string*, R*, 8513a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold Args...) const, 86e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymo Args... args) { 87f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // Evaluate the policy. 887b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo R result; 899c155d2110381fbf7d8e4b8f840bf54c3008fe0cAlex Vakulenko EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...); 907b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo 917b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo if (status != EvalStatus::kAskMeAgainLater) { 927b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo // AsyncPolicyRequest finished. 937b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo callback.Run(status, result); 947b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo return; 957b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo } 96f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold 9753556eccd206bacd5c9c8bb6605bcceb1bcb6190Alex Deymo // Re-schedule the policy request based on used variables. 98f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold base::Closure reeval_callback = base::Bind( 9963784a578dd26880454d70797519358a2326291bAlex Deymo &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>, 100f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold base::Unretained(this), ec, callback, 101f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold policy_method, args...); 102f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold if (ec->RunOnValueChangeOrTimeout(reeval_callback)) 103f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold return; // Reevaluation scheduled successfully. 104f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold 105f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // Scheduling a reevaluation can fail because policy method didn't use any 106f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // non-const variable nor there's any time-based event that will change the 107f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // status of evaluation. Alternatively, this may indicate an error in the use 108f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold // of the scheduling interface. 109f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold LOG(ERROR) << "Failed to schedule a reevaluation of policy " 110f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold << policy_->PolicyRequestName(policy_method) << "; this is a bug."; 111f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold callback.Run(status, result); 1127b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo} 1137b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo 11413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnoldtemplate<typename R, typename... ActualArgs, typename... ExpectedArgs> 11563784a578dd26880454d70797519358a2326291bAlex DeymoEvalStatus UpdateManager::PolicyRequest( 11613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, 11713a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold std::string*, R*, 11813a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold ExpectedArgs...) const, 11913a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold R* result, ActualArgs... args) { 120b227199133f2d694414293697c67599a761f23beGilad Arnold scoped_refptr<EvaluationContext> ec( 121b227199133f2d694414293697c67599a761f23beGilad Arnold new EvaluationContext(clock_, evaluation_timeout_)); 122072359ca138504065e1e0c1189eb38c09576d324Alex Vakulenko // A PolicyRequest always consists on a single evaluation on a new 1237b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo // EvaluationContext. 12413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we 12513a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold // explicitly instantiate EvaluatePolicy with the latter in lieu of the 12613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold // former. 1279c155d2110381fbf7d8e4b8f840bf54c3008fe0cAlex Vakulenko EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method, 1289c155d2110381fbf7d8e4b8f840bf54c3008fe0cAlex Vakulenko result, args...); 129897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold // Sync policy requests must not block, if they do then this is an error. 130897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold DCHECK(EvalStatus::kAskMeAgainLater != ret); 131897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret) 132f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold << "Sync request used with an async policy; this is a bug"; 133897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold return ret; 1347b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo} 1357b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo 13613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnoldtemplate<typename R, typename... ActualArgs, typename... ExpectedArgs> 13763784a578dd26880454d70797519358a2326291bAlex Deymovoid UpdateManager::AsyncPolicyRequest( 1387b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo base::Callback<void(EvalStatus, const R& result)> callback, 13913a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold EvalStatus (Policy::*policy_method)(EvaluationContext*, State*, 14013a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold std::string*, R*, 14113a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold ExpectedArgs...) const, 14213a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold ActualArgs... args) { 143b227199133f2d694414293697c67599a761f23beGilad Arnold scoped_refptr<EvaluationContext> ec = 14483ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold new EvaluationContext( 14583ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold clock_, evaluation_timeout_, expiration_timeout_, 14602f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan std::unique_ptr<base::Callback<void(EvaluationContext*)>>( 14783ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold new base::Callback<void(EvaluationContext*)>( 14883ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold base::Bind(&UpdateManager::UnregisterEvalContext, 14983ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold weak_ptr_factory_.GetWeakPtr())))); 15083ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold if (!ec_repo_.insert(ec.get()).second) { 15183ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold LOG(ERROR) << "Failed to register evaluation context; this is a bug."; 15283ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold } 15383ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold 15413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we 15563784a578dd26880454d70797519358a2326291bAlex Deymo // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the 15613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold // latter in lieu of the former. 157f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold base::Closure eval_callback = base::Bind( 15863784a578dd26880454d70797519358a2326291bAlex Deymo &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>, 1597b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo base::Unretained(this), ec, callback, policy_method, args...); 1603f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback); 1617b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo} 1627b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo 16363784a578dd26880454d70797519358a2326291bAlex Deymo} // namespace chromeos_update_manager 164c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo 16548415f1f6c6c356bfa9ac85b76d8ebcf053f7157Gilad Arnold#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_ 166