From c7025658d79551ee9f28520fbe010526cb893ab9 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Tue, 1 Nov 2022 23:29:21 +0900 Subject: [PATCH] [Tizen][Web] Fix WebView terminate crash Due to the web context closed before all webview released, mPlugin and mDestroyWebEnginePtr are invalid. This patch make reference count so we can assume that plugin is alive Change-Id: I15938f5b4a955bbf2fa40747939937bfe228ee3d Signed-off-by: Eunki, Hong --- .../internal/web-engine/common/web-engine-impl.cpp | 225 ++++++++++++++------- dali/internal/web-engine/common/web-engine-impl.h | 19 -- 2 files changed, 147 insertions(+), 97 deletions(-) mode change 100755 => 100644 dali/internal/web-engine/common/web-engine-impl.cpp diff --git a/dali/internal/web-engine/common/web-engine-impl.cpp b/dali/internal/web-engine/common/web-engine-impl.cpp old mode 100755 new mode 100644 index 558dac7..c530481 --- a/dali/internal/web-engine/common/web-engine-impl.cpp +++ b/dali/internal/web-engine/common/web-engine-impl.cpp @@ -53,10 +53,6 @@ constexpr char const* const kPluginFullNamePrefix = "libdali2-web-engine-"; constexpr char const* const kPluginFullNamePostfix = "-plugin.so"; constexpr char const* const kPluginFullNameDefault = "libdali2-web-engine-plugin.so"; -// Note: Dali WebView policy does not allow to use multiple web engines in an application. -// So once pluginName is set to non-empty string, it will not change. -std::string pluginName; - std::string MakePluginName(const char* environmentName) { std::stringstream fullName; @@ -71,114 +67,184 @@ Dali::BaseHandle Create() Dali::TypeRegistration type(typeid(Dali::WebEngine), typeid(Dali::BaseHandle), Create); -} // unnamed namespace - -void* WebEngine::mHandle = nullptr; -WebEngine::CreateWebEngineFunction WebEngine::mCreateWebEnginePtr = nullptr; -WebEngine::DestroyWebEngineFunction WebEngine::mDestroyWebEnginePtr = nullptr; - -WebEnginePtr WebEngine::New() -{ - WebEngine* instance = new WebEngine(); - if(!instance->Initialize()) +/** + * @brief Control the WebEnginePlugin library lifecycle. + */ +struct WebEnginePluginObject +{ +public: + WebEnginePluginObject() + : mPluginName{}, + mHandle{nullptr}, + mCreateWebEnginePtr{nullptr}, + mDestroyWebEnginePtr{nullptr}, + mGetWebEngineContextPtr{nullptr}, + mGetWebEngineCookieManagerPtr{nullptr} { - delete instance; - return nullptr; } - return instance; -} - -Dali::WebEngineContext* WebEngine::GetContext() -{ - if(!InitializePluginHandle()) + ~WebEnginePluginObject() { - return nullptr; + if(mHandle) + { + dlclose(mHandle); + mHandle = nullptr; + } } - using GetWebEngineContext = Dali::WebEngineContext* (*)(); - GetWebEngineContext getWebEngineContextPtr = reinterpret_cast(dlsym(mHandle, "GetWebEngineContext")); - if(getWebEngineContextPtr) + bool InitializePluginHandle() { - return getWebEngineContextPtr(); - } + if(mHandle) + { + DALI_LOG_ERROR("Plugin.so has been opened already.\n"); + return true; + } - return nullptr; -} + if(mPluginName.length() == 0) + { + // mPluginName is not initialized yet. + const char* name = EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_WEB_ENGINE_NAME); + if(name) + { + mPluginName = MakePluginName(name); + } + else + { + mPluginName = std::string(kPluginFullNameDefault); + } + } -Dali::WebEngineCookieManager* WebEngine::GetCookieManager() -{ - if(!InitializePluginHandle()) - { - return nullptr; + mHandle = dlopen(mPluginName.c_str(), RTLD_LAZY); + if(!mHandle) + { + DALI_LOG_ERROR("Can't load %s : %s\n", mPluginName.c_str(), dlerror()); + return false; + } + + mCreateWebEnginePtr = reinterpret_cast(dlsym(mHandle, "CreateWebEnginePlugin")); + if(mCreateWebEnginePtr == nullptr) + { + DALI_LOG_ERROR("Can't load symbol CreateWebEnginePlugin(), error: %s\n", dlerror()); + + return false; + } + + mDestroyWebEnginePtr = reinterpret_cast(dlsym(mHandle, "DestroyWebEnginePlugin")); + if(mDestroyWebEnginePtr == nullptr) + { + DALI_LOG_ERROR("Can't load symbol DestroyWebEnginePlugin(), error: %s\n", dlerror()); + return false; + } + + return true; } - using GetWebEngineCookieManager = Dali::WebEngineCookieManager* (*)(); - GetWebEngineCookieManager getWebEngineCookieManagerPtr = reinterpret_cast(dlsym(mHandle, "GetWebEngineCookieManager")); - if(getWebEngineCookieManagerPtr) + bool InitializeContextHandle() { - return getWebEngineCookieManagerPtr(); - } + if(!InitializePluginHandle()) + { + return false; + } - return nullptr; -} + mGetWebEngineContextPtr = reinterpret_cast(dlsym(mHandle, "GetWebEngineContext")); + + if(!mGetWebEngineContextPtr) + { + DALI_LOG_ERROR("Can't load symbol GetWebEngineContext(), error: %s\n", dlerror()); + return false; + } -bool WebEngine::InitializePluginHandle() -{ - if(mHandle) - { - DALI_LOG_ERROR("Plugin.so has been opened already.\n"); return true; } - if(pluginName.length() == 0) + bool InitializeCookieManagerHandle() { - // pluginName is not initialized yet. - const char* name = EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_WEB_ENGINE_NAME); - if(name) + if(!InitializePluginHandle()) { - pluginName = MakePluginName(name); + return false; } - else + + mGetWebEngineCookieManagerPtr = reinterpret_cast(dlsym(mHandle, "GetWebEngineCookieManager")); + + if(!mGetWebEngineCookieManagerPtr) { - pluginName = std::string(kPluginFullNameDefault); + DALI_LOG_ERROR("Can't load symbol GetWebEngineCookieManager(), error: %s\n", dlerror()); + return false; } + + return true; } - mHandle = dlopen(pluginName.c_str(), RTLD_LAZY); - if(!mHandle) +private: + WebEnginePluginObject(const WebEnginePluginObject&) = delete; + WebEnginePluginObject(WebEnginePluginObject&&) = delete; + WebEnginePluginObject& operator=(const WebEnginePluginObject&) = delete; + WebEnginePluginObject& operator=(WebEnginePluginObject&&) = delete; + +private: + std::string mPluginName; ///< Name of web engine plugin + /// Note: Dali WebView policy does not allow to use multiple web engines in an application. + /// So once pluginName is set to non-empty string, it will not change. + +public: + using CreateWebEngineFunction = Dali::WebEnginePlugin* (*)(); + using DestroyWebEngineFunction = void (*)(Dali::WebEnginePlugin* plugin); + + using GetWebEngineContext = Dali::WebEngineContext* (*)(); + using GetWebEngineCookieManager = Dali::WebEngineCookieManager* (*)(); + + void* mHandle; ///< Handle for the loaded library + CreateWebEngineFunction mCreateWebEnginePtr; ///< Function to create plugin instance + DestroyWebEngineFunction mDestroyWebEnginePtr; ///< Function to destroy plugin instance + + GetWebEngineContext mGetWebEngineContextPtr; ///< Function to get WebEngineContext + GetWebEngineCookieManager mGetWebEngineCookieManagerPtr; ///< Function to get WebEngineCookieManager +}; + +static WebEnginePluginObject gPluginHandle; // Keep this object as static, so Let we assume that library closed after all WebEngines are disposed. + +} // unnamed namespace + +WebEnginePtr WebEngine::New() +{ + WebEngine* instance = new WebEngine(); + if(!instance->Initialize()) { - DALI_LOG_ERROR("Can't load %s : %s\n", pluginName.c_str(), dlerror()); - return false; + delete instance; + return nullptr; } - // Make sure that mHandle would be closed. - Dali::LifecycleController::Get().TerminateSignal().Connect(&WebEngine::ClosePluginHandle); + return instance; +} - mCreateWebEnginePtr = reinterpret_cast(dlsym(mHandle, "CreateWebEnginePlugin")); - if(mCreateWebEnginePtr == nullptr) +Dali::WebEngineContext* WebEngine::GetContext() +{ + if(!gPluginHandle.InitializeContextHandle()) { - DALI_LOG_ERROR("Can't load symbol CreateWebEnginePlugin(), error: %s\n", dlerror()); - return false; + return nullptr; } - mDestroyWebEnginePtr = reinterpret_cast(dlsym(mHandle, "DestroyWebEnginePlugin")); - if(mDestroyWebEnginePtr == nullptr) + if(gPluginHandle.mGetWebEngineContextPtr) { - DALI_LOG_ERROR("Can't load symbol DestroyWebEnginePlugin(), error: %s\n", dlerror()); - return false; + return gPluginHandle.mGetWebEngineContextPtr(); } - return true; + return nullptr; } -void WebEngine::ClosePluginHandle() +Dali::WebEngineCookieManager* WebEngine::GetCookieManager() { - if(mHandle) + if(!gPluginHandle.InitializeCookieManagerHandle()) + { + return nullptr; + } + + if(gPluginHandle.mGetWebEngineCookieManagerPtr) { - dlclose(mHandle); - mHandle = nullptr; + return gPluginHandle.mGetWebEngineCookieManagerPtr(); } + + return nullptr; } WebEngine::WebEngine() @@ -188,27 +254,30 @@ WebEngine::WebEngine() WebEngine::~WebEngine() { - if(mPlugin != nullptr && mDestroyWebEnginePtr != nullptr) + if(mPlugin != nullptr) { mPlugin->Destroy(); - mDestroyWebEnginePtr(mPlugin); + if(gPluginHandle.mDestroyWebEnginePtr != nullptr) + { + gPluginHandle.mDestroyWebEnginePtr(mPlugin); + } + mPlugin = nullptr; } } bool WebEngine::Initialize() { - if(!InitializePluginHandle()) + if(!gPluginHandle.InitializePluginHandle()) { return false; } - mPlugin = mCreateWebEnginePtr(); + mPlugin = gPluginHandle.mCreateWebEnginePtr(); if(mPlugin == nullptr) { DALI_LOG_ERROR("Can't create the WebEnginePlugin object\n"); return false; } - return true; } diff --git a/dali/internal/web-engine/common/web-engine-impl.h b/dali/internal/web-engine/common/web-engine-impl.h index 085c28a..96e6eac 100755 --- a/dali/internal/web-engine/common/web-engine-impl.h +++ b/dali/internal/web-engine/common/web-engine-impl.h @@ -576,27 +576,8 @@ private: */ bool Initialize(); - /** - * @brief Initialize library handle by loading web engine plugin. - * - * @return Whether the initialization succeed or not. - */ - static bool InitializePluginHandle(); - - /** - * @brief Close library handle. - */ - static void ClosePluginHandle(); - private: - using CreateWebEngineFunction = Dali::WebEnginePlugin* (*)(); - using DestroyWebEngineFunction = void (*)(Dali::WebEnginePlugin* plugin); - Dali::WebEnginePlugin* mPlugin; ///< WebEnginePlugin instance - - static void* mHandle; ///< Handle for the loaded library - static CreateWebEngineFunction mCreateWebEnginePtr; ///< Function to create plugin instance - static DestroyWebEngineFunction mDestroyWebEnginePtr; ///< Function to destroy plugin instance }; } // namespace Adaptor -- 2.7.4