From f18858bec9f01a9265eb628ccc7d772ed02b7675 Mon Sep 17 00:00:00 2001 From: MuHong Byun Date: Wed, 26 May 2021 14:52:55 +0900 Subject: [PATCH 1/4] Introduce spawn API at embedder * This uses Shell's Spawn. Signed-off-by: MuHong Byun --- shell/platform/embedder/embedder.cc | 57 +++++++ shell/platform/embedder/embedder.h | 62 +++++++ shell/platform/embedder/embedder_engine.cc | 33 ++++ shell/platform/embedder/embedder_engine.h | 7 + .../embedder/tests/embedder_unittests.cc | 34 ++++ shell/platform/tizen/flutter_tizen.cc | 9 + shell/platform/tizen/flutter_tizen_engine.cc | 159 +++++++++++++++++- shell/platform/tizen/flutter_tizen_engine.h | 14 +- shell/platform/tizen/public/flutter_tizen.h | 6 + 9 files changed, 378 insertions(+), 3 deletions(-) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index b1f673ca1a8cc..ce90ff90293b4 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -839,6 +839,24 @@ FlutterEngineResult FlutterEngineRun(size_t version, return FlutterEngineRunInitialized(*engine_out); } +FlutterEngineResult FlutterEngineSpawn(size_t version, + const FlutterRendererConfig* config, + const FlutterProjectArgs* args, + void* user_data, + FLUTTER_API_SYMBOL(FlutterEngine) * + engine_out, + FLUTTER_API_SYMBOL(FlutterEngine) + engine_main) { + auto result = + FlutterEngineInitialize(version, config, args, user_data, engine_out); + + if (result != kSuccess) { + return result; + } + + return FlutterEngineSpawnInitialized(*engine_out, engine_main); +} + FlutterEngineResult FlutterEngineInitialize(size_t version, const FlutterRendererConfig* config, const FlutterProjectArgs* args, @@ -1309,6 +1327,44 @@ FlutterEngineResult FlutterEngineRunInitialized( return kSuccess; } +FlutterEngineResult FlutterEngineSpawnInitialized( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FLUTTER_API_SYMBOL(FlutterEngine) engine_main) { + if (!engine || !engine_main) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); + } + + auto embedder_engine = reinterpret_cast(engine); + auto embedder_engine_main = + reinterpret_cast(engine_main); + + // The engine must not already be running. Initialize may only be called + // once on an engine instance. + if (embedder_engine->IsValid()) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); + } + + // The main engine must be running. + if (!embedder_engine_main->IsValid()) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); + } + + // Spawn the shell. + if (!embedder_engine->SpawnShell(embedder_engine_main)) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Could not launch the engine using supplied " + "initialization arguments."); + } + + // Step 2: Tell the platform view to initialize itself. + if (!embedder_engine->NotifyCreated()) { + return LOG_EMBEDDER_ERROR(kInternalInconsistency, + "Could not create platform view components."); + } + + return kSuccess; +} + FLUTTER_EXPORT FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine) engine) { @@ -2220,6 +2276,7 @@ FlutterEngineResult FlutterEngineGetProcAddresses( SET_PROC(CreateAOTData, FlutterEngineCreateAOTData); SET_PROC(CollectAOTData, FlutterEngineCollectAOTData); SET_PROC(Run, FlutterEngineRun); + SET_PROC(Spawn, FlutterEngineSpawn); SET_PROC(Shutdown, FlutterEngineShutdown); SET_PROC(Initialize, FlutterEngineInitialize); SET_PROC(Deinitialize, FlutterEngineDeinitialize); diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 5678455b445c7..49ab7ac49699d 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1598,6 +1598,42 @@ FlutterEngineResult FlutterEngineRun(size_t version, FLUTTER_API_SYMBOL(FlutterEngine) * engine_out); +//------------------------------------------------------------------------------ +/// @brief Initialize and run a Flutter engine instance and return a handle +/// to it. This is a convenience method for the pair of calls to +/// `FlutterEngineInitialize` and `FlutterEngineRunInitialized`. +/// +/// @note This method of running a Flutter engine works well except in +/// cases where the embedder specifies custom task runners via +/// `FlutterProjectArgs::custom_task_runners`. In such cases, the +/// engine may need the embedder to post tasks back to it before +/// `FlutterEngineRun` has returned. Embedders can only post tasks +/// to the engine if they have a handle to the engine. In such +/// cases, embedders are advised to get the engine handle via the +/// `FlutterInitializeCall`. Then they can call +/// `FlutterEngineRunInitialized` knowing that they will be able to +/// service custom tasks on other threads with the engine handle. +/// +/// @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[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) * + engine_out, + FLUTTER_API_SYMBOL(FlutterEngine) + engine_main); + //------------------------------------------------------------------------------ /// @brief Shuts down a Flutter engine instance. The engine handle is no /// longer valid for any calls in the embedder API after this point. @@ -1673,6 +1709,24 @@ FLUTTER_EXPORT FlutterEngineResult FlutterEngineRunInitialized( FLUTTER_API_SYMBOL(FlutterEngine) engine); +//------------------------------------------------------------------------------ +/// @brief Runs an initialized engine instance. An engine can be +/// initialized via `FlutterEngineInitialize`. An initialized +/// instance can only be run once. During and after this call, +/// custom task runners supplied by the embedder are expected to +/// start servicing tasks. +/// +/// @param[in] engine An initialized engine instance that has not previously +/// been run. +/// +/// @return The result of the call to run the initialized Flutter +/// engine instance. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineSpawnInitialized( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + FLUTTER_API_SYMBOL(FlutterEngine) engine_main); + FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendWindowMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, @@ -2204,6 +2258,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_out, + FLUTTER_API_SYMBOL(FlutterEngine) engine_main); typedef FlutterEngineResult (*FlutterEngineShutdownFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine); typedef FlutterEngineResult (*FlutterEngineInitializeFnPtr)( @@ -2315,6 +2376,7 @@ typedef struct { FlutterEngineCreateAOTDataFnPtr CreateAOTData; FlutterEngineCollectAOTDataFnPtr CollectAOTData; FlutterEngineRunFnPtr Run; + FlutterEngineSpawnFnPtr Spawn; FlutterEngineShutdownFnPtr Shutdown; FlutterEngineInitializeFnPtr Initialize; FlutterEngineDeinitializeFnPtr Deinitialize; diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc index 0b0adf8793f63..132ca0e1bf769 100644 --- a/shell/platform/embedder/embedder_engine.cc +++ b/shell/platform/embedder/embedder_engine.cc @@ -60,6 +60,39 @@ bool EmbedderEngine::LaunchShell() { return IsValid(); } +bool EmbedderEngine::SpawnShell(EmbedderEngine* main) { + if (!shell_args_) { + FML_DLOG(ERROR) << "Invalid shell arguments."; + return false; + } + + if (shell_) { + FML_DLOG(ERROR) << "Shell already initialized"; + } + + if (!run_configuration_.IsValid()) { + FML_DLOG(ERROR) << "Invalid Configration"; + } + + shell_ = main->SpawnShell(std::move(run_configuration_), + shell_args_->on_create_platform_view, + shell_args_->on_create_rasterizer); + + // // Reset the args no matter what. They will never be used to initialize a + // // shell again. + shell_args_.reset(); + + return IsValid(); +} + +std::unique_ptr EmbedderEngine::SpawnShell( + RunConfiguration run_configuration, + const Shell::CreateCallback& on_create_platform_view, + const Shell::CreateCallback& on_create_rasterizer) { + return shell_->Spawn(std::move(run_configuration), on_create_platform_view, + on_create_rasterizer); +} + bool EmbedderEngine::CollectShell() { shell_.reset(); return IsValid(); diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h index ab0de7b1f1d1b..931f38e14ec56 100644 --- a/shell/platform/embedder/embedder_engine.h +++ b/shell/platform/embedder/embedder_engine.h @@ -35,6 +35,13 @@ class EmbedderEngine { bool LaunchShell(); + bool SpawnShell(EmbedderEngine* main); + + std::unique_ptr SpawnShell( + RunConfiguration run_configuration, + const Shell::CreateCallback& on_create_platform_view, + const Shell::CreateCallback& on_create_rasterizer); + bool CollectShell(); const TaskRunners& GetTaskRunners() const; diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 293aab15c6eef..ad1ece9878090 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -1434,5 +1434,39 @@ TEST_F(EmbedderTest, KeyDataResponseIsCorrectlyInvoked) { EXPECT_TRUE(user_data3.returned); } +//------------------------------------------------------------------------------ +/// +TEST_F(EmbedderTest, CabRunFlutterEngineSpawnInitialized) { + EmbedderConfigBuilder builder( + GetEmbedderContext(EmbedderTestContextType::kSoftwareContext)); + builder.SetSoftwareRendererConfig(); + auto engine = builder.InitializeEngine(); + auto main_engine = builder.InitializeEngine(); + + ASSERT_TRUE(engine.is_valid()); + ASSERT_TRUE(main_engine.is_valid()); + + // Spawn with invalid parameter + ASSERT_EQ(FlutterEngineSpawnInitialized(nullptr, nullptr), kInvalidArguments); + ASSERT_EQ(FlutterEngineSpawnInitialized(engine.get(), nullptr), + kInvalidArguments); + ASSERT_EQ(FlutterEngineSpawnInitialized(nullptr, main_engine.get()), + kInvalidArguments); + + // Test with the main engine not running + ASSERT_EQ(FlutterEngineSpawnInitialized(engine.get(), main_engine.get()), + kInvalidArguments); + + // Execute main engine + ASSERT_EQ(FlutterEngineRunInitialized(main_engine.get()), kSuccess); + + // Test spawn API + ASSERT_EQ(FlutterEngineSpawnInitialized(engine.get(), main_engine.get()), + kSuccess); + + engine.reset(); + main_engine.reset(); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index 12a22388047bb..e574c5103194f 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -38,6 +38,15 @@ FlutterDesktopEngineRef FlutterDesktopRunEngine( return HandleForEngine(engine.release()); } +FlutterDesktopEngineRef FlutterDesktopSpawnEngine( + FlutterDesktopEngineRef engine_ref, + const FlutterDesktopEngineProperties& engine_properties, + bool headed) { + auto engine = EngineFromHandle(engine_ref); + auto spawned_engine = engine->SpawnEngine(headed, engine_properties); + return HandleForEngine(spawned_engine); +} + void FlutterDesktopShutdownEngine(FlutterDesktopEngineRef engine_ref) { auto engine = EngineFromHandle(engine_ref); engine->StopEngine(); diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index 6edb3f73d6a5e..e8d60953001a5 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -67,6 +67,13 @@ FlutterTizenEngine::FlutterTizenEngine(bool headed, void* win) } } +FlutterTizenEngine::FlutterTizenEngine(FlutterTizenEngine* main_engine, + bool headed, + void* win) + : FlutterTizenEngine(headed, win) { + main_engine_ = main_engine; +} + FlutterTizenEngine::~FlutterTizenEngine() { renderer = nullptr; } @@ -85,8 +92,8 @@ void FlutterTizenEngine::InitializeRenderer() { renderer.get()); #else renderer = std::make_unique(*this); - - tizen_vsync_waiter_ = std::make_unique(this); + // Disable temporary + // tizen_vsync_waiter_ = std::make_unique(this); #endif } @@ -191,10 +198,13 @@ bool FlutterTizenEngine::RunEngine( args.custom_task_runners = &custom_task_runners; #ifndef TIZEN_RENDERER_EVAS_GL if (IsHeaded()) { + // Disable temporary + /* args.vsync_callback = [](void* user_data, intptr_t baton) -> void { reinterpret_cast(user_data) ->tizen_vsync_waiter_->AsyncWaitForVsync(baton); }; + */ } #endif @@ -248,6 +258,148 @@ bool FlutterTizenEngine::RunEngine( return true; } +bool FlutterTizenEngine::RunSpawnedEngine( + const FlutterDesktopEngineProperties& engine_properties) { + if (IsHeaded() && !renderer->IsValid()) { + FT_LOGE("The display was not valid."); + 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 argv = {"placeholder"}; + if (engine_properties.switches_count > 0) { + argv.insert(argv.end(), &engine_properties.switches[0], + &engine_properties.switches[engine_properties.switches_count]); + } + + // Configure task runners. + FlutterTaskRunnerDescription platform_task_runner = {}; + platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); + platform_task_runner.user_data = event_loop_.get(); + platform_task_runner.runs_task_on_current_thread_callback = + [](void* data) -> bool { + return static_cast(data)->RunsTasksOnCurrentThread(); + }; + platform_task_runner.post_task_callback = + [](FlutterTask task, uint64_t target_time_nanos, void* data) -> void { + static_cast(data)->PostTask(task, target_time_nanos); + }; + platform_task_runner.identifier = kPlatformTaskRunnerIdentifier; + FlutterCustomTaskRunners custom_task_runners = {}; + custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); + custom_task_runners.platform_task_runner = &platform_task_runner; + +#ifdef TIZEN_RENDERER_EVAS_GL + FlutterTaskRunnerDescription render_task_runner = {}; + if (IsHeaded()) { + render_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); + render_task_runner.user_data = render_loop_.get(); + render_task_runner.runs_task_on_current_thread_callback = + [](void* data) -> bool { + return static_cast(data)->RunsTasksOnCurrentThread(); + }; + render_task_runner.post_task_callback = + [](FlutterTask task, uint64_t target_time_nanos, void* data) -> void { + static_cast(data)->PostTask(task, target_time_nanos); + }; + render_task_runner.identifier = kRenderTaskRunnerIdentifier; + custom_task_runners.render_task_runner = &render_task_runner; + } +#endif + + FlutterProjectArgs args = {}; + args.struct_size = sizeof(FlutterProjectArgs); + args.assets_path = engine_properties.assets_path; + args.icu_data_path = engine_properties.icu_data_path; + args.command_line_argc = static_cast(argv.size()); + args.command_line_argv = &argv[0]; + args.platform_message_callback = + [](const FlutterPlatformMessage* engine_message, void* user_data) { + if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { + FT_LOGE( + "Invalid message size received. Expected: %zu, but received %zu", + sizeof(FlutterPlatformMessage), engine_message->struct_size); + return; + } + auto engine = reinterpret_cast(user_data); + auto message = engine->ConvertToDesktopMessage(*engine_message); + engine->message_dispatcher->HandleMessage(message); + }; + args.custom_task_runners = &custom_task_runners; +#ifndef TIZEN_RENDERER_EVAS_GL + if (IsHeaded()) { + // args.vsync_callback = [](void* user_data, intptr_t baton) -> void { + // reinterpret_cast(user_data) + // ->tizen_vsync_waiter_->AsyncWaitForVsync(baton); + // }; + } +#endif + + if (embedder_api_.RunsAOTCompiledDartCode()) { + aot_data_ = LoadAotData(engine_properties.aot_library_path); + if (!aot_data_) { + FT_LOGE("Unable to start engine without AOT data."); + return false; + } + args.aot_data = aot_data_.get(); + } + + FlutterRendererConfig renderer_config = GetRendererConfig(); + + auto result = + embedder_api_.Spawn(FLUTTER_ENGINE_VERSION, &renderer_config, &args, this, + &engine_, main_engine_->Engine()); + if (result == kSuccess && engine_ != nullptr) { + FT_LOGD("FlutterEngineRun Success!"); + } else { + FT_LOGE("FlutterEngineRun Failure! result: %d", result); + return false; + } + + internal_plugin_registrar_ = + std::make_unique(plugin_registrar_.get()); + + platform_channel = std::make_unique( + internal_plugin_registrar_->messenger(), renderer.get()); + settings_channel = std::make_unique( + internal_plugin_registrar_->messenger()); + localization_channel = std::make_unique(this); + localization_channel->SendLocales(); + lifecycle_channel = std::make_unique(this); + + if (IsHeaded()) { + texture_registrar_ = std::make_unique(this); + key_event_channel = std::make_unique( + internal_plugin_registrar_->messenger()); + navigation_channel = std::make_unique( + internal_plugin_registrar_->messenger()); + text_input_channel = std::make_unique( + internal_plugin_registrar_->messenger(), this); + platform_view_channel = std::make_unique( + internal_plugin_registrar_->messenger(), this); + key_event_handler_ = std::make_unique(this); + touch_event_handler_ = std::make_unique(this); + + SetWindowOrientation(0); + } + + return true; +} + +FlutterTizenEngine* FlutterTizenEngine::SpawnEngine( + bool headed, + const FlutterDesktopEngineProperties& engine_properties) { + auto engine = std::make_unique( + this, true, engine_properties.custom_win); + if (!engine->RunSpawnedEngine(engine_properties)) { + FT_LOGE("Failed to run the Flutter engine."); + return nullptr; + } + return engine.release(); +} + bool FlutterTizenEngine::StopEngine() { if (engine_) { if (platform_view_channel) { @@ -268,6 +420,9 @@ FlutterDesktopPluginRegistrarRef FlutterTizenEngine::GetPluginRegistrar() { } FlutterTizenTextureRegistrar* FlutterTizenEngine::GetTextureRegistrar() { + if (!IsHeaded()) { + FT_LOGW("Headless, texture is not supported."); + } return texture_registrar_.get(); } diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 419d7b7349b7a..3eb45ec2beb64 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -59,7 +59,10 @@ enum DeviceProfile { kUnknown, kMobile, kWearable, kTV, kCommon }; // Manages state associated with the underlying FlutterEngine. class FlutterTizenEngine : public TizenRenderer::Delegate { public: - explicit FlutterTizenEngine(bool headed, void* win ); + explicit FlutterTizenEngine(bool headed, void* win); + explicit FlutterTizenEngine(FlutterTizenEngine* main_engine, + bool headed, + void* win); virtual ~FlutterTizenEngine(); // Prevent copying. @@ -68,6 +71,12 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { void InitializeRenderer(); bool RunEngine(const FlutterDesktopEngineProperties& engine_properties); + bool RunSpawnedEngine( + const FlutterDesktopEngineProperties& engine_properties); + + FlutterTizenEngine* SpawnEngine( + bool headed, + const FlutterDesktopEngineProperties& engine_properties); bool StopEngine(); // Returns the currently configured Plugin Registrar. @@ -144,6 +153,8 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { const DeviceProfile device_profile; + FLUTTER_API_SYMBOL(FlutterEngine) Engine() { return engine_; } + private: bool IsHeaded() { return renderer != nullptr; } UniqueAotDataPtr LoadAotData(std::string aot_data_path); @@ -193,6 +204,7 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { FlutterTransformation transformation_; void* custom_window_; + FlutterTizenEngine* main_engine_; }; #endif // EMBEDDER_FLUTTER_TIZEN_ENGINE_H_ diff --git a/shell/platform/tizen/public/flutter_tizen.h b/shell/platform/tizen/public/flutter_tizen.h index fd36ca2597e5a..67905604f9625 100644 --- a/shell/platform/tizen/public/flutter_tizen.h +++ b/shell/platform/tizen/public/flutter_tizen.h @@ -47,6 +47,12 @@ FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopRunEngine(const FlutterDesktopEngineProperties& engine_properties, bool headed); +// FIXME: It's POC code! +FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopSpawnEngine( + FlutterDesktopEngineRef engine_ref, + const FlutterDesktopEngineProperties& engine_properties, + bool headed); + // Shuts down the given engine instance. // // |engine| is no longer valid after this call. From 7e47b1df7be02f84e4baef8b4b207269c0394b21 Mon Sep 17 00:00:00 2001 From: MuHong Byun Date: Tue, 22 Jun 2021 11:19:06 +0900 Subject: [PATCH 2/4] Apply review's comment Signed-off-by: MuHong Byun Co-authored-by: Boram Bae --- shell/platform/embedder/embedder.h | 37 ++------------------ shell/platform/tizen/flutter_tizen_engine.cc | 3 -- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 49ab7ac49699d..edc27bc8c3ea0 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1599,30 +1599,7 @@ FlutterEngineResult FlutterEngineRun(size_t version, engine_out); //------------------------------------------------------------------------------ -/// @brief Initialize and run a Flutter engine instance and return a handle -/// to it. This is a convenience method for the pair of calls to -/// `FlutterEngineInitialize` and `FlutterEngineRunInitialized`. -/// -/// @note This method of running a Flutter engine works well except in -/// cases where the embedder specifies custom task runners via -/// `FlutterProjectArgs::custom_task_runners`. In such cases, the -/// engine may need the embedder to post tasks back to it before -/// `FlutterEngineRun` has returned. Embedders can only post tasks -/// to the engine if they have a handle to the engine. In such -/// cases, embedders are advised to get the engine handle via the -/// `FlutterInitializeCall`. Then they can call -/// `FlutterEngineRunInitialized` knowing that they will be able to -/// service custom tasks on other threads with the engine handle. -/// -/// @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[out] engine_out The engine handle on successful engine creation. -/// -/// @return The result of the call to run the Flutter engine. +// TODO : Update required /// FLUTTER_EXPORT FlutterEngineResult FlutterEngineSpawn(size_t version, @@ -1710,17 +1687,7 @@ FlutterEngineResult FlutterEngineRunInitialized( FLUTTER_API_SYMBOL(FlutterEngine) engine); //------------------------------------------------------------------------------ -/// @brief Runs an initialized engine instance. An engine can be -/// initialized via `FlutterEngineInitialize`. An initialized -/// instance can only be run once. During and after this call, -/// custom task runners supplied by the embedder are expected to -/// start servicing tasks. -/// -/// @param[in] engine An initialized engine instance that has not previously -/// been run. -/// -/// @return The result of the call to run the initialized Flutter -/// engine instance. +// TODO : Update required /// FLUTTER_EXPORT FlutterEngineResult FlutterEngineSpawnInitialized( diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index e8d60953001a5..660cd2c0ae5ed 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -420,9 +420,6 @@ FlutterDesktopPluginRegistrarRef FlutterTizenEngine::GetPluginRegistrar() { } FlutterTizenTextureRegistrar* FlutterTizenEngine::GetTextureRegistrar() { - if (!IsHeaded()) { - FT_LOGW("Headless, texture is not supported."); - } return texture_registrar_.get(); } From 42dd31e11581bf8537f7d5460bd2b376debe50c4 Mon Sep 17 00:00:00 2001 From: MuHong Byun Date: Tue, 22 Jun 2021 16:27:34 +0900 Subject: [PATCH 3/4] Apply Extract Method pattern at FlutterTizenEngine Signed-off-by: MuHong Byun Co-authored-by: Boram Bae --- shell/platform/tizen/flutter_tizen_engine.cc | 209 ++++++------------- shell/platform/tizen/flutter_tizen_engine.h | 7 + 2 files changed, 67 insertions(+), 149 deletions(-) diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index 660cd2c0ae5ed..aba442af4e9bb 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -126,8 +126,12 @@ UniqueAotDataPtr FlutterTizenEngine::LoadAotData(std::string aot_data_path) { return UniqueAotDataPtr(data); } -bool FlutterTizenEngine::RunEngine( - const FlutterDesktopEngineProperties& engine_properties) { +bool FlutterTizenEngine::PrepareFlutterProjectArgs( + const FlutterDesktopEngineProperties& engine_properties, + FlutterProjectArgs* args, + FlutterTaskRunnerDescription* platform_task_runner, + FlutterTaskRunnerDescription* render_task_runner, + FlutterCustomTaskRunners* custom_task_runners) { if (IsHeaded() && !renderer->IsValid()) { FT_LOGE("The display was not valid."); return false; @@ -143,47 +147,43 @@ bool FlutterTizenEngine::RunEngine( } // Configure task runners. - FlutterTaskRunnerDescription platform_task_runner = {}; - platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); - platform_task_runner.user_data = event_loop_.get(); - platform_task_runner.runs_task_on_current_thread_callback = + platform_task_runner->struct_size = sizeof(FlutterTaskRunnerDescription); + platform_task_runner->user_data = event_loop_.get(); + platform_task_runner->runs_task_on_current_thread_callback = [](void* data) -> bool { return static_cast(data)->RunsTasksOnCurrentThread(); }; - platform_task_runner.post_task_callback = + platform_task_runner->post_task_callback = [](FlutterTask task, uint64_t target_time_nanos, void* data) -> void { static_cast(data)->PostTask(task, target_time_nanos); }; - platform_task_runner.identifier = kPlatformTaskRunnerIdentifier; - FlutterCustomTaskRunners custom_task_runners = {}; - custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); - custom_task_runners.platform_task_runner = &platform_task_runner; + platform_task_runner->identifier = kPlatformTaskRunnerIdentifier; + custom_task_runners->struct_size = sizeof(FlutterCustomTaskRunners); + custom_task_runners->platform_task_runner = platform_task_runner; #ifdef TIZEN_RENDERER_EVAS_GL - FlutterTaskRunnerDescription render_task_runner = {}; if (IsHeaded()) { - render_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); - render_task_runner.user_data = render_loop_.get(); - render_task_runner.runs_task_on_current_thread_callback = + render_task_runner->struct_size = sizeof(FlutterTaskRunnerDescription); + render_task_runner->user_data = render_loop_.get(); + render_task_runner->runs_task_on_current_thread_callback = [](void* data) -> bool { return static_cast(data)->RunsTasksOnCurrentThread(); }; - render_task_runner.post_task_callback = + render_task_runner->post_task_callback = [](FlutterTask task, uint64_t target_time_nanos, void* data) -> void { static_cast(data)->PostTask(task, target_time_nanos); }; - render_task_runner.identifier = kRenderTaskRunnerIdentifier; - custom_task_runners.render_task_runner = &render_task_runner; + render_task_runner->identifier = kRenderTaskRunnerIdentifier; + custom_task_runners->render_task_runner = render_task_runner; } #endif - FlutterProjectArgs args = {}; - args.struct_size = sizeof(FlutterProjectArgs); - args.assets_path = engine_properties.assets_path; - args.icu_data_path = engine_properties.icu_data_path; - args.command_line_argc = static_cast(argv.size()); - args.command_line_argv = &argv[0]; - args.platform_message_callback = + args->struct_size = sizeof(FlutterProjectArgs); + args->assets_path = engine_properties.assets_path; + args->icu_data_path = engine_properties.icu_data_path; + args->command_line_argc = static_cast(argv.size()); + args->command_line_argv = &argv[0]; + args->platform_message_callback = [](const FlutterPlatformMessage* engine_message, void* user_data) { if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { FT_LOGE( @@ -195,12 +195,12 @@ bool FlutterTizenEngine::RunEngine( auto message = engine->ConvertToDesktopMessage(*engine_message); engine->message_dispatcher->HandleMessage(message); }; - args.custom_task_runners = &custom_task_runners; + args->custom_task_runners = custom_task_runners; #ifndef TIZEN_RENDERER_EVAS_GL if (IsHeaded()) { // Disable temporary /* - args.vsync_callback = [](void* user_data, intptr_t baton) -> void { + args->vsync_callback = [](void* user_data, intptr_t baton) -> void { reinterpret_cast(user_data) ->tizen_vsync_waiter_->AsyncWaitForVsync(baton); }; @@ -214,20 +214,12 @@ bool FlutterTizenEngine::RunEngine( FT_LOGE("Unable to start engine without AOT data."); return false; } - args.aot_data = aot_data_.get(); - } - - FlutterRendererConfig renderer_config = GetRendererConfig(); - - auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config, - &args, this, &engine_); - if (result == kSuccess && engine_ != nullptr) { - FT_LOGD("FlutterEngineRun Success!"); - } else { - FT_LOGE("FlutterEngineRun Failure! result: %d", result); - return false; + args->aot_data = aot_data_.get(); } + return true; +} +void FlutterTizenEngine::PreparePlatformResource() { internal_plugin_registrar_ = std::make_unique(plugin_registrar_.get()); @@ -254,100 +246,46 @@ bool FlutterTizenEngine::RunEngine( SetWindowOrientation(0); } - - return true; } -bool FlutterTizenEngine::RunSpawnedEngine( +bool FlutterTizenEngine::RunEngine( const FlutterDesktopEngineProperties& engine_properties) { - if (IsHeaded() && !renderer->IsValid()) { - FT_LOGE("The display was not valid."); - 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 argv = {"placeholder"}; - if (engine_properties.switches_count > 0) { - argv.insert(argv.end(), &engine_properties.switches[0], - &engine_properties.switches[engine_properties.switches_count]); - } - - // Configure task runners. + FlutterProjectArgs args = {}; FlutterTaskRunnerDescription platform_task_runner = {}; - platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); - platform_task_runner.user_data = event_loop_.get(); - platform_task_runner.runs_task_on_current_thread_callback = - [](void* data) -> bool { - return static_cast(data)->RunsTasksOnCurrentThread(); - }; - platform_task_runner.post_task_callback = - [](FlutterTask task, uint64_t target_time_nanos, void* data) -> void { - static_cast(data)->PostTask(task, target_time_nanos); - }; - platform_task_runner.identifier = kPlatformTaskRunnerIdentifier; + FlutterTaskRunnerDescription render_task_runner = {}; FlutterCustomTaskRunners custom_task_runners = {}; - custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); - custom_task_runners.platform_task_runner = &platform_task_runner; -#ifdef TIZEN_RENDERER_EVAS_GL - FlutterTaskRunnerDescription render_task_runner = {}; - if (IsHeaded()) { - render_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); - render_task_runner.user_data = render_loop_.get(); - render_task_runner.runs_task_on_current_thread_callback = - [](void* data) -> bool { - return static_cast(data)->RunsTasksOnCurrentThread(); - }; - render_task_runner.post_task_callback = - [](FlutterTask task, uint64_t target_time_nanos, void* data) -> void { - static_cast(data)->PostTask(task, target_time_nanos); - }; - render_task_runner.identifier = kRenderTaskRunnerIdentifier; - custom_task_runners.render_task_runner = &render_task_runner; + if (!PrepareFlutterProjectArgs(engine_properties, &args, + &platform_task_runner, &render_task_runner, + &custom_task_runners)) { + return false; } -#endif + FlutterRendererConfig renderer_config = GetRendererConfig(); + auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config, + &args, this, &engine_); + if (result == kSuccess && engine_ != nullptr) { + FT_LOGD("FlutterEngineRun Success!"); + } else { + FT_LOGE("FlutterEngineRun Failure! result: %d", result); + return false; + } + PreparePlatformResource(); + return true; +} +bool FlutterTizenEngine::RunSpawnedEngine( + const FlutterDesktopEngineProperties& engine_properties) { FlutterProjectArgs args = {}; - args.struct_size = sizeof(FlutterProjectArgs); - args.assets_path = engine_properties.assets_path; - args.icu_data_path = engine_properties.icu_data_path; - args.command_line_argc = static_cast(argv.size()); - args.command_line_argv = &argv[0]; - args.platform_message_callback = - [](const FlutterPlatformMessage* engine_message, void* user_data) { - if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { - FT_LOGE( - "Invalid message size received. Expected: %zu, but received %zu", - sizeof(FlutterPlatformMessage), engine_message->struct_size); - return; - } - auto engine = reinterpret_cast(user_data); - auto message = engine->ConvertToDesktopMessage(*engine_message); - engine->message_dispatcher->HandleMessage(message); - }; - args.custom_task_runners = &custom_task_runners; -#ifndef TIZEN_RENDERER_EVAS_GL - if (IsHeaded()) { - // args.vsync_callback = [](void* user_data, intptr_t baton) -> void { - // reinterpret_cast(user_data) - // ->tizen_vsync_waiter_->AsyncWaitForVsync(baton); - // }; - } -#endif + FlutterTaskRunnerDescription platform_task_runner = {}; + FlutterTaskRunnerDescription render_task_runner = {}; + FlutterCustomTaskRunners custom_task_runners = {}; - if (embedder_api_.RunsAOTCompiledDartCode()) { - aot_data_ = LoadAotData(engine_properties.aot_library_path); - if (!aot_data_) { - FT_LOGE("Unable to start engine without AOT data."); - return false; - } - args.aot_data = aot_data_.get(); + if (!PrepareFlutterProjectArgs(engine_properties, &args, + &platform_task_runner, &render_task_runner, + &custom_task_runners)) { + return false; } - FlutterRendererConfig renderer_config = GetRendererConfig(); - auto result = embedder_api_.Spawn(FLUTTER_ENGINE_VERSION, &renderer_config, &args, this, &engine_, main_engine_->Engine()); @@ -357,34 +295,7 @@ bool FlutterTizenEngine::RunSpawnedEngine( FT_LOGE("FlutterEngineRun Failure! result: %d", result); return false; } - - internal_plugin_registrar_ = - std::make_unique(plugin_registrar_.get()); - - platform_channel = std::make_unique( - internal_plugin_registrar_->messenger(), renderer.get()); - settings_channel = std::make_unique( - internal_plugin_registrar_->messenger()); - localization_channel = std::make_unique(this); - localization_channel->SendLocales(); - lifecycle_channel = std::make_unique(this); - - if (IsHeaded()) { - texture_registrar_ = std::make_unique(this); - key_event_channel = std::make_unique( - internal_plugin_registrar_->messenger()); - navigation_channel = std::make_unique( - internal_plugin_registrar_->messenger()); - text_input_channel = std::make_unique( - internal_plugin_registrar_->messenger(), this); - platform_view_channel = std::make_unique( - internal_plugin_registrar_->messenger(), this); - key_event_handler_ = std::make_unique(this); - touch_event_handler_ = std::make_unique(this); - - SetWindowOrientation(0); - } - + PreparePlatformResource(); return true; } diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 3eb45ec2beb64..d7b5e6fdeeeb5 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -161,6 +161,13 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { FlutterDesktopMessage ConvertToDesktopMessage( const FlutterPlatformMessage& engine_message); FlutterRendererConfig GetRendererConfig(); + bool PrepareFlutterProjectArgs( + const FlutterDesktopEngineProperties& engine_properties, + FlutterProjectArgs* args, + FlutterTaskRunnerDescription* platform_task_runner, + FlutterTaskRunnerDescription* render_task_runner, + FlutterCustomTaskRunners* custom_task_runners); + void PreparePlatformResource(); FlutterEngineProcTable embedder_api_ = {}; From 04eaa322f8d03b1134afef9241e39995f9760a2b Mon Sep 17 00:00:00 2001 From: MuHong Byun Date: Tue, 22 Jun 2021 17:15:10 +0900 Subject: [PATCH 4/4] Apply review's comment Signed-off-by: MuHong Byun Co-authored-by: Boram Bae --- shell/platform/tizen/flutter_tizen_engine.cc | 2 +- shell/platform/tizen/flutter_tizen_engine.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index aba442af4e9bb..81aa52f52b212 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -288,7 +288,7 @@ bool FlutterTizenEngine::RunSpawnedEngine( FlutterRendererConfig renderer_config = GetRendererConfig(); auto result = embedder_api_.Spawn(FLUTTER_ENGINE_VERSION, &renderer_config, &args, this, - &engine_, main_engine_->Engine()); + &engine_, main_engine_->engine_); if (result == kSuccess && engine_ != nullptr) { FT_LOGD("FlutterEngineRun Success!"); } else { diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index d7b5e6fdeeeb5..92518808e55ce 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -153,8 +153,6 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { const DeviceProfile device_profile; - FLUTTER_API_SYMBOL(FlutterEngine) Engine() { return engine_; } - private: bool IsHeaded() { return renderer != nullptr; } UniqueAotDataPtr LoadAotData(std::string aot_data_path);