Home | History | Annotate | Download | only in update_manager
      1 //
      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 //
     16 
     17 #ifndef UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
     18 #define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
     19 
     20 #include <memory>
     21 #include <string>
     22 
     23 #include <base/bind.h>
     24 #include <base/location.h>
     25 #include <brillo/message_loops/message_loop.h>
     26 
     27 #include "update_engine/update_manager/evaluation_context.h"
     28 
     29 namespace chromeos_update_manager {
     30 
     31 template<typename R, typename... Args>
     32 EvalStatus UpdateManager::EvaluatePolicy(
     33     EvaluationContext* ec,
     34     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
     35                                         std::string*, R*,
     36                                         Args...) const,
     37     R* result, Args... args) {
     38   // 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   }
     47 
     48   // Reset the evaluation context.
     49   ec->ResetEvaluation();
     50 
     51   const std::string policy_name = policy_->PolicyRequestName(policy_method);
     52   LOG(INFO) << policy_name << ": START";
     53 
     54   // First try calling the actual policy.
     55   std::string error;
     56   EvalStatus status = (policy_.get()->*policy_method)(ec, state_.get(), &error,
     57                                                       result, args...);
     58   // If evaluating the main policy failed, defer to the default policy.
     59   if (status == EvalStatus::kFailed) {
     60     LOG(WARNING) << "Evaluating policy failed: " << error
     61                  << "\nEvaluation context: " << ec->DumpContext();
     62     error.clear();
     63     status = (default_policy_.*policy_method)(ec, state_.get(), &error, result,
     64                                               args...);
     65     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.";
     70       status = EvalStatus::kFailed;
     71     }
     72   }
     73 
     74   LOG(INFO) << policy_name << ": END";
     75 
     76   return status;
     77 }
     78 
     79 template<typename R, typename... Args>
     80 void UpdateManager::OnPolicyReadyToEvaluate(
     81     scoped_refptr<EvaluationContext> ec,
     82     base::Callback<void(EvalStatus status, const R& result)> callback,
     83     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
     84                                         std::string*, R*,
     85                                         Args...) const,
     86     Args... args) {
     87   // Evaluate the policy.
     88   R result;
     89   EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
     90 
     91   if (status != EvalStatus::kAskMeAgainLater) {
     92     // AsyncPolicyRequest finished.
     93     callback.Run(status, result);
     94     return;
     95   }
     96 
     97   // 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);
    112 }
    113 
    114 template<typename R, typename... ActualArgs, typename... ExpectedArgs>
    115 EvalStatus UpdateManager::PolicyRequest(
    116     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
    117                                         std::string*, R*,
    118                                         ExpectedArgs...) const,
    119     R* result, ActualArgs... args) {
    120   scoped_refptr<EvaluationContext> ec(
    121       new EvaluationContext(clock_, evaluation_timeout_));
    122   // A PolicyRequest always consists on a single evaluation on a new
    123   // EvaluationContext.
    124   // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
    125   // explicitly instantiate EvaluatePolicy with the latter in lieu of the
    126   // former.
    127   EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(ec.get(), policy_method,
    128                                                       result, args...);
    129   // 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)
    132       << "Sync request used with an async policy; this is a bug";
    133   return ret;
    134 }
    135 
    136 template<typename R, typename... ActualArgs, typename... ExpectedArgs>
    137 void UpdateManager::AsyncPolicyRequest(
    138     base::Callback<void(EvalStatus, const R& result)> callback,
    139     EvalStatus (Policy::*policy_method)(EvaluationContext*, State*,
    140                                         std::string*, R*,
    141                                         ExpectedArgs...) const,
    142     ActualArgs... args) {
    143   scoped_refptr<EvaluationContext> ec =
    144       new EvaluationContext(
    145           clock_, evaluation_timeout_, expiration_timeout_,
    146           std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
    147               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 
    154   // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
    155   // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
    156   // latter in lieu of the former.
    157   base::Closure eval_callback = base::Bind(
    158       &UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
    159       base::Unretained(this), ec, callback, policy_method, args...);
    160   brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
    161 }
    162 
    163 }  // namespace chromeos_update_manager
    164 
    165 #endif  // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
    166