blob: b8fef280063510e73901fa7f60b210fc49d82c04 [file] [log] [blame]
Alex Deymoc705cc82014-02-19 11:15:00 -08001// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnold48415f12014-06-27 07:10:58 -07005#ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
6#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
Alex Deymoc705cc82014-02-19 11:15:00 -08007
Ben Chan02f7c1d2014-10-18 15:18:02 -07008#include <memory>
Alex Deymo53556ec2014-03-17 10:05:57 -07009#include <string>
10
Alex Deymo7b948f02014-03-10 17:01:10 -070011#include <base/bind.h>
Alex Deymo0bb23412015-06-19 00:04:46 -070012#include <base/location.h>
Alex Deymo509dd532015-06-10 14:11:05 -070013#include <chromeos/message_loops/message_loop.h>
Alex Deymo7b948f02014-03-10 17:01:10 -070014
Alex Deymo63784a52014-05-28 10:46:14 -070015#include "update_engine/update_manager/evaluation_context.h"
Alex Deymoc705cc82014-02-19 11:15:00 -080016
Alex Deymo63784a52014-05-28 10:46:14 -070017namespace chromeos_update_manager {
Alex Deymoc705cc82014-02-19 11:15:00 -080018
Alex Deymoe75e0252014-04-08 14:00:11 -070019template<typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070020EvalStatus UpdateManager::EvaluatePolicy(
Alex Deymoe75e0252014-04-08 14:00:11 -070021 EvaluationContext* ec,
Gilad Arnold13a82432014-05-19 12:52:44 -070022 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
23 std::string*, R*,
24 Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070025 R* result, Args... args) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070026 // If expiration timeout fired, dump the context and reset expiration.
27 // IMPORTANT: We must still proceed with evaluation of the policy in this
28 // case, so that the evaluation time (and corresponding reevaluation timeouts)
29 // are readjusted.
30 if (ec->is_expired()) {
31 LOG(WARNING) << "Request timed out, evaluation context: "
32 << ec->DumpContext();
33 ec->ResetExpiration();
34 }
Alex Deymoc705cc82014-02-19 11:15:00 -080035
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070036 // Reset the evaluation context.
37 ec->ResetEvaluation();
38
Gilad Arnoldfd45a732014-08-07 15:53:46 -070039 const std::string policy_name = policy_->PolicyRequestName(policy_method);
40 LOG(INFO) << policy_name << ": START";
Alex Deymoc705cc82014-02-19 11:15:00 -080041
Gilad Arnoldfd45a732014-08-07 15:53:46 -070042 // First try calling the actual policy.
43 std::string error;
44 EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error,
45 result, args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070046 // If evaluating the main policy failed, defer to the default policy.
Alex Deymoe636c3c2014-03-11 19:02:08 -070047 if (status == EvalStatus::kFailed) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070048 LOG(WARNING) << "Evaluating policy failed: " << error
49 << "\nEvaluation context: " << ec->DumpContext();
50 error.clear();
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070051 status = (default_policy_.*policy_method)(ec, state_.get(), &error, result,
52 args...);
Gilad Arnoldfd45a732014-08-07 15:53:46 -070053 if (status == EvalStatus::kFailed) {
54 LOG(WARNING) << "Evaluating default policy failed: " << error;
55 } else if (status == EvalStatus::kAskMeAgainLater) {
56 LOG(ERROR)
57 << "Default policy would block; this is a bug, forcing failure.";
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070058 status = EvalStatus::kFailed;
Alex Deymoc705cc82014-02-19 11:15:00 -080059 }
60 }
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070061
Gilad Arnoldfd45a732014-08-07 15:53:46 -070062 LOG(INFO) << policy_name << ": END";
Gilad Arnoldb3b05442014-05-30 14:25:05 -070063
Alex Deymoc705cc82014-02-19 11:15:00 -080064 return status;
65}
66
Alex Deymoe75e0252014-04-08 14:00:11 -070067template<typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070068void UpdateManager::OnPolicyReadyToEvaluate(
Alex Deymo7b948f02014-03-10 17:01:10 -070069 scoped_refptr<EvaluationContext> ec,
70 base::Callback<void(EvalStatus status, const R& result)> callback,
Gilad Arnold13a82432014-05-19 12:52:44 -070071 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
72 std::string*, R*,
73 Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070074 Args... args) {
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070075 // Evaluate the policy.
Alex Deymo7b948f02014-03-10 17:01:10 -070076 R result;
Alex Vakulenko9c155d22014-12-10 12:52:31 -080077 EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
Alex Deymo7b948f02014-03-10 17:01:10 -070078
79 if (status != EvalStatus::kAskMeAgainLater) {
80 // AsyncPolicyRequest finished.
81 callback.Run(status, result);
82 return;
83 }
Alex Deymo53556ec2014-03-17 10:05:57 -070084
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070085 // Re-schedule the policy request based on used variables.
86 base::Closure reeval_callback = base::Bind(
87 &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
88 base::Unretained(this), ec, callback,
89 policy_method, args...);
90 if (ec->RunOnValueChangeOrTimeout(reeval_callback))
91 return; // Reevaluation scheduled successfully.
92
93 // Scheduling a reevaluation can fail because policy method didn't use any
94 // non-const variable nor there's any time-based event that will change the
95 // status of evaluation. Alternatively, this may indicate an error in the use
96 // of the scheduling interface.
97 LOG(ERROR) << "Failed to schedule a reevaluation of policy "
98 << policy_->PolicyRequestName(policy_method) << "; this is a bug.";
99 callback.Run(status, result);
Alex Deymo7b948f02014-03-10 17:01:10 -0700100}
101
Gilad Arnold13a82432014-05-19 12:52:44 -0700102template<typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700103EvalStatus UpdateManager::PolicyRequest(
Gilad Arnold13a82432014-05-19 12:52:44 -0700104 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
105 std::string*, R*,
106 ExpectedArgs...) const,
107 R* result, ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700108 scoped_refptr<EvaluationContext> ec(
109 new EvaluationContext(clock_, evaluation_timeout_));
Alex Vakulenko072359c2014-07-18 11:41:07 -0700110 // A PolicyRequest always consists on a single evaluation on a new
Alex Deymo7b948f02014-03-10 17:01:10 -0700111 // EvaluationContext.
Gilad Arnold13a82432014-05-19 12:52:44 -0700112 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
113 // explicitly instantiate EvaluatePolicy with the latter in lieu of the
114 // former.
Alex Vakulenko9c155d22014-12-10 12:52:31 -0800115 EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method,
116 result, args...);
Gilad Arnold897b5e52014-05-21 09:37:18 -0700117 // Sync policy requests must not block, if they do then this is an error.
118 DCHECK(EvalStatus::kAskMeAgainLater != ret);
119 LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret)
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700120 << "Sync request used with an async policy; this is a bug";
Gilad Arnold897b5e52014-05-21 09:37:18 -0700121 return ret;
Alex Deymo7b948f02014-03-10 17:01:10 -0700122}
123
Gilad Arnold13a82432014-05-19 12:52:44 -0700124template<typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700125void UpdateManager::AsyncPolicyRequest(
Alex Deymo7b948f02014-03-10 17:01:10 -0700126 base::Callback<void(EvalStatus, const R& result)> callback,
Gilad Arnold13a82432014-05-19 12:52:44 -0700127 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
128 std::string*, R*,
129 ExpectedArgs...) const,
130 ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700131 scoped_refptr<EvaluationContext> ec =
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700132 new EvaluationContext(
133 clock_, evaluation_timeout_, expiration_timeout_,
Ben Chan02f7c1d2014-10-18 15:18:02 -0700134 std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700135 new base::Callback<void(EvaluationContext*)>(
136 base::Bind(&UpdateManager::UnregisterEvalContext,
137 weak_ptr_factory_.GetWeakPtr()))));
138 if (!ec_repo_.insert(ec.get()).second) {
139 LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
140 }
141
Gilad Arnold13a82432014-05-19 12:52:44 -0700142 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
Alex Deymo63784a52014-05-28 10:46:14 -0700143 // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
Gilad Arnold13a82432014-05-19 12:52:44 -0700144 // latter in lieu of the former.
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700145 base::Closure eval_callback = base::Bind(
Alex Deymo63784a52014-05-28 10:46:14 -0700146 &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
Alex Deymo7b948f02014-03-10 17:01:10 -0700147 base::Unretained(this), ec, callback, policy_method, args...);
Alex Deymo0bb23412015-06-19 00:04:46 -0700148 chromeos::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
Alex Deymo7b948f02014-03-10 17:01:10 -0700149}
150
Alex Deymo63784a52014-05-28 10:46:14 -0700151} // namespace chromeos_update_manager
Alex Deymoc705cc82014-02-19 11:15:00 -0800152
Gilad Arnold48415f12014-06-27 07:10:58 -0700153#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_