diff --git a/packages/flutter_inappwebview/CHANGELOG.md b/packages/flutter_inappwebview/CHANGELOG.md index 39d9ed658..c4437e489 100644 --- a/packages/flutter_inappwebview/CHANGELOG.md +++ b/packages/flutter_inappwebview/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.2 + +- Fix a SIGTRAP crash on TV app teardown by calling + `ewk_init()`/`ewk_shutdown()` exactly once per process. + ## 0.1.1 - Fix a crash when a webview is disposed. diff --git a/packages/flutter_inappwebview/README.md b/packages/flutter_inappwebview/README.md index 456d45fb9..f932e7e1c 100644 --- a/packages/flutter_inappwebview/README.md +++ b/packages/flutter_inappwebview/README.md @@ -26,7 +26,7 @@ Add the internet privilege to the app manifest: ```yaml dependencies: flutter_inappwebview: ^6.1.5 - flutter_inappwebview_tizen: ^0.1.1 + flutter_inappwebview_tizen: ^0.1.2 ``` ```dart diff --git a/packages/flutter_inappwebview/pubspec.yaml b/packages/flutter_inappwebview/pubspec.yaml index b9e860a4c..3138cba0b 100644 --- a/packages/flutter_inappwebview/pubspec.yaml +++ b/packages/flutter_inappwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_inappwebview_tizen description: Tizen implementation of the flutter_inappwebview plugin. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/flutter_inappwebview -version: 0.1.1 +version: 0.1.2 environment: sdk: ">=3.8.0 <4.0.0" diff --git a/packages/flutter_inappwebview/tizen/src/flutter_inappwebview_tizen_plugin.cc b/packages/flutter_inappwebview/tizen/src/flutter_inappwebview_tizen_plugin.cc index fd77a5be7..472cd0245 100644 --- a/packages/flutter_inappwebview/tizen/src/flutter_inappwebview_tizen_plugin.cc +++ b/packages/flutter_inappwebview/tizen/src/flutter_inappwebview_tizen_plugin.cc @@ -45,6 +45,7 @@ class FlutterInappwebviewTizenPlugin : public flutter::Plugin { cookie_channel) : manager_channel_(std::move(manager_channel)), cookie_channel_(std::move(cookie_channel)) { + WebView::InitializeEngine(); manager_channel_->SetMethodCallHandler( [this](const auto& call, auto result) { HandleManagerMethodCall(call, std::move(result)); @@ -55,7 +56,7 @@ class FlutterInappwebviewTizenPlugin : public flutter::Plugin { }); } - virtual ~FlutterInappwebviewTizenPlugin() {} + virtual ~FlutterInappwebviewTizenPlugin() { WebView::ShutdownEngine(); } private: void HandleManagerMethodCall( diff --git a/packages/flutter_inappwebview/tizen/src/webview.cc b/packages/flutter_inappwebview/tizen/src/webview.cc index 323947569..57966762c 100644 --- a/packages/flutter_inappwebview/tizen/src/webview.cc +++ b/packages/flutter_inappwebview/tizen/src/webview.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -212,6 +213,35 @@ bool WebView::ClearAllCookies() { return false; } +// static +void WebView::InitializeEngine() { ewk_init(); } + +// static +void WebView::ShutdownEngine() { + // WebView::Dispose() erases from instances_ synchronously, so by normal + // plugin teardown order (platform views destroyed before the plugin + // itself) this is already empty. Wait defensively anyway: ewk_shutdown() + // fatally CHECKs (SIGTRAP) if any Ewk_View is still alive. + constexpr gint64 kDeadlineUsec = 2 * G_USEC_PER_SEC; + const gint64 deadline = g_get_monotonic_time() + kDeadlineUsec; + for (;;) { + { + std::lock_guard lock(instances_mutex_); + if (instances_.empty()) { + break; + } + } + if (g_get_monotonic_time() >= deadline) { + LOG_WARN( + "ShutdownEngine: WebView instance(s) still alive past the " + "deadline; calling ewk_shutdown() anyway."); + break; + } + g_usleep(1000); + } + ewk_shutdown(); +} + std::string WebView::GetDefaultUserAgent() { std::lock_guard lock(instances_mutex_); for (auto* instance : instances_) { @@ -369,8 +399,6 @@ void WebView::Dispose() { } ecore_evas_ = nullptr; - - // ewk_shutdown(); } void WebView::Offset(double left, double top) { @@ -530,15 +558,9 @@ bool WebView::InitWebView() { chromium_argv); }); - // TODO(jsuya): ewk_init() and ewk_shutdown() are designed to be called only - // once in a process.(If ewk_init() is called after ewk_shutdown() is - // called, SIGTRAP is called internally.) ewk_init() initializes the efl - // modules and web engine's arguments data. The efl modules are initialized - // by default in OS, and arguments data is also initialized through - // SetArguments() API, so calling ewk_init() is not necessary. Therefore, - // temporarily comment out ewk_init() and ewk_shutdown(). It can be reverted - // depending on updates to chromium-efl. - // ewk_init(); + // ewk_init()/ewk_shutdown() are called once per process by + // WebView::InitializeEngine()/ShutdownEngine(), driven by the plugin's + // constructor/destructor. static Ecore_Evas* shared_ecore_evas = nullptr; if (!shared_ecore_evas) { shared_ecore_evas = ecore_evas_new("wayland_egl", 0, 0, 1, 1, 0); diff --git a/packages/flutter_inappwebview/tizen/src/webview.h b/packages/flutter_inappwebview/tizen/src/webview.h index cf42b38f0..7823d0fd7 100644 --- a/packages/flutter_inappwebview/tizen/src/webview.h +++ b/packages/flutter_inappwebview/tizen/src/webview.h @@ -70,6 +70,12 @@ class WebView : public PlatformView { static bool ClearAllCookies(); static std::string GetDefaultUserAgent(); + // Must be called exactly once, before any WebView is constructed. + static void InitializeEngine(); + // Must be called exactly once, after every WebView has been destroyed. + // ewk_shutdown() fatally CHECKs if any Ewk_View is still alive. + static void ShutdownEngine(); + private: void HandleWebViewMethodCall(const FlMethodCall& method_call, std::unique_ptr result);