• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef UPDATE_ENGINE_COMMON_ACTION_H_
18 #define UPDATE_ENGINE_COMMON_ACTION_H_
19 
20 #include <stdio.h>
21 
22 #include <memory>
23 #include <string>
24 
25 #include <base/logging.h>
26 #include <base/macros.h>
27 
28 #include "update_engine/common/action_pipe.h"
29 #include "update_engine/common/action_processor.h"
30 
31 // The structure of these classes (Action, ActionPipe, ActionProcessor, etc.)
32 // is based on the KSAction* classes from the Google Update Engine code at
33 // http://code.google.com/p/update-engine/ . The author of this file sends
34 // a big thanks to that team for their high quality design, implementation,
35 // and documentation.
36 //
37 // Readers may want to consult this wiki page from the Update Engine site:
38 // http://code.google.com/p/update-engine/wiki/ActionProcessor
39 // Although it's referring to the Objective-C KSAction* classes, much
40 // applies here as well.
41 //
42 // How it works:
43 //
44 // First off, there is only one thread and all I/O should be asynchronous.
45 // A message loop blocks whenever there is no work to be done. This happens
46 // where there is no CPU work to be done and no I/O ready to transfer in or
47 // out. Two kinds of events can wake up the message loop: timer alarm or file
48 // descriptors. If either of these happens, the message loop finds out the owner
49 // of what fired and calls the appropriate code to handle it. As such, all the
50 // code in the Action* classes and the code that is calls is non-blocking.
51 //
52 // An ActionProcessor contains a queue of Actions to perform. When
53 // ActionProcessor::StartProcessing() is called, it executes the first action.
54 // Each action tells the processor when it has completed, which causes the
55 // Processor to execute the next action. ActionProcessor may have a delegate
56 // (an object of type ActionProcessorDelegate). If it does, the delegate
57 // is called to be notified of events as they happen.
58 //
59 // ActionPipe classes
60 //
61 // See action_pipe.h
62 //
63 // ActionTraits
64 //
65 // We need to use an extra class ActionTraits. ActionTraits is a simple
66 // templated class that contains only two typedefs: OutputObjectType and
67 // InputObjectType. Each action class also has two typedefs of the same name
68 // that are of the same type. So, to get the input/output types of, e.g., the
69 // DownloadAction class, we look at the type of
70 // DownloadAction::InputObjectType.
71 //
72 // Each concrete Action class derives from Action<T>. This means that during
73 // template instantiation of Action<T>, T is declared but not defined, which
74 // means that T::InputObjectType (and OutputObjectType) is not defined.
75 // However, the traits class is constructed in such a way that it will be
76 // template instantiated first, so Action<T> *can* find the types it needs by
77 // consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
78 // This is why the ActionTraits classes are needed.
79 
80 namespace chromeos_update_engine {
81 
82 // It is handy to have a non-templated base class of all Actions.
83 class AbstractAction {
84  public:
AbstractAction()85   AbstractAction() : processor_(nullptr) {}
86   virtual ~AbstractAction() = default;
87 
88   // Begin performing the action. Since this code is asynchronous, when this
89   // method returns, it means only that the action has started, not necessarily
90   // completed. However, it's acceptable for this method to perform the
91   // action synchronously; Action authors should understand the implications
92   // of synchronously performing, though, because this is a single-threaded
93   // app, the entire process will be blocked while the action performs.
94   //
95   // When the action is complete, it must call
96   // ActionProcessor::ActionComplete(this); to notify the processor that it's
97   // done.
98   virtual void PerformAction() = 0;
99 
100   // Called on ActionProcess::ActionComplete() by ActionProcessor.
ActionCompleted(ErrorCode code)101   virtual void ActionCompleted(ErrorCode code) {}
102 
103   // Called by the ActionProcessor to tell this Action which processor
104   // it belongs to.
SetProcessor(ActionProcessor * processor)105   void SetProcessor(ActionProcessor* processor) {
106     if (processor)
107       CHECK(!processor_);
108     else
109       CHECK(processor_);
110     processor_ = processor;
111   }
112 
113   // Returns true iff the action is the current action of its ActionProcessor.
IsRunning()114   bool IsRunning() const {
115     if (!processor_)
116       return false;
117     return processor_->current_action() == this;
118   }
119 
120   // Called on asynchronous actions if canceled. Actions may implement if
121   // there's any cleanup to do. There is no need to call
122   // ActionProcessor::ActionComplete() because the processor knows this
123   // action is terminating.
124   // Only the ActionProcessor should call this.
TerminateProcessing()125   virtual void TerminateProcessing() {}
126 
127   // Called on asynchronous actions if the processing is suspended and resumed,
128   // respectively. These methods are called by the ActionProcessor and should
129   // not be explicitly called.
130   // The action may still call ActionCompleted() once the action is completed
131   // while the processing is suspended, for example if suspend/resume is not
132   // implemented for the given action.
SuspendAction()133   virtual void SuspendAction() {}
ResumeAction()134   virtual void ResumeAction() {}
135 
136   // These methods are useful for debugging. TODO(adlr): consider using
137   // std::type_info for this?
138   // Type() returns a string of the Action type. I.e., for DownloadAction,
139   // Type() would return "DownloadAction".
140   virtual std::string Type() const = 0;
141 
142  protected:
143   // A weak pointer to the processor that owns this Action.
144   ActionProcessor* processor_;
145 };
146 
147 // Forward declare a couple classes we use.
148 template <typename T>
149 class ActionPipe;
150 template <typename T>
151 class ActionTraits;
152 
153 template <typename SubClass>
154 class Action : public AbstractAction {
155  public:
~Action()156   ~Action() override {}
157 
158   // Attaches an input pipe to this Action. This is optional; an Action
159   // doesn't need to have an input pipe. The input pipe must be of the type
160   // of object that this class expects.
161   // This is generally called by ActionPipe::Bond()
set_in_pipe(const std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>> & in_pipe)162   void set_in_pipe(
163       // this type is a fancy way of saying: a shared_ptr to an
164       // ActionPipe<InputObjectType>.
165       const std::shared_ptr<
166           ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>&
167           in_pipe) {
168     in_pipe_ = in_pipe;
169   }
170 
171   // Attaches an output pipe to this Action. This is optional; an Action
172   // doesn't need to have an output pipe. The output pipe must be of the type
173   // of object that this class expects.
174   // This is generally called by ActionPipe::Bond()
set_out_pipe(const std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>> & out_pipe)175   void set_out_pipe(
176       // this type is a fancy way of saying: a shared_ptr to an
177       // ActionPipe<OutputObjectType>.
178       const std::shared_ptr<
179           ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>&
180           out_pipe) {
181     out_pipe_ = out_pipe;
182   }
183 
184   // Returns true iff there is an associated input pipe. If there's an input
185   // pipe, there's an input object, but it may have been constructed with the
186   // default ctor if the previous action didn't call SetOutputObject().
HasInputObject()187   bool HasInputObject() const { return in_pipe_.get(); }
188 
189   // returns a const reference to the object in the input pipe.
GetInputObject()190   const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
191       const {
192     CHECK(HasInputObject());
193     return in_pipe_->contents();
194   }
195 
196   // Returns true iff there's an output pipe.
HasOutputPipe()197   bool HasOutputPipe() const { return out_pipe_.get(); }
198 
199   // Copies the object passed into the output pipe. It will be accessible to
200   // the next Action via that action's input pipe (which is the same as this
201   // Action's output pipe).
SetOutputObject(const typename ActionTraits<SubClass>::OutputObjectType & out_obj)202   void SetOutputObject(
203       const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
204     CHECK(HasOutputPipe());
205     out_pipe_->set_contents(out_obj);
206   }
207 
208   // Returns a reference to the object sitting in the output pipe.
GetOutputObject()209   const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
210     CHECK(HasOutputPipe());
211     return out_pipe_->contents();
212   }
213 
214  protected:
215   // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
216   // point to when the last such shared_ptr object dies. We consider the
217   // Actions on either end of a pipe to "own" the pipe. When the last Action
218   // of the two dies, the ActionPipe will die, too.
219   std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
220       in_pipe_;
221   std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
222       out_pipe_;
223 };
224 
225 };  // namespace chromeos_update_engine
226 
227 #endif  // UPDATE_ENGINE_COMMON_ACTION_H_
228