in shell/platform/embedder/embedder.cc [1077:1516]
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,
"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.");
}
}
PopulateSnapshotMappingCallbacks(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, fml::closure callback) {
fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(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);
}
flutter::PlatformViewEmbedder::UpdateSemanticsNodesCallback
update_semantics_nodes_callback = nullptr;
if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) {
update_semantics_nodes_callback =
[ptr = args->update_semantics_node_callback,
user_data](flutter::SemanticsNodeUpdates update) {
for (const auto& value : update) {
const auto& node = value.second;
SkMatrix transform = node.transform.asM33();
FlutterTransformation flutter_transform{
transform.get(SkMatrix::kMScaleX),
transform.get(SkMatrix::kMSkewX),
transform.get(SkMatrix::kMTransX),
transform.get(SkMatrix::kMSkewY),
transform.get(SkMatrix::kMScaleY),
transform.get(SkMatrix::kMTransY),
transform.get(SkMatrix::kMPersp0),
transform.get(SkMatrix::kMPersp1),
transform.get(SkMatrix::kMPersp2)};
const FlutterSemanticsNode embedder_node{
sizeof(FlutterSemanticsNode),
node.id,
static_cast<FlutterSemanticsFlag>(node.flags),
static_cast<FlutterSemanticsAction>(node.actions),
node.textSelectionBase,
node.textSelectionExtent,
node.scrollChildren,
node.scrollIndex,
node.scrollPosition,
node.scrollExtentMax,
node.scrollExtentMin,
node.elevation,
node.thickness,
node.label.c_str(),
node.hint.c_str(),
node.value.c_str(),
node.increasedValue.c_str(),
node.decreasedValue.c_str(),
static_cast<FlutterTextDirection>(node.textDirection),
FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
node.rect.fBottom},
flutter_transform,
node.childrenInTraversalOrder.size(),
node.childrenInTraversalOrder.data(),
node.childrenInHitTestOrder.data(),
node.customAccessibilityActions.size(),
node.customAccessibilityActions.data(),
node.platformViewId,
};
ptr(&embedder_node, user_data);
}
const FlutterSemanticsNode batch_end_sentinel = {
sizeof(FlutterSemanticsNode),
kFlutterSemanticsNodeIdBatchEnd,
};
ptr(&batch_end_sentinel, user_data);
};
}
flutter::PlatformViewEmbedder::UpdateSemanticsCustomActionsCallback
update_semantics_custom_actions_callback = nullptr;
if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
nullptr) {
update_semantics_custom_actions_callback =
[ptr = args->update_semantics_custom_action_callback,
user_data](flutter::CustomAccessibilityActionUpdates actions) {
for (const auto& value : actions) {
const auto& action = value.second;
const FlutterSemanticsCustomAction embedder_action = {
sizeof(FlutterSemanticsCustomAction),
action.id,
static_cast<FlutterSemanticsAction>(action.overrideId),
action.label.c_str(),
action.hint.c_str(),
};
ptr(&embedder_action, user_data);
}
const FlutterSemanticsCustomAction batch_end_sentinel = {
sizeof(FlutterSemanticsCustomAction),
kFlutterSemanticsCustomActionIdBatchEnd,
};
ptr(&batch_end_sentinel, 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_nodes_callback, //
update_semantics_custom_actions_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 thread_host =
flutter::EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost(
SAFE_ACCESS(args, custom_task_runners, nullptr));
if (!thread_host || !thread_host->IsValid()) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Could not set up or infer thread configuration "
"to run the Flutter engine on.");
}
auto task_runners = thread_host->GetTaskRunners();
if (!task_runners.IsValid()) {
return LOG_EMBEDDER_ERROR(kInternalInconsistency,
"Task runner configuration was invalid.");
}
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.size() != 0) {
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.");
}
// 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, //
std::move(external_texture_resolver) //
);
// Release the ownership of the embedder engine to the caller.
*engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(
embedder_engine.release());
return kSuccess;
}