blob: e9dee3f20807cae9b63b3ecb976d16d20a00012a [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
Alex Deymoc705cc82014-02-19 11:15:00 -080016
Gilad Arnold48415f12014-06-27 07:10:58 -070017#ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
18#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
Alex Deymoc705cc82014-02-19 11:15:00 -080019
Ben Chan02f7c1d2014-10-18 15:18:02 -070020#include <memory>
Alex Deymo53556ec2014-03-17 10:05:57 -070021#include <string>
22
Alex Deymo7b948f02014-03-10 17:01:10 -070023#include <base/bind.h>
Alex Deymo0bb23412015-06-19 00:04:46 -070024#include <base/location.h>
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070025#include <brillo/message_loops/message_loop.h>
Alex Deymo7b948f02014-03-10 17:01:10 -070026
Alex Deymo63784a52014-05-28 10:46:14 -070027#include "update_engine/update_manager/evaluation_context.h"
Alex Deymoc705cc82014-02-19 11:15:00 -080028
Alex Deymo63784a52014-05-28 10:46:14 -070029namespace chromeos_update_manager {
Alex Deymoc705cc82014-02-19 11:15:00 -080030
Amin Hassani4b717432019-01-14 16:24:20 -080031template <typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070032EvalStatus UpdateManager::EvaluatePolicy(
Alex Deymoe75e0252014-04-08 14:00:11 -070033 EvaluationContext* ec,
Amin Hassani4b717432019-01-14 16:24:20 -080034 EvalStatus (Policy::*policy_method)(
35 EvaluationContext*, State*, std::string*, R*, Args...) const,
36 R* result,
37 Args... args) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070038 // 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 }
Alex Deymoc705cc82014-02-19 11:15:00 -080047
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070048 // Reset the evaluation context.
49 ec->ResetEvaluation();
50
Gilad Arnoldfd45a732014-08-07 15:53:46 -070051 const std::string policy_name = policy_->PolicyRequestName(policy_method);
52 LOG(INFO) << policy_name << ": START";
Alex Deymoc705cc82014-02-19 11:15:00 -080053
Gilad Arnoldfd45a732014-08-07 15:53:46 -070054 // First try calling the actual policy.
55 std::string error;
Amin Hassani4b717432019-01-14 16:24:20 -080056 EvalStatus status = (policy_.get()->*policy_method)(
57 ec, state_.get(), &error, result, args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070058 // If evaluating the main policy failed, defer to the default policy.
Alex Deymoe636c3c2014-03-11 19:02:08 -070059 if (status == EvalStatus::kFailed) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070060 LOG(WARNING) << "Evaluating policy failed: " << error
61 << "\nEvaluation context: " << ec->DumpContext();
62 error.clear();
Amin Hassani4b717432019-01-14 16:24:20 -080063 status = (default_policy_.*policy_method)(
64 ec, state_.get(), &error, result, args...);
Gilad Arnoldfd45a732014-08-07 15:53:46 -070065 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.";
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070070 status = EvalStatus::kFailed;
Alex Deymoc705cc82014-02-19 11:15:00 -080071 }
72 }
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070073
Gilad Arnoldfd45a732014-08-07 15:53:46 -070074 LOG(INFO) << policy_name << ": END";
Gilad Arnoldb3b05442014-05-30 14:25:05 -070075
Alex Deymoc705cc82014-02-19 11:15:00 -080076 return status;
77}
78
Amin Hassani4b717432019-01-14 16:24:20 -080079template <typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070080void UpdateManager::OnPolicyReadyToEvaluate(
Alex Deymo7b948f02014-03-10 17:01:10 -070081 scoped_refptr<EvaluationContext> ec,
82 base::Callback<void(EvalStatus status, const R& result)> callback,
Amin Hassani4b717432019-01-14 16:24:20 -080083 EvalStatus (Policy::*policy_method)(
84 EvaluationContext*, State*, std::string*, R*, Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070085 Args... args) {
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070086 // Evaluate the policy.
Alex Deymo7b948f02014-03-10 17:01:10 -070087 R result;
Alex Vakulenko9c155d22014-12-10 12:52:31 -080088 EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
Alex Deymo7b948f02014-03-10 17:01:10 -070089
90 if (status != EvalStatus::kAskMeAgainLater) {
91 // AsyncPolicyRequest finished.
92 callback.Run(status, result);
93 return;
94 }
Alex Deymo53556ec2014-03-17 10:05:57 -070095
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070096 // Re-schedule the policy request based on used variables.
Amin Hassani4b717432019-01-14 16:24:20 -080097 base::Closure reeval_callback =
98 base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
99 base::Unretained(this),
100 ec,
101 callback,
102 policy_method,
103 args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700104 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);
Alex Deymo7b948f02014-03-10 17:01:10 -0700114}
115
Amin Hassani4b717432019-01-14 16:24:20 -0800116template <typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700117EvalStatus UpdateManager::PolicyRequest(
Amin Hassani4b717432019-01-14 16:24:20 -0800118 EvalStatus (Policy::*policy_method)(
119 EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
120 R* result,
121 ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700122 scoped_refptr<EvaluationContext> ec(
123 new EvaluationContext(clock_, evaluation_timeout_));
Alex Vakulenko072359c2014-07-18 11:41:07 -0700124 // A PolicyRequest always consists on a single evaluation on a new
Alex Deymo7b948f02014-03-10 17:01:10 -0700125 // EvaluationContext.
Gilad Arnold13a82432014-05-19 12:52:44 -0700126 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
127 // explicitly instantiate EvaluatePolicy with the latter in lieu of the
128 // former.
Amin Hassani4b717432019-01-14 16:24:20 -0800129 EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(
130 ec.get(), policy_method, result, args...);
Gilad Arnold897b5e52014-05-21 09:37:18 -0700131 // 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)
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700134 << "Sync request used with an async policy; this is a bug";
Gilad Arnold897b5e52014-05-21 09:37:18 -0700135 return ret;
Alex Deymo7b948f02014-03-10 17:01:10 -0700136}
137
Amin Hassani4b717432019-01-14 16:24:20 -0800138template <typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700139void UpdateManager::AsyncPolicyRequest(
Alex Deymo7b948f02014-03-10 17:01:10 -0700140 base::Callback<void(EvalStatus, const R& result)> callback,
Amin Hassani4b717432019-01-14 16:24:20 -0800141 EvalStatus (Policy::*policy_method)(
142 EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
Gilad Arnold13a82432014-05-19 12:52:44 -0700143 ActualArgs... args) {
Amin Hassani4b717432019-01-14 16:24:20 -0800144 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()))));
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700152 if (!ec_repo_.insert(ec.get()).second) {
153 LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
154 }
155
Gilad Arnold13a82432014-05-19 12:52:44 -0700156 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
Alex Deymo63784a52014-05-28 10:46:14 -0700157 // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
Gilad Arnold13a82432014-05-19 12:52:44 -0700158 // latter in lieu of the former.
Amin Hassani4b717432019-01-14 16:24:20 -0800159 base::Closure eval_callback =
160 base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
161 base::Unretained(this),
162 ec,
163 callback,
164 policy_method,
165 args...);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700166 brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
Alex Deymo7b948f02014-03-10 17:01:10 -0700167}
168
Alex Deymo63784a52014-05-28 10:46:14 -0700169} // namespace chromeos_update_manager
Alex Deymoc705cc82014-02-19 11:15:00 -0800170
Gilad Arnold48415f12014-06-27 07:10:58 -0700171#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_