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