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