From 10756a63724289d670c313130f12ad2475033264 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 6 Nov 2024 19:14:09 +0800 Subject: [PATCH] [application] refactor to decouple Application with InfraLinkSelector (#2574) This commit refactors the `Application` class. In specific: 1. Decouple `Application` with `InfraLinkSelector` by moving `InfraLinkSelector` out of the `Application` class. The current dependency causes that we cannot move the creation of `ThreadHost` instance out of the constructor of the `Application` class. 2. Move `Ncp::ThreadHost::Create` out of the `Application` constructor. This change solves the fuzzer test issue in Android: When we create an `Application` object, we have to initlialize the radio which will cause error in the fuzz environment. With this change, we can pass a FuzzThreadHost object to the `Application`. --- src/agent/application.cpp | 51 ++++++++++++++------------------------- src/agent/application.hpp | 38 +++++++++++++++++------------ src/agent/main.cpp | 19 +++++++++++++-- 3 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/agent/application.cpp b/src/agent/application.cpp index 381d60aadf5..fb6cee2cb46 100644 --- a/src/agent/application.cpp +++ b/src/agent/application.cpp @@ -51,33 +51,23 @@ namespace otbr { std::atomic_bool Application::sShouldTerminate(false); const struct timeval Application::kPollTimeout = {OTBR_MAINLOOP_POLL_TIMEOUT_SEC, 0}; -Application::Application(const std::string &aInterfaceName, - const std::vector &aBackboneInterfaceNames, - const std::vector &aRadioUrls, - bool aEnableAutoAttach, - const std::string &aRestListenAddress, - int aRestListenPort) +Application::Application(Ncp::ThreadHost &aHost, + const std::string &aInterfaceName, + const std::string &aBackboneInterfaceName, + const std::string &aRestListenAddress, + int aRestListenPort) : mInterfaceName(aInterfaceName) -#if __linux__ - , mInfraLinkSelector(aBackboneInterfaceNames) - , mBackboneInterfaceName(mInfraLinkSelector.Select()) -#else - , mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front()) -#endif - , mHost(Ncp::ThreadHost::Create(mInterfaceName.c_str(), - aRadioUrls, - mBackboneInterfaceName, - /* aDryRun */ false, - aEnableAutoAttach)) + , mBackboneInterfaceName(aBackboneInterfaceName.c_str()) + , mHost(aHost) #if OTBR_ENABLE_MDNS , mPublisher( Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { mMdnsStateSubject.UpdateState(aState); })) #endif #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT - , mDBusAgent(MakeUnique(*mHost, *mPublisher)) + , mDBusAgent(MakeUnique(mHost, *mPublisher)) #endif { - if (mHost->GetCoprocessorType() == OT_COPROCESSOR_RCP) + if (mHost.GetCoprocessorType() == OT_COPROCESSOR_RCP) { CreateRcpMode(aRestListenAddress, aRestListenPort); } @@ -85,9 +75,9 @@ Application::Application(const std::string &aInterfaceName, void Application::Init(void) { - mHost->Init(); + mHost.Init(); - switch (mHost->GetCoprocessorType()) + switch (mHost.GetCoprocessorType()) { case OT_COPROCESSOR_RCP: InitRcpMode(); @@ -100,12 +90,12 @@ void Application::Init(void) break; } - otbrLogInfo("Co-processor version: %s", mHost->GetCoprocessorVersion()); + otbrLogInfo("Co-processor version: %s", mHost.GetCoprocessorVersion()); } void Application::Deinit(void) { - switch (mHost->GetCoprocessorType()) + switch (mHost.GetCoprocessorType()) { case OT_COPROCESSOR_RCP: DeinitRcpMode(); @@ -118,15 +108,13 @@ void Application::Deinit(void) break; } - mHost->Deinit(); + mHost.Deinit(); } otbrError Application::Run(void) { otbrError error = OTBR_ERROR_NONE; - otbrLogInfo("Thread Border Router started on AIL %s.", mBackboneInterfaceName); - #ifdef HAVE_LIBSYSTEMD if (getenv("SYSTEMD_EXEC_PID") != nullptr) { @@ -173,17 +161,14 @@ otbrError Application::Run(void) { MainloopManager::GetInstance().Process(mainloop); -#if __linux__ + if (mErrorCondition) { - const char *newInfraLink = mInfraLinkSelector.Select(); - - if (mBackboneInterfaceName != newInfraLink) + error = mErrorCondition(); + if (error != OTBR_ERROR_NONE) { - error = OTBR_ERROR_INFRA_LINK_CHANGED; break; } } -#endif } else if (errno != EINTR) { @@ -204,7 +189,7 @@ void Application::HandleSignal(int aSignal) void Application::CreateRcpMode(const std::string &aRestListenAddress, int aRestListenPort) { - otbr::Ncp::RcpHost &rcpHost = static_cast(*mHost); + otbr::Ncp::RcpHost &rcpHost = static_cast(mHost); #if OTBR_ENABLE_BORDER_AGENT mBorderAgent = MakeUnique(rcpHost, *mPublisher); #endif diff --git a/src/agent/application.hpp b/src/agent/application.hpp index c09d6908ff7..9ae141ba5d3 100644 --- a/src/agent/application.hpp +++ b/src/agent/application.hpp @@ -87,22 +87,22 @@ class VendorServer; class Application : private NonCopyable { public: + typedef std::function ErrorCondition; + /** * This constructor initializes the Application instance. * + * @param[in] aHost A reference to the ThreadHost object. * @param[in] aInterfaceName Name of the Thread network interface. * @param[in] aBackboneInterfaceName Name of the backbone network interface. - * @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio). - * @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network. * @param[in] aRestListenAddress Network address to listen on. * @param[in] aRestListenPort Network port to listen on. */ - explicit Application(const std::string &aInterfaceName, - const std::vector &aBackboneInterfaceNames, - const std::vector &aRadioUrls, - bool aEnableAutoAttach, - const std::string &aRestListenAddress, - int aRestListenPort); + explicit Application(Ncp::ThreadHost &aHost, + const std::string &aInterfaceName, + const std::string &aBackboneInterfaceName, + const std::string &aRestListenAddress, + int aRestListenPort); /** * This method initializes the Application instance. @@ -114,6 +114,16 @@ class Application : private NonCopyable */ void Deinit(void); + /** + * This method sets an error condition for the application. + * + * If the error condition returns an error other than 'OTBR_ERROR_NONE', the application will + * exit the loop in `Run`. + * + * @param[in] aErrorCondition The error condition. + */ + void SetErrorCondition(ErrorCondition aErrorCondition) { mErrorCondition = aErrorCondition; } + /** * This method runs the application until exit. * @@ -127,7 +137,7 @@ class Application : private NonCopyable * * @returns The OpenThread controller object. */ - Ncp::ThreadHost &GetHost(void) { return *mHost; } + Ncp::ThreadHost &GetHost(void) { return mHost; } #if OTBR_ENABLE_MDNS /** @@ -250,12 +260,9 @@ class Application : private NonCopyable void InitNcpMode(void); void DeinitNcpMode(void); - std::string mInterfaceName; -#if __linux__ - otbr::Utils::InfraLinkSelector mInfraLinkSelector; -#endif - const char *mBackboneInterfaceName; - std::unique_ptr mHost; + std::string mInterfaceName; + const char *mBackboneInterfaceName; + Ncp::ThreadHost &mHost; #if OTBR_ENABLE_MDNS Mdns::StateSubject mMdnsStateSubject; std::unique_ptr mPublisher; @@ -289,6 +296,7 @@ class Application : private NonCopyable #endif static std::atomic_bool sShouldTerminate; + ErrorCondition mErrorCondition; }; /** diff --git a/src/agent/main.cpp b/src/agent/main.cpp index 525ea3f74b5..1732ba9b0c8 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -319,11 +319,26 @@ static int realmain(int argc, char *argv[]) } { - otbr::Application app(interfaceName, backboneInterfaceNames, radioUrls, enableAutoAttach, restListenAddress, - restListenPort); +#if __linux__ + otbr::Utils::InfraLinkSelector infraLinkSelector(backboneInterfaceNames); + const std::string backboneInterfaceName = infraLinkSelector.Select(); + otbr::Application::ErrorCondition errorCondition = [&backboneInterfaceName, &infraLinkSelector](void) { + return std::string(infraLinkSelector.Select()) == backboneInterfaceName ? OTBR_ERROR_NONE + : OTBR_ERROR_INFRA_LINK_CHANGED; + }; +#else + const std::string backboneInterfaceName = backboneInterfaceNames.empty() ? "" : backboneInterfaceNames.front(); +#endif + std::unique_ptr host = otbr::Ncp::ThreadHost::Create( + interfaceName, radioUrls, backboneInterfaceName.c_str(), /* aDryRun */ false, enableAutoAttach); + + otbr::Application app(*host, interfaceName, backboneInterfaceName, restListenAddress, restListenPort); gApp = &app; app.Init(); +#if __linux__ + app.SetErrorCondition(errorCondition); +#endif ret = app.Run();