Skip to content
Closed
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
376 changes: 376 additions & 0 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1979,6 +1979,381 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
return kSuccess;
}

FlutterEngineResult FlutterEngineSpawn(size_t version,
const FlutterRendererConfig* config,
const FlutterProjectArgs* args,
void* user_data,
FLUTTER_API_SYMBOL(FlutterEngine)
engine_spawner,
FLUTTER_API_SYMBOL(FlutterEngine) *
engine_out) {
// Step 0. Figure out arguments for shell spawn.
if (version != FLUTTER_ENGINE_VERSION) {
return LOG_EMBEDDER_ERROR(
kInvalidLibraryVersion,
"Flutter embedder version mismatch. There has been a breaking change. "
"Please consult the changelog and update the embedder.");
}

if (engine_out == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"The engine out parameter was missing.");
}

if (args == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"The Flutter project arguments were missing.");
}

if (SAFE_ACCESS(args, assets_path, nullptr) == nullptr) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"The assets path in the Flutter project arguments was missing.");
}

if (SAFE_ACCESS(args, main_path__unused__, nullptr) != nullptr) {
FML_LOG(WARNING)
<< "FlutterProjectArgs.main_path is deprecated and should be set null.";
}

if (SAFE_ACCESS(args, packages_path__unused__, nullptr) != nullptr) {
FML_LOG(WARNING) << "FlutterProjectArgs.packages_path is deprecated and "
"should be set null.";
}

if (!IsRendererValid(config)) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"The renderer configuration was invalid.");
}

std::string icu_data_path;
if (SAFE_ACCESS(args, icu_data_path, nullptr) != nullptr) {
icu_data_path = SAFE_ACCESS(args, icu_data_path, nullptr);
}

if (SAFE_ACCESS(args, persistent_cache_path, nullptr) != nullptr) {
std::string persistent_cache_path =
SAFE_ACCESS(args, persistent_cache_path, nullptr);
flutter::PersistentCache::SetCacheDirectoryPath(persistent_cache_path);
}

if (SAFE_ACCESS(args, is_persistent_cache_read_only, false)) {
flutter::PersistentCache::gIsReadOnly = true;
}

fml::CommandLine command_line;
if (SAFE_ACCESS(args, command_line_argc, 0) != 0 &&
SAFE_ACCESS(args, command_line_argv, nullptr) != nullptr) {
command_line = fml::CommandLineFromArgcArgv(
SAFE_ACCESS(args, command_line_argc, 0),
SAFE_ACCESS(args, command_line_argv, nullptr));
}

flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);

if (SAFE_ACCESS(args, aot_data, nullptr)) {
if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) ||
SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) ||
SAFE_ACCESS(args, isolate_snapshot_data, nullptr) ||
SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr)) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Multiple AOT sources specified. Embedders should provide either "
"*_snapshot_* buffers or aot_data, not both.");
}
}

if (flutter::DartVM::IsRunningPrecompiledCode()) {
PopulateAOTSnapshotMappingCallbacks(args, settings);
} else {
PopulateJITSnapshotMappingCallbacks(args, settings);
}

settings.icu_data_path = icu_data_path;
settings.assets_path = args->assets_path;
settings.leak_vm = !SAFE_ACCESS(args, shutdown_dart_vm_when_done, false);
settings.old_gen_heap_size = SAFE_ACCESS(args, dart_old_gen_heap_size, -1);

if (!flutter::DartVM::IsRunningPrecompiledCode()) {
// Verify the assets path contains Dart 2 kernel assets.
const std::string kApplicationKernelSnapshotFileName = "kernel_blob.bin";
std::string application_kernel_path = fml::paths::JoinPaths(
{settings.assets_path, kApplicationKernelSnapshotFileName});
if (!fml::IsFile(application_kernel_path)) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Not running in AOT mode but could not resolve the kernel binary.");
}
settings.application_kernel_asset = kApplicationKernelSnapshotFileName;
}

settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
};
settings.task_observer_remove = [](intptr_t key) {
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
};
if (SAFE_ACCESS(args, root_isolate_create_callback, nullptr) != nullptr) {
VoidCallback callback =
SAFE_ACCESS(args, root_isolate_create_callback, nullptr);
settings.root_isolate_create_callback =
[callback, user_data](const auto& isolate) { callback(user_data); };
}
if (SAFE_ACCESS(args, log_message_callback, nullptr) != nullptr) {
FlutterLogMessageCallback callback =
SAFE_ACCESS(args, log_message_callback, nullptr);
settings.log_message_callback = [callback, user_data](
const std::string& tag,
const std::string& message) {
callback(tag.c_str(), message.c_str(), user_data);
};
}
if (SAFE_ACCESS(args, log_tag, nullptr) != nullptr) {
settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr);
}

bool has_update_semantics_2_callback =
SAFE_ACCESS(args, update_semantics_callback2, nullptr) != nullptr;
bool has_update_semantics_callback =
SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr;
bool has_legacy_update_semantics_callback =
SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr ||
SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
nullptr;

int semantic_callback_count = (has_update_semantics_2_callback ? 1 : 0) +
(has_update_semantics_callback ? 1 : 0) +
(has_legacy_update_semantics_callback ? 1 : 0);

if (semantic_callback_count > 1) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Multiple semantics update callbacks provided. "
"Embedders should provide either `update_semantics_callback2`, "
"`update_semantics_callback`, or both "
"`update_semantics_node_callback` and "
"`update_semantics_custom_action_callback`.");
}

flutter::PlatformViewEmbedder::UpdateSemanticsCallback
update_semantics_callback =
CreateEmbedderSemanticsUpdateCallback(args, user_data);

flutter::PlatformViewEmbedder::PlatformMessageResponseCallback
platform_message_response_callback = nullptr;
if (SAFE_ACCESS(args, platform_message_callback, nullptr) != nullptr) {
platform_message_response_callback =
[ptr = args->platform_message_callback,
user_data](std::unique_ptr<flutter::PlatformMessage> message) {
auto handle = new FlutterPlatformMessageResponseHandle();
const FlutterPlatformMessage incoming_message = {
sizeof(FlutterPlatformMessage), // struct_size
message->channel().c_str(), // channel
message->data().GetMapping(), // message
message->data().GetSize(), // message_size
handle, // response_handle
};
handle->message = std::move(message);
return ptr(&incoming_message, user_data);
};
}

flutter::VsyncWaiterEmbedder::VsyncCallback vsync_callback = nullptr;
if (SAFE_ACCESS(args, vsync_callback, nullptr) != nullptr) {
vsync_callback = [ptr = args->vsync_callback, user_data](intptr_t baton) {
return ptr(user_data, baton);
};
}

flutter::PlatformViewEmbedder::ComputePlatformResolvedLocaleCallback
compute_platform_resolved_locale_callback = nullptr;
if (SAFE_ACCESS(args, compute_platform_resolved_locale_callback, nullptr) !=
nullptr) {
compute_platform_resolved_locale_callback =
[ptr = args->compute_platform_resolved_locale_callback](
const std::vector<std::string>& supported_locales_data) {
const size_t number_of_strings_per_locale = 3;
size_t locale_count =
supported_locales_data.size() / number_of_strings_per_locale;
std::vector<FlutterLocale> supported_locales;
std::vector<const FlutterLocale*> supported_locales_ptr;
for (size_t i = 0; i < locale_count; ++i) {
supported_locales.push_back(
{.struct_size = sizeof(FlutterLocale),
.language_code =
supported_locales_data[i * number_of_strings_per_locale +
0]
.c_str(),
.country_code =
supported_locales_data[i * number_of_strings_per_locale +
1]
.c_str(),
.script_code =
supported_locales_data[i * number_of_strings_per_locale +
2]
.c_str(),
.variant_code = nullptr});
supported_locales_ptr.push_back(&supported_locales[i]);
}

const FlutterLocale* result =
ptr(supported_locales_ptr.data(), locale_count);

std::unique_ptr<std::vector<std::string>> out =
std::make_unique<std::vector<std::string>>();
if (result) {
std::string language_code(SAFE_ACCESS(result, language_code, ""));
if (language_code != "") {
out->push_back(language_code);
out->emplace_back(SAFE_ACCESS(result, country_code, ""));
out->emplace_back(SAFE_ACCESS(result, script_code, ""));
}
}
return out;
};
}

flutter::PlatformViewEmbedder::OnPreEngineRestartCallback
on_pre_engine_restart_callback = nullptr;
if (SAFE_ACCESS(args, on_pre_engine_restart_callback, nullptr) != nullptr) {
on_pre_engine_restart_callback = [ptr =
args->on_pre_engine_restart_callback,
user_data]() { return ptr(user_data); };
}

auto external_view_embedder_result =
InferExternalViewEmbedderFromArgs(SAFE_ACCESS(args, compositor, nullptr));
if (external_view_embedder_result.second) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Compositor arguments were invalid.");
}

flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
{
update_semantics_callback, //
platform_message_response_callback, //
vsync_callback, //
compute_platform_resolved_locale_callback, //
on_pre_engine_restart_callback, //
};

auto on_create_platform_view = InferPlatformViewCreationCallback(
config, user_data, platform_dispatch_table,
std::move(external_view_embedder_result.first));

if (!on_create_platform_view) {
return LOG_EMBEDDER_ERROR(
kInternalInconsistency,
"Could not infer platform view creation callback.");
}

flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
[](flutter::Shell& shell) {
return std::make_unique<flutter::Rasterizer>(shell);
};

using ExternalTextureResolver = flutter::EmbedderExternalTextureResolver;
std::unique_ptr<ExternalTextureResolver> external_texture_resolver;
external_texture_resolver = std::make_unique<ExternalTextureResolver>();

#ifdef SHELL_ENABLE_GL
flutter::EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback;
if (config->type == kOpenGL) {
const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
if (SAFE_ACCESS(open_gl_config, gl_external_texture_frame_callback,
nullptr) != nullptr) {
external_texture_callback =
[ptr = open_gl_config->gl_external_texture_frame_callback, user_data](
int64_t texture_identifier, size_t width,
size_t height) -> std::unique_ptr<FlutterOpenGLTexture> {
std::unique_ptr<FlutterOpenGLTexture> texture =
std::make_unique<FlutterOpenGLTexture>();
if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
return nullptr;
}
return texture;
};
external_texture_resolver =
std::make_unique<ExternalTextureResolver>(external_texture_callback);
}
}
#endif
#ifdef SHELL_ENABLE_METAL
flutter::EmbedderExternalTextureMetal::ExternalTextureCallback
external_texture_metal_callback;
if (config->type == kMetal) {
const FlutterMetalRendererConfig* metal_config = &config->metal;
if (SAFE_ACCESS(metal_config, external_texture_frame_callback, nullptr)) {
external_texture_metal_callback =
[ptr = metal_config->external_texture_frame_callback, user_data](
int64_t texture_identifier, size_t width,
size_t height) -> std::unique_ptr<FlutterMetalExternalTexture> {
std::unique_ptr<FlutterMetalExternalTexture> texture =
std::make_unique<FlutterMetalExternalTexture>();
texture->struct_size = sizeof(FlutterMetalExternalTexture);
if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
return nullptr;
}
return texture;
};
external_texture_resolver = std::make_unique<ExternalTextureResolver>(
external_texture_metal_callback);
}
}
#endif

auto run_configuration =
flutter::RunConfiguration::InferFromSettings(settings);

if (SAFE_ACCESS(args, custom_dart_entrypoint, nullptr) != nullptr) {
auto dart_entrypoint = std::string{args->custom_dart_entrypoint};
if (!dart_entrypoint.empty()) {
run_configuration.SetEntrypoint(std::move(dart_entrypoint));
}
}

if (SAFE_ACCESS(args, dart_entrypoint_argc, 0) > 0) {
if (SAFE_ACCESS(args, dart_entrypoint_argv, nullptr) == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Could not determine Dart entrypoint arguments "
"as dart_entrypoint_argc "
"was set, but dart_entrypoint_argv was null.");
}
std::vector<std::string> arguments(args->dart_entrypoint_argc);
for (int i = 0; i < args->dart_entrypoint_argc; ++i) {
arguments[i] = std::string{args->dart_entrypoint_argv[i]};
}
run_configuration.SetEntrypointArgs(std::move(arguments));
}

if (!run_configuration.IsValid()) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Could not infer the Flutter project to run from given arguments.");
}

// Spawn the engine by using spawner
auto embedder_engine_spawner =
reinterpret_cast<flutter::EmbedderEngine*>(engine_spawner);
auto embedder_engine = embedder_engine_spawner->SpawnEmbedderEngine(
std::move(settings), //
std::move(run_configuration), //
on_create_platform_view, //
on_create_rasterizer, //
std::move(external_texture_resolver));

if (!embedder_engine->NotifyCreated()) {
return LOG_EMBEDDER_ERROR(kInternalInconsistency,
"Could not create platform view components.");
}

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

FlutterEngineResult FlutterEngineRunInitialized(
FLUTTER_API_SYMBOL(FlutterEngine) engine) {
if (!engine) {
Expand Down Expand Up @@ -3074,6 +3449,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);
Expand Down
Loading