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