blob: 77224cfb3aa4defadabc3ba1c708033dd9eeefab [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
Alex Deymoe75e0252014-04-08 14:00:11 -070031template<typename R, typename... Args>
Alex Deymo63784a52014-05-28 10:46:14 -070032EvalStatus UpdateManager::EvaluatePolicy(
Alex Deymoe75e0252014-04-08 14:00:11 -070033 EvaluationContext* ec,
Gilad Arnold13a82432014-05-19 12:52:44 -070034 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
35 std::string*, R*,
36 Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070037 R* result, 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;
56 EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error,
57 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();
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070063 status = (default_policy_.*policy_method)(ec, state_.get(), &error, result,
64 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
Alex Deymoe75e0252014-04-08 14:00:11 -070079template<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,
Gilad Arnold13a82432014-05-19 12:52:44 -070083 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
84 std::string*, R*,
85 Args...) const,
Alex Deymoe75e0252014-04-08 14:00:11 -070086 Args... args) {
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070087 // Evaluate the policy.
Alex Deymo7b948f02014-03-10 17:01:10 -070088 R result;
Alex Vakulenko9c155d22014-12-10 12:52:31 -080089 EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
Alex Deymo7b948f02014-03-10 17:01:10 -070090
91 if (status != EvalStatus::kAskMeAgainLater) {
92 // AsyncPolicyRequest finished.
93 callback.Run(status, result);
94 return;
95 }
Alex Deymo53556ec2014-03-17 10:05:57 -070096
Gilad Arnoldf9f85d62014-06-19 18:07:01 -070097 // Re-schedule the policy request based on used variables.
98 base::Closure reeval_callback = base::Bind(
99 &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
100 base::Unretained(this), ec, callback,
101 policy_method, args...);
102 if (ec->RunOnValueChangeOrTimeout(reeval_callback))
103 return; // Reevaluation scheduled successfully.
104
105 // Scheduling a reevaluation can fail because policy method didn't use any
106 // non-const variable nor there's any time-based event that will change the
107 // status of evaluation. Alternatively, this may indicate an error in the use
108 // of the scheduling interface.
109 LOG(ERROR) << "Failed to schedule a reevaluation of policy "
110 << policy_->PolicyRequestName(policy_method) << "; this is a bug.";
111 callback.Run(status, result);
Alex Deymo7b948f02014-03-10 17:01:10 -0700112}
113
Gilad Arnold13a82432014-05-19 12:52:44 -0700114template<typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700115EvalStatus UpdateManager::PolicyRequest(
Gilad Arnold13a82432014-05-19 12:52:44 -0700116 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
117 std::string*, R*,
118 ExpectedArgs...) const,
119 R* result, ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700120 scoped_refptr<EvaluationContext> ec(
121 new EvaluationContext(clock_, evaluation_timeout_));
Alex Vakulenko072359c2014-07-18 11:41:07 -0700122 // A PolicyRequest always consists on a single evaluation on a new
Alex Deymo7b948f02014-03-10 17:01:10 -0700123 // EvaluationContext.
Gilad Arnold13a82432014-05-19 12:52:44 -0700124 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
125 // explicitly instantiate EvaluatePolicy with the latter in lieu of the
126 // former.
Alex Vakulenko9c155d22014-12-10 12:52:31 -0800127 EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method,
128 result, args...);
Gilad Arnold897b5e52014-05-21 09:37:18 -0700129 // Sync policy requests must not block, if they do then this is an error.
130 DCHECK(EvalStatus::kAskMeAgainLater != ret);
131 LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret)
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700132 << "Sync request used with an async policy; this is a bug";
Gilad Arnold897b5e52014-05-21 09:37:18 -0700133 return ret;
Alex Deymo7b948f02014-03-10 17:01:10 -0700134}
135
Gilad Arnold13a82432014-05-19 12:52:44 -0700136template<typename R, typename... ActualArgs, typename... ExpectedArgs>
Alex Deymo63784a52014-05-28 10:46:14 -0700137void UpdateManager::AsyncPolicyRequest(
Alex Deymo7b948f02014-03-10 17:01:10 -0700138 base::Callback<void(EvalStatus, const R& result)> callback,
Gilad Arnold13a82432014-05-19 12:52:44 -0700139 EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
140 std::string*, R*,
141 ExpectedArgs...) const,
142 ActualArgs... args) {
Gilad Arnoldb2271992014-06-19 12:35:24 -0700143 scoped_refptr<EvaluationContext> ec =
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700144 new EvaluationContext(
145 clock_, evaluation_timeout_, expiration_timeout_,
Ben Chan02f7c1d2014-10-18 15:18:02 -0700146 std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
Gilad Arnold83ffdda2014-08-08 13:30:31 -0700147 new base::Callback<void(EvaluationContext*)>(
148 base::Bind(&UpdateManager::UnregisterEvalContext,
149 weak_ptr_factory_.GetWeakPtr()))));
150 if (!ec_repo_.insert(ec.get()).second) {
151 LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
152 }
153
Gilad Arnold13a82432014-05-19 12:52:44 -0700154 // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
Alex Deymo63784a52014-05-28 10:46:14 -0700155 // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
Gilad Arnold13a82432014-05-19 12:52:44 -0700156 // latter in lieu of the former.
Gilad Arnoldf9f85d62014-06-19 18:07:01 -0700157 base::Closure eval_callback = base::Bind(
Alex Deymo63784a52014-05-28 10:46:14 -0700158 &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
Alex Deymo7b948f02014-03-10 17:01:10 -0700159 base::Unretained(this), ec, callback, policy_method, args...);
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700160 brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
Alex Deymo7b948f02014-03-10 17:01:10 -0700161}
162
Alex Deymo63784a52014-05-28 10:46:14 -0700163} // namespace chromeos_update_manager
Alex Deymoc705cc82014-02-19 11:15:00 -0800164
Gilad Arnold48415f12014-06-27 07:10:58 -0700165#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_