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