blob: 3cbc26b22e740f4bfe4a7509e36f9754c0305475 [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnoldcf175a02014-07-10 16:48:47 -07005#ifndef UPDATE_ENGINE_ACTION_H_
6#define UPDATE_ENGINE_ACTION_H_
rspangler@google.com49fdf182009-10-10 00:57:34 +00007
8#include <stdio.h>
Alex Deymobc91a272014-05-20 16:45:33 -07009
Alex Deymobc91a272014-05-20 16:45:33 -070010#include <memory>
Alex Vakulenkod2779df2014-06-16 13:19:00 -070011#include <string>
Alex Deymobc91a272014-05-20 16:45:33 -070012
Alex Deymobc91a272014-05-20 16:45:33 -070013#include <base/logging.h>
Ben Chan05735a12014-09-03 07:48:22 -070014#include <base/macros.h>
Alex Deymobc91a272014-05-20 16:45:33 -070015
adlr@google.comc98a7ed2009-12-04 18:54:03 +000016#include "update_engine/action_pipe.h"
Alex Deymobc91a272014-05-20 16:45:33 -070017#include "update_engine/action_processor.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000018
19// The structure of these classes (Action, ActionPipe, ActionProcessor, etc.)
20// is based on the KSAction* classes from the Google Update Engine code at
21// http://code.google.com/p/update-engine/ . The author of this file sends
22// a big thanks to that team for their high quality design, implementation,
23// and documentation.
24//
25// Readers may want to consult this wiki page from the Update Engine site:
26// http://code.google.com/p/update-engine/wiki/ActionProcessor
27// Although it's referring to the Objective-C KSAction* classes, much
28// applies here as well.
29//
30// How it works:
31//
32// First off, there is only one thread and all I/O should be asynchronous.
Alex Deymo0b3db6b2015-08-10 15:19:37 -070033// A message loop blocks whenever there is no work to be done. This happens
rspangler@google.com49fdf182009-10-10 00:57:34 +000034// where there is no CPU work to be done and no I/O ready to transfer in or
Alex Deymo0b3db6b2015-08-10 15:19:37 -070035// out. Two kinds of events can wake up the message loop: timer alarm or file
36// descriptors. If either of these happens, the message loop finds out the owner
37// of what fired and calls the appropriate code to handle it. As such, all the
38// code in the Action* classes and the code that is calls is non-blocking.
rspangler@google.com49fdf182009-10-10 00:57:34 +000039//
40// An ActionProcessor contains a queue of Actions to perform. When
41// ActionProcessor::StartProcessing() is called, it executes the first action.
42// Each action tells the processor when it has completed, which causes the
43// Processor to execute the next action. ActionProcessor may have a delegate
44// (an object of type ActionProcessorDelegate). If it does, the delegate
45// is called to be notified of events as they happen.
46//
47// ActionPipe classes
48//
49// See action_pipe.h
50//
51// ActionTraits
52//
53// We need to use an extra class ActionTraits. ActionTraits is a simple
54// templated class that contains only two typedefs: OutputObjectType and
55// InputObjectType. Each action class also has two typedefs of the same name
56// that are of the same type. So, to get the input/output types of, e.g., the
57// DownloadAction class, we look at the type of
58// DownloadAction::InputObjectType.
59//
60// Each concrete Action class derives from Action<T>. This means that during
Alex Vakulenkod2779df2014-06-16 13:19:00 -070061// template instantiation of Action<T>, T is declared but not defined, which
rspangler@google.com49fdf182009-10-10 00:57:34 +000062// means that T::InputObjectType (and OutputObjectType) is not defined.
63// However, the traits class is constructed in such a way that it will be
Alex Vakulenkod2779df2014-06-16 13:19:00 -070064// template instantiated first, so Action<T> *can* find the types it needs by
rspangler@google.com49fdf182009-10-10 00:57:34 +000065// consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
66// This is why the ActionTraits classes are needed.
67
rspangler@google.com49fdf182009-10-10 00:57:34 +000068namespace chromeos_update_engine {
69
70// It is handy to have a non-templated base class of all Actions.
71class AbstractAction {
72 public:
Alex Vakulenko88b591f2014-08-28 16:48:57 -070073 AbstractAction() : processor_(nullptr) {}
Alex Deymoe8948702014-11-11 21:44:45 -080074 virtual ~AbstractAction() = default;
rspangler@google.com49fdf182009-10-10 00:57:34 +000075
76 // Begin performing the action. Since this code is asynchronous, when this
77 // method returns, it means only that the action has started, not necessarily
78 // completed. However, it's acceptable for this method to perform the
79 // action synchronously; Action authors should understand the implications
80 // of synchronously performing, though, because this is a single-threaded
81 // app, the entire process will be blocked while the action performs.
82 //
83 // When the action is complete, it must call
84 // ActionProcessor::ActionComplete(this); to notify the processor that it's
85 // done.
86 virtual void PerformAction() = 0;
87
David Zeuthen33bae492014-02-25 16:16:18 -080088 // Called on ActionProcess::ActionComplete() by ActionProcessor.
89 virtual void ActionCompleted(ErrorCode code) {}
90
rspangler@google.com49fdf182009-10-10 00:57:34 +000091 // Called by the ActionProcessor to tell this Action which processor
92 // it belongs to.
93 void SetProcessor(ActionProcessor* processor) {
94 if (processor)
95 CHECK(!processor_);
96 else
97 CHECK(processor_);
98 processor_ = processor;
99 }
100
101 // Returns true iff the action is the current action of its ActionProcessor.
102 bool IsRunning() const {
103 if (!processor_)
104 return false;
105 return processor_->current_action() == this;
106 }
107
108 // Called on asynchronous actions if canceled. Actions may implement if
109 // there's any cleanup to do. There is no need to call
110 // ActionProcessor::ActionComplete() because the processor knows this
111 // action is terminating.
112 // Only the ActionProcessor should call this.
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700113 virtual void TerminateProcessing() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000114
115 // These methods are useful for debugging. TODO(adlr): consider using
116 // std::type_info for this?
117 // Type() returns a string of the Action type. I.e., for DownloadAction,
118 // Type() would return "DownloadAction".
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800119 virtual std::string Type() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120
121 protected:
122 // A weak pointer to the processor that owns this Action.
123 ActionProcessor* processor_;
124};
125
126// Forward declare a couple classes we use.
127template<typename T>
128class ActionPipe;
129template<typename T>
130class ActionTraits;
131
132template<typename SubClass>
133class Action : public AbstractAction {
134 public:
Alex Deymo610277e2014-11-11 21:18:11 -0800135 ~Action() override {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000136
137 // Attaches an input pipe to this Action. This is optional; an Action
138 // doesn't need to have an input pipe. The input pipe must be of the type
139 // of object that this class expects.
140 // This is generally called by ActionPipe::Bond()
141 void set_in_pipe(
142 // this type is a fancy way of saying: a shared_ptr to an
143 // ActionPipe<InputObjectType>.
Alex Deymobc91a272014-05-20 16:45:33 -0700144 const std::shared_ptr<ActionPipe<
Ben Chanf9cb98c2014-09-21 18:31:30 -0700145 typename ActionTraits<SubClass>::InputObjectType>>& in_pipe) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000146 in_pipe_ = in_pipe;
147 }
148
149 // Attaches an output pipe to this Action. This is optional; an Action
150 // doesn't need to have an output pipe. The output pipe must be of the type
151 // of object that this class expects.
152 // This is generally called by ActionPipe::Bond()
153 void set_out_pipe(
154 // this type is a fancy way of saying: a shared_ptr to an
155 // ActionPipe<OutputObjectType>.
Alex Deymobc91a272014-05-20 16:45:33 -0700156 const std::shared_ptr<ActionPipe<
Ben Chanf9cb98c2014-09-21 18:31:30 -0700157 typename ActionTraits<SubClass>::OutputObjectType>>& out_pipe) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000158 out_pipe_ = out_pipe;
159 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000160
rspangler@google.com49fdf182009-10-10 00:57:34 +0000161 // Returns true iff there is an associated input pipe. If there's an input
162 // pipe, there's an input object, but it may have been constructed with the
163 // default ctor if the previous action didn't call SetOutputObject().
164 bool HasInputObject() const { return in_pipe_.get(); }
165
166 // returns a const reference to the object in the input pipe.
167 const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
168 const {
169 CHECK(HasInputObject());
170 return in_pipe_->contents();
171 }
172
173 // Returns true iff there's an output pipe.
174 bool HasOutputPipe() const {
175 return out_pipe_.get();
176 }
177
178 // Copies the object passed into the output pipe. It will be accessible to
179 // the next Action via that action's input pipe (which is the same as this
180 // Action's output pipe).
181 void SetOutputObject(
182 const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
183 CHECK(HasOutputPipe());
184 out_pipe_->set_contents(out_obj);
185 }
186
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000187 // Returns a reference to the object sitting in the output pipe.
188 const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
189 CHECK(HasOutputPipe());
190 return out_pipe_->contents();
191 }
192
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700193 protected:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000194 // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
195 // point to when the last such shared_ptr object dies. We consider the
196 // Actions on either end of a pipe to "own" the pipe. When the last Action
197 // of the two dies, the ActionPipe will die, too.
Ben Chanf9cb98c2014-09-21 18:31:30 -0700198 std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
rspangler@google.com49fdf182009-10-10 00:57:34 +0000199 in_pipe_;
Ben Chanf9cb98c2014-09-21 18:31:30 -0700200 std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
rspangler@google.com49fdf182009-10-10 00:57:34 +0000201 out_pipe_;
202};
203
204}; // namespace chromeos_update_engine
205
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700206#endif // UPDATE_ENGINE_ACTION_H_