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
21 #include <base/logging.h>
22
23 #include "update_engine/common/action.h"
24 #include "update_engine/common/error_code_utils.h"
25
26 using std::string;
27
28 namespace chromeos_update_engine {
29
~ActionProcessor()30 ActionProcessor::~ActionProcessor() {
31 if (IsRunning())
32 StopProcessing();
33 for (auto action : actions_)
34 action->SetProcessor(nullptr);
35 }
36
EnqueueAction(AbstractAction * action)37 void ActionProcessor::EnqueueAction(AbstractAction* action) {
38 actions_.push_back(action);
39 action->SetProcessor(this);
40 }
41
StartProcessing()42 void ActionProcessor::StartProcessing() {
43 CHECK(!IsRunning());
44 if (!actions_.empty()) {
45 current_action_ = actions_.front();
46 LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
47 actions_.pop_front();
48 current_action_->PerformAction();
49 }
50 }
51
StopProcessing()52 void ActionProcessor::StopProcessing() {
53 CHECK(IsRunning());
54 if (current_action_) {
55 current_action_->TerminateProcessing();
56 current_action_->SetProcessor(nullptr);
57 }
58 LOG(INFO) << "ActionProcessor: aborted "
59 << (current_action_ ? current_action_->Type() : "")
60 << (suspended_ ? " while suspended" : "");
61 current_action_ = nullptr;
62 suspended_ = false;
63 // Delete all the actions before calling the delegate.
64 for (auto action : actions_)
65 action->SetProcessor(nullptr);
66 actions_.clear();
67 if (delegate_)
68 delegate_->ProcessingStopped(this);
69 }
70
SuspendProcessing()71 void ActionProcessor::SuspendProcessing() {
72 // No current_action_ when not suspended means that the action processor was
73 // never started or already finished.
74 if (suspended_ || !current_action_) {
75 LOG(WARNING) << "Called SuspendProcessing while not processing.";
76 return;
77 }
78 suspended_ = true;
79
80 // If there's a current action we should notify it that it should suspend, but
81 // the action can ignore that and terminate at any point.
82 LOG(INFO) << "ActionProcessor: suspending " << current_action_->Type();
83 current_action_->SuspendAction();
84 }
85
ResumeProcessing()86 void ActionProcessor::ResumeProcessing() {
87 if (!suspended_) {
88 LOG(WARNING) << "Called ResumeProcessing while not suspended.";
89 return;
90 }
91 suspended_ = false;
92 if (current_action_) {
93 // The current_action_ did not call ActionComplete while suspended, so we
94 // should notify it of the resume operation.
95 LOG(INFO) << "ActionProcessor: resuming " << current_action_->Type();
96 current_action_->ResumeAction();
97 } else {
98 // The last action called ActionComplete while suspended, so there is
99 // already a log message with the type of the finished action. We simply
100 // state that we are resuming processing and the next function will log the
101 // start of the next action or processing completion.
102 LOG(INFO) << "ActionProcessor: resuming processing";
103 StartNextActionOrFinish(suspended_error_code_);
104 }
105 }
106
ActionComplete(AbstractAction * actionptr,ErrorCode code)107 void ActionProcessor::ActionComplete(AbstractAction* actionptr,
108 ErrorCode code) {
109 CHECK_EQ(actionptr, current_action_);
110 if (delegate_)
111 delegate_->ActionCompleted(this, actionptr, code);
112 string old_type = current_action_->Type();
113 current_action_->ActionCompleted(code);
114 current_action_->SetProcessor(nullptr);
115 current_action_ = nullptr;
116 LOG(INFO) << "ActionProcessor: finished "
117 << (actions_.empty() ? "last action " : "") << old_type
118 << (suspended_ ? " while suspended" : "")
119 << " with code " << 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_ = 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