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.
239 lines
9.1 KiB
239 lines
9.1 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.
|
|
//
|
|
|
|
#ifndef UPDATE_ENGINE_COMMON_ACTION_H_
|
|
#define UPDATE_ENGINE_COMMON_ACTION_H_
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include <base/logging.h>
|
|
#include <base/macros.h>
|
|
|
|
#include "update_engine/common/action_pipe.h"
|
|
#include "update_engine/common/action_processor.h"
|
|
|
|
// The structure of these classes (Action, ActionPipe, ActionProcessor, etc.)
|
|
// is based on the KSAction* classes from the Google Update Engine code at
|
|
// http://code.google.com/p/update-engine/ . The author of this file sends
|
|
// a big thanks to that team for their high quality design, implementation,
|
|
// and documentation.
|
|
//
|
|
// Readers may want to consult this wiki page from the Update Engine site:
|
|
// http://code.google.com/p/update-engine/wiki/ActionProcessor
|
|
// Although it's referring to the Objective-C KSAction* classes, much
|
|
// applies here as well.
|
|
//
|
|
// How it works:
|
|
//
|
|
// First off, there is only one thread and all I/O should be asynchronous.
|
|
// A message loop blocks whenever there is no work to be done. This happens
|
|
// where there is no CPU work to be done and no I/O ready to transfer in or
|
|
// out. Two kinds of events can wake up the message loop: timer alarm or file
|
|
// descriptors. If either of these happens, the message loop finds out the owner
|
|
// of what fired and calls the appropriate code to handle it. As such, all the
|
|
// code in the Action* classes and the code that is calls is non-blocking.
|
|
//
|
|
// An ActionProcessor contains a queue of Actions to perform. When
|
|
// ActionProcessor::StartProcessing() is called, it executes the first action.
|
|
// Each action tells the processor when it has completed, which causes the
|
|
// Processor to execute the next action. ActionProcessor may have a delegate
|
|
// (an object of type ActionProcessorDelegate). If it does, the delegate
|
|
// is called to be notified of events as they happen.
|
|
//
|
|
// ActionPipe classes
|
|
//
|
|
// See action_pipe.h
|
|
//
|
|
// ActionTraits
|
|
//
|
|
// We need to use an extra class ActionTraits. ActionTraits is a simple
|
|
// templated class that contains only two typedefs: OutputObjectType and
|
|
// InputObjectType. Each action class also has two typedefs of the same name
|
|
// that are of the same type. So, to get the input/output types of, e.g., the
|
|
// DownloadAction class, we look at the type of
|
|
// DownloadAction::InputObjectType.
|
|
//
|
|
// Each concrete Action class derives from Action<T>. This means that during
|
|
// template instantiation of Action<T>, T is declared but not defined, which
|
|
// means that T::InputObjectType (and OutputObjectType) is not defined.
|
|
// However, the traits class is constructed in such a way that it will be
|
|
// template instantiated first, so Action<T> *can* find the types it needs by
|
|
// consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
|
|
// This is why the ActionTraits classes are needed.
|
|
|
|
namespace chromeos_update_engine {
|
|
|
|
// It is handy to have a non-templated base class of all Actions.
|
|
class AbstractAction {
|
|
public:
|
|
AbstractAction() : processor_(nullptr) {}
|
|
virtual ~AbstractAction() = default;
|
|
|
|
// Begin performing the action. Since this code is asynchronous, when this
|
|
// method returns, it means only that the action has started, not necessarily
|
|
// completed. However, it's acceptable for this method to perform the
|
|
// action synchronously; Action authors should understand the implications
|
|
// of synchronously performing, though, because this is a single-threaded
|
|
// app, the entire process will be blocked while the action performs.
|
|
//
|
|
// When the action is complete, it must call
|
|
// ActionProcessor::ActionComplete(this); to notify the processor that it's
|
|
// done.
|
|
virtual void PerformAction() = 0;
|
|
|
|
// Called on ActionProcess::ActionComplete() by ActionProcessor.
|
|
virtual void ActionCompleted(ErrorCode code) {}
|
|
|
|
// Called by the ActionProcessor to tell this Action which processor
|
|
// it belongs to.
|
|
void SetProcessor(ActionProcessor* processor) {
|
|
if (processor)
|
|
CHECK(!processor_);
|
|
else
|
|
CHECK(processor_);
|
|
processor_ = processor;
|
|
}
|
|
|
|
// Returns true iff the action is the current action of its ActionProcessor.
|
|
bool IsRunning() const {
|
|
if (!processor_)
|
|
return false;
|
|
return processor_->current_action() == this;
|
|
}
|
|
|
|
// Called on asynchronous actions if canceled. Actions may implement if
|
|
// there's any cleanup to do. There is no need to call
|
|
// ActionProcessor::ActionComplete() because the processor knows this
|
|
// action is terminating.
|
|
// Only the ActionProcessor should call this.
|
|
virtual void TerminateProcessing() {}
|
|
|
|
// Called on asynchronous actions if the processing is suspended and resumed,
|
|
// respectively. These methods are called by the ActionProcessor and should
|
|
// not be explicitly called.
|
|
// The action may still call ActionCompleted() once the action is completed
|
|
// while the processing is suspended, for example if suspend/resume is not
|
|
// implemented for the given action.
|
|
virtual void SuspendAction() {}
|
|
virtual void ResumeAction() {}
|
|
|
|
// These methods are useful for debugging. TODO(adlr): consider using
|
|
// std::type_info for this?
|
|
// Type() returns a string of the Action type. I.e., for DownloadAction,
|
|
// Type() would return "DownloadAction".
|
|
virtual std::string Type() const = 0;
|
|
|
|
protected:
|
|
// A weak pointer to the processor that owns this Action.
|
|
ActionProcessor* processor_;
|
|
};
|
|
|
|
// Forward declare a couple classes we use.
|
|
template <typename T>
|
|
class ActionPipe;
|
|
template <typename T>
|
|
class ActionTraits;
|
|
|
|
template <typename SubClass>
|
|
class Action : public AbstractAction {
|
|
public:
|
|
~Action() override {}
|
|
|
|
// Attaches an input pipe to this Action. This is optional; an Action
|
|
// doesn't need to have an input pipe. The input pipe must be of the type
|
|
// of object that this class expects.
|
|
// This is generally called by ActionPipe::Bond()
|
|
void set_in_pipe(
|
|
// this type is a fancy way of saying: a shared_ptr to an
|
|
// ActionPipe<InputObjectType>.
|
|
const std::shared_ptr<
|
|
ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>&
|
|
in_pipe) {
|
|
in_pipe_ = in_pipe;
|
|
}
|
|
|
|
// Attaches an output pipe to this Action. This is optional; an Action
|
|
// doesn't need to have an output pipe. The output pipe must be of the type
|
|
// of object that this class expects.
|
|
// This is generally called by ActionPipe::Bond()
|
|
void set_out_pipe(
|
|
// this type is a fancy way of saying: a shared_ptr to an
|
|
// ActionPipe<OutputObjectType>.
|
|
const std::shared_ptr<
|
|
ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>&
|
|
out_pipe) {
|
|
out_pipe_ = out_pipe;
|
|
}
|
|
|
|
// Returns true iff there is an associated input pipe. If there's an input
|
|
// pipe, there's an input object, but it may have been constructed with the
|
|
// default ctor if the previous action didn't call SetOutputObject().
|
|
bool HasInputObject() const { return in_pipe_.get(); }
|
|
|
|
// returns a const reference to the object in the input pipe.
|
|
const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
|
|
const {
|
|
CHECK(HasInputObject());
|
|
return in_pipe_->contents();
|
|
}
|
|
|
|
// Returns true iff there's an output pipe.
|
|
bool HasOutputPipe() const { return out_pipe_.get(); }
|
|
|
|
// Copies the object passed into the output pipe. It will be accessible to
|
|
// the next Action via that action's input pipe (which is the same as this
|
|
// Action's output pipe).
|
|
void SetOutputObject(
|
|
const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
|
|
CHECK(HasOutputPipe());
|
|
out_pipe_->set_contents(out_obj);
|
|
}
|
|
|
|
// Returns a reference to the object sitting in the output pipe.
|
|
const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
|
|
CHECK(HasOutputPipe());
|
|
return out_pipe_->contents();
|
|
}
|
|
|
|
protected:
|
|
// We use a shared_ptr to the pipe. shared_ptr objects destroy what they
|
|
// point to when the last such shared_ptr object dies. We consider the
|
|
// Actions on either end of a pipe to "own" the pipe. When the last Action
|
|
// of the two dies, the ActionPipe will die, too.
|
|
std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
|
|
in_pipe_;
|
|
std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
|
|
out_pipe_;
|
|
};
|
|
|
|
// An action that does nothing and completes with kSuccess immediately.
|
|
class NoOpAction : public AbstractAction {
|
|
public:
|
|
~NoOpAction() override {}
|
|
void PerformAction() override {
|
|
processor_->ActionComplete(this, ErrorCode::kSuccess);
|
|
}
|
|
static std::string StaticType() { return "NoOpAction"; }
|
|
std::string Type() const override { return StaticType(); }
|
|
};
|
|
|
|
}; // namespace chromeos_update_engine
|
|
|
|
#endif // UPDATE_ENGINE_COMMON_ACTION_H_
|