From 66076f9883b8eaff198ca4309365a72f03374e4b Mon Sep 17 00:00:00 2001 From: "swan.seo" Date: Tue, 13 Jun 2023 23:58:54 +1100 Subject: [PATCH] Implement SpawnEngine of FlutterTizenEngine Signed-off-by: swan.seo --- flutter/shell/platform/embedder/embedder.h | 34 +++++ flutter/shell/platform/tizen/BUILD.gn | 1 + flutter/shell/platform/tizen/flutter_tizen.cc | 44 +++--- .../tizen/flutter_tizen_elementary.cc | 7 +- .../platform/tizen/flutter_tizen_engine.cc | 135 ++++++++++++++++++ .../platform/tizen/flutter_tizen_engine.h | 10 ++ .../tizen/flutter_tizen_engine_group.cc | 34 +++++ .../tizen/flutter_tizen_engine_group.h | 32 +++++ .../shell/platform/tizen/flutter_tizen_nui.cc | 7 +- .../platform/tizen/flutter_tizen_view.cc | 10 +- .../shell/platform/tizen/flutter_tizen_view.h | 6 +- 11 files changed, 285 insertions(+), 35 deletions(-) create mode 100644 flutter/shell/platform/tizen/flutter_tizen_engine_group.cc create mode 100644 flutter/shell/platform/tizen/flutter_tizen_engine_group.h diff --git a/flutter/shell/platform/embedder/embedder.h b/flutter/shell/platform/embedder/embedder.h index 5cdba06..bf1b407 100644 --- a/flutter/shell/platform/embedder/embedder.h +++ b/flutter/shell/platform/embedder/embedder.h @@ -2169,6 +2169,32 @@ FlutterEngineResult FlutterEngineRun(size_t version, engine_out); //------------------------------------------------------------------------------ +/// @brief Spawn a Flutter engine instance. It is implemented by modifying +/// `FlutterInitiaize`. Unlike `FlutterEngineInitialize`, +/// `FlutterEngineSpawn` uses the shell of given spawner engine to +/// spawn a engine instance. +/// +/// @param[in] version The Flutter embedder API version. Must be +/// FLUTTER_ENGINE_VERSION. +/// @param[in] config The renderer configuration. +/// @param[in] args The Flutter project arguments. +/// @param user_data A user data baton passed back to embedders in +/// callbacks. +/// @param[in] spawner The spawner engine handle. +/// @param[out] engine_out The engine handle on successful engine creation. +/// +/// @return The result of the call to run the Flutter engine. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineSpawn(size_t version, + const FlutterRendererConfig* config, + const FlutterProjectArgs* args, + void* user_data, + FLUTTER_API_SYMBOL(FlutterEngine) + spawner, + FLUTTER_API_SYMBOL(FlutterEngine) * + engine_out); +//------------------------------------------------------------------------------ /// @brief Shuts down a Flutter engine instance. The engine handle is no /// longer valid for any calls in the embedder API after this point. /// Making additional calls with this handle is undefined behavior. @@ -2805,6 +2831,13 @@ typedef FlutterEngineResult (*FlutterEngineRunFnPtr)( const FlutterProjectArgs* args, void* user_data, FLUTTER_API_SYMBOL(FlutterEngine) * engine_out); +typedef FlutterEngineResult (*FlutterEngineSpawnFnPtr)( + size_t version, + const FlutterRendererConfig* config, + const FlutterProjectArgs* args, + void* user_data, + FLUTTER_API_SYMBOL(FlutterEngine) engine_spawner, + FLUTTER_API_SYMBOL(FlutterEngine) * engine_out); typedef FlutterEngineResult (*FlutterEngineShutdownFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine); typedef FlutterEngineResult (*FlutterEngineInitializeFnPtr)( @@ -2922,6 +2955,7 @@ typedef struct { FlutterEngineCreateAOTDataFnPtr CreateAOTData; FlutterEngineCollectAOTDataFnPtr CollectAOTData; FlutterEngineRunFnPtr Run; + FlutterEngineSpawnFnPtr Spawn; FlutterEngineShutdownFnPtr Shutdown; FlutterEngineInitializeFnPtr Initialize; FlutterEngineDeinitializeFnPtr Deinitialize; diff --git a/flutter/shell/platform/tizen/BUILD.gn b/flutter/shell/platform/tizen/BUILD.gn index b1788a3..5153d0b 100644 --- a/flutter/shell/platform/tizen/BUILD.gn +++ b/flutter/shell/platform/tizen/BUILD.gn @@ -99,6 +99,7 @@ template("embedder") { "flutter_tizen.cc", "flutter_tizen_elementary.cc", "flutter_tizen_engine.cc", + "flutter_tizen_engine_group.cc", "flutter_tizen_texture_registrar.cc", "flutter_tizen_view.cc", "logger.cc", diff --git a/flutter/shell/platform/tizen/flutter_tizen.cc b/flutter/shell/platform/tizen/flutter_tizen.cc index 7317385..cb31b34 100644 --- a/flutter/shell/platform/tizen/flutter_tizen.cc +++ b/flutter/shell/platform/tizen/flutter_tizen.cc @@ -11,6 +11,7 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h" #include "flutter/shell/platform/tizen/flutter_tizen_view.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/public/flutter_platform_view.h" @@ -63,29 +64,35 @@ FlutterDesktopViewRef HandleForView(flutter::FlutterTizenView* view) { FlutterDesktopEngineRef FlutterDesktopEngineCreate( const FlutterDesktopEngineProperties& engine_properties) { flutter::FlutterProjectBundle project(engine_properties); - if (project.HasArgument("--verbose-logging")) { - flutter::Logger::SetLoggingLevel(flutter::kLogLevelDebug); - } - std::string logging_port; - if (project.GetArgumentValue("--tizen-logging-port", &logging_port)) { - flutter::Logger::SetLoggingPort(std::stoi(logging_port)); + flutter::FlutterTizenEngineGroup& engine_group = + flutter::FlutterTizenEngineGroup::GetInstance(); + if (!engine_group.GetEngineCount()) { + if (project.HasArgument("--verbose-logging")) { + flutter::Logger::SetLoggingLevel(flutter::kLogLevelDebug); + } + std::string logging_port; + if (project.GetArgumentValue("--tizen-logging-port", &logging_port)) { + flutter::Logger::SetLoggingPort(std::stoi(logging_port)); + } + flutter::Logger::Start(); } - flutter::Logger::Start(); - - auto engine = std::make_unique(project); - return HandleForEngine(engine.release()); + auto* engine = engine_group.MakeEngineWithProject(project); + return HandleForEngine(engine); } bool FlutterDesktopEngineRun(const FlutterDesktopEngineRef engine) { - return EngineFromHandle(engine)->RunEngine(); + return EngineFromHandle(engine)->RunOrSpawnEngine(); } void FlutterDesktopEngineShutdown(FlutterDesktopEngineRef engine_ref) { - flutter::Logger::Stop(); - flutter::FlutterTizenEngine* engine = EngineFromHandle(engine_ref); - engine->StopEngine(); - delete engine; + flutter::FlutterTizenEngineGroup& engine_group = + flutter::FlutterTizenEngineGroup::GetInstance(); + engine_group.StopEngine(engine->id()); + + if (!engine_group.GetEngineCount()) { + flutter::Logger::Stop(); + } } FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView( @@ -220,12 +227,11 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow( auto view = std::make_unique(std::move(window)); - // Take ownership of the engine, starting it if necessary. - view->SetEngine( - std::unique_ptr(EngineFromHandle(engine))); + // Starting it if necessary. + view->SetEngine(EngineFromHandle(engine)); view->CreateRenderSurface(window_properties.renderer_type); if (!view->engine()->IsRunning()) { - if (!view->engine()->RunEngine()) { + if (!view->engine()->RunOrSpawnEngine()) { return nullptr; } } diff --git a/flutter/shell/platform/tizen/flutter_tizen_elementary.cc b/flutter/shell/platform/tizen/flutter_tizen_elementary.cc index 9123930..4d094e7 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_elementary.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_elementary.cc @@ -33,12 +33,11 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromElmParent( auto view = std::make_unique(std::move(tizen_view)); - // Take ownership of the engine, starting it if necessary. - view->SetEngine( - std::unique_ptr(EngineFromHandle(engine))); + // Starting it if necessary. + view->SetEngine(EngineFromHandle(engine)); view->CreateRenderSurface(FlutterDesktopRendererType::kEvasGL); if (!view->engine()->IsRunning()) { - if (!view->engine()->RunEngine()) { + if (!view->engine()->RunOrSpawnEngine()) { return nullptr; } } diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine.cc b/flutter/shell/platform/tizen/flutter_tizen_engine.cc index b981ca1..e2f254a 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_engine.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_engine.cc @@ -14,6 +14,7 @@ #include "flutter/shell/platform/tizen/flutter_platform_node_delegate_tizen.h" #include "flutter/shell/platform/tizen/tizen_renderer_egl.h" #endif +#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h" #include "flutter/shell/platform/tizen/flutter_tizen_view.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/system_utils.h" @@ -100,6 +101,14 @@ void FlutterTizenEngine::CreateRenderer( #endif } +bool FlutterTizenEngine::RunOrSpawnEngine() { + if (FlutterTizenEngineGroup::GetInstance().GetEngineCount() <= 1) { + return RunEngine(); + } else { + return SpawnEngine(); + } +} + bool FlutterTizenEngine::RunEngine() { if (engine_ != nullptr) { FT_LOG(Error) << "The engine has already started."; @@ -259,6 +268,132 @@ bool FlutterTizenEngine::RunEngine() { return true; } +bool FlutterTizenEngine::SpawnEngine() { + if (engine_ != nullptr) { + FT_LOG(Error) << "The engine has already started."; + return false; + } + if (IsHeaded() && !renderer_->IsValid()) { + FT_LOG(Error) << "The display was not valid."; + return false; + } + + if (!project_->HasValidPaths()) { + FT_LOG(Error) << "Missing or unresolvable path to assets."; + return false; + } + std::string assets_path_string = project_->assets_path().u8string(); + std::string icu_path_string = project_->icu_path().u8string(); + if (embedder_api_.RunsAOTCompiledDartCode()) { + aot_data_ = project_->LoadAotData(embedder_api_); + if (!aot_data_) { + FT_LOG(Error) << "Unable to start engine without AOT data."; + return false; + } + } + + // FlutterProjectArgs is expecting a full argv, so when processing it for + // flags the first item is treated as the executable and ignored. Add a dummy + // value so that all provided arguments are used. + std::vector engine_args = project_->engine_arguments(); + std::vector engine_argv = {"placeholder"}; + std::transform( + engine_args.begin(), engine_args.end(), std::back_inserter(engine_argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); + + const std::vector& entrypoint_args = + project_->dart_entrypoint_arguments(); + std::vector entrypoint_argv; + std::transform( + entrypoint_args.begin(), entrypoint_args.end(), + std::back_inserter(entrypoint_argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); + + FlutterProjectArgs args = {}; + args.struct_size = sizeof(FlutterProjectArgs); + args.assets_path = assets_path_string.c_str(); + args.icu_data_path = icu_path_string.c_str(); + args.command_line_argc = static_cast(engine_argv.size()); + args.command_line_argv = + engine_argv.size() > 0 ? engine_argv.data() : nullptr; + args.dart_entrypoint_argc = static_cast(entrypoint_argv.size()); + args.dart_entrypoint_argv = + entrypoint_argv.size() > 0 ? entrypoint_argv.data() : nullptr; + args.platform_message_callback = + [](const FlutterPlatformMessage* engine_message, void* user_data) { + if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { + FT_LOG(Error) << "Invalid message size received. Expected: " + << sizeof(FlutterPlatformMessage) << ", but received " + << engine_message->struct_size; + return; + } + auto* engine = static_cast(user_data); + FlutterDesktopMessage message = + engine->ConvertToDesktopMessage(*engine_message); + engine->message_dispatcher_->HandleMessage(message); + }; + if (aot_data_) { + args.aot_data = aot_data_.get(); + } + if (!project_->custom_dart_entrypoint().empty()) { + args.custom_dart_entrypoint = project_->custom_dart_entrypoint().c_str(); + } +#ifndef WEARABLE_PROFILE + args.update_semantics_callback2 = [](const FlutterSemanticsUpdate2* update, + void* user_data) { + auto* engine = static_cast(user_data); + engine->OnUpdateSemantics(update); + }; + + if (IsHeaded() && dynamic_cast(renderer_.get())) { + vsync_waiter_ = std::make_unique(this); + args.vsync_callback = [](void* user_data, intptr_t baton) -> void { + auto* engine = static_cast(user_data); + engine->vsync_waiter_->AsyncWaitForVsync(baton); + }; + } +#endif + + auto* spawner = FlutterTizenEngineGroup::GetInstance().GetEngineSpawner(); + FlutterRendererConfig renderer_config = GetRendererConfig(); + FlutterEngineResult result = + embedder_api_.Spawn(FLUTTER_ENGINE_VERSION, &renderer_config, &args, this, + spawner->engine_, &engine_); + + if (result != kSuccess || engine_ == nullptr) { + FT_LOG(Error) << "Failed to start the Flutter engine with error: " + << result; + return false; + } + + internal_plugin_registrar_ = + std::make_unique(plugin_registrar_.get()); + accessibility_channel_ = std::make_unique( + internal_plugin_registrar_->messenger()); + app_control_channel_ = std::make_unique( + internal_plugin_registrar_->messenger()); + lifecycle_channel_ = std::make_unique( + internal_plugin_registrar_->messenger()); + settings_channel_ = std::make_unique( + internal_plugin_registrar_->messenger()); + + if (IsHeaded()) { + texture_registrar_ = std::make_unique(this); + key_event_channel_ = std::make_unique( + internal_plugin_registrar_->messenger(), + [this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback, + void* user_data) { SendKeyEvent(event, callback, user_data); }); + navigation_channel_ = std::make_unique( + internal_plugin_registrar_->messenger()); + } + + accessibility_settings_ = std::make_unique(this); + + SetupLocales(); + + return true; +} + bool FlutterTizenEngine::StopEngine() { if (engine_) { for (const auto& [callback, registrar] : diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine.h b/flutter/shell/platform/tizen/flutter_tizen_engine.h index 6108d63..9115f62 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_engine.h +++ b/flutter/shell/platform/tizen/flutter_tizen_engine.h @@ -68,6 +68,10 @@ class FlutterTizenEngine { // Returns false if the engine couldn't be started. bool RunEngine(); + bool RunOrSpawnEngine(); + + bool SpawnEngine(); + // Returns true if the engine is currently running. bool IsRunning() { return engine_ != nullptr; } @@ -81,6 +85,10 @@ class FlutterTizenEngine { // headless engines. FlutterTizenView* view() { return view_; } + void SetId(uint32_t id) { id_ = id; } + + uint32_t id() { return id_; } + FlutterDesktopMessengerRef messenger() { return messenger_.get(); } IncomingMessageDispatcher* message_dispatcher() { @@ -275,6 +283,8 @@ class FlutterTizenEngine { // The vsync waiter for the embedder. std::unique_ptr vsync_waiter_; #endif + + uint32_t id_; }; } // namespace flutter diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine_group.cc b/flutter/shell/platform/tizen/flutter_tizen_engine_group.cc new file mode 100644 index 0000000..791686e --- /dev/null +++ b/flutter/shell/platform/tizen/flutter_tizen_engine_group.cc @@ -0,0 +1,34 @@ +#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h" + +namespace flutter { + +FlutterTizenEngine* FlutterTizenEngineGroup::MakeEngineWithProject( + const FlutterProjectBundle& project) { + std::unique_ptr engine = + std::make_unique(project); + + static uint32_t engine_id = 0; + engine->SetId(engine_id++); + + engines_.push_back(std::move(engine)); + return engines_.back().get(); +} + +FlutterTizenEngine* FlutterTizenEngineGroup::GetEngineSpawner() { + return engines_[0].get(); +} + +int FlutterTizenEngineGroup::GetEngineCount() { + return engines_.size(); +} + +void FlutterTizenEngineGroup::StopEngine(uint32_t id) { + for (auto it = engines_.begin(); it != engines_.end(); ++it) { + if (id == it->get()->id()) { + engines_.erase(it); + return; + } + } +} + +} // namespace flutter \ No newline at end of file diff --git a/flutter/shell/platform/tizen/flutter_tizen_engine_group.h b/flutter/shell/platform/tizen/flutter_tizen_engine_group.h new file mode 100644 index 0000000..da0cd6f --- /dev/null +++ b/flutter/shell/platform/tizen/flutter_tizen_engine_group.h @@ -0,0 +1,32 @@ +#ifndef EMBEDDER_FLUTTER_TIZEN_ENGINE_GROUP_H_ +#define EMBEDDER_FLUTTER_TIZEN_ENGINE_GROUP_H_ + +#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" + +namespace flutter { + +class FlutterTizenEngineGroup { + public: + static FlutterTizenEngineGroup& GetInstance() { + static FlutterTizenEngineGroup instance; + return instance; + } + + FlutterTizenEngine* GetEngineSpawner(); + + FlutterTizenEngine* MakeEngineWithProject( + const FlutterProjectBundle& project); + + int GetEngineCount(); + + void StopEngine(uint32_t id); + + private: + FlutterTizenEngineGroup() {} + + std::vector> engines_; +}; + +} // namespace flutter + +#endif \ No newline at end of file diff --git a/flutter/shell/platform/tizen/flutter_tizen_nui.cc b/flutter/shell/platform/tizen/flutter_tizen_nui.cc index f9ad52e..e5a1b88 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_nui.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_nui.cc @@ -42,12 +42,11 @@ FlutterDesktopViewRef FlutterDesktopViewCreateFromImageView( auto view = std::make_unique(std::move(tizen_view)); - // Take ownership of the engine, starting it if necessary. - view->SetEngine( - std::unique_ptr(EngineFromHandle(engine))); + // Starting it if necessary. + view->SetEngine(EngineFromHandle(engine)); view->CreateRenderSurface(FlutterDesktopRendererType::kEGL); if (!view->engine()->IsRunning()) { - if (!view->engine()->RunEngine()) { + if (!view->engine()->RunOrSpawnEngine()) { return nullptr; } } diff --git a/flutter/shell/platform/tizen/flutter_tizen_view.cc b/flutter/shell/platform/tizen/flutter_tizen_view.cc index b3da539..5639d4a 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_view.cc +++ b/flutter/shell/platform/tizen/flutter_tizen_view.cc @@ -5,6 +5,7 @@ #include "flutter_tizen_view.h" +#include "flutter/shell/platform/tizen/flutter_tizen_engine_group.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view.h" #ifdef NUI_SUPPORT @@ -80,13 +81,13 @@ FlutterTizenView::~FlutterTizenView() { if (platform_view_channel_) { platform_view_channel_->Dispose(); } - engine_->StopEngine(); + FlutterTizenEngineGroup::GetInstance().StopEngine(engine_->id()); } DestroyRenderSurface(); } -void FlutterTizenView::SetEngine(std::unique_ptr engine) { - engine_ = std::move(engine); +void FlutterTizenView::SetEngine(FlutterTizenEngine* engine) { + engine_ = engine; engine_->SetView(this); internal_plugin_registrar_ = @@ -346,8 +347,7 @@ void FlutterTizenView::OnKey(const char* key, if (engine_->key_event_channel()) { engine_->key_event_channel()->SendKey( key, string, compose, modifiers, scan_code, is_down, - [engine = engine_.get(), symbol = std::string(key), - is_down](bool handled) { + [engine = engine_, symbol = std::string(key), is_down](bool handled) { if (handled) { return; } diff --git a/flutter/shell/platform/tizen/flutter_tizen_view.h b/flutter/shell/platform/tizen/flutter_tizen_view.h index ccc5f49..b055574 100644 --- a/flutter/shell/platform/tizen/flutter_tizen_view.h +++ b/flutter/shell/platform/tizen/flutter_tizen_view.h @@ -29,9 +29,9 @@ class FlutterTizenView : public TizenViewEventHandlerDelegate { // Configures the window instance with an instance of a running Flutter // engine. - void SetEngine(std::unique_ptr engine); + void SetEngine(FlutterTizenEngine* engine); - FlutterTizenEngine* engine() { return engine_.get(); } + FlutterTizenEngine* engine() { return engine_; } TizenViewBase* tizen_view() { return tizen_view_.get(); } @@ -165,7 +165,7 @@ class FlutterTizenView : public TizenViewEventHandlerDelegate { PointerState* state); // The engine associated with this view. - std::unique_ptr engine_; + FlutterTizenEngine* engine_; // The platform view associated with this Flutter view. std::unique_ptr tizen_view_;