blob: 045ecffa00448ae45a7d7c11d436b09e64bde440 [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);
Alex Deymoc705cc82014-02-19 11:15:00 -080052
Gilad Arnoldfd45a732014-08-07 15:53:46 -070053 // First try calling the actual policy.
54 std::string error;
Amin Hassani4b717432019-01-14 16:24:20 -080055 EvalStatus status = (policy_.get()->*policy_method)(
56 ec, state_.get(), &error, result, args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070057 // If evaluating the main policy failed, defer to the default policy.
Alex Deymoe636c3c2014-03-11 19:02:08 -070058 if (status == EvalStatus::kFailed) {
Gilad Arnoldfd45a732014-08-07 15:53:46 -070059 LOG(WARNING) << "Evaluating policy failed: " << error
60 << "\nEvaluation context: " << ec->DumpContext();
61 error.clear();
Amin Hassani4b717432019-01-14 16:24:20 -080062 status = (default_policy_.*policy_method)(
63 ec, state_.get(), &error, result, args...);
Gilad Arnoldfd45a732014-08-07 15:53:46 -070064 if (status == EvalStatus::kFailed) {
65 LOG(WARNING) << "Evaluating default policy failed: " << error;
66 } else if (status == EvalStatus::kAskMeAgainLater) {
67 LOG(ERROR)
68 << "Default policy would block; this is a bug, forcing failure.";
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070069 status = EvalStatus::kFailed;
Alex Deymoc705cc82014-02-19 11:15:00 -080070 }
71 }
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070072
Alex Deymoc705cc82014-02-19 11:15:00 -080073 return status;
74}
75
Amin Hassani4b717432019-01-14 16:24:20 -080076template <typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070077void UpdateManager::OnPolicyReadyToEvaluate(
Amin Hassania2c8b922019-08-14 19:41:03 -070078 std::shared_ptr<EvaluationContext> ec,
Alex Deymo7b948f02014-03-10 17:01:10 -070079 base::Callback<void(EvalStatus status, const R& result)> callback,
Amin Hassani4b717432019-01-14 16:24:20 -080080 EvalStatus (Policy::*policy_method)(
81 EvaluationContext*, State*, std::string*, R*, Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070082 Args... args) {
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070083 // Evaluate the policy.
Alex Deymo7b948f02014-03-10 17:01:10 -070084 R result;
Alex Vakulenko9c155d22014-12-10 12:52:31 -080085 EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
Alex Deymo7b948f02014-03-10 17:01:10 -070086
87 if (status != EvalStatus::kAskMeAgainLater) {
88 // AsyncPolicyRequest finished.
89 callback.Run(status, result);
90 return;
91 }
Alex Deymo53556ec2014-03-17 10:05:57 -070092
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070093 // Re-schedule the policy request based on used variables.
Amin Hassani4b717432019-01-14 16:24:20 -080094 base::Closure reeval_callback =
95 base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
96 base::Unretained(this),
97 ec,
98 callback,
99 policy_method,
100 args...);
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700101 if (ec->RunOnValueChangeOrTimeout(reeval_callback))
102 return; // Reevaluation scheduled successfully.
103
104 // Scheduling a reevaluation can fail because policy method didn't use any
105 // non-const variable nor there's any time-based event that will change the
106 // status of evaluation. Alternatively, this may indicate an error in the use
107 // of the scheduling interface.
108 LOG(ERROR) << "Failed to schedule a reevaluation of policy "
109 << policy_->PolicyRequestName(policy_method) << "; this is a bug.";
110 callback.Run(status, result);
Alex Deymo7b948f02014-03-10 17:01:10 -0700111}
112
Amin Hassani4b717432019-01-14 16:24:20 -0800113template <typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700114EvalStatus UpdateManager::PolicyRequest(
Amin Hassani4b717432019-01-14 16:24:20 -0800115 EvalStatus (Policy::*policy_method)(
116 EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
117 R* result,
118 ActualArgs... args) {
Amin Hassani0468a762020-11-17 23:53:48 -0800119 auto ec = std::make_shared<EvaluationContext>(evaluation_timeout_);
Alex Vakulenko072359c2014-07-18 11:41:07 -0700120 // A PolicyRequest always consists on a single evaluation on a new
Alex Deymo7b948f02014-03-10 17:01:10 -0700121 // EvaluationContext.
Gilad Arnold13a82432014-05-19 12:52:44 -0700122 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
123 // explicitly instantiate EvaluatePolicy with the latter in lieu of the
124 // former.
Amin Hassani4b717432019-01-14 16:24:20 -0800125 EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(
126 ec.get(), policy_method, result, args...);
Gilad Arnold897b5e52014-05-21 09:37:18 -0700127 // Sync policy requests must not block, if they do then this is an error.
128 DCHECK(EvalStatus::kAskMeAgainLater != ret);
129 LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret)
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700130 << "Sync request used with an async policy; this is a bug";
Gilad Arnold897b5e52014-05-21 09:37:18 -0700131 return ret;
Alex Deymo7b948f02014-03-10 17:01:10 -0700132}
133
Amin Hassani4b717432019-01-14 16:24:20 -0800134template <typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700135void UpdateManager::AsyncPolicyRequest(
Alex Deymo7b948f02014-03-10 17:01:10 -0700136 base::Callback<void(EvalStatus, const R& result)> callback,
Amin Hassani4b717432019-01-14 16:24:20 -0800137 EvalStatus (Policy::*policy_method)(
138 EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
Gilad Arnold13a82432014-05-19 12:52:44 -0700139 ActualArgs... args) {
Amin Hassania2c8b922019-08-14 19:41:03 -0700140 auto ec = std::make_shared<EvaluationContext>(
Amin Hassani4b717432019-01-14 16:24:20 -0800141 evaluation_timeout_,
142 expiration_timeout_,
143 std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
144 new base::Callback<void(EvaluationContext*)>(
145 base::Bind(&UpdateManager::UnregisterEvalContext,
146 weak_ptr_factory_.GetWeakPtr()))));
Amin Hassania2c8b922019-08-14 19:41:03 -0700147 if (!ec_repo_.insert(ec).second) {
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700148 LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
149 }
150
Gilad Arnold13a82432014-05-19 12:52:44 -0700151 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
Alex Deymo63784a52014-05-28 10:46:14 -0700152 // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
Gilad Arnold13a82432014-05-19 12:52:44 -0700153 // latter in lieu of the former.
Amin Hassani4b717432019-01-14 16:24:20 -0800154 base::Closure eval_callback =
155 base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
156 base::Unretained(this),
157 ec,
158 callback,
159 policy_method,
160 args...);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700161 brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
Alex Deymo7b948f02014-03-10 17:01:10 -0700162}
163
Alex Deymo63784a52014-05-28 10:46:14 -0700164} // namespace chromeos_update_manager
Alex Deymoc705cc82014-02-19 11:15:00 -0800165
Gilad Arnold48415f12014-06-27 07:10:58 -0700166#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_