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;
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 };
160 
161 class ModuleDumper {
162  public:
ModuleDumper(const ModuleRegistry & module_registry,const char * title)163   ModuleDumper(const ModuleRegistry& module_registry, const char* title)
164       : module_registry_(module_registry), title_(title) {}
165   void DumpState(std::string* output) const;
166 
167  private:
168   const ModuleRegistry& module_registry_;
169   const std::string title_;
170 };
171 
172 class TestModuleRegistry : public ModuleRegistry {
173  public:
InjectTestModule(const ModuleFactory * module,Module * instance)174   void InjectTestModule(const ModuleFactory* module, Module* instance) {
175     start_order_.push_back(module);
176     started_modules_[module] = instance;
177     set_registry_and_handler(instance, &test_thread);
178     instance->Start();
179   }
180 
GetModuleUnderTest(const ModuleFactory * module)181   Module* GetModuleUnderTest(const ModuleFactory* module) const {
182     return Get(module);
183   }
184 
185   template <class T>
GetModuleUnderTest()186   T* GetModuleUnderTest() const {
187     return static_cast<T*>(GetModuleUnderTest(&T::Factory));
188   }
189 
GetTestModuleHandler(const ModuleFactory * module)190   os::Handler* GetTestModuleHandler(const ModuleFactory* module) const {
191     return GetModuleHandler(module);
192   }
193 
GetTestThread()194   os::Thread& GetTestThread() {
195     return test_thread;
196   }
197 
SynchronizeModuleHandler(const ModuleFactory * module,std::chrono::milliseconds timeout)198   bool SynchronizeModuleHandler(const ModuleFactory* module, std::chrono::milliseconds timeout) const {
199     return SynchronizeHandler(GetTestModuleHandler(module), timeout);
200   }
201 
SynchronizeHandler(os::Handler * handler,std::chrono::milliseconds timeout)202   bool SynchronizeHandler(os::Handler* handler, std::chrono::milliseconds timeout) const {
203     std::promise<void> promise;
204     auto future = promise.get_future();
205     handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
206     return future.wait_for(timeout) == std::future_status::ready;
207   }
208 
209  private:
210   os::Thread test_thread{"test_thread", os::Thread::Priority::NORMAL};
211 };
212 
213 class FuzzTestModuleRegistry : public TestModuleRegistry {
214  public:
215   template <class T>
Inject(const ModuleFactory * overriding)216   T* Inject(const ModuleFactory* overriding) {
217     Module* instance = T::Factory.ctor_();
218     InjectTestModule(overriding, instance);
219     return static_cast<T*>(instance);
220   }
221 
222   template <class T>
Start()223   T* Start() {
224     return ModuleRegistry::Start<T>(&GetTestThread());
225   }
226 
WaitForIdleAndStopAll()227   void WaitForIdleAndStopAll() {
228     if (!GetTestThread().GetReactor()->WaitForIdle(std::chrono::milliseconds(100))) {
229       LOG_ERROR("idle timed out");
230     }
231     StopAll();
232   }
233 };
234 
235 }  // namespace bluetooth
236