1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2014 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
16c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
1748415f1f6c6c356bfa9ac85b76d8ebcf053f7157Gilad Arnold#ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
1848415f1f6c6c356bfa9ac85b76d8ebcf053f7157Gilad Arnold#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
19c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
2002f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan#include <memory>
2153556eccd206bacd5c9c8bb6605bcceb1bcb6190Alex Deymo#include <string>
2253556eccd206bacd5c9c8bb6605bcceb1bcb6190Alex Deymo
237b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo#include <base/bind.h>
240bb234147ea8f0247b733375fcf1685eaf329aacAlex Deymo#include <base/location.h>
253f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/message_loops/message_loop.h>
267b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo
2763784a578dd26880454d70797519358a2326291bAlex Deymo#include "update_engine/update_manager/evaluation_context.h"
28c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
2963784a578dd26880454d70797519358a2326291bAlex Deymonamespace chromeos_update_manager {
30c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
31e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymotemplate<typename R, typename... Args>
3263784a578dd26880454d70797519358a2326291bAlex DeymoEvalStatus UpdateManager::EvaluatePolicy(
33e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymo    EvaluationContext* ec,
3413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
3513a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        std::string*, R*,
3613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        Args...) const,
37e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymo    R* result, Args... args) {
38fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  // If expiration timeout fired, dump the context and reset expiration.
39fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  // IMPORTANT: We must still proceed with evaluation of the policy in this
40fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  // case, so that the evaluation time (and corresponding reevaluation timeouts)
41fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  // are readjusted.
42fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  if (ec->is_expired()) {
43fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold    LOG(WARNING) << "Request timed out, evaluation context: "
44fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold                 << ec->DumpContext();
45fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold    ec->ResetExpiration();
46fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  }
47f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold
48f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // Reset the evaluation context.
49f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  ec->ResetEvaluation();
50c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
51fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  const std::string policy_name = policy_->PolicyRequestName(policy_method);
52fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  LOG(INFO) << policy_name << ": START";
53c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
54fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  // First try calling the actual policy.
55fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  std::string error;
56fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error,
57fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold                                                      result, args...);
58f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // If evaluating the main policy failed, defer to the default policy.
59f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  if (status == EvalStatus::kFailed) {
60fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold    LOG(WARNING) << "Evaluating policy failed: " << error
61fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold                 << "\nEvaluation context: " << ec->DumpContext();
62fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold    error.clear();
63f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold    status = (default_policy_.*policy_method)(ec, state_.get(), &error, result,
64f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold                                              args...);
65fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold    if (status == EvalStatus::kFailed) {
66fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold      LOG(WARNING) << "Evaluating default policy failed: " << error;
67fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold    } else if (status == EvalStatus::kAskMeAgainLater) {
68fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold      LOG(ERROR)
69fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold          << "Default policy would block; this is a bug, forcing failure.";
70f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold      status = EvalStatus::kFailed;
71c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo    }
72c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo  }
73f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold
74fd45a731d9f9176ce134b34e2a84acc0cf403d1dGilad Arnold  LOG(INFO) << policy_name << ": END";
75b3b05446d3ef9620c90084e11cd1ae4eca20f4a2Gilad Arnold
76c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo  return status;
77c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo}
78c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
79e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymotemplate<typename R, typename... Args>
8063784a578dd26880454d70797519358a2326291bAlex Deymovoid UpdateManager::OnPolicyReadyToEvaluate(
817b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo    scoped_refptr<EvaluationContext> ec,
827b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo    base::Callback<void(EvalStatus status, const R& result)> callback,
8313a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
8413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        std::string*, R*,
8513a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        Args...) const,
86e75e02563ddd1c48db5489149bd935efc62551a4Alex Deymo    Args... args) {
87f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // Evaluate the policy.
887b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo  R result;
899c155d2110381fbf7d8e4b8f840bf54c3008fe0cAlex Vakulenko  EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
907b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo
917b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo  if (status != EvalStatus::kAskMeAgainLater) {
927b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo    // AsyncPolicyRequest finished.
937b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo    callback.Run(status, result);
947b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo    return;
957b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo  }
96f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold
9753556eccd206bacd5c9c8bb6605bcceb1bcb6190Alex Deymo  // Re-schedule the policy request based on used variables.
98f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  base::Closure reeval_callback = base::Bind(
9963784a578dd26880454d70797519358a2326291bAlex Deymo      &UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
100f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold      base::Unretained(this), ec, callback,
101f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold      policy_method, args...);
102f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  if (ec->RunOnValueChangeOrTimeout(reeval_callback))
103f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold    return;  // Reevaluation scheduled successfully.
104f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold
105f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // Scheduling a reevaluation can fail because policy method didn't use any
106f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // non-const variable nor there's any time-based event that will change the
107f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // status of evaluation.  Alternatively, this may indicate an error in the use
108f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  // of the scheduling interface.
109f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  LOG(ERROR) << "Failed to schedule a reevaluation of policy "
110f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold             << policy_->PolicyRequestName(policy_method) << "; this is a bug.";
111f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  callback.Run(status, result);
1127b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo}
1137b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo
11413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnoldtemplate<typename R, typename... ActualArgs, typename... ExpectedArgs>
11563784a578dd26880454d70797519358a2326291bAlex DeymoEvalStatus UpdateManager::PolicyRequest(
11613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
11713a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        std::string*, R*,
11813a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        ExpectedArgs...) const,
11913a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold    R* result, ActualArgs... args) {
120b227199133f2d694414293697c67599a761f23beGilad Arnold  scoped_refptr<EvaluationContext> ec(
121b227199133f2d694414293697c67599a761f23beGilad Arnold      new EvaluationContext(clock_, evaluation_timeout_));
122072359ca138504065e1e0c1189eb38c09576d324Alex Vakulenko  // A PolicyRequest always consists on a single evaluation on a new
1237b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo  // EvaluationContext.
12413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold  // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
12513a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold  // explicitly instantiate EvaluatePolicy with the latter in lieu of the
12613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold  // former.
1279c155d2110381fbf7d8e4b8f840bf54c3008fe0cAlex Vakulenko  EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method,
1289c155d2110381fbf7d8e4b8f840bf54c3008fe0cAlex Vakulenko                                                      result, args...);
129897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold  // Sync policy requests must not block, if they do then this is an error.
130897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold  DCHECK(EvalStatus::kAskMeAgainLater != ret);
131897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold  LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret)
132f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold      << "Sync request used with an async policy; this is a bug";
133897b5e592cf64e3c04ed1151d19ce5cd51a90592Gilad Arnold  return ret;
1347b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo}
1357b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo
13613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnoldtemplate<typename R, typename... ActualArgs, typename... ExpectedArgs>
13763784a578dd26880454d70797519358a2326291bAlex Deymovoid UpdateManager::AsyncPolicyRequest(
1387b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo    base::Callback<void(EvalStatus, const R& result)> callback,
13913a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold    EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
14013a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        std::string*, R*,
14113a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold                                        ExpectedArgs...) const,
14213a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold    ActualArgs... args) {
143b227199133f2d694414293697c67599a761f23beGilad Arnold  scoped_refptr<EvaluationContext> ec =
14483ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold      new EvaluationContext(
14583ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold          clock_, evaluation_timeout_, expiration_timeout_,
14602f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan          std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
14783ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold              new base::Callback<void(EvaluationContext*)>(
14883ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold                  base::Bind(&UpdateManager::UnregisterEvalContext,
14983ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold                             weak_ptr_factory_.GetWeakPtr()))));
15083ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold  if (!ec_repo_.insert(ec.get()).second) {
15183ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold    LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
15283ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold  }
15383ffddaa3b09ceb4361e5c01ba300d57ab697a7eGilad Arnold
15413a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold  // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
15563784a578dd26880454d70797519358a2326291bAlex Deymo  // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
15613a824344dd7b3502ca79d60545e22dd2e435d69Gilad Arnold  // latter in lieu of the former.
157f9f85d6680164064648ce3ed1d31589e1f1b7a29Gilad Arnold  base::Closure eval_callback = base::Bind(
15863784a578dd26880454d70797519358a2326291bAlex Deymo      &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
1597b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo      base::Unretained(this), ec, callback, policy_method, args...);
1603f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
1617b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo}
1627b948f060281eb1f9ab198bce67da5aadf03df60Alex Deymo
16363784a578dd26880454d70797519358a2326291bAlex Deymo}  // namespace chromeos_update_manager
164c705cc86983dd46df4261ce692cb7558a515e282Alex Deymo
16548415f1f6c6c356bfa9ac85b76d8ebcf053f7157Gilad Arnold#endif  // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
166