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