5#define FML_USED_ON_EMBEDDER
28#include "third_party/abseil-cpp/absl/base/no_destructor.h"
29#include "third_party/dart/runtime/include/bin/dart_io_api.h"
30#include "third_party/dart/runtime/include/dart_api.h"
31#include "third_party/skia/include/core/SkSurface.h"
37#if defined(FML_OS_WIN)
38#include <combaseapi.h>
41#if defined(FML_OS_POSIX)
47static absl::NoDestructor<std::unique_ptr<Shell>>
g_shell;
50std::unique_ptr<TesterContext> CreateTesterContext(
const Settings& settings) {
51 std::unique_ptr<TesterContext> tester_context;
52#if TESTER_ENABLE_METAL
58#if TESTER_ENABLE_VULKAN
64 return tester_context;
71 auto device_pixel_ratio = 3.0;
72 auto physical_width = 2400.0;
73 auto physical_height = 1800.0;
75 std::vector<std::unique_ptr<Display>>
displays;
76 displays.push_back(std::make_unique<Display>(
77 0, 60, physical_width, physical_height, device_pixel_ratio));
82 metrics.physical_width = physical_width;
83 metrics.physical_height = physical_height;
84 metrics.display_id = 0;
85 metrics.physical_min_width_constraint = physical_width;
86 metrics.physical_max_width_constraint = physical_width;
87 metrics.physical_min_height_constraint = physical_height;
88 metrics.physical_max_height_constraint = physical_height;
94 DlCanvas* GetRootCanvas()
override {
return nullptr; }
97 void CancelFrame()
override {}
100 void BeginFrame(GrDirectContext* context,
102 raster_thread_merger)
override {}
105 void PrepareFlutterView(
DlISize frame_size,
106 double device_pixel_ratio)
override {}
109 void PrerollCompositeEmbeddedView(
111 std::unique_ptr<EmbeddedViewParams>
params)
override {}
125 bool render_to_surface)
136 std::unique_ptr<TesterContext> tester_context)
138 tester_context_(
std::move(tester_context)) {}
146 if (tester_context_) {
147 return tester_context_->GetImpellerContext();
154 if (tester_context_ &&
156 return tester_context_->CreateRenderingSurface();
158 auto surface = std::make_unique<TesterGPUSurfaceSoftware>(
166 if (sk_surface_ !=
nullptr &&
167 sk_surface_->width() ==
size.width &&
168 sk_surface_->height() ==
size.height) {
173 SkImageInfo info = SkImageInfo::MakeN32(
174 size.width,
size.height, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
175 sk_surface_ = SkSurfaces::Raster(info,
nullptr);
177 if (sk_surface_ ==
nullptr) {
179 <<
"Could not create backing store for software rendering.";
193 return external_view_embedder_;
197 sk_sp<SkSurface> sk_surface_ =
nullptr;
199 std::shared_ptr<TesterContext> tester_context_;
200 std::shared_ptr<TesterExternalViewEmbedder> external_view_embedder_ =
201 std::make_shared<TesterExternalViewEmbedder>();
213 main_task_runner_(
std::move(main_task_runner)),
214 ui_task_runner_(
std::move(ui_task_runner)),
215 run_forever_(run_forever) {}
241 if (!has_terminated_) {
243 has_terminated_ =
true;
254 bool run_forever_ =
false;
255 std::optional<DartErrorCode> last_error_;
256 bool has_terminated_ =
false;
268#if defined(FML_OS_POSIX)
271 sigaddset(&
set, SIGPROF);
272 pthread_sigmask(SIG_UNBLOCK, &
set, NULL);
278 bool multithreaded) {
279 const auto thread_label =
"io.flutter.test.";
292 std::unique_ptr<ThreadHost> threadhost;
299 threadhost = std::make_unique<ThreadHost>(
302 platform_task_runner = current_task_runner;
303 raster_task_runner = threadhost->raster_thread->GetTaskRunner();
304 ui_task_runner = threadhost->ui_thread->GetTaskRunner();
305 io_task_runner = threadhost->io_thread->GetTaskRunner();
307 platform_task_runner = raster_task_runner = ui_task_runner =
308 io_task_runner = current_task_runner;
312 platform_task_runner,
318 std::unique_ptr<TesterContext> tester_context = CreateTesterContext(settings);
325 [tester_context = std::move(tester_context)](
Shell& shell)
mutable {
326 return std::make_unique<TesterPlatformView>(
331 return std::make_unique<Rasterizer>(
338 on_create_platform_view,
344 if (!shell || !shell->
IsSetup()) {
345 FML_LOG(ERROR) <<
"Could not set up the shell.";
350 FML_LOG(ERROR) <<
"Dart kernel file not specified.";
359 const char* locale_json =
360 "{\"method\":\"setLocale\",\"args\":[\"en\",\"US\",\"\",\"\",\"zh\","
361 "\"CN\",\"\",\"\"]}";
363 locale_json, locale_json + std::strlen(locale_json));
366 std::make_unique<flutter::PlatformMessage>(
367 "flutter/localization", std::move(locale_bytes), response));
369 std::initializer_list<fml::FileMapping::Protection> protection = {
371 auto main_dart_file_mapping = std::make_unique<fml::FileMapping>(
377 auto isolate_configuration =
380 if (!isolate_configuration) {
381 FML_LOG(ERROR) <<
"Could create isolate configuration.";
385 auto asset_manager = std::make_shared<flutter::AssetManager>();
386 asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
388 asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
394 std::move(asset_manager));
406 bool engine_did_run =
false;
409 auto task_observer_add = [&completion_observer]() {
411 reinterpret_cast<intptr_t
>(&completion_observer),
412 [&completion_observer]() { completion_observer.
DidProcessTask(); });
415 auto task_observer_remove = [&completion_observer, &latch]() {
417 reinterpret_cast<intptr_t
>(&completion_observer));
421 shell->
RunEngine(std::move(run_configuration),
422 [&engine_did_run, &ui_task_runner,
425 engine_did_run =
true;
445 if (!engine_did_run) {
455#define EXPORTED __declspec(dllexport)
457#define EXPORTED __attribute__((visibility("default")))
462 std::shared_ptr<fml::FileMapping> mapping =
474 Dart_Handle lib = Dart_LookupLibrary(Dart_NewStringFromCString(uri));
475 if (Dart_IsError(lib)) {
478 return Dart_GetField(lib, Dart_NewStringFromCString(
name));
483 auto isolate = Dart_CurrentIsolate();
484 auto spawn_task = [shell, entrypoint = std::string(entrypoint),
485 route = std::string(route)]() {
487 shell->GetSettings(),
nullptr,
489 configuration.SetEntrypoint(entrypoint);
493 std::unique_ptr<TesterContext> tester_context =
495 return std::make_unique<TesterPlatformView>(
500 return std::make_unique<Rasterizer>(
508 ->
Spawn(std::move(configuration), route, on_create_platform_view,
509 on_create_rasterizer)
515 spawned_shell->GetTaskRunners().GetUITaskRunner(), [spawned_shell]() {
516 fml::MessageLoop::GetCurrent().AddTaskObserver(
517 reinterpret_cast<intptr_t>(spawned_shell), [spawned_shell]() {
518 if (spawned_shell->EngineHasLivePorts()) {
522 fml::MessageLoop::GetCurrent().RemoveTaskObserver(
523 reinterpret_cast<intptr_t>(spawned_shell));
525 fml::TaskRunner::RunNowOrPostTask(
526 spawned_shell->GetTaskRunners().GetPlatformTaskRunner(),
527 [spawned_shell]() { delete spawned_shell; });
536 shell->GetTaskRunners().GetPlatformTaskRunner(), spawn_task);
538 Dart_EnterIsolate(isolate);
544 Dart_Handle isolate_lib = Dart_LookupLibrary(
tonic::ToDart(
"dart:isolate"));
546 Dart_Handle isolate_type = Dart_GetNonNullableType(
550 Dart_SetField(isolate_type,
tonic::ToDart(
"_mayExit"), Dart_True());
558 dart::bin::SetExecutableName(
argv[0]);
559 dart::bin::SetExecutableArguments(argc - 1,
argv);
569 if (!command_line.positional_args().empty()) {
572 settings.application_kernel_asset = command_line.positional_args()[0];
575 if (settings.application_kernel_asset.empty()) {
576 FML_LOG(ERROR) <<
"Dart kernel file not specified.";
580 settings.leak_vm =
false;
581 settings.enable_platform_isolates =
true;
583 if (settings.icu_data_path.empty()) {
584 settings.icu_data_path =
"icudtl.dat";
588 settings.log_tag =
"";
590 settings.log_message_callback = [](
const std::string& tag,
593 std::cout << tag <<
": ";
595 std::cout <<
message << std::endl;
610 settings.unhandled_exception_callback = [](
const std::string&
error,
611 const std::string& stack_trace) {
612 FML_LOG(ERROR) <<
"Unhandled exception" << std::endl
613 <<
"Exception: " <<
error << std::endl
614 <<
"Stack trace: " << stack_trace;
619#if defined(FML_OS_WIN)
620 CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
625 flutter::Switch::RunForever)),
627 flutter::Switch::ForceMultithreading)));
static Dart_Handle LoadLibraryFromKernel(const std::shared_ptr< const fml::Mapping > &mapping)
Developer-facing API for rendering anything within the engine.
RunStatus
Indicates the result of the call to Engine::Run.
Interface implemented by all platform surfaces that can present a software backing store to the "scre...
static std::unique_ptr< IsolateConfiguration > CreateForKernel(std::unique_ptr< const fml::Mapping > kernel)
Creates a JIT isolate configuration using the specified snapshot. This is a convenience method for th...
Specifies all the configuration required by the runtime library to launch the root isolate....
static RunConfiguration InferFromSettings(const Settings &settings, const fml::RefPtr< fml::TaskRunner > &io_worker=nullptr, IsolateLaunchType launch_type=IsolateLaunchType::kNewGroup)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
ScriptCompletionTaskObserver(Shell &shell, fml::RefPtr< fml::TaskRunner > main_task_runner, fml::RefPtr< fml::TaskRunner > ui_task_runner, bool run_forever)
int GetExitCodeForLastError() const
std::optional< DartErrorCode > GetUIIsolateLastError() const
Used by embedders to get the last error from the Dart UI Isolate, if one exists.
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, const TaskRunners &task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer, bool is_gpu_disabled=false)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
bool EngineHasLivePorts() const
Used by embedders to check if the Engine is running and has any live ports remaining....
void RunEngine(RunConfiguration run_configuration)
Starts an isolate for the given RunConfiguration.
std::unique_ptr< Shell > Spawn(RunConfiguration run_configuration, const std::string &initial_route, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer) const
Creates one Shell from another Shell where the created Shell takes the opportunity to share any inter...
bool EngineHasPendingMicrotasks() const
Used by embedders to check if the Engine is running and has any microtasks that have been queued but ...
const Settings & GetSettings() const override
void OnDisplayUpdates(std::vector< std::unique_ptr< Display > > displays)
Notifies the display manager of the updates.
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
bool IsSetup() const
Used by embedders to check if all shell subcomponents are initialized. It is the embedder's responsib...
fml::WeakPtr< PlatformView > GetPlatformView()
Platform views may only be accessed on the platform task runner.
static std::unique_ptr< TesterContext > Create()
static std::unique_ptr< TesterContext > Create(bool enable_validation)
bool EnableRasterCache() const override
TesterGPUSurfaceSoftware(GPUSurfaceSoftwareDelegate *delegate, bool render_to_surface)
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
static MallocMapping Copy(const T *begin, const T *end)
void RemoveTaskObserver(intptr_t key)
static void EnsureInitializedForCurrentThread()
void AddTaskObserver(intptr_t key, const fml::closure &callback)
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static TaskQueueId GetCurrentTaskQueueId()
static MessageLoopTaskQueues * GetInstance()
void AddTaskObserver(TaskQueueId queue_id, intptr_t key, const fml::closure &callback)
void RemoveTaskObserver(TaskQueueId queue_id, intptr_t key)
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
virtual void PostTask(const fml::closure &task) override
const EmbeddedViewParams * params
const uint8_t uint32_t uint32_t GError ** error
G_BEGIN_DECLS FlutterViewId view_id
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
static void UnblockSIGPROF()
EXPORTED Dart_Handle LookupEntryPoint(const char *uri, const char *name)
@ NoError
No error has occurred.
int RunTester(const flutter::Settings &settings, bool run_forever, bool multithreaded)
void PrintUsage(const std::string &executable_name)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library name
constexpr FlutterViewId kImplicitViewId
EXPORTED void ForceShutdownIsolate()
static void ConfigureShell(Shell *shell)
static absl::NoDestructor< std::unique_ptr< Shell > > g_shell
Settings SettingsFromCommandLine(const fml::CommandLine &command_line, bool require_merged_platform_ui_thread)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
EXPORTED void Spawn(const char *entrypoint, const char *route)
EXPORTED Dart_Handle LoadLibraryFromKernel(const char *path)
const std::string_view FlagForSwitch(Switch swtch)
std::string AbsolutePath(const std::string &path)
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor)
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
internal::CopyableLambda< T > MakeCopyable(T lambda)
std::function< void()> closure
CommandLine CommandLineFromPlatformOrArgcArgv(int argc, const char *const *argv)
fml::UniqueFD OpenFile(const char *path, bool create_if_necessary, FilePermission permission)
This can open a directory on POSIX, but not on Windows.
Dart_Handle ToDart(const T &object)
bool CheckAndHandleError(Dart_Handle handle)
std::string application_kernel_asset
fml::UniqueFD::element_type assets_dir
bool enable_vulkan_validation
std::optional< std::string > requested_rendering_backend
double device_pixel_ratio
int main(int argc, char *argv[])