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..edc27bc8c3ea0 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1598,6 +1598,19 @@ FlutterEngineResult FlutterEngineRun(size_t version, FLUTTER_API_SYMBOL(FlutterEngine) * engine_out); +//------------------------------------------------------------------------------ +// TODO : Update required +/// +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 +1686,14 @@ FLUTTER_EXPORT FlutterEngineResult FlutterEngineRunInitialized( FLUTTER_API_SYMBOL(FlutterEngine) engine); +//------------------------------------------------------------------------------ +// TODO : Update required +/// +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 +2225,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 +2343,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..81aa52f52b212 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 } @@ -119,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; @@ -136,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( @@ -188,13 +195,16 @@ 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()) { - args.vsync_callback = [](void* user_data, intptr_t baton) -> void { + // Disable temporary + /* + args->vsync_callback = [](void* user_data, intptr_t baton) -> void { reinterpret_cast(user_data) ->tizen_vsync_waiter_->AsyncWaitForVsync(baton); }; + */ } #endif @@ -204,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()); @@ -244,10 +246,71 @@ bool FlutterTizenEngine::RunEngine( SetWindowOrientation(0); } +} + +bool FlutterTizenEngine::RunEngine( + const FlutterDesktopEngineProperties& engine_properties) { + FlutterProjectArgs args = {}; + FlutterTaskRunnerDescription platform_task_runner = {}; + FlutterTaskRunnerDescription render_task_runner = {}; + FlutterCustomTaskRunners custom_task_runners = {}; + + if (!PrepareFlutterProjectArgs(engine_properties, &args, + &platform_task_runner, &render_task_runner, + &custom_task_runners)) { + return false; + } + 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 = {}; + FlutterTaskRunnerDescription platform_task_runner = {}; + FlutterTaskRunnerDescription render_task_runner = {}; + FlutterCustomTaskRunners custom_task_runners = {}; + 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_); + if (result == kSuccess && engine_ != nullptr) { + FT_LOGD("FlutterEngineRun Success!"); + } else { + FT_LOGE("FlutterEngineRun Failure! result: %d", result); + return false; + } + PreparePlatformResource(); 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) { diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 419d7b7349b7a..92518808e55ce 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. @@ -150,6 +159,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_ = {}; @@ -193,6 +209,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.