• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 // Timeout for waiting for a handler to stop, used in Handler::WaitUntilStopped()
36 constexpr std::chrono::milliseconds kHandlerStopTimeout = std::chrono::milliseconds(2000);
37 
38 namespace shim {
39 class Stack;
40 }  // namespace shim
41 
42 class Module;
43 class ModuleRegistry;
44 class TestModuleRegistry;
45 class FuzzTestModuleRegistry;
46 
47 class ModuleFactory {
48   friend ModuleRegistry;
49   friend FuzzTestModuleRegistry;
50 
51 public:
52   ModuleFactory(std::function<Module*()> ctor);
53 
54 private:
55   std::function<Module*()> ctor_;
56 };
57 
58 class ModuleList {
59   friend Module;
60   friend ModuleRegistry;
61 
62 public:
63   template <class T>
add()64   void add() {
65     list_.push_back(&T::Factory);
66   }
67 
68   // Return the number of modules in this list
NumModules()69   size_t NumModules() const { return list_.size(); }
70 
71 private:
72   std::vector<const ModuleFactory*> list_;
73 };
74 
75 // Each leaf node module must have a factory like so:
76 //
77 // static const ModuleFactory Factory;
78 //
79 // which will provide a constructor for the module registry to call.
80 // The module registry will also use the factory as the identifier
81 // for that module.
82 class Module {
83   friend ModuleRegistry;
84   friend TestModuleRegistry;
85 
86 public:
87   virtual ~Module() = default;
88 
89 protected:
90   Module() = default;
Module(os::Handler * handler)91   Module(os::Handler* handler) : handler_(handler) {}
92 
93   // Populate the provided list with modules that must start before yours
94   virtual void ListDependencies(ModuleList* list) const = 0;
95 
96   // You can grab your started dependencies during or after this call
97   // using GetDependency(), or access the module registry via GetModuleRegistry()
98   virtual void Start() = 0;
99 
100   // Release all resources, you're about to be deleted
101   virtual void Stop() = 0;
102 
103   virtual std::string ToString() const = 0;
104 
105   ::bluetooth::os::Handler* GetHandler() const;
106 
107   const ModuleRegistry* GetModuleRegistry() const;
108 
109   template <class T>
GetDependency()110   T* GetDependency() const {
111     return static_cast<T*>(GetDependency(&T::Factory));
112   }
113 
114   template <typename Functor, typename... Args>
Call(Functor && functor,Args &&...args)115   void Call(Functor&& functor, Args&&... args) {
116     GetHandler()->Call(std::forward<Functor>(functor), std::forward<Args>(args)...);
117   }
118 
119   template <typename T, typename Functor, typename... Args>
CallOn(T * obj,Functor && functor,Args &&...args)120   void CallOn(T* obj, Functor&& functor, Args&&... args) {
121     GetHandler()->CallOn(obj, std::forward<Functor>(functor), std::forward<Args>(args)...);
122   }
123 
124 private:
125   Module* GetDependency(const ModuleFactory* module) const;
126 
127   ::bluetooth::os::Handler* handler_ = nullptr;
128   ModuleList dependencies_;
129   const ModuleRegistry* registry_ = nullptr;
130 };
131 
132 class ModuleRegistry {
133   friend Module;
134   friend shim::Stack;
135 
136 public:
137   template <class T>
IsStarted()138   bool IsStarted() const {
139     return IsStarted(&T::Factory);
140   }
141 
142   bool IsStarted(const ModuleFactory* factory) const;
143 
144   // Start all the modules on this list and their dependencies
145   // in dependency order
146   void Start(ModuleList* modules, ::bluetooth::os::Thread* thread, os::Handler* handler);
147 
148   template <class T>
Start(::bluetooth::os::Thread * thread,os::Handler * handler)149   T* Start(::bluetooth::os::Thread* thread, os::Handler* handler) {
150     return static_cast<T*>(Start(&T::Factory, thread, handler));
151   }
152 
153   Module* Start(const ModuleFactory* id, ::bluetooth::os::Thread* thread, os::Handler* handler);
154 
155   // Stop all running modules in reverse order of start
156   void StopAll();
157 
158 protected:
159   Module* Get(const ModuleFactory* module) const;
160 
161   void set_registry_and_handler(Module* instance, ::bluetooth::os::Thread* thread,
162                                 os::Handler* handler) const;
163 
164   os::Handler* GetModuleHandler(const ModuleFactory* module) const;
165 
166   std::map<const ModuleFactory*, Module*> started_modules_;
167   std::vector<const ModuleFactory*> start_order_;
168   std::string last_instance_;
169 
170 private:
171   mutable std::mutex started_modules_guard_;
172 };
173 
174 class TestModuleRegistry : public ModuleRegistry {
175 public:
InjectTestModule(const ModuleFactory * module,Module * instance)176   void InjectTestModule(const ModuleFactory* module, Module* instance) {
177     start_order_.push_back(module);
178     started_modules_[module] = instance;
179     set_registry_and_handler(instance, &test_thread, test_handler_);
180     instance->Start();
181   }
182 
GetModuleUnderTest(const ModuleFactory * module)183   Module* GetModuleUnderTest(const ModuleFactory* module) const { return Get(module); }
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() { return test_thread; }
GetTestHandler()195   os::Handler* GetTestHandler() { return test_handler_; }
196 
197   // Override the StopAll method to use the test thread and handler.
198   void StopAll();
199 
SynchronizeModuleHandler(const ModuleFactory * module,std::chrono::milliseconds timeout)200   bool SynchronizeModuleHandler(const ModuleFactory* module,
201                                 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   os::Handler* test_handler_ = new os::Handler(&test_thread);
215 };
216 
217 class FuzzTestModuleRegistry : public TestModuleRegistry {
218 public:
219   template <class T>
Inject(const ModuleFactory * overriding)220   T* Inject(const ModuleFactory* overriding) {
221     Module* instance = T::Factory.ctor_();
222     InjectTestModule(overriding, instance);
223     return static_cast<T*>(instance);
224   }
225 
226   template <class T>
Start()227   T* Start() {
228     return ModuleRegistry::Start<T>(&GetTestThread(), GetTestHandler());
229   }
230 
WaitForIdleAndStopAll()231   void WaitForIdleAndStopAll() {
232     if (!GetTestThread().GetReactor()->WaitForIdle(std::chrono::milliseconds(100))) {
233       log::error("idle timed out");
234     }
235     StopAll();
236   }
237 };
238 
239 }  // namespace bluetooth
240