Skip to content

Commit e44b418

Browse files
committed
Implement FlutterEngineSpawn
Signed-off-by: swan.seo <[email protected]>
1 parent 439a832 commit e44b418

File tree

4 files changed

+447
-4
lines changed

4 files changed

+447
-4
lines changed

shell/platform/embedder/embedder.cc

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,381 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
19791979
return kSuccess;
19801980
}
19811981

1982+
FlutterEngineResult FlutterEngineSpawn(size_t version,
1983+
const FlutterRendererConfig* config,
1984+
const FlutterProjectArgs* args,
1985+
void* user_data,
1986+
FLUTTER_API_SYMBOL(FlutterEngine)
1987+
engine_spawner,
1988+
FLUTTER_API_SYMBOL(FlutterEngine) *
1989+
engine_out) {
1990+
// Step 0. Figure out arguments for shell spawn.
1991+
if (version != FLUTTER_ENGINE_VERSION) {
1992+
return LOG_EMBEDDER_ERROR(
1993+
kInvalidLibraryVersion,
1994+
"Flutter embedder version mismatch. There has been a breaking change. "
1995+
"Please consult the changelog and update the embedder.");
1996+
}
1997+
1998+
if (engine_out == nullptr) {
1999+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
2000+
"The engine out parameter was missing.");
2001+
}
2002+
2003+
if (args == nullptr) {
2004+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
2005+
"The Flutter project arguments were missing.");
2006+
}
2007+
2008+
if (SAFE_ACCESS(args, assets_path, nullptr) == nullptr) {
2009+
return LOG_EMBEDDER_ERROR(
2010+
kInvalidArguments,
2011+
"The assets path in the Flutter project arguments was missing.");
2012+
}
2013+
2014+
if (SAFE_ACCESS(args, main_path__unused__, nullptr) != nullptr) {
2015+
FML_LOG(WARNING)
2016+
<< "FlutterProjectArgs.main_path is deprecated and should be set null.";
2017+
}
2018+
2019+
if (SAFE_ACCESS(args, packages_path__unused__, nullptr) != nullptr) {
2020+
FML_LOG(WARNING) << "FlutterProjectArgs.packages_path is deprecated and "
2021+
"should be set null.";
2022+
}
2023+
2024+
if (!IsRendererValid(config)) {
2025+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
2026+
"The renderer configuration was invalid.");
2027+
}
2028+
2029+
std::string icu_data_path;
2030+
if (SAFE_ACCESS(args, icu_data_path, nullptr) != nullptr) {
2031+
icu_data_path = SAFE_ACCESS(args, icu_data_path, nullptr);
2032+
}
2033+
2034+
if (SAFE_ACCESS(args, persistent_cache_path, nullptr) != nullptr) {
2035+
std::string persistent_cache_path =
2036+
SAFE_ACCESS(args, persistent_cache_path, nullptr);
2037+
flutter::PersistentCache::SetCacheDirectoryPath(persistent_cache_path);
2038+
}
2039+
2040+
if (SAFE_ACCESS(args, is_persistent_cache_read_only, false)) {
2041+
flutter::PersistentCache::gIsReadOnly = true;
2042+
}
2043+
2044+
fml::CommandLine command_line;
2045+
if (SAFE_ACCESS(args, command_line_argc, 0) != 0 &&
2046+
SAFE_ACCESS(args, command_line_argv, nullptr) != nullptr) {
2047+
command_line = fml::CommandLineFromArgcArgv(
2048+
SAFE_ACCESS(args, command_line_argc, 0),
2049+
SAFE_ACCESS(args, command_line_argv, nullptr));
2050+
}
2051+
2052+
flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
2053+
2054+
if (SAFE_ACCESS(args, aot_data, nullptr)) {
2055+
if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) ||
2056+
SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) ||
2057+
SAFE_ACCESS(args, isolate_snapshot_data, nullptr) ||
2058+
SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr)) {
2059+
return LOG_EMBEDDER_ERROR(
2060+
kInvalidArguments,
2061+
"Multiple AOT sources specified. Embedders should provide either "
2062+
"*_snapshot_* buffers or aot_data, not both.");
2063+
}
2064+
}
2065+
2066+
if (flutter::DartVM::IsRunningPrecompiledCode()) {
2067+
PopulateAOTSnapshotMappingCallbacks(args, settings);
2068+
} else {
2069+
PopulateJITSnapshotMappingCallbacks(args, settings);
2070+
}
2071+
2072+
settings.icu_data_path = icu_data_path;
2073+
settings.assets_path = args->assets_path;
2074+
settings.leak_vm = !SAFE_ACCESS(args, shutdown_dart_vm_when_done, false);
2075+
settings.old_gen_heap_size = SAFE_ACCESS(args, dart_old_gen_heap_size, -1);
2076+
2077+
if (!flutter::DartVM::IsRunningPrecompiledCode()) {
2078+
// Verify the assets path contains Dart 2 kernel assets.
2079+
const std::string kApplicationKernelSnapshotFileName = "kernel_blob.bin";
2080+
std::string application_kernel_path = fml::paths::JoinPaths(
2081+
{settings.assets_path, kApplicationKernelSnapshotFileName});
2082+
if (!fml::IsFile(application_kernel_path)) {
2083+
return LOG_EMBEDDER_ERROR(
2084+
kInvalidArguments,
2085+
"Not running in AOT mode but could not resolve the kernel binary.");
2086+
}
2087+
settings.application_kernel_asset = kApplicationKernelSnapshotFileName;
2088+
}
2089+
2090+
settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
2091+
fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
2092+
};
2093+
settings.task_observer_remove = [](intptr_t key) {
2094+
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
2095+
};
2096+
if (SAFE_ACCESS(args, root_isolate_create_callback, nullptr) != nullptr) {
2097+
VoidCallback callback =
2098+
SAFE_ACCESS(args, root_isolate_create_callback, nullptr);
2099+
settings.root_isolate_create_callback =
2100+
[callback, user_data](const auto& isolate) { callback(user_data); };
2101+
}
2102+
if (SAFE_ACCESS(args, log_message_callback, nullptr) != nullptr) {
2103+
FlutterLogMessageCallback callback =
2104+
SAFE_ACCESS(args, log_message_callback, nullptr);
2105+
settings.log_message_callback = [callback, user_data](
2106+
const std::string& tag,
2107+
const std::string& message) {
2108+
callback(tag.c_str(), message.c_str(), user_data);
2109+
};
2110+
}
2111+
if (SAFE_ACCESS(args, log_tag, nullptr) != nullptr) {
2112+
settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr);
2113+
}
2114+
2115+
bool has_update_semantics_2_callback =
2116+
SAFE_ACCESS(args, update_semantics_callback2, nullptr) != nullptr;
2117+
bool has_update_semantics_callback =
2118+
SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr;
2119+
bool has_legacy_update_semantics_callback =
2120+
SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr ||
2121+
SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
2122+
nullptr;
2123+
2124+
int semantic_callback_count = (has_update_semantics_2_callback ? 1 : 0) +
2125+
(has_update_semantics_callback ? 1 : 0) +
2126+
(has_legacy_update_semantics_callback ? 1 : 0);
2127+
2128+
if (semantic_callback_count > 1) {
2129+
return LOG_EMBEDDER_ERROR(
2130+
kInvalidArguments,
2131+
"Multiple semantics update callbacks provided. "
2132+
"Embedders should provide either `update_semantics_callback2`, "
2133+
"`update_semantics_callback`, or both "
2134+
"`update_semantics_node_callback` and "
2135+
"`update_semantics_custom_action_callback`.");
2136+
}
2137+
2138+
flutter::PlatformViewEmbedder::UpdateSemanticsCallback
2139+
update_semantics_callback =
2140+
CreateEmbedderSemanticsUpdateCallback(args, user_data);
2141+
2142+
flutter::PlatformViewEmbedder::PlatformMessageResponseCallback
2143+
platform_message_response_callback = nullptr;
2144+
if (SAFE_ACCESS(args, platform_message_callback, nullptr) != nullptr) {
2145+
platform_message_response_callback =
2146+
[ptr = args->platform_message_callback,
2147+
user_data](std::unique_ptr<flutter::PlatformMessage> message) {
2148+
auto handle = new FlutterPlatformMessageResponseHandle();
2149+
const FlutterPlatformMessage incoming_message = {
2150+
sizeof(FlutterPlatformMessage), // struct_size
2151+
message->channel().c_str(), // channel
2152+
message->data().GetMapping(), // message
2153+
message->data().GetSize(), // message_size
2154+
handle, // response_handle
2155+
};
2156+
handle->message = std::move(message);
2157+
return ptr(&incoming_message, user_data);
2158+
};
2159+
}
2160+
2161+
flutter::VsyncWaiterEmbedder::VsyncCallback vsync_callback = nullptr;
2162+
if (SAFE_ACCESS(args, vsync_callback, nullptr) != nullptr) {
2163+
vsync_callback = [ptr = args->vsync_callback, user_data](intptr_t baton) {
2164+
return ptr(user_data, baton);
2165+
};
2166+
}
2167+
2168+
flutter::PlatformViewEmbedder::ComputePlatformResolvedLocaleCallback
2169+
compute_platform_resolved_locale_callback = nullptr;
2170+
if (SAFE_ACCESS(args, compute_platform_resolved_locale_callback, nullptr) !=
2171+
nullptr) {
2172+
compute_platform_resolved_locale_callback =
2173+
[ptr = args->compute_platform_resolved_locale_callback](
2174+
const std::vector<std::string>& supported_locales_data) {
2175+
const size_t number_of_strings_per_locale = 3;
2176+
size_t locale_count =
2177+
supported_locales_data.size() / number_of_strings_per_locale;
2178+
std::vector<FlutterLocale> supported_locales;
2179+
std::vector<const FlutterLocale*> supported_locales_ptr;
2180+
for (size_t i = 0; i < locale_count; ++i) {
2181+
supported_locales.push_back(
2182+
{.struct_size = sizeof(FlutterLocale),
2183+
.language_code =
2184+
supported_locales_data[i * number_of_strings_per_locale +
2185+
0]
2186+
.c_str(),
2187+
.country_code =
2188+
supported_locales_data[i * number_of_strings_per_locale +
2189+
1]
2190+
.c_str(),
2191+
.script_code =
2192+
supported_locales_data[i * number_of_strings_per_locale +
2193+
2]
2194+
.c_str(),
2195+
.variant_code = nullptr});
2196+
supported_locales_ptr.push_back(&supported_locales[i]);
2197+
}
2198+
2199+
const FlutterLocale* result =
2200+
ptr(supported_locales_ptr.data(), locale_count);
2201+
2202+
std::unique_ptr<std::vector<std::string>> out =
2203+
std::make_unique<std::vector<std::string>>();
2204+
if (result) {
2205+
std::string language_code(SAFE_ACCESS(result, language_code, ""));
2206+
if (language_code != "") {
2207+
out->push_back(language_code);
2208+
out->emplace_back(SAFE_ACCESS(result, country_code, ""));
2209+
out->emplace_back(SAFE_ACCESS(result, script_code, ""));
2210+
}
2211+
}
2212+
return out;
2213+
};
2214+
}
2215+
2216+
flutter::PlatformViewEmbedder::OnPreEngineRestartCallback
2217+
on_pre_engine_restart_callback = nullptr;
2218+
if (SAFE_ACCESS(args, on_pre_engine_restart_callback, nullptr) != nullptr) {
2219+
on_pre_engine_restart_callback = [ptr =
2220+
args->on_pre_engine_restart_callback,
2221+
user_data]() { return ptr(user_data); };
2222+
}
2223+
2224+
auto external_view_embedder_result =
2225+
InferExternalViewEmbedderFromArgs(SAFE_ACCESS(args, compositor, nullptr));
2226+
if (external_view_embedder_result.second) {
2227+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
2228+
"Compositor arguments were invalid.");
2229+
}
2230+
2231+
flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
2232+
{
2233+
update_semantics_callback, //
2234+
platform_message_response_callback, //
2235+
vsync_callback, //
2236+
compute_platform_resolved_locale_callback, //
2237+
on_pre_engine_restart_callback, //
2238+
};
2239+
2240+
auto on_create_platform_view = InferPlatformViewCreationCallback(
2241+
config, user_data, platform_dispatch_table,
2242+
std::move(external_view_embedder_result.first));
2243+
2244+
if (!on_create_platform_view) {
2245+
return LOG_EMBEDDER_ERROR(
2246+
kInternalInconsistency,
2247+
"Could not infer platform view creation callback.");
2248+
}
2249+
2250+
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
2251+
[](flutter::Shell& shell) {
2252+
return std::make_unique<flutter::Rasterizer>(shell);
2253+
};
2254+
2255+
using ExternalTextureResolver = flutter::EmbedderExternalTextureResolver;
2256+
std::unique_ptr<ExternalTextureResolver> external_texture_resolver;
2257+
external_texture_resolver = std::make_unique<ExternalTextureResolver>();
2258+
2259+
#ifdef SHELL_ENABLE_GL
2260+
flutter::EmbedderExternalTextureGL::ExternalTextureCallback
2261+
external_texture_callback;
2262+
if (config->type == kOpenGL) {
2263+
const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
2264+
if (SAFE_ACCESS(open_gl_config, gl_external_texture_frame_callback,
2265+
nullptr) != nullptr) {
2266+
external_texture_callback =
2267+
[ptr = open_gl_config->gl_external_texture_frame_callback, user_data](
2268+
int64_t texture_identifier, size_t width,
2269+
size_t height) -> std::unique_ptr<FlutterOpenGLTexture> {
2270+
std::unique_ptr<FlutterOpenGLTexture> texture =
2271+
std::make_unique<FlutterOpenGLTexture>();
2272+
if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
2273+
return nullptr;
2274+
}
2275+
return texture;
2276+
};
2277+
external_texture_resolver =
2278+
std::make_unique<ExternalTextureResolver>(external_texture_callback);
2279+
}
2280+
}
2281+
#endif
2282+
#ifdef SHELL_ENABLE_METAL
2283+
flutter::EmbedderExternalTextureMetal::ExternalTextureCallback
2284+
external_texture_metal_callback;
2285+
if (config->type == kMetal) {
2286+
const FlutterMetalRendererConfig* metal_config = &config->metal;
2287+
if (SAFE_ACCESS(metal_config, external_texture_frame_callback, nullptr)) {
2288+
external_texture_metal_callback =
2289+
[ptr = metal_config->external_texture_frame_callback, user_data](
2290+
int64_t texture_identifier, size_t width,
2291+
size_t height) -> std::unique_ptr<FlutterMetalExternalTexture> {
2292+
std::unique_ptr<FlutterMetalExternalTexture> texture =
2293+
std::make_unique<FlutterMetalExternalTexture>();
2294+
texture->struct_size = sizeof(FlutterMetalExternalTexture);
2295+
if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
2296+
return nullptr;
2297+
}
2298+
return texture;
2299+
};
2300+
external_texture_resolver = std::make_unique<ExternalTextureResolver>(
2301+
external_texture_metal_callback);
2302+
}
2303+
}
2304+
#endif
2305+
2306+
auto run_configuration =
2307+
flutter::RunConfiguration::InferFromSettings(settings);
2308+
2309+
if (SAFE_ACCESS(args, custom_dart_entrypoint, nullptr) != nullptr) {
2310+
auto dart_entrypoint = std::string{args->custom_dart_entrypoint};
2311+
if (!dart_entrypoint.empty()) {
2312+
run_configuration.SetEntrypoint(std::move(dart_entrypoint));
2313+
}
2314+
}
2315+
2316+
if (SAFE_ACCESS(args, dart_entrypoint_argc, 0) > 0) {
2317+
if (SAFE_ACCESS(args, dart_entrypoint_argv, nullptr) == nullptr) {
2318+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
2319+
"Could not determine Dart entrypoint arguments "
2320+
"as dart_entrypoint_argc "
2321+
"was set, but dart_entrypoint_argv was null.");
2322+
}
2323+
std::vector<std::string> arguments(args->dart_entrypoint_argc);
2324+
for (int i = 0; i < args->dart_entrypoint_argc; ++i) {
2325+
arguments[i] = std::string{args->dart_entrypoint_argv[i]};
2326+
}
2327+
run_configuration.SetEntrypointArgs(std::move(arguments));
2328+
}
2329+
2330+
if (!run_configuration.IsValid()) {
2331+
return LOG_EMBEDDER_ERROR(
2332+
kInvalidArguments,
2333+
"Could not infer the Flutter project to run from given arguments.");
2334+
}
2335+
2336+
// Spawn the engine by using spawner
2337+
auto embedder_engine_spawner =
2338+
reinterpret_cast<flutter::EmbedderEngine*>(engine_spawner);
2339+
auto embedder_engine = embedder_engine_spawner->SpawnEmbedderEngine(
2340+
std::move(settings), //
2341+
std::move(run_configuration), //
2342+
on_create_platform_view, //
2343+
on_create_rasterizer, //
2344+
std::move(external_texture_resolver));
2345+
2346+
if (!embedder_engine->NotifyCreated()) {
2347+
return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2348+
"Could not create platform view components.");
2349+
}
2350+
2351+
// Release the ownership of the embedder engine to the caller.
2352+
*engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(
2353+
embedder_engine.release());
2354+
return kSuccess;
2355+
}
2356+
19822357
FlutterEngineResult FlutterEngineRunInitialized(
19832358
FLUTTER_API_SYMBOL(FlutterEngine) engine) {
19842359
if (!engine) {
@@ -3074,6 +3449,7 @@ FlutterEngineResult FlutterEngineGetProcAddresses(
30743449
SET_PROC(CreateAOTData, FlutterEngineCreateAOTData);
30753450
SET_PROC(CollectAOTData, FlutterEngineCollectAOTData);
30763451
SET_PROC(Run, FlutterEngineRun);
3452+
SET_PROC(Spawn, FlutterEngineSpawn);
30773453
SET_PROC(Shutdown, FlutterEngineShutdown);
30783454
SET_PROC(Initialize, FlutterEngineInitialize);
30793455
SET_PROC(Deinitialize, FlutterEngineDeinitialize);

0 commit comments

Comments
 (0)