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 // An action that does nothing and completes with kSuccess immediately. 226 class NoOpAction : public AbstractAction { 227 public: ~NoOpAction()228 ~NoOpAction() override {} PerformAction()229 void PerformAction() override { 230 processor_->ActionComplete(this, ErrorCode::kSuccess); 231 } StaticType()232 static std::string StaticType() { return "NoOpAction"; } Type()233 std::string Type() const override { return StaticType(); } 234 }; 235 236 }; // namespace chromeos_update_engine 237 238 #endif // UPDATE_ENGINE_COMMON_ACTION_H_ 239