You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.8 KiB
147 lines
4.8 KiB
// |
|
// Copyright (C) 2009 The Android Open Source Project |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
// |
|
|
|
#include "update_engine/common/action_processor.h" |
|
|
|
#include <string> |
|
|
|
#include <base/logging.h> |
|
|
|
#include "update_engine/common/action.h" |
|
#include "update_engine/common/error_code_utils.h" |
|
|
|
using std::string; |
|
|
|
namespace chromeos_update_engine { |
|
|
|
ActionProcessor::~ActionProcessor() { |
|
if (IsRunning()) |
|
StopProcessing(); |
|
for (auto action : actions_) |
|
action->SetProcessor(nullptr); |
|
} |
|
|
|
void ActionProcessor::EnqueueAction(AbstractAction* action) { |
|
actions_.push_back(action); |
|
action->SetProcessor(this); |
|
} |
|
|
|
void ActionProcessor::StartProcessing() { |
|
CHECK(!IsRunning()); |
|
if (!actions_.empty()) { |
|
current_action_ = actions_.front(); |
|
LOG(INFO) << "ActionProcessor: starting " << current_action_->Type(); |
|
actions_.pop_front(); |
|
current_action_->PerformAction(); |
|
} |
|
} |
|
|
|
void ActionProcessor::StopProcessing() { |
|
CHECK(IsRunning()); |
|
if (current_action_) { |
|
current_action_->TerminateProcessing(); |
|
current_action_->SetProcessor(nullptr); |
|
} |
|
LOG(INFO) << "ActionProcessor: aborted " |
|
<< (current_action_ ? current_action_->Type() : "") |
|
<< (suspended_ ? " while suspended" : ""); |
|
current_action_ = nullptr; |
|
suspended_ = false; |
|
// Delete all the actions before calling the delegate. |
|
for (auto action : actions_) |
|
action->SetProcessor(nullptr); |
|
actions_.clear(); |
|
if (delegate_) |
|
delegate_->ProcessingStopped(this); |
|
} |
|
|
|
void ActionProcessor::SuspendProcessing() { |
|
// No current_action_ when not suspended means that the action processor was |
|
// never started or already finished. |
|
if (suspended_ || !current_action_) { |
|
LOG(WARNING) << "Called SuspendProcessing while not processing."; |
|
return; |
|
} |
|
suspended_ = true; |
|
|
|
// If there's a current action we should notify it that it should suspend, but |
|
// the action can ignore that and terminate at any point. |
|
LOG(INFO) << "ActionProcessor: suspending " << current_action_->Type(); |
|
current_action_->SuspendAction(); |
|
} |
|
|
|
void ActionProcessor::ResumeProcessing() { |
|
if (!suspended_) { |
|
LOG(WARNING) << "Called ResumeProcessing while not suspended."; |
|
return; |
|
} |
|
suspended_ = false; |
|
if (current_action_) { |
|
// The current_action_ did not call ActionComplete while suspended, so we |
|
// should notify it of the resume operation. |
|
LOG(INFO) << "ActionProcessor: resuming " << current_action_->Type(); |
|
current_action_->ResumeAction(); |
|
} else { |
|
// The last action called ActionComplete while suspended, so there is |
|
// already a log message with the type of the finished action. We simply |
|
// state that we are resuming processing and the next function will log the |
|
// start of the next action or processing completion. |
|
LOG(INFO) << "ActionProcessor: resuming processing"; |
|
StartNextActionOrFinish(suspended_error_code_); |
|
} |
|
} |
|
|
|
void ActionProcessor::ActionComplete(AbstractAction* actionptr, |
|
ErrorCode code) { |
|
CHECK_EQ(actionptr, current_action_); |
|
if (delegate_) |
|
delegate_->ActionCompleted(this, actionptr, code); |
|
string old_type = current_action_->Type(); |
|
current_action_->ActionCompleted(code); |
|
current_action_->SetProcessor(nullptr); |
|
current_action_ = nullptr; |
|
LOG(INFO) << "ActionProcessor: finished " |
|
<< (actions_.empty() ? "last action " : "") << old_type |
|
<< (suspended_ ? " while suspended" : "") |
|
<< " with code " << utils::ErrorCodeToString(code); |
|
if (!actions_.empty() && code != ErrorCode::kSuccess) { |
|
LOG(INFO) << "ActionProcessor: Aborting processing due to failure."; |
|
actions_.clear(); |
|
} |
|
if (suspended_) { |
|
// If an action finished while suspended we don't start the next action (or |
|
// terminate the processing) until the processor is resumed. This condition |
|
// will be flagged by a nullptr current_action_ while suspended_ is true. |
|
suspended_error_code_ = code; |
|
return; |
|
} |
|
StartNextActionOrFinish(code); |
|
} |
|
|
|
void ActionProcessor::StartNextActionOrFinish(ErrorCode code) { |
|
if (actions_.empty()) { |
|
if (delegate_) { |
|
delegate_->ProcessingDone(this, code); |
|
} |
|
return; |
|
} |
|
current_action_ = actions_.front(); |
|
actions_.pop_front(); |
|
LOG(INFO) << "ActionProcessor: starting " << current_action_->Type(); |
|
current_action_->PerformAction(); |
|
} |
|
|
|
} // namespace chromeos_update_engine
|
|
|