1 /* 2 * Copyright 2019 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 #pragma once 18 19 #include <bluetooth/log.h> 20 21 #include <chrono> 22 #include <functional> 23 #include <future> 24 #include <map> 25 #include <sstream> 26 #include <string> 27 #include <utility> 28 #include <vector> 29 30 #include "common/bind.h" 31 #include "os/handler.h" 32 #include "os/thread.h" 33 34 namespace bluetooth { 35 36 class Module; 37 class ModuleRegistry; 38 class TestModuleRegistry; 39 class FuzzTestModuleRegistry; 40 41 class ModuleFactory { 42 friend ModuleRegistry; 43 friend FuzzTestModuleRegistry; 44 45 public: 46 ModuleFactory(std::function<Module*()> ctor); 47 48 private: 49 std::function<Module*()> ctor_; 50 }; 51 52 class ModuleList { 53 friend Module; 54 friend ModuleRegistry; 55 56 public: 57 template <class T> add()58 void add() { 59 list_.push_back(&T::Factory); 60 } 61 62 // Return the number of modules in this list NumModules()63 size_t NumModules() const { return list_.size(); } 64 65 private: 66 std::vector<const ModuleFactory*> list_; 67 }; 68 69 // Each leaf node module must have a factory like so: 70 // 71 // static const ModuleFactory Factory; 72 // 73 // which will provide a constructor for the module registry to call. 74 // The module registry will also use the factory as the identifier 75 // for that module. 76 class Module { 77 friend ModuleRegistry; 78 friend TestModuleRegistry; 79 80 public: 81 virtual ~Module() = default; 82 83 protected: 84 // Populate the provided list with modules that must start before yours 85 virtual void ListDependencies(ModuleList* list) const = 0; 86 87 // You can grab your started dependencies during or after this call 88 // using GetDependency(), or access the module registry via GetModuleRegistry() 89 virtual void Start() = 0; 90 91 // Release all resources, you're about to be deleted 92 virtual void Stop() = 0; 93 94 virtual std::string ToString() const = 0; 95 96 ::bluetooth::os::Handler* GetHandler() const; 97 98 const ModuleRegistry* GetModuleRegistry() const; 99 100 template <class T> GetDependency()101 T* GetDependency() const { 102 return static_cast<T*>(GetDependency(&T::Factory)); 103 } 104 105 template <typename Functor, typename... Args> Call(Functor && functor,Args &&...args)106 void Call(Functor&& functor, Args&&... args) { 107 GetHandler()->Call(std::forward<Functor>(functor), std::forward<Args>(args)...); 108 } 109 110 template <typename T, typename Functor, typename... Args> CallOn(T * obj,Functor && functor,Args &&...args)111 void CallOn(T* obj, Functor&& functor, Args&&... args) { 112 GetHandler()->CallOn(obj, std::forward<Functor>(functor), std::forward<Args>(args)...); 113 } 114 115 private: 116 Module* GetDependency(const ModuleFactory* module) const; 117 118 ::bluetooth::os::Handler* handler_ = nullptr; 119 ModuleList dependencies_; 120 const ModuleRegistry* registry_; 121 }; 122 123 class ModuleRegistry { 124 friend Module; 125 friend class StackManager; 126 127 public: 128 template <class T> IsStarted()129 bool IsStarted() const { 130 return IsStarted(&T::Factory); 131 } 132 133 bool IsStarted(const ModuleFactory* factory) const; 134 135 // Start all the modules on this list and their dependencies 136 // in dependency order 137 void Start(ModuleList* modules, ::bluetooth::os::Thread* thread); 138 139 template <class T> Start(::bluetooth::os::Thread * thread)140 T* Start(::bluetooth::os::Thread* thread) { 141 return static_cast<T*>(Start(&T::Factory, thread)); 142 } 143 144 Module* Start(const ModuleFactory* id, ::bluetooth::os::Thread* thread); 145 146 // Stop all running modules in reverse order of start 147 void StopAll(); 148 149 protected: 150 Module* Get(const ModuleFactory* module) const; 151 152 void set_registry_and_handler(Module* instance, ::bluetooth::os::Thread* thread) const; 153 154 os::Handler* GetModuleHandler(const ModuleFactory* module) const; 155 156 std::map<const ModuleFactory*, Module*> started_modules_; 157 std::vector<const ModuleFactory*> start_order_; 158 std::string last_instance_; 159 }; 160 161 class TestModuleRegistry : public ModuleRegistry { 162 public: InjectTestModule(const ModuleFactory * module,Module * instance)163 void InjectTestModule(const ModuleFactory* module, Module* instance) { 164 start_order_.push_back(module); 165 started_modules_[module] = instance; 166 set_registry_and_handler(instance, &test_thread); 167 instance->Start(); 168 } 169 GetModuleUnderTest(const ModuleFactory * module)170 Module* GetModuleUnderTest(const ModuleFactory* module) const { return Get(module); } 171 172 template <class T> GetModuleUnderTest()173 T* GetModuleUnderTest() const { 174 return static_cast<T*>(GetModuleUnderTest(&T::Factory)); 175 } 176 GetTestModuleHandler(const ModuleFactory * module)177 os::Handler* GetTestModuleHandler(const ModuleFactory* module) const { 178 return GetModuleHandler(module); 179 } 180 GetTestThread()181 os::Thread& GetTestThread() { return test_thread; } 182 SynchronizeModuleHandler(const ModuleFactory * module,std::chrono::milliseconds timeout)183 bool SynchronizeModuleHandler(const ModuleFactory* module, 184 std::chrono::milliseconds timeout) const { 185 return SynchronizeHandler(GetTestModuleHandler(module), timeout); 186 } 187 SynchronizeHandler(os::Handler * handler,std::chrono::milliseconds timeout)188 bool SynchronizeHandler(os::Handler* handler, std::chrono::milliseconds timeout) const { 189 std::promise<void> promise; 190 auto future = promise.get_future(); 191 handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise))); 192 return future.wait_for(timeout) == std::future_status::ready; 193 } 194 195 private: 196 os::Thread test_thread{"test_thread", os::Thread::Priority::NORMAL}; 197 }; 198 199 class FuzzTestModuleRegistry : public TestModuleRegistry { 200 public: 201 template <class T> Inject(const ModuleFactory * overriding)202 T* Inject(const ModuleFactory* overriding) { 203 Module* instance = T::Factory.ctor_(); 204 InjectTestModule(overriding, instance); 205 return static_cast<T*>(instance); 206 } 207 208 template <class T> Start()209 T* Start() { 210 return ModuleRegistry::Start<T>(&GetTestThread()); 211 } 212 WaitForIdleAndStopAll()213 void WaitForIdleAndStopAll() { 214 if (!GetTestThread().GetReactor()->WaitForIdle(std::chrono::milliseconds(100))) { 215 log::error("idle timed out"); 216 } 217 StopAll(); 218 } 219 }; 220 221 } // namespace bluetooth 222