blob: c806b48698b6ebebbe473f7263c4afcdd5ccc363 [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.
33// A glib main loop blocks whenever there is no work to be done. This happens
34// where there is no CPU work to be done and no I/O ready to transfer in or
35// out. Two kinds of events can wake up the main loop: timer alarm or file
36// descriptors. If either of these happens, glib finds out the owner of what
37// fired and calls the appropriate code to handle it. As such, all the code
38// in the Action* classes and the code that is calls is non-blocking.
39//
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) {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000074
75 // Begin performing the action. Since this code is asynchronous, when this
76 // method returns, it means only that the action has started, not necessarily
77 // completed. However, it's acceptable for this method to perform the
78 // action synchronously; Action authors should understand the implications
79 // of synchronously performing, though, because this is a single-threaded
80 // app, the entire process will be blocked while the action performs.
81 //
82 // When the action is complete, it must call
83 // ActionProcessor::ActionComplete(this); to notify the processor that it's
84 // done.
85 virtual void PerformAction() = 0;
86
David Zeuthen33bae492014-02-25 16:16:18 -080087 // Called on ActionProcess::ActionComplete() by ActionProcessor.
88 virtual void ActionCompleted(ErrorCode code) {}
89
rspangler@google.com49fdf182009-10-10 00:57:34 +000090 // Called by the ActionProcessor to tell this Action which processor
91 // it belongs to.
92 void SetProcessor(ActionProcessor* processor) {
93 if (processor)
94 CHECK(!processor_);
95 else
96 CHECK(processor_);
97 processor_ = processor;
98 }
99
100 // Returns true iff the action is the current action of its ActionProcessor.
101 bool IsRunning() const {
102 if (!processor_)
103 return false;
104 return processor_->current_action() == this;
105 }
106
107 // Called on asynchronous actions if canceled. Actions may implement if
108 // there's any cleanup to do. There is no need to call
109 // ActionProcessor::ActionComplete() because the processor knows this
110 // action is terminating.
111 // Only the ActionProcessor should call this.
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700112 virtual void TerminateProcessing() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113
114 // These methods are useful for debugging. TODO(adlr): consider using
115 // std::type_info for this?
116 // Type() returns a string of the Action type. I.e., for DownloadAction,
117 // Type() would return "DownloadAction".
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800118 virtual std::string Type() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000119
120 protected:
121 // A weak pointer to the processor that owns this Action.
122 ActionProcessor* processor_;
123};
124
125// Forward declare a couple classes we use.
126template<typename T>
127class ActionPipe;
128template<typename T>
129class ActionTraits;
130
131template<typename SubClass>
132class Action : public AbstractAction {
133 public:
Darin Petkovfbb40092010-07-29 17:05:50 -0700134 virtual ~Action() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000135
136 // Attaches an input pipe to this Action. This is optional; an Action
137 // doesn't need to have an input pipe. The input pipe must be of the type
138 // of object that this class expects.
139 // This is generally called by ActionPipe::Bond()
140 void set_in_pipe(
141 // this type is a fancy way of saying: a shared_ptr to an
142 // ActionPipe<InputObjectType>.
Alex Deymobc91a272014-05-20 16:45:33 -0700143 const std::shared_ptr<ActionPipe<
Ben Chanf9cb98c2014-09-21 18:31:30 -0700144 typename ActionTraits<SubClass>::InputObjectType>>& in_pipe) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000145 in_pipe_ = in_pipe;
146 }
147
148 // Attaches an output pipe to this Action. This is optional; an Action
149 // doesn't need to have an output pipe. The output pipe must be of the type
150 // of object that this class expects.
151 // This is generally called by ActionPipe::Bond()
152 void set_out_pipe(
153 // this type is a fancy way of saying: a shared_ptr to an
154 // ActionPipe<OutputObjectType>.
Alex Deymobc91a272014-05-20 16:45:33 -0700155 const std::shared_ptr<ActionPipe<
Ben Chanf9cb98c2014-09-21 18:31:30 -0700156 typename ActionTraits<SubClass>::OutputObjectType>>& out_pipe) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000157 out_pipe_ = out_pipe;
158 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000159
rspangler@google.com49fdf182009-10-10 00:57:34 +0000160 // Returns true iff there is an associated input pipe. If there's an input
161 // pipe, there's an input object, but it may have been constructed with the
162 // default ctor if the previous action didn't call SetOutputObject().
163 bool HasInputObject() const { return in_pipe_.get(); }
164
165 // returns a const reference to the object in the input pipe.
166 const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
167 const {
168 CHECK(HasInputObject());
169 return in_pipe_->contents();
170 }
171
172 // Returns true iff there's an output pipe.
173 bool HasOutputPipe() const {
174 return out_pipe_.get();
175 }
176
177 // Copies the object passed into the output pipe. It will be accessible to
178 // the next Action via that action's input pipe (which is the same as this
179 // Action's output pipe).
180 void SetOutputObject(
181 const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
182 CHECK(HasOutputPipe());
183 out_pipe_->set_contents(out_obj);
184 }
185
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000186 // Returns a reference to the object sitting in the output pipe.
187 const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
188 CHECK(HasOutputPipe());
189 return out_pipe_->contents();
190 }
191
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700192 protected:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000193 // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
194 // point to when the last such shared_ptr object dies. We consider the
195 // Actions on either end of a pipe to "own" the pipe. When the last Action
196 // of the two dies, the ActionPipe will die, too.
Ben Chanf9cb98c2014-09-21 18:31:30 -0700197 std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
rspangler@google.com49fdf182009-10-10 00:57:34 +0000198 in_pipe_;
Ben Chanf9cb98c2014-09-21 18:31:30 -0700199 std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
rspangler@google.com49fdf182009-10-10 00:57:34 +0000200 out_pipe_;
201};
202
203}; // namespace chromeos_update_engine
204
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700205#endif // UPDATE_ENGINE_ACTION_H_