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 <flatbuffers/flatbuffers.h> 20 #include <chrono> 21 #include <functional> 22 #include <future> 23 #include <map> 24 #include <string> 25 #include <utility> 26 #include <vector> 27 28 #include "common/bind.h" 29 #include "dumpsys_data_generated.h" 30 #include "os/handler.h" 31 #include "os/log.h" 32 #include "os/thread.h" 33 34 namespace bluetooth { 35 36 class Module; 37 class ModuleDumper; 38 class ModuleRegistry; 39 class TestModuleRegistry; 40 class FuzzTestModuleRegistry; 41 42 class ModuleFactory { 43 friend ModuleRegistry; 44 friend FuzzTestModuleRegistry; 45 46 public: 47 ModuleFactory(std::function<Module*()> ctor); 48 49 private: 50 std::function<Module*()> ctor_; 51 }; 52 53 class ModuleList { 54 friend Module; 55 friend ModuleRegistry; 56 57 public: 58 template <class T> add()59 void add() { 60 list_.push_back(&T::Factory); 61 } 62 63 private: 64 std::vector<const ModuleFactory*> list_; 65 }; 66 67 using DumpsysDataFinisher = std::function<void(DumpsysDataBuilder* dumpsys_data_builder)>; 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 ModuleDumper; 78 friend ModuleRegistry; 79 friend TestModuleRegistry; 80 81 public: 82 virtual ~Module() = default; 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 // Get relevant state data from the module 95 virtual DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const; 96 97 virtual std::string ToString() const = 0; 98 99 ::bluetooth::os::Handler* GetHandler() const; 100 101 const ModuleRegistry* GetModuleRegistry() const; 102 103 template <class T> GetDependency()104 T* GetDependency() const { 105 return static_cast<T*>(GetDependency(&T::Factory)); 106 } 107 108 template <typename Functor, typename... Args> Call(Functor && functor,Args &&...args)109 void Call(Functor&& functor, Args&&... args) { 110 GetHandler()->Call(std::forward<Functor>(functor), std::forward<Args>(args)...); 111 } 112 113 template <typename T, typename Functor, typename... Args> CallOn(T * obj,Functor && functor,Args &&...args)114 void CallOn(T* obj, Functor&& functor, Args&&... args) { 115 GetHandler()->CallOn(obj, std::forward<Functor>(functor), std::forward<Args>(args)...); 116 } 117 118 private: 119 Module* GetDependency(const ModuleFactory* module) const; 120 121 ::bluetooth::os::Handler* handler_ = nullptr; 122 ModuleList dependencies_; 123 const ModuleRegistry* registry_; 124 }; 125 126 class ModuleRegistry { 127 friend Module; 128 friend ModuleDumper; 129 friend class StackManager; 130 public: 131 template <class T> IsStarted()132 bool IsStarted() const { 133 return IsStarted(&T::Factory); 134 } 135 136 bool IsStarted(const ModuleFactory* factory) const; 137 138 // Start all the modules on this list and their dependencies 139 // in dependency order 140 void Start(ModuleList* modules, ::bluetooth::os::Thread* thread); 141 142 template <class T> Start(::bluetooth::os::Thread * thread)143 T* Start(::bluetooth::os::Thread* thread) { 144 return static_cast<T*>(Start(&T::Factory, thread)); 145 } 146 147 Module* Start(const ModuleFactory* id, ::bluetooth::os::Thread* thread); 148 149 // Stop all running modules in reverse order of start 150 void StopAll(); 151 152 protected: 153 Module* Get(const ModuleFactory* module) const; 154 155 void set_registry_and_handler(Module* instance, ::bluetooth::os::Thread* thread) const; 156 157 os::Handler* GetModuleHandler(const ModuleFactory* module) const; 158 159 std::map<const ModuleFactory*, Module*> started_modules_; 160 std::vector<const ModuleFactory*> start_order_; 161 std::string last_instance_; 162 }; 163 164 class ModuleDumper { 165 public: ModuleDumper(const ModuleRegistry & module_registry,const char * title)166 ModuleDumper(const ModuleRegistry& module_registry, const char* title) 167 : module_registry_(module_registry), title_(title) {} 168 void DumpState(std::string* output) const; 169 170 private: 171 const ModuleRegistry& module_registry_; 172 const std::string title_; 173 }; 174 175 class TestModuleRegistry : public ModuleRegistry { 176 public: InjectTestModule(const ModuleFactory * module,Module * instance)177 void InjectTestModule(const ModuleFactory* module, Module* instance) { 178 start_order_.push_back(module); 179 started_modules_[module] = instance; 180 set_registry_and_handler(instance, &test_thread); 181 instance->Start(); 182 } 183 GetModuleUnderTest(const ModuleFactory * module)184 Module* GetModuleUnderTest(const ModuleFactory* module) const { 185 return Get(module); 186 } 187 188 template <class T> GetModuleUnderTest()189 T* GetModuleUnderTest() const { 190 return static_cast<T*>(GetModuleUnderTest(&T::Factory)); 191 } 192 GetTestModuleHandler(const ModuleFactory * module)193 os::Handler* GetTestModuleHandler(const ModuleFactory* module) const { 194 return GetModuleHandler(module); 195 } 196 GetTestThread()197 os::Thread& GetTestThread() { 198 return test_thread; 199 } 200 SynchronizeModuleHandler(const ModuleFactory * module,std::chrono::milliseconds timeout)201 bool SynchronizeModuleHandler(const ModuleFactory* module, std::chrono::milliseconds timeout) const { 202 return SynchronizeHandler(GetTestModuleHandler(module), timeout); 203 } 204 SynchronizeHandler(os::Handler * handler,std::chrono::milliseconds timeout)205 bool SynchronizeHandler(os::Handler* handler, std::chrono::milliseconds timeout) const { 206 std::promise<void> promise; 207 auto future = promise.get_future(); 208 handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise))); 209 return future.wait_for(timeout) == std::future_status::ready; 210 } 211 212 private: 213 os::Thread test_thread{"test_thread", os::Thread::Priority::NORMAL}; 214 }; 215 216 class FuzzTestModuleRegistry : public TestModuleRegistry { 217 public: 218 template <class T> Inject(const ModuleFactory * overriding)219 T* Inject(const ModuleFactory* overriding) { 220 Module* instance = T::Factory.ctor_(); 221 InjectTestModule(overriding, instance); 222 return static_cast<T*>(instance); 223 } 224 225 template <class T> Start()226 T* Start() { 227 return ModuleRegistry::Start<T>(&GetTestThread()); 228 } 229 WaitForIdleAndStopAll()230 void WaitForIdleAndStopAll() { 231 if (!GetTestThread().GetReactor()->WaitForIdle(std::chrono::milliseconds(100))) { 232 LOG_ERROR("idle timed out"); 233 } 234 StopAll(); 235 } 236 }; 237 238 } // namespace bluetooth 239