blob: 5e3003131ac61535abbb23f8773aca76b071eda7 [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>
12
Alex Deymo63784a52014-05-28 10:46:14 -070013#include "update_engine/update_manager/evaluation_context.h"
14#include "update_engine/update_manager/event_loop.h"
Alex Deymoc705cc82014-02-19 11:15:00 -080015
Alex Deymo63784a52014-05-28 10:46:14 -070016namespace chromeos_update_manager {
Alex Deymoc705cc82014-02-19 11:15:00 -080017
Alex Deymoe75e0252014-04-08 14:00:11 -070018template<typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070019EvalStatus UpdateManager::EvaluatePolicy(
Alex Deymoe75e0252014-04-08 14:00:11 -070020 EvaluationContext* ec,
Gilad Arnold13a82432014-05-19 12:52:44 -070021 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
22 std::string*, R*,
23 Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070024 R* result, Args... args) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070025 // If expiration timeout fired, dump the context and reset expiration.
26 // IMPORTANT: We must still proceed with evaluation of the policy in this
27 // case, so that the evaluation time (and corresponding reevaluation timeouts)
28 // are readjusted.
29 if (ec->is_expired()) {
30 LOG(WARNING) << "Request timed out, evaluation context: "
31 << ec->DumpContext();
32 ec->ResetExpiration();
33 }
Alex Deymoc705cc82014-02-19 11:15:00 -080034
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070035 // Reset the evaluation context.
36 ec->ResetEvaluation();
37
Gilad Arnoldfd45a732014-08-07 15:53:46 -070038 const std::string policy_name = policy_->PolicyRequestName(policy_method);
39 LOG(INFO) << policy_name << ": START";
Alex Deymoc705cc82014-02-19 11:15:00 -080040
Gilad Arnoldfd45a732014-08-07 15:53:46 -070041 // First try calling the actual policy.
42 std::string error;
43 EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error,
44 result, args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070045 // If evaluating the main policy failed, defer to the default policy.
Alex Deymoe636c3c2014-03-11 19:02:08 -070046 if (status == EvalStatus::kFailed) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070047 LOG(WARNING) << "Evaluating policy failed: " << error
48 << "\nEvaluation context: " << ec->DumpContext();
49 error.clear();
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070050 status = (default_policy_.*policy_method)(ec, state_.get(), &error, result,
51 args...);
Gilad Arnoldfd45a732014-08-07 15:53:46 -070052 if (status == EvalStatus::kFailed) {
53 LOG(WARNING) << "Evaluating default policy failed: " << error;
54 } else if (status == EvalStatus::kAskMeAgainLater) {
55 LOG(ERROR)
56 << "Default policy would block; this is a bug, forcing failure.";
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070057 status = EvalStatus::kFailed;
Alex Deymoc705cc82014-02-19 11:15:00 -080058 }
59 }
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070060
Gilad Arnoldfd45a732014-08-07 15:53:46 -070061 LOG(INFO) << policy_name << ": END";
Gilad Arnoldb3b05442014-05-30 14:25:05 -070062
Alex Deymoc705cc82014-02-19 11:15:00 -080063 return status;
64}
65
Alex Deymoe75e0252014-04-08 14:00:11 -070066template<typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070067void UpdateManager::OnPolicyReadyToEvaluate(
Alex Deymo7b948f02014-03-10 17:01:10 -070068 scoped_refptr<EvaluationContext> ec,
69 base::Callback<void(EvalStatus status, const R& result)> callback,
Gilad Arnold13a82432014-05-19 12:52:44 -070070 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
71 std::string*, R*,
72 Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070073 Args... args) {
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070074 // Evaluate the policy.
Alex Deymo7b948f02014-03-10 17:01:10 -070075 R result;
76 EvalStatus status = EvaluatePolicy(ec, policy_method, &result, args...);
77
78 if (status != EvalStatus::kAskMeAgainLater) {
79 // AsyncPolicyRequest finished.
80 callback.Run(status, result);
81 return;
82 }
Alex Deymo53556ec2014-03-17 10:05:57 -070083
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070084 // Re-schedule the policy request based on used variables.
85 base::Closure reeval_callback = base::Bind(
86 &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
87 base::Unretained(this), ec, callback,
88 policy_method, args...);
89 if (ec->RunOnValueChangeOrTimeout(reeval_callback))
90 return; // Reevaluation scheduled successfully.
91
92 // Scheduling a reevaluation can fail because policy method didn't use any
93 // non-const variable nor there's any time-based event that will change the
94 // status of evaluation. Alternatively, this may indicate an error in the use
95 // of the scheduling interface.
96 LOG(ERROR) << "Failed to schedule a reevaluation of policy "
97 << policy_->PolicyRequestName(policy_method) << "; this is a bug.";
98 callback.Run(status, result);
Alex Deymo7b948f02014-03-10 17:01:10 -070099}
100
Gilad Arnold13a82432014-05-19 12:52:44 -0700101template<typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700102EvalStatus UpdateManager::PolicyRequest(
Gilad Arnold13a82432014-05-19 12:52:44 -0700103 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
104 std::string*, R*,
105 ExpectedArgs...) const,
106 R* result, ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700107 scoped_refptr<EvaluationContext> ec(
108 new EvaluationContext(clock_, evaluation_timeout_));
Alex Vakulenko072359c2014-07-18 11:41:07 -0700109 // A PolicyRequest always consists on a single evaluation on a new
Alex Deymo7b948f02014-03-10 17:01:10 -0700110 // EvaluationContext.
Gilad Arnold13a82432014-05-19 12:52:44 -0700111 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
112 // explicitly instantiate EvaluatePolicy with the latter in lieu of the
113 // former.
Gilad Arnold897b5e52014-05-21 09:37:18 -0700114 EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec, policy_method, result,
115 args...);
116 // Sync policy requests must not block, if they do then this is an error.
117 DCHECK(EvalStatus::kAskMeAgainLater != ret);
118 LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret)
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700119 << "Sync request used with an async policy; this is a bug";
Gilad Arnold897b5e52014-05-21 09:37:18 -0700120 return ret;
Alex Deymo7b948f02014-03-10 17:01:10 -0700121}
122
Gilad Arnold13a82432014-05-19 12:52:44 -0700123template<typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700124void UpdateManager::AsyncPolicyRequest(
Alex Deymo7b948f02014-03-10 17:01:10 -0700125 base::Callback<void(EvalStatus, const R& result)> callback,
Gilad Arnold13a82432014-05-19 12:52:44 -0700126 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
127 std::string*, R*,
128 ExpectedArgs...) const,
129 ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700130 scoped_refptr<EvaluationContext> ec =
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700131 new EvaluationContext(
132 clock_, evaluation_timeout_, expiration_timeout_,
Ben Chan02f7c1d2014-10-18 15:18:02 -0700133 std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700134 new base::Callback<void(EvaluationContext*)>(
135 base::Bind(&UpdateManager::UnregisterEvalContext,
136 weak_ptr_factory_.GetWeakPtr()))));
137 if (!ec_repo_.insert(ec.get()).second) {
138 LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
139 }
140
Gilad Arnold13a82432014-05-19 12:52:44 -0700141 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
Alex Deymo63784a52014-05-28 10:46:14 -0700142 // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
Gilad Arnold13a82432014-05-19 12:52:44 -0700143 // latter in lieu of the former.
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700144 base::Closure eval_callback = base::Bind(
Alex Deymo63784a52014-05-28 10:46:14 -0700145 &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
Alex Deymo7b948f02014-03-10 17:01:10 -0700146 base::Unretained(this), ec, callback, policy_method, args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700147 RunFromMainLoop(eval_callback);
Alex Deymo7b948f02014-03-10 17:01:10 -0700148}
149
Alex Deymo63784a52014-05-28 10:46:14 -0700150} // namespace chromeos_update_manager
Alex Deymoc705cc82014-02-19 11:15:00 -0800151
Gilad Arnold48415f12014-06-27 07:10:58 -0700152#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_