diff --git a/packages/flutter_inappwebview/CHANGELOG.md b/packages/flutter_inappwebview/CHANGELOG.md index d8bf4b684..c6321e01e 100644 --- a/packages/flutter_inappwebview/CHANGELOG.md +++ b/packages/flutter_inappwebview/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4 + +- Fix a SIGTRAP crash on TV app teardown by calling `ewk_init()`/`ewk_shutdown()` exactly once per process. + ## 0.1.3 * Add an `implements` entry to the pubspec to improve discoverability on pub.dev. diff --git a/packages/flutter_inappwebview/README.md b/packages/flutter_inappwebview/README.md index d81cd44f4..551631da5 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.3 + flutter_inappwebview_tizen: ^0.1.4 ``` ```dart diff --git a/packages/flutter_inappwebview/pubspec.yaml b/packages/flutter_inappwebview/pubspec.yaml index a9f408cb6..2373e7234 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/main/packages/flutter_inappwebview -version: 0.1.3 +version: 0.1.4 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..9523b37da 100644 --- a/packages/flutter_inappwebview/tizen/src/webview.cc +++ b/packages/flutter_inappwebview/tizen/src/webview.cc @@ -8,10 +8,12 @@ #include #include #include +#include #include #include #include +#include #include "buffer_pool.h" #include "log.h" @@ -212,6 +214,39 @@ bool WebView::ClearAllCookies() { return false; } +void WebView::InitializeEngine() { ewk_init(); } + +void WebView::ShutdownEngine() { + // ewk_shutdown() fatally CHECKs (SIGTRAP) on a live Ewk_View. Dispose() + // normally empties instances_ already; past the deadline, force-dispose + // the stragglers instead of shutting down anyway. + constexpr gint64 kDeadlineUsec = 2 * G_USEC_PER_SEC; + const gint64 deadline = g_get_monotonic_time() + kDeadlineUsec; + for (;;) { + std::vector stragglers; + { + std::lock_guard lock(instances_mutex_); + if (instances_.empty()) { + break; + } + if (g_get_monotonic_time() >= deadline) { + stragglers.assign(instances_.begin(), instances_.end()); + } + } + if (!stragglers.empty()) { + LOG_WARN( + "ShutdownEngine: WebView instance(s) still alive past the " + "deadline; force-disposing them before calling ewk_shutdown()."); + for (auto* instance : stragglers) { + instance->Dispose(); + } + continue; + } + g_usleep(1000); + } + ewk_shutdown(); +} + std::string WebView::GetDefaultUserAgent() { std::lock_guard lock(instances_mutex_); for (auto* instance : instances_) { @@ -369,8 +404,6 @@ void WebView::Dispose() { } ecore_evas_ = nullptr; - - // ewk_shutdown(); } void WebView::Offset(double left, double top) { @@ -530,15 +563,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);