You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
6.3 KiB
237 lines
6.3 KiB
/*
|
|
* Copyright 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <flatbuffers/flatbuffers.h>
|
|
#include <functional>
|
|
#include <future>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "common/bind.h"
|
|
#include "dumpsys_data_generated.h"
|
|
#include "os/handler.h"
|
|
#include "os/log.h"
|
|
#include "os/thread.h"
|
|
|
|
namespace bluetooth {
|
|
|
|
class Module;
|
|
class ModuleDumper;
|
|
class ModuleRegistry;
|
|
class TestModuleRegistry;
|
|
class FuzzTestModuleRegistry;
|
|
|
|
class ModuleFactory {
|
|
friend ModuleRegistry;
|
|
friend FuzzTestModuleRegistry;
|
|
|
|
public:
|
|
ModuleFactory(std::function<Module*()> ctor);
|
|
|
|
private:
|
|
std::function<Module*()> ctor_;
|
|
};
|
|
|
|
class ModuleList {
|
|
friend Module;
|
|
friend ModuleRegistry;
|
|
|
|
public:
|
|
template <class T>
|
|
void add() {
|
|
list_.push_back(&T::Factory);
|
|
}
|
|
|
|
private:
|
|
std::vector<const ModuleFactory*> list_;
|
|
};
|
|
|
|
using DumpsysDataFinisher = std::function<void(DumpsysDataBuilder* dumpsys_data_builder)>;
|
|
|
|
// Each leaf node module must have a factory like so:
|
|
//
|
|
// static const ModuleFactory Factory;
|
|
//
|
|
// which will provide a constructor for the module registry to call.
|
|
// The module registry will also use the factory as the identifier
|
|
// for that module.
|
|
class Module {
|
|
friend ModuleDumper;
|
|
friend ModuleRegistry;
|
|
friend TestModuleRegistry;
|
|
|
|
public:
|
|
virtual ~Module() = default;
|
|
protected:
|
|
// Populate the provided list with modules that must start before yours
|
|
virtual void ListDependencies(ModuleList* list) = 0;
|
|
|
|
// You can grab your started dependencies during or after this call
|
|
// using GetDependency(), or access the module registry via GetModuleRegistry()
|
|
virtual void Start() = 0;
|
|
|
|
// Release all resources, you're about to be deleted
|
|
virtual void Stop() = 0;
|
|
|
|
// Get relevant state data from the module
|
|
virtual DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const;
|
|
|
|
virtual std::string ToString() const = 0;
|
|
|
|
::bluetooth::os::Handler* GetHandler() const;
|
|
|
|
const ModuleRegistry* GetModuleRegistry() const;
|
|
|
|
template <class T>
|
|
T* GetDependency() const {
|
|
return static_cast<T*>(GetDependency(&T::Factory));
|
|
}
|
|
|
|
template <typename Functor, typename... Args>
|
|
void Call(Functor&& functor, Args&&... args) {
|
|
GetHandler()->Call(std::forward<Functor>(functor), std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <typename T, typename Functor, typename... Args>
|
|
void CallOn(T* obj, Functor&& functor, Args&&... args) {
|
|
GetHandler()->CallOn(obj, std::forward<Functor>(functor), std::forward<Args>(args)...);
|
|
}
|
|
|
|
private:
|
|
Module* GetDependency(const ModuleFactory* module) const;
|
|
|
|
::bluetooth::os::Handler* handler_ = nullptr;
|
|
ModuleList dependencies_;
|
|
const ModuleRegistry* registry_;
|
|
};
|
|
|
|
class ModuleRegistry {
|
|
friend Module;
|
|
friend ModuleDumper;
|
|
friend class StackManager;
|
|
public:
|
|
template <class T>
|
|
bool IsStarted() const {
|
|
return IsStarted(&T::Factory);
|
|
}
|
|
|
|
bool IsStarted(const ModuleFactory* factory) const;
|
|
|
|
// Start all the modules on this list and their dependencies
|
|
// in dependency order
|
|
void Start(ModuleList* modules, ::bluetooth::os::Thread* thread);
|
|
|
|
template <class T>
|
|
T* Start(::bluetooth::os::Thread* thread) {
|
|
return static_cast<T*>(Start(&T::Factory, thread));
|
|
}
|
|
|
|
Module* Start(const ModuleFactory* id, ::bluetooth::os::Thread* thread);
|
|
|
|
// Stop all running modules in reverse order of start
|
|
void StopAll();
|
|
|
|
protected:
|
|
Module* Get(const ModuleFactory* module) const;
|
|
|
|
void set_registry_and_handler(Module* instance, ::bluetooth::os::Thread* thread) const;
|
|
|
|
os::Handler* GetModuleHandler(const ModuleFactory* module) const;
|
|
|
|
std::map<const ModuleFactory*, Module*> started_modules_;
|
|
std::vector<const ModuleFactory*> start_order_;
|
|
std::string last_instance_;
|
|
};
|
|
|
|
class ModuleDumper {
|
|
public:
|
|
ModuleDumper(const ModuleRegistry& module_registry, const char* title)
|
|
: module_registry_(module_registry), title_(title) {}
|
|
void DumpState(std::string* output) const;
|
|
|
|
private:
|
|
const ModuleRegistry& module_registry_;
|
|
const std::string title_;
|
|
};
|
|
|
|
class TestModuleRegistry : public ModuleRegistry {
|
|
public:
|
|
void InjectTestModule(const ModuleFactory* module, Module* instance) {
|
|
start_order_.push_back(module);
|
|
started_modules_[module] = instance;
|
|
set_registry_and_handler(instance, &test_thread);
|
|
instance->Start();
|
|
}
|
|
|
|
Module* GetModuleUnderTest(const ModuleFactory* module) const {
|
|
return Get(module);
|
|
}
|
|
|
|
template <class T>
|
|
T* GetModuleUnderTest() const {
|
|
return static_cast<T*>(GetModuleUnderTest(&T::Factory));
|
|
}
|
|
|
|
os::Handler* GetTestModuleHandler(const ModuleFactory* module) const {
|
|
return GetModuleHandler(module);
|
|
}
|
|
|
|
os::Thread& GetTestThread() {
|
|
return test_thread;
|
|
}
|
|
|
|
bool SynchronizeModuleHandler(const ModuleFactory* module, std::chrono::milliseconds timeout) const {
|
|
return SynchronizeHandler(GetTestModuleHandler(module), timeout);
|
|
}
|
|
|
|
bool SynchronizeHandler(os::Handler* handler, std::chrono::milliseconds timeout) const {
|
|
std::promise<void> promise;
|
|
auto future = promise.get_future();
|
|
handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
|
|
return future.wait_for(timeout) == std::future_status::ready;
|
|
}
|
|
|
|
private:
|
|
os::Thread test_thread{"test_thread", os::Thread::Priority::NORMAL};
|
|
};
|
|
|
|
class FuzzTestModuleRegistry : public TestModuleRegistry {
|
|
public:
|
|
template <class T>
|
|
T* Inject(const ModuleFactory* overriding) {
|
|
Module* instance = T::Factory.ctor_();
|
|
InjectTestModule(overriding, instance);
|
|
return static_cast<T*>(instance);
|
|
}
|
|
|
|
template <class T>
|
|
T* Start() {
|
|
return ModuleRegistry::Start<T>(&GetTestThread());
|
|
}
|
|
|
|
void WaitForIdleAndStopAll() {
|
|
if (!GetTestThread().GetReactor()->WaitForIdle(std::chrono::milliseconds(100))) {
|
|
LOG_ERROR("idle timed out");
|
|
}
|
|
StopAll();
|
|
}
|
|
};
|
|
|
|
} // namespace bluetooth
|