• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  //
2  // Copyright (C) 2009 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  #include "update_engine/common/action_processor.h"
18  
19  #include <string>
20  #include <utility>
21  
22  #include <base/logging.h>
23  
24  #include "update_engine/common/action.h"
25  #include "update_engine/common/error_code_utils.h"
26  
27  using std::string;
28  using std::unique_ptr;
29  
30  namespace chromeos_update_engine {
31  
~ActionProcessor()32  ActionProcessor::~ActionProcessor() {
33    if (IsRunning())
34      StopProcessing();
35  }
36  
EnqueueAction(unique_ptr<AbstractAction> action)37  void ActionProcessor::EnqueueAction(unique_ptr<AbstractAction> action) {
38    action->SetProcessor(this);
39    actions_.push_back(std::move(action));
40  }
41  
IsRunning() const42  bool ActionProcessor::IsRunning() const {
43    return current_action_ != nullptr || suspended_;
44  }
45  
StartProcessing()46  void ActionProcessor::StartProcessing() {
47    CHECK(!IsRunning());
48    if (!actions_.empty()) {
49      current_action_ = std::move(actions_.front());
50      actions_.pop_front();
51      LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
52      current_action_->PerformAction();
53    }
54  }
55  
StopProcessing()56  void ActionProcessor::StopProcessing() {
57    CHECK(IsRunning());
58    if (current_action_) {
59      current_action_->TerminateProcessing();
60    }
61    LOG(INFO) << "ActionProcessor: aborted "
62              << (current_action_ ? current_action_->Type() : "")
63              << (suspended_ ? " while suspended" : "");
64    current_action_.reset();
65    suspended_ = false;
66    // Delete all the actions before calling the delegate.
67    actions_.clear();
68    if (delegate_)
69      delegate_->ProcessingStopped(this);
70  }
71  
SuspendProcessing()72  void ActionProcessor::SuspendProcessing() {
73    // No current_action_ when not suspended means that the action processor was
74    // never started or already finished.
75    if (suspended_ || !current_action_) {
76      LOG(WARNING) << "Called SuspendProcessing while not processing.";
77      return;
78    }
79    suspended_ = true;
80  
81    // If there's a current action we should notify it that it should suspend, but
82    // the action can ignore that and terminate at any point.
83    LOG(INFO) << "ActionProcessor: suspending " << current_action_->Type();
84    current_action_->SuspendAction();
85  }
86  
ResumeProcessing()87  void ActionProcessor::ResumeProcessing() {
88    if (!suspended_) {
89      LOG(WARNING) << "Called ResumeProcessing while not suspended.";
90      return;
91    }
92    suspended_ = false;
93    if (current_action_) {
94      // The current_action_ did not call ActionComplete while suspended, so we
95      // should notify it of the resume operation.
96      LOG(INFO) << "ActionProcessor: resuming " << current_action_->Type();
97      current_action_->ResumeAction();
98    } else {
99      // The last action called ActionComplete while suspended, so there is
100      // already a log message with the type of the finished action. We simply
101      // state that we are resuming processing and the next function will log the
102      // start of the next action or processing completion.
103      LOG(INFO) << "ActionProcessor: resuming processing";
104      StartNextActionOrFinish(suspended_error_code_);
105    }
106  }
107  
ActionComplete(AbstractAction * actionptr,ErrorCode code)108  void ActionProcessor::ActionComplete(AbstractAction* actionptr,
109                                       ErrorCode code) {
110    CHECK_EQ(actionptr, current_action_.get());
111    if (delegate_)
112      delegate_->ActionCompleted(this, actionptr, code);
113    string old_type = current_action_->Type();
114    current_action_->ActionCompleted(code);
115    current_action_.reset();
116    LOG(INFO) << "ActionProcessor: finished "
117              << (actions_.empty() ? "last action " : "") << old_type
118              << (suspended_ ? " while suspended" : "") << " with code "
119              << utils::ErrorCodeToString(code);
120    if (!actions_.empty() && code != ErrorCode::kSuccess) {
121      LOG(INFO) << "ActionProcessor: Aborting processing due to failure.";
122      actions_.clear();
123    }
124    if (suspended_) {
125      // If an action finished while suspended we don't start the next action (or
126      // terminate the processing) until the processor is resumed. This condition
127      // will be flagged by a nullptr current_action_ while suspended_ is true.
128      suspended_error_code_ = code;
129      return;
130    }
131    StartNextActionOrFinish(code);
132  }
133  
StartNextActionOrFinish(ErrorCode code)134  void ActionProcessor::StartNextActionOrFinish(ErrorCode code) {
135    if (actions_.empty()) {
136      if (delegate_) {
137        delegate_->ProcessingDone(this, code);
138      }
139      return;
140    }
141    current_action_ = std::move(actions_.front());
142    actions_.pop_front();
143    LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
144    current_action_->PerformAction();
145  }
146  
147  }  // namespace chromeos_update_engine
148