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"
38#if defined(FML_OS_WIN)
39#include <combaseapi.h>
42#if defined(FML_OS_POSIX)
48static absl::NoDestructor<std::unique_ptr<Shell>>
g_shell;
51std::unique_ptr<TesterContext> CreateTesterContext(
const Settings& settings) {
52 std::unique_ptr<TesterContext> tester_context;
53#if TESTER_ENABLE_METAL
59#if TESTER_ENABLE_OPENGLES
65#if TESTER_ENABLE_VULKAN
73 return tester_context;
80 auto device_pixel_ratio = 3.0;
81 auto physical_width = 2400.0;
82 auto physical_height = 1800.0;
84 std::vector<std::unique_ptr<Display>>
displays;
85 displays.push_back(std::make_unique<Display>(
86 0, 60, physical_width, physical_height, device_pixel_ratio));
91 metrics.physical_width = physical_width;
92 metrics.physical_height = physical_height;
93 metrics.display_id = 0;
94 metrics.physical_min_width_constraint = physical_width;
95 metrics.physical_max_width_constraint = physical_width;
96 metrics.physical_min_height_constraint = physical_height;
97 metrics.physical_max_height_constraint = physical_height;
103 DlCanvas* GetRootCanvas()
override {
return nullptr; }
106 void CancelFrame()
override {}
109 void BeginFrame(GrDirectContext* context,
111 raster_thread_merger)
override {}
114 void PrepareFlutterView(
DlISize frame_size,
115 double device_pixel_ratio)
override {}
118 void PrerollCompositeEmbeddedView(
120 std::unique_ptr<EmbeddedViewParams>
params)
override {}
134 bool render_to_surface)
145 std::unique_ptr<TesterContext> tester_context)
147 tester_context_(
std::move(tester_context)) {}
155 if (tester_context_) {
156 return tester_context_->GetImpellerContext();
163 if (tester_context_ &&
165 return tester_context_->CreateRenderingSurface();
167 auto surface = std::make_unique<TesterGPUSurfaceSoftware>(
175 if (sk_surface_ !=
nullptr &&
176 sk_surface_->width() ==
size.width &&
177 sk_surface_->height() ==
size.height) {
182 SkImageInfo info = SkImageInfo::MakeN32(
183 size.width,
size.height, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
184 sk_surface_ = SkSurfaces::Raster(info,
nullptr);
186 if (sk_surface_ ==
nullptr) {
188 <<
"Could not create backing store for software rendering.";
202 return external_view_embedder_;
206 sk_sp<SkSurface> sk_surface_ =
nullptr;
208 std::shared_ptr<TesterContext> tester_context_;
209 std::shared_ptr<TesterExternalViewEmbedder> external_view_embedder_ =
210 std::make_shared<TesterExternalViewEmbedder>();
222 main_task_runner_(
std::move(main_task_runner)),
223 ui_task_runner_(
std::move(ui_task_runner)),
224 run_forever_(run_forever) {}
250 if (!has_terminated_) {
252 has_terminated_ =
true;
263 bool run_forever_ =
false;
264 std::optional<DartErrorCode> last_error_;
265 bool has_terminated_ =
false;
277#if defined(FML_OS_POSIX)
280 sigaddset(&
set, SIGPROF);
281 pthread_sigmask(SIG_UNBLOCK, &
set, NULL);
287 bool multithreaded) {
288 const auto thread_label =
"io.flutter.test.";
301 std::unique_ptr<ThreadHost> threadhost;
308 threadhost = std::make_unique<ThreadHost>(
311 platform_task_runner = current_task_runner;
312 raster_task_runner = threadhost->raster_thread->GetTaskRunner();
313 ui_task_runner = threadhost->ui_thread->GetTaskRunner();
314 io_task_runner = threadhost->io_thread->GetTaskRunner();
316 platform_task_runner = raster_task_runner = ui_task_runner =
317 io_task_runner = current_task_runner;
321 platform_task_runner,
327 std::unique_ptr<TesterContext> tester_context = CreateTesterContext(settings);
329 FML_LOG(ERROR) <<
"Could not create tester context.";
335 [tester_context = std::move(tester_context)](
Shell& shell)
mutable {
336 return std::make_unique<TesterPlatformView>(
341 return std::make_unique<Rasterizer>(
348 on_create_platform_view,
354 if (!shell || !shell->
IsSetup()) {
355 FML_LOG(ERROR) <<
"Could not set up the shell.";
360 FML_LOG(ERROR) <<
"Dart kernel file not specified.";
369 const char* locale_json =
370 "{\"method\":\"setLocale\",\"args\":[\"en\",\"US\",\"\",\"\",\"zh\","
371 "\"CN\",\"\",\"\"]}";
373 locale_json, locale_json + std::strlen(locale_json));
376 std::make_unique<flutter::PlatformMessage>(
377 "flutter/localization", std::move(locale_bytes), response));
379 std::initializer_list<fml::FileMapping::Protection> protection = {
381 auto main_dart_file_mapping = std::make_unique<fml::FileMapping>(
387 auto isolate_configuration =
390 if (!isolate_configuration) {
391 FML_LOG(ERROR) <<
"Could create isolate configuration.";
395 auto asset_manager = std::make_shared<flutter::AssetManager>();
396 asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
398 asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
404 std::move(asset_manager));
416 bool engine_did_run =
false;
419 auto task_observer_add = [&completion_observer]() {
421 reinterpret_cast<intptr_t
>(&completion_observer),
422 [&completion_observer]() { completion_observer.
DidProcessTask(); });
425 auto task_observer_remove = [&completion_observer, &latch]() {
427 reinterpret_cast<intptr_t
>(&completion_observer));
431 shell->
RunEngine(std::move(run_configuration),
432 [&engine_did_run, &ui_task_runner,
435 engine_did_run =
true;
455 if (!engine_did_run) {
465#define EXPORTED __declspec(dllexport)
467#define EXPORTED __attribute__((visibility("default")))
472 std::shared_ptr<fml::FileMapping> mapping =
484 Dart_Handle lib = Dart_LookupLibrary(Dart_NewStringFromCString(uri));
485 if (Dart_IsError(lib)) {
488 return Dart_GetField(lib, Dart_NewStringFromCString(
name));
493 auto isolate = Dart_CurrentIsolate();
494 auto spawn_task = [shell, entrypoint = std::string(entrypoint),
495 route = std::string(route)]() {
497 shell->GetSettings(),
nullptr,
499 configuration.SetEntrypoint(entrypoint);
503 std::unique_ptr<TesterContext> tester_context =
505 return std::make_unique<TesterPlatformView>(
510 return std::make_unique<Rasterizer>(
518 ->
Spawn(std::move(configuration), route, on_create_platform_view,
519 on_create_rasterizer)
525 spawned_shell->GetTaskRunners().GetUITaskRunner(), [spawned_shell]() {
526 fml::MessageLoop::GetCurrent().AddTaskObserver(
527 reinterpret_cast<intptr_t>(spawned_shell), [spawned_shell]() {
528 if (spawned_shell->EngineHasLivePorts()) {
532 fml::MessageLoop::GetCurrent().RemoveTaskObserver(
533 reinterpret_cast<intptr_t>(spawned_shell));
535 fml::TaskRunner::RunNowOrPostTask(
536 spawned_shell->GetTaskRunners().GetPlatformTaskRunner(),
537 [spawned_shell]() { delete spawned_shell; });
546 shell->GetTaskRunners().GetPlatformTaskRunner(), spawn_task);
548 Dart_EnterIsolate(isolate);
554 Dart_Handle isolate_lib = Dart_LookupLibrary(
tonic::ToDart(
"dart:isolate"));
556 Dart_Handle isolate_type = Dart_GetNonNullableType(
560 Dart_SetField(isolate_type,
tonic::ToDart(
"_mayExit"), Dart_True());
568 dart::bin::SetExecutableName(
argv[0]);
569 dart::bin::SetExecutableArguments(argc - 1,
argv);
579 if (!command_line.positional_args().empty()) {
582 settings.application_kernel_asset = command_line.positional_args()[0];
585 if (settings.application_kernel_asset.empty()) {
586 FML_LOG(ERROR) <<
"Dart kernel file not specified.";
590 settings.leak_vm =
false;
591 settings.enable_platform_isolates =
true;
593 if (settings.icu_data_path.empty()) {
594 settings.icu_data_path =
"icudtl.dat";
598 settings.log_tag =
"";
600 settings.log_message_callback = [](
const std::string& tag,
603 std::cout << tag <<
": ";
605 std::cout <<
message << std::endl;
620 settings.unhandled_exception_callback = [](
const std::string&
error,
621 const std::string& stack_trace) {
622 FML_LOG(ERROR) <<
"Unhandled exception" << std::endl
623 <<
"Exception: " <<
error << std::endl
624 <<
"Stack trace: " << stack_trace;
629#if defined(FML_OS_WIN)
630 CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
635 flutter::Switch::RunForever)),
637 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()
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[])