Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 76 additions & 26 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,22 @@ FlutterEngineResult FlutterEngineRun(size_t version,
void* user_data,
FLUTTER_API_SYMBOL(FlutterEngine) *
engine_out) {
auto result =
FlutterEngineInitialize(version, config, args, user_data, engine_out);

if (result != kSuccess) {
return result;
}

return FlutterEngineRunInitialized(*engine_out);
}

FlutterEngineResult FlutterEngineInitialize(size_t version,
const FlutterRendererConfig* config,
const FlutterProjectArgs* args,
void* user_data,
FLUTTER_API_SYMBOL(FlutterEngine) *
engine_out) {
// Step 0: Figure out arguments for shell creation.
if (version != FLUTTER_ENGINE_VERSION) {
return LOG_EMBEDDER_ERROR(kInvalidLibraryVersion);
Expand Down Expand Up @@ -861,26 +877,6 @@ FlutterEngineResult FlutterEngineRun(size_t version,
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

// Step 1: Create the engine.
auto embedder_engine =
std::make_unique<flutter::EmbedderEngine>(std::move(thread_host), //
std::move(task_runners), //
settings, //
on_create_platform_view, //
on_create_rasterizer, //
external_texture_callback //
);

if (!embedder_engine->IsValid()) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

// Step 2: Setup the rendering surface.
if (!embedder_engine->NotifyCreated()) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

// Step 3: Run the engine.
auto run_configuration =
flutter::RunConfiguration::InferFromSettings(settings);

Expand All @@ -895,23 +891,77 @@ FlutterEngineResult FlutterEngineRun(size_t version,
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

if (!embedder_engine->Run(std::move(run_configuration))) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}
// Create the engine but don't launch the shell or run the root isolate.
auto embedder_engine = std::make_unique<flutter::EmbedderEngine>(
std::move(thread_host), //
std::move(task_runners), //
std::move(settings), //
std::move(run_configuration), //
on_create_platform_view, //
on_create_rasterizer, //
external_texture_callback //
);

// Finally! Release the ownership of the embedder engine to the caller.
// Release the ownership of the embedder engine to the caller.
*engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(
embedder_engine.release());
return kSuccess;
}

FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine)
engine) {
FlutterEngineResult FlutterEngineRunInitialized(
FLUTTER_API_SYMBOL(FlutterEngine) engine) {
if (!engine) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);

// 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);
}

// Step 1: Launch the shell.
if (!embedder_engine->LaunchShell()) {
FML_LOG(ERROR) << "Could not launch the engine using supplied "
"initialization arguments.";
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

// Step 2: Tell the platform view to initialize itself.
if (!embedder_engine->NotifyCreated()) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

// Step 3: Launch the root isolate.
if (!embedder_engine->RunRootIsolate()) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

return kSuccess;
}

FLUTTER_EXPORT
FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine)
engine) {
if (engine == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments);
}

auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
embedder_engine->NotifyDestroyed();
embedder_engine->CollectShell();
return kSuccess;
}

FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine)
engine) {
auto result = FlutterEngineDeinitialize(engine);
if (result != kSuccess) {
return result;
}
auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
delete embedder_engine;
return kSuccess;
}
Expand Down
109 changes: 108 additions & 1 deletion shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,14 +603,24 @@ typedef struct {
///
/// @attention This field is required.
FlutterTaskRunnerPostTaskCallback post_task_callback;
/// A unique identifier for the task runner. If multiple task runners service
/// tasks on the same thread, their identifiers must match.
size_t identifier;
} FlutterTaskRunnerDescription;

typedef struct {
/// The size of this struct. Must be sizeof(FlutterCustomTaskRunners).
size_t struct_size;
/// Specify the task runner for the thread on which the `FlutterEngineRun`
/// call is made.
/// call is made. The same task runner description can be specified for both
/// the render and platform task runners. This makes the Flutter engine use
/// the same thread for both task runners.
const FlutterTaskRunnerDescription* platform_task_runner;
/// Specify the task runner for the thread on which the render tasks will be
/// run. The same task runner description can be specified for both the render
/// and platform task runners. This makes the Flutter engine use the same
/// thread for both task runners.
const FlutterTaskRunnerDescription* render_task_runner;
} FlutterCustomTaskRunners;

typedef struct {
Expand Down Expand Up @@ -950,6 +960,32 @@ typedef struct {
const FlutterCompositor* compositor;
} FlutterProjectArgs;

//------------------------------------------------------------------------------
/// @brief Initialize and run a Flutter engine instance and return a handle
/// to it. This is a convenience method for the 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 FlutterEngineRun(size_t version,
const FlutterRendererConfig* config,
Expand All @@ -958,10 +994,81 @@ FlutterEngineResult FlutterEngineRun(size_t version,
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.
///
/// @note This de-initializes the Flutter engine instance (via an implicit
/// call to `FlutterEngineDeinitialize`) if necessary.
///
/// @param[in] engine The Flutter engine instance to collect.
///
/// @return The result of the call to shutdown the Flutter engine instance.
///
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine)
engine);

//------------------------------------------------------------------------------
/// @brief Initialize a Flutter engine instance. This does not run the
/// Flutter application code till the `FlutterEngineRunInitialized`
/// call is made. Besides Flutter application code, no tasks are
/// scheduled on embedder managed task runners either. This allows
/// embedders providing custom task runners to the Flutter engine to
/// obtain a handle to the Flutter engine before the engine can post
/// tasks on these task runners.
///
/// @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 initialize the Flutter engine.
///
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineInitialize(size_t version,
const FlutterRendererConfig* config,
const FlutterProjectArgs* args,
void* user_data,
FLUTTER_API_SYMBOL(FlutterEngine) *
engine_out);

//------------------------------------------------------------------------------
/// @brief Stops running the Flutter engine instance. After this call, the
/// embedder is also guaranteed that no more calls to post tasks
/// onto custom task runners specified by the embedder are made. The
/// Flutter engine handle still needs to be collected via a call to
/// `FlutterEngineShutdown`.
///
/// @param[in] engine The running engine instance to de-initialize.
///
/// @return The result of the call to de-initialize the Flutter engine.
///
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineDeinitialize(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 FlutterEngineRunInitialized(
FLUTTER_API_SYMBOL(FlutterEngine) engine);

FLUTTER_EXPORT
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(
FLUTTER_API_SYMBOL(FlutterEngine) engine,
Expand Down
78 changes: 59 additions & 19 deletions shell/platform/embedder/embedder_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,73 @@

namespace flutter {

struct ShellArgs {
Settings settings;
Shell::CreateCallback<PlatformView> on_create_platform_view;
Shell::CreateCallback<Rasterizer> on_create_rasterizer;
ShellArgs(Settings p_settings,
Shell::CreateCallback<PlatformView> p_on_create_platform_view,
Shell::CreateCallback<Rasterizer> p_on_create_rasterizer)
: settings(std::move(p_settings)),
on_create_platform_view(std::move(p_on_create_platform_view)),
on_create_rasterizer(std::move(p_on_create_rasterizer)) {}
};

EmbedderEngine::EmbedderEngine(
std::unique_ptr<EmbedderThreadHost> thread_host,
flutter::TaskRunners task_runners,
flutter::Settings settings,
RunConfiguration run_configuration,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback)
: thread_host_(std::move(thread_host)),
task_runners_(task_runners),
shell_(Shell::Create(task_runners_,
std::move(settings),
on_create_platform_view,
on_create_rasterizer)),
external_texture_callback_(external_texture_callback) {
if (!shell_) {
return;
run_configuration_(std::move(run_configuration)),
shell_args_(std::make_unique<ShellArgs>(std::move(settings),
on_create_platform_view,
on_create_rasterizer)),
external_texture_callback_(external_texture_callback) {}

EmbedderEngine::~EmbedderEngine() = default;

bool EmbedderEngine::LaunchShell() {
if (!shell_args_) {
FML_DLOG(ERROR) << "Invalid shell arguments.";
return false;
}

if (shell_) {
FML_DLOG(ERROR) << "Shell already initialized";
}

is_valid_ = true;
shell_ = Shell::Create(task_runners_, shell_args_->settings,
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();
}

EmbedderEngine::~EmbedderEngine() = default;
bool EmbedderEngine::CollectShell() {
shell_.reset();
return IsValid();
}

bool EmbedderEngine::RunRootIsolate() {
if (!IsValid() || !run_configuration_.IsValid()) {
return false;
}
shell_->RunEngine(std::move(run_configuration_));
return true;
}

bool EmbedderEngine::IsValid() const {
return is_valid_;
return static_cast<bool>(shell_);
}

const TaskRunners& EmbedderEngine::GetTaskRunners() const {
Expand All @@ -59,14 +100,6 @@ bool EmbedderEngine::NotifyDestroyed() {
return true;
}

bool EmbedderEngine::Run(RunConfiguration run_configuration) {
if (!IsValid() || !run_configuration.IsValid()) {
return false;
}
shell_->RunEngine(std::move(run_configuration));
return true;
}

bool EmbedderEngine::SetViewportMetrics(flutter::ViewportMetrics metrics) {
if (!IsValid()) {
return false;
Expand Down Expand Up @@ -187,6 +220,10 @@ bool EmbedderEngine::OnVsyncEvent(intptr_t baton,
}

bool EmbedderEngine::ReloadSystemFonts() {
if (!IsValid()) {
return false;
}

return shell_->ReloadSystemFonts();
}

Expand All @@ -200,7 +237,10 @@ bool EmbedderEngine::PostRenderThreadTask(fml::closure task) {
}

bool EmbedderEngine::RunTask(const FlutterTask* task) {
if (!IsValid() || task == nullptr) {
// The shell doesn't need to be running or valid for access to the thread
// host. This is why there is no `IsValid` check here. This allows embedders
// to perform custom task runner interop before the shell is running.
if (task == nullptr) {
return false;
}
return thread_host_->PostTask(reinterpret_cast<int64_t>(task->runner),
Expand Down
Loading