Flutter Engine
shell.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #define RAPIDJSON_HAS_STDSTRING 1
6 #include "flutter/shell/common/shell.h"
7 
8 #include <memory>
9 #include <sstream>
10 #include <vector>
11 
12 #include "flutter/assets/directory_asset_bundle.h"
13 #include "flutter/fml/file.h"
14 #include "flutter/fml/icu_util.h"
15 #include "flutter/fml/log_settings.h"
16 #include "flutter/fml/logging.h"
17 #include "flutter/fml/make_copyable.h"
18 #include "flutter/fml/message_loop.h"
19 #include "flutter/fml/paths.h"
20 #include "flutter/fml/trace_event.h"
21 #include "flutter/fml/unique_fd.h"
22 #include "flutter/runtime/dart_vm.h"
23 #include "flutter/shell/common/engine.h"
24 #include "flutter/shell/common/persistent_cache.h"
25 #include "flutter/shell/common/skia_event_tracer_impl.h"
26 #include "flutter/shell/common/switches.h"
27 #include "flutter/shell/common/vsync_waiter.h"
28 #include "rapidjson/stringbuffer.h"
29 #include "rapidjson/writer.h"
30 #include "third_party/dart/runtime/include/dart_tools_api.h"
31 #include "third_party/skia/include/core/SkGraphics.h"
32 #include "third_party/skia/include/utils/SkBase64.h"
34 
35 namespace flutter {
36 
37 constexpr char kSkiaChannel[] = "flutter/skia";
38 constexpr char kSystemChannel[] = "flutter/system";
39 constexpr char kTypeKey[] = "type";
40 constexpr char kFontChange[] = "fontsChange";
41 
42 std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
43  DartVMRef vm,
44  TaskRunners task_runners,
45  const PlatformData platform_data,
46  Settings settings,
47  fml::RefPtr<const DartSnapshot> isolate_snapshot,
48  const Shell::CreateCallback<PlatformView>& on_create_platform_view,
49  const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
50  if (!task_runners.IsValid()) {
51  FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
52  return nullptr;
53  }
54 
55  auto shell =
56  std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
57 
58  // Create the rasterizer on the raster thread.
59  std::promise<std::unique_ptr<Rasterizer>> rasterizer_promise;
60  auto rasterizer_future = rasterizer_promise.get_future();
61  std::promise<fml::WeakPtr<SnapshotDelegate>> snapshot_delegate_promise;
62  auto snapshot_delegate_future = snapshot_delegate_promise.get_future();
64  task_runners.GetRasterTaskRunner(), [&rasterizer_promise, //
65  &snapshot_delegate_promise,
66  on_create_rasterizer, //
67  shell = shell.get() //
68  ]() {
69  TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
70  std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
71  snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate());
72  rasterizer_promise.set_value(std::move(rasterizer));
73  });
74 
75  // Create the platform view on the platform thread (this thread).
76  auto platform_view = on_create_platform_view(*shell.get());
77  if (!platform_view || !platform_view->GetWeakPtr()) {
78  return nullptr;
79  }
80 
81  // Ask the platform view for the vsync waiter. This will be used by the engine
82  // to create the animator.
83  auto vsync_waiter = platform_view->CreateVSyncWaiter();
84  if (!vsync_waiter) {
85  return nullptr;
86  }
87 
88  // Create the IO manager on the IO thread. The IO manager must be initialized
89  // first because it has state that the other subsystems depend on. It must
90  // first be booted and the necessary references obtained to initialize the
91  // other subsystems.
92  std::promise<std::unique_ptr<ShellIOManager>> io_manager_promise;
93  auto io_manager_future = io_manager_promise.get_future();
94  std::promise<fml::WeakPtr<ShellIOManager>> weak_io_manager_promise;
95  auto weak_io_manager_future = weak_io_manager_promise.get_future();
96  std::promise<fml::RefPtr<SkiaUnrefQueue>> unref_queue_promise;
97  auto unref_queue_future = unref_queue_promise.get_future();
98  auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
99 
100  // TODO(gw280): The WeakPtr here asserts that we are derefing it on the
101  // same thread as it was created on. We are currently on the IO thread
102  // inside this lambda but we need to deref the PlatformView, which was
103  // constructed on the platform thread.
104  //
105  // https://github.com/flutter/flutter/issues/42948
107  io_task_runner,
108  [&io_manager_promise, //
109  &weak_io_manager_promise, //
110  &unref_queue_promise, //
111  platform_view = platform_view->GetWeakPtr(), //
112  io_task_runner, //
113  is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch() //
114  ]() {
115  TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
116  auto io_manager = std::make_unique<ShellIOManager>(
117  platform_view.getUnsafe()->CreateResourceContext(),
118  is_backgrounded_sync_switch, io_task_runner);
119  weak_io_manager_promise.set_value(io_manager->GetWeakPtr());
120  unref_queue_promise.set_value(io_manager->GetSkiaUnrefQueue());
121  io_manager_promise.set_value(std::move(io_manager));
122  });
123 
124  // Send dispatcher_maker to the engine constructor because shell won't have
125  // platform_view set until Shell::Setup is called later.
126  auto dispatcher_maker = platform_view->GetDispatcherMaker();
127 
128  // Create the engine on the UI thread.
129  std::promise<std::unique_ptr<Engine>> engine_promise;
130  auto engine_future = engine_promise.get_future();
132  shell->GetTaskRunners().GetUITaskRunner(),
133  fml::MakeCopyable([&engine_promise, //
134  shell = shell.get(), //
135  &dispatcher_maker, //
136  &platform_data, //
137  isolate_snapshot = std::move(isolate_snapshot), //
138  vsync_waiter = std::move(vsync_waiter), //
139  &weak_io_manager_future, //
140  &snapshot_delegate_future, //
141  &unref_queue_future //
142  ]() mutable {
143  TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
144  const auto& task_runners = shell->GetTaskRunners();
145 
146  // The animator is owned by the UI thread but it gets its vsync pulses
147  // from the platform.
148  auto animator = std::make_unique<Animator>(*shell, task_runners,
149  std::move(vsync_waiter));
150 
151  engine_promise.set_value(std::make_unique<Engine>(
152  *shell, //
153  dispatcher_maker, //
154  *shell->GetDartVM(), //
155  std::move(isolate_snapshot), //
156  task_runners, //
157  platform_data, //
158  shell->GetSettings(), //
159  std::move(animator), //
160  weak_io_manager_future.get(), //
161  unref_queue_future.get(), //
162  snapshot_delegate_future.get() //
163  ));
164  }));
165 
166  if (!shell->Setup(std::move(platform_view), //
167  engine_future.get(), //
168  rasterizer_future.get(), //
169  io_manager_future.get()) //
170  ) {
171  return nullptr;
172  }
173 
174  return shell;
175 }
176 
177 static void Tokenize(const std::string& input,
178  std::vector<std::string>* results,
179  char delimiter) {
180  std::istringstream ss(input);
181  std::string token;
182  while (std::getline(ss, token, delimiter)) {
183  results->push_back(token);
184  }
185 }
186 
187 // Though there can be multiple shells, some settings apply to all components in
188 // the process. These have to be setup before the shell or any of its
189 // sub-components can be initialized. In a perfect world, this would be empty.
190 // TODO(chinmaygarde): The unfortunate side effect of this call is that settings
191 // that cause shell initialization failures will still lead to some of their
192 // settings being applied.
193 static void PerformInitializationTasks(Settings& settings) {
194  {
195  fml::LogSettings log_settings;
196  log_settings.min_log_level =
198  fml::SetLogSettings(log_settings);
199  }
200 
201  static std::once_flag gShellSettingsInitialization = {};
202  std::call_once(gShellSettingsInitialization, [&settings] {
203  if (settings.engine_start_timestamp.count() == 0) {
204  settings.engine_start_timestamp =
205  std::chrono::microseconds(Dart_TimelineGetMicros());
206  }
207 
209  [](const char* message) { FML_LOG(ERROR) << message; });
210 
211  if (settings.trace_skia) {
213  }
214 
215  if (!settings.trace_allowlist.empty()) {
216  std::vector<std::string> prefixes;
217  Tokenize(settings.trace_allowlist, &prefixes, ',');
219  }
220 
221  if (!settings.skia_deterministic_rendering_on_cpu) {
222  SkGraphics::Init();
223  } else {
224  FML_DLOG(INFO) << "Skia deterministic rendering is enabled.";
225  }
226 
227  if (settings.icu_initialization_required) {
228  if (settings.icu_data_path.size() != 0) {
230  } else if (settings.icu_mapper) {
232  } else {
233  FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
234  }
235  }
236  });
237 }
238 
239 std::unique_ptr<Shell> Shell::Create(
240  TaskRunners task_runners,
241  Settings settings,
242  const Shell::CreateCallback<PlatformView>& on_create_platform_view,
243  const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
244  return Shell::Create(std::move(task_runners), //
245  PlatformData{/* default platform data */}, //
246  std::move(settings), //
247  std::move(on_create_platform_view), //
248  std::move(on_create_rasterizer) //
249  );
250 }
251 
252 std::unique_ptr<Shell> Shell::Create(
253  TaskRunners task_runners,
254  const PlatformData platform_data,
255  Settings settings,
256  Shell::CreateCallback<PlatformView> on_create_platform_view,
257  Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
258  PerformInitializationTasks(settings);
260 
261  TRACE_EVENT0("flutter", "Shell::Create");
262 
263  auto vm = DartVMRef::Create(settings);
264  FML_CHECK(vm) << "Must be able to initialize the VM.";
265 
266  auto vm_data = vm->GetVMData();
267 
268  return Shell::Create(std::move(task_runners), //
269  std::move(platform_data), //
270  std::move(settings), //
271  vm_data->GetIsolateSnapshot(), // isolate snapshot
272  on_create_platform_view, //
273  on_create_rasterizer, //
274  std::move(vm) //
275  );
276 }
277 
278 std::unique_ptr<Shell> Shell::Create(
279  TaskRunners task_runners,
280  const PlatformData platform_data,
281  Settings settings,
282  fml::RefPtr<const DartSnapshot> isolate_snapshot,
283  const Shell::CreateCallback<PlatformView>& on_create_platform_view,
284  const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
285  DartVMRef vm) {
286  PerformInitializationTasks(settings);
288 
289  TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
290 
291  if (!task_runners.IsValid() || !on_create_platform_view ||
292  !on_create_rasterizer) {
293  return nullptr;
294  }
295 
297  std::unique_ptr<Shell> shell;
299  task_runners.GetPlatformTaskRunner(),
300  fml::MakeCopyable([&latch, //
301  vm = std::move(vm), //
302  &shell, //
303  task_runners = std::move(task_runners), //
304  platform_data, //
305  settings, //
306  isolate_snapshot = std::move(isolate_snapshot), //
307  on_create_platform_view, //
308  on_create_rasterizer //
309  ]() mutable {
310  shell = CreateShellOnPlatformThread(std::move(vm),
311  std::move(task_runners), //
312  platform_data, //
313  settings, //
314  std::move(isolate_snapshot), //
315  on_create_platform_view, //
316  on_create_rasterizer //
317  );
318  latch.Signal();
319  }));
320  latch.Wait();
321  return shell;
322 }
323 
324 Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
325  : task_runners_(std::move(task_runners)),
326  settings_(std::move(settings)),
327  vm_(std::move(vm)),
328  is_gpu_disabled_sync_switch_(new fml::SyncSwitch()),
329  weak_factory_gpu_(nullptr),
330  weak_factory_(this) {
331  FML_CHECK(vm_) << "Must have access to VM to create a shell.";
332  FML_DCHECK(task_runners_.IsValid());
334 
335  display_manager_ = std::make_unique<DisplayManager>();
336 
337  // Generate a WeakPtrFactory for use with the raster thread. This does not
338  // need to wait on a latch because it can only ever be used from the raster
339  // thread from this class, so we have ordering guarantees.
341  task_runners_.GetRasterTaskRunner(), fml::MakeCopyable([this]() mutable {
342  this->weak_factory_gpu_ =
343  std::make_unique<fml::TaskRunnerAffineWeakPtrFactory<Shell>>(this);
344  }));
345 
346  // Install service protocol handlers.
347 
348  service_protocol_handlers_[ServiceProtocol::kScreenshotExtensionName] = {
349  task_runners_.GetRasterTaskRunner(),
350  std::bind(&Shell::OnServiceProtocolScreenshot, this,
351  std::placeholders::_1, std::placeholders::_2)};
352  service_protocol_handlers_[ServiceProtocol::kScreenshotSkpExtensionName] = {
353  task_runners_.GetRasterTaskRunner(),
354  std::bind(&Shell::OnServiceProtocolScreenshotSKP, this,
355  std::placeholders::_1, std::placeholders::_2)};
356  service_protocol_handlers_[ServiceProtocol::kRunInViewExtensionName] = {
357  task_runners_.GetUITaskRunner(),
358  std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1,
359  std::placeholders::_2)};
360  service_protocol_handlers_
362  task_runners_.GetUITaskRunner(),
363  std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this,
364  std::placeholders::_1, std::placeholders::_2)};
365  service_protocol_handlers_
367  task_runners_.GetUITaskRunner(),
368  std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this,
369  std::placeholders::_1, std::placeholders::_2)};
370  service_protocol_handlers_
372  task_runners_.GetUITaskRunner(),
373  std::bind(&Shell::OnServiceProtocolGetDisplayRefreshRate, this,
374  std::placeholders::_1, std::placeholders::_2)};
375  service_protocol_handlers_[ServiceProtocol::kGetSkSLsExtensionName] = {
376  task_runners_.GetIOTaskRunner(),
377  std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
378  std::placeholders::_2)};
379  service_protocol_handlers_
381  task_runners_.GetRasterTaskRunner(),
382  std::bind(&Shell::OnServiceProtocolEstimateRasterCacheMemory, this,
383  std::placeholders::_1, std::placeholders::_2)};
384 }
385 
388  task_runners_.GetIOTaskRunner());
389 
390  vm_->GetServiceProtocol()->RemoveHandler(this);
391 
392  fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;
393 
395  task_runners_.GetUITaskRunner(),
396  fml::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable {
397  engine.reset();
398  ui_latch.Signal();
399  }));
400  ui_latch.Wait();
401 
403  task_runners_.GetRasterTaskRunner(),
405  [this, rasterizer = std::move(rasterizer_), &gpu_latch]() mutable {
406  rasterizer.reset();
407  this->weak_factory_gpu_.reset();
408  gpu_latch.Signal();
409  }));
410  gpu_latch.Wait();
411 
413  task_runners_.GetIOTaskRunner(),
414  fml::MakeCopyable([io_manager = std::move(io_manager_),
415  platform_view = platform_view_.get(),
416  &io_latch]() mutable {
417  io_manager.reset();
418  if (platform_view) {
419  platform_view->ReleaseResourceContext();
420  }
421  io_latch.Signal();
422  }));
423 
424  io_latch.Wait();
425 
426  // The platform view must go last because it may be holding onto platform side
427  // counterparts to resources owned by subsystems running on other threads. For
428  // example, the NSOpenGLContext on the Mac.
430  task_runners_.GetPlatformTaskRunner(),
431  fml::MakeCopyable([platform_view = std::move(platform_view_),
432  &platform_latch]() mutable {
433  platform_view.reset();
434  platform_latch.Signal();
435  }));
436  platform_latch.Wait();
437 }
438 
440  auto trace_id = fml::tracing::TraceNonce();
441  TRACE_EVENT_ASYNC_BEGIN0("flutter", "Shell::NotifyLowMemoryWarning",
442  trace_id);
443  // This does not require a current isolate but does require a running VM.
444  // Since a valid shell will not be returned to the embedder without a valid
445  // DartVMRef, we can be certain that this is a safe spot to assume a VM is
446  // running.
447  ::Dart_NotifyLowMemory();
448 
449  task_runners_.GetRasterTaskRunner()->PostTask(
450  [rasterizer = rasterizer_->GetWeakPtr(), trace_id = trace_id]() {
451  if (rasterizer) {
452  rasterizer->NotifyLowMemoryWarning();
453  }
454  TRACE_EVENT_ASYNC_END0("flutter", "Shell::NotifyLowMemoryWarning",
455  trace_id);
456  });
457  // The IO Manager uses resource cache limits of 0, so it is not necessary
458  // to purge them.
459 }
460 
461 void Shell::RunEngine(RunConfiguration run_configuration) {
462  RunEngine(std::move(run_configuration), nullptr);
463 }
464 
466  RunConfiguration run_configuration,
467  const std::function<void(Engine::RunStatus)>& result_callback) {
468  auto result = [platform_runner = task_runners_.GetPlatformTaskRunner(),
469  result_callback](Engine::RunStatus run_result) {
470  if (!result_callback) {
471  return;
472  }
473  platform_runner->PostTask(
474  [result_callback, run_result]() { result_callback(run_result); });
475  };
476  FML_DCHECK(is_setup_);
478 
480  task_runners_.GetUITaskRunner(),
482  [run_configuration = std::move(run_configuration),
483  weak_engine = weak_engine_, result]() mutable {
484  if (!weak_engine) {
485  FML_LOG(ERROR)
486  << "Could not launch engine with configuration - no engine.";
488  return;
489  }
490  auto run_result = weak_engine->Run(std::move(run_configuration));
491  if (run_result == flutter::Engine::RunStatus::Failure) {
492  FML_LOG(ERROR) << "Could not launch engine with configuration.";
493  }
494  result(run_result);
495  }));
496 }
497 
498 std::optional<DartErrorCode> Shell::GetUIIsolateLastError() const {
499  FML_DCHECK(is_setup_);
501 
502  if (!weak_engine_) {
503  return std::nullopt;
504  }
505  switch (weak_engine_->GetUIIsolateLastError()) {
512  case tonic::kNoError:
513  return DartErrorCode::NoError;
514  }
516 }
517 
519  FML_DCHECK(is_setup_);
521 
522  if (!weak_engine_) {
523  return false;
524  }
525 
526  return weak_engine_->UIIsolateHasLivePorts();
527 }
528 
529 bool Shell::IsSetup() const {
530  return is_setup_;
531 }
532 
533 bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
534  std::unique_ptr<Engine> engine,
535  std::unique_ptr<Rasterizer> rasterizer,
536  std::unique_ptr<ShellIOManager> io_manager) {
537  if (is_setup_) {
538  return false;
539  }
540 
541  if (!platform_view || !engine || !rasterizer || !io_manager) {
542  return false;
543  }
544 
545  platform_view_ = std::move(platform_view);
546  engine_ = std::move(engine);
547  rasterizer_ = std::move(rasterizer);
548  io_manager_ = std::move(io_manager);
549 
550  // The weak ptr must be generated in the platform thread which owns the unique
551  // ptr.
552  weak_engine_ = engine_->GetWeakPtr();
553  weak_rasterizer_ = rasterizer_->GetWeakPtr();
554  weak_platform_view_ = platform_view_->GetWeakPtr();
555 
556  // Setup the time-consuming default font manager right after engine created.
558  [engine = weak_engine_] {
559  if (engine) {
560  engine->SetupDefaultFontManager();
561  }
562  });
563 
564  is_setup_ = true;
565 
567  task_runners_.GetIOTaskRunner());
568 
571 
572  if (settings_.purge_persistent_cache) {
574  }
575 
576  return true;
577 }
578 
579 const Settings& Shell::GetSettings() const {
580  return settings_;
581 }
582 
584  return task_runners_;
585 }
586 
588  FML_DCHECK(is_setup_);
589  return weak_rasterizer_;
590 }
591 
593  FML_DCHECK(is_setup_);
594  return weak_engine_;
595 }
596 
598  FML_DCHECK(is_setup_);
599  return weak_platform_view_;
600 }
601 
603  FML_DCHECK(is_setup_);
604  return io_manager_->GetWeakPtr();
605 }
606 
608  return &vm_;
609 }
610 
611 // |PlatformView::Delegate|
612 void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
613  TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
614  FML_DCHECK(is_setup_);
616 
617  // Prevent any request to change the thread configuration for raster and
618  // platform queues while the platform view is being created.
619  //
620  // This prevents false positives such as this method starts assuming that the
621  // raster and platform queues have a given thread configuration, but then the
622  // configuration is changed by a task, and the asumption is not longer true.
623  //
624  // This incorrect assumption can lead to dead lock.
625  // See `should_post_raster_task` for more.
626  rasterizer_->DisableThreadMergerIfNeeded();
627 
628  // The normal flow executed by this method is that the platform thread is
629  // starting the sequence and waiting on the latch. Later the UI thread posts
630  // raster_task to the raster thread which signals the latch. If the raster and
631  // the platform threads are the same this results in a deadlock as the
632  // raster_task will never be posted to the plaform/raster thread that is
633  // blocked on a latch. To avoid the described deadlock, if the raster and the
634  // platform threads are the same, should_post_raster_task will be false, and
635  // then instead of posting a task to the raster thread, the ui thread just
636  // signals the latch and the platform/raster thread follows with executing
637  // raster_task.
638  const bool should_post_raster_task =
639  !task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread();
640 
641  // Note:
642  // This is a synchronous operation because certain platforms depend on
643  // setup/suspension of all activities that may be interacting with the GPU in
644  // a synchronous fashion.
646  auto raster_task =
647  fml::MakeCopyable([&waiting_for_first_frame = waiting_for_first_frame_,
648  rasterizer = rasterizer_->GetWeakPtr(), //
649  surface = std::move(surface), //
650  &latch]() mutable {
651  if (rasterizer) {
652  // Enables the thread merger which may be used by the external view
653  // embedder.
654  rasterizer->EnableThreadMergerIfNeeded();
655  rasterizer->Setup(std::move(surface));
656  }
657 
658  waiting_for_first_frame.store(true);
659 
660  // Step 3: All done. Signal the latch that the platform thread is
661  // waiting on.
662  latch.Signal();
663  });
664 
665  auto ui_task = [engine = engine_->GetWeakPtr(), //
666  raster_task_runner = task_runners_.GetRasterTaskRunner(), //
667  raster_task, should_post_raster_task,
668  &latch //
669  ] {
670  if (engine) {
671  engine->OnOutputSurfaceCreated();
672  }
673  // Step 2: Next, tell the raster thread that it should create a surface for
674  // its rasterizer.
675  if (should_post_raster_task) {
676  fml::TaskRunner::RunNowOrPostTask(raster_task_runner, raster_task);
677  } else {
678  // See comment on should_post_raster_task, in this case we just unblock
679  // the platform thread.
680  latch.Signal();
681  }
682  };
683 
684  // Threading: Capture platform view by raw pointer and not the weak pointer.
685  // We are going to use the pointer on the IO thread which is not safe with a
686  // weak pointer. However, we are preventing the platform view from being
687  // collected by using a latch.
688  auto* platform_view = platform_view_.get();
689 
690  FML_DCHECK(platform_view);
691 
692  auto io_task = [io_manager = io_manager_->GetWeakPtr(), platform_view,
693  ui_task_runner = task_runners_.GetUITaskRunner(), ui_task] {
694  if (io_manager && !io_manager->GetResourceContext()) {
695  io_manager->NotifyResourceContextAvailable(
696  platform_view->CreateResourceContext());
697  }
698  // Step 1: Next, post a task on the UI thread to tell the engine that it has
699  // an output surface.
700  fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
701  };
702 
703  fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task);
704 
705  latch.Wait();
706  if (!should_post_raster_task) {
707  // See comment on should_post_raster_task, in this case the raster_task
708  // wasn't executed, and we just run it here as the platform thread
709  // is the raster thread.
710  raster_task();
711  }
712 }
713 
714 // |PlatformView::Delegate|
715 void Shell::OnPlatformViewDestroyed() {
716  TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
717  FML_DCHECK(is_setup_);
719 
720  // Prevent any request to change the thread configuration for raster and
721  // platform queues while the platform view is being destroyed.
722  //
723  // This prevents false positives such as this method starts assuming that the
724  // raster and platform queues have a given thread configuration, but then the
725  // configuration is changed by a task, and the asumption is not longer true.
726  //
727  // This incorrect assumption can lead to dead lock.
728  // See `should_post_raster_task` for more.
729  rasterizer_->DisableThreadMergerIfNeeded();
730 
731  // The normal flow executed by this method is that the platform thread is
732  // starting the sequence and waiting on the latch. Later the UI thread posts
733  // raster_task to the raster thread triggers signaling the latch(on the IO
734  // thread). If the raster and the platform threads are the same this results
735  // in a deadlock as the raster_task will never be posted to the plaform/raster
736  // thread that is blocked on a latch. To avoid the described deadlock, if the
737  // raster and the platform threads are the same, should_post_raster_task will
738  // be false, and then instead of posting a task to the raster thread, the ui
739  // thread just signals the latch and the platform/raster thread follows with
740  // executing raster_task.
741  const bool should_post_raster_task =
742  !task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread();
743 
744  // Note:
745  // This is a synchronous operation because certain platforms depend on
746  // setup/suspension of all activities that may be interacting with the GPU in
747  // a synchronous fashion.
748 
750 
751  auto io_task = [io_manager = io_manager_.get(), &latch]() {
752  // Execute any pending Skia object deletions while GPU access is still
753  // allowed.
754  io_manager->GetIsGpuDisabledSyncSwitch()->Execute(
755  fml::SyncSwitch::Handlers().SetIfFalse(
756  [&] { io_manager->GetSkiaUnrefQueue()->Drain(); }));
757  // Step 3: All done. Signal the latch that the platform thread is waiting
758  // on.
759  latch.Signal();
760  };
761 
762  auto raster_task = [rasterizer = rasterizer_->GetWeakPtr(),
763  io_task_runner = task_runners_.GetIOTaskRunner(),
764  io_task]() {
765  if (rasterizer) {
766  // Enables the thread merger which is required prior tearing down the
767  // rasterizer. If the raster and platform threads are merged, tearing down
768  // the rasterizer unmerges the threads.
769  rasterizer->EnableThreadMergerIfNeeded();
770  rasterizer->Teardown();
771  }
772  // Step 2: Next, tell the IO thread to complete its remaining work.
773  fml::TaskRunner::RunNowOrPostTask(io_task_runner, io_task);
774  };
775 
776  auto ui_task = [engine = engine_->GetWeakPtr(),
777  raster_task_runner = task_runners_.GetRasterTaskRunner(),
778  raster_task, should_post_raster_task, &latch]() {
779  if (engine) {
780  engine->OnOutputSurfaceDestroyed();
781  }
782  if (should_post_raster_task) {
783  fml::TaskRunner::RunNowOrPostTask(raster_task_runner, raster_task);
784  } else {
785  // See comment on should_post_raster_task, in this case we just unblock
786  // the platform thread.
787  latch.Signal();
788  }
789  };
790 
791  // Step 0: Post a task onto the UI thread to tell the engine that its output
792  // surface is about to go away.
793  fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task);
794 
795  latch.Wait();
796  if (!should_post_raster_task) {
797  // See comment on should_post_raster_task, in this case the raster_task
798  // wasn't executed, and we just run it here as the platform thread
799  // is the raster thread.
800  raster_task();
801  latch.Wait();
802  }
803 }
804 
805 // |PlatformView::Delegate|
806 void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) {
807  FML_DCHECK(is_setup_);
809 
810  if (metrics.device_pixel_ratio <= 0 || metrics.physical_width <= 0 ||
811  metrics.physical_height <= 0) {
812  FML_DLOG(ERROR)
813  << "Embedding reported invalid ViewportMetrics, ignoring update."
814  << "\nphysical_width: " << metrics.physical_width
815  << "\nphysical_height: " << metrics.physical_height
816  << "\ndevice_pixel_ratio: " << metrics.device_pixel_ratio;
817  return;
818  }
819 
820  // This is the formula Android uses.
821  // https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/renderthread/CacheManager.cpp#41
822  size_t max_bytes = metrics.physical_width * metrics.physical_height * 12 * 4;
823  task_runners_.GetRasterTaskRunner()->PostTask(
824  [rasterizer = rasterizer_->GetWeakPtr(), max_bytes] {
825  if (rasterizer) {
826  rasterizer->SetResourceCacheMaxBytes(max_bytes, false);
827  }
828  });
829 
830  task_runners_.GetUITaskRunner()->PostTask(
831  [engine = engine_->GetWeakPtr(), metrics]() {
832  if (engine) {
833  engine->SetViewportMetrics(metrics);
834  }
835  });
836 
837  {
838  std::scoped_lock<std::mutex> lock(resize_mutex_);
839  expected_frame_size_ =
840  SkISize::Make(metrics.physical_width, metrics.physical_height);
841  }
842 }
843 
844 // |PlatformView::Delegate|
845 void Shell::OnPlatformViewDispatchPlatformMessage(
847  FML_DCHECK(is_setup_);
849 
850  task_runners_.GetUITaskRunner()->PostTask(
851  [engine = engine_->GetWeakPtr(), message = std::move(message)] {
852  if (engine) {
853  engine->DispatchPlatformMessage(std::move(message));
854  }
855  });
856 }
857 
858 // |PlatformView::Delegate|
859 void Shell::OnPlatformViewDispatchPointerDataPacket(
860  std::unique_ptr<PointerDataPacket> packet) {
861  TRACE_EVENT0("flutter", "Shell::OnPlatformViewDispatchPointerDataPacket");
862  TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_);
863  FML_DCHECK(is_setup_);
865  task_runners_.GetUITaskRunner()->PostTask(
866  fml::MakeCopyable([engine = weak_engine_, packet = std::move(packet),
867  flow_id = next_pointer_flow_id_]() mutable {
868  if (engine) {
869  engine->DispatchPointerDataPacket(std::move(packet), flow_id);
870  }
871  }));
872  next_pointer_flow_id_++;
873 }
874 
875 // |PlatformView::Delegate|
876 void Shell::OnPlatformViewDispatchSemanticsAction(int32_t id,
878  std::vector<uint8_t> args) {
879  FML_DCHECK(is_setup_);
881 
882  task_runners_.GetUITaskRunner()->PostTask(
883  [engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] {
884  if (engine) {
885  engine->DispatchSemanticsAction(id, action, std::move(args));
886  }
887  });
888 }
889 
890 // |PlatformView::Delegate|
891 void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) {
892  FML_DCHECK(is_setup_);
894 
895  task_runners_.GetUITaskRunner()->PostTask(
896  [engine = engine_->GetWeakPtr(), enabled] {
897  if (engine) {
898  engine->SetSemanticsEnabled(enabled);
899  }
900  });
901 }
902 
903 // |PlatformView::Delegate|
904 void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
905  FML_DCHECK(is_setup_);
907 
908  task_runners_.GetUITaskRunner()->PostTask(
909  [engine = engine_->GetWeakPtr(), flags] {
910  if (engine) {
911  engine->SetAccessibilityFeatures(flags);
912  }
913  });
914 }
915 
916 // |PlatformView::Delegate|
917 void Shell::OnPlatformViewRegisterTexture(
918  std::shared_ptr<flutter::Texture> texture) {
919  FML_DCHECK(is_setup_);
921 
922  task_runners_.GetRasterTaskRunner()->PostTask(
923  [rasterizer = rasterizer_->GetWeakPtr(), texture] {
924  if (rasterizer) {
925  if (auto* registry = rasterizer->GetTextureRegistry()) {
926  registry->RegisterTexture(texture);
927  }
928  }
929  });
930 }
931 
932 // |PlatformView::Delegate|
933 void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) {
934  FML_DCHECK(is_setup_);
936 
937  task_runners_.GetRasterTaskRunner()->PostTask(
938  [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
939  if (rasterizer) {
940  if (auto* registry = rasterizer->GetTextureRegistry()) {
941  registry->UnregisterTexture(texture_id);
942  }
943  }
944  });
945 }
946 
947 // |PlatformView::Delegate|
948 void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) {
949  FML_DCHECK(is_setup_);
951 
952  // Tell the rasterizer that one of its textures has a new frame available.
953  task_runners_.GetRasterTaskRunner()->PostTask(
954  [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
955  auto* registry = rasterizer->GetTextureRegistry();
956 
957  if (!registry) {
958  return;
959  }
960 
961  auto texture = registry->GetTexture(texture_id);
962 
963  if (!texture) {
964  return;
965  }
966 
967  texture->MarkNewFrameAvailable();
968  });
969 
970  // Schedule a new frame without having to rebuild the layer tree.
971  task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() {
972  if (engine) {
973  engine->ScheduleFrame(false);
974  }
975  });
976 }
977 
978 // |PlatformView::Delegate|
979 void Shell::OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {
980  FML_DCHECK(is_setup_);
982 
983  task_runners_.GetRasterTaskRunner()->PostTask(
984  [rasterizer = rasterizer_->GetWeakPtr(), closure = closure]() {
985  if (rasterizer) {
986  rasterizer->SetNextFrameCallback(std::move(closure));
987  }
988  });
989 }
990 
991 // |Animator::Delegate|
992 void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time) {
993  FML_DCHECK(is_setup_);
995 
996  // record the target time for use by rasterizer.
997  {
998  std::scoped_lock time_recorder_lock(time_recorder_mutex_);
999  latest_frame_target_time_.emplace(frame_target_time);
1000  }
1001  if (engine_) {
1002  engine_->BeginFrame(frame_target_time);
1003  }
1004 }
1005 
1006 // |Animator::Delegate|
1007 void Shell::OnAnimatorNotifyIdle(int64_t deadline) {
1008  FML_DCHECK(is_setup_);
1010 
1011  if (engine_) {
1012  engine_->NotifyIdle(deadline);
1013  }
1014 }
1015 
1016 // |Animator::Delegate|
1017 void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline,
1018  fml::TimePoint frame_target_time) {
1019  FML_DCHECK(is_setup_);
1020 
1021  // record the target time for use by rasterizer.
1022  {
1023  std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1024  if (!latest_frame_target_time_) {
1025  latest_frame_target_time_ = frame_target_time;
1026  } else if (latest_frame_target_time_ < frame_target_time) {
1027  latest_frame_target_time_ = frame_target_time;
1028  }
1029  }
1030 
1031  auto discard_callback = [this](flutter::LayerTree& tree) {
1032  std::scoped_lock<std::mutex> lock(resize_mutex_);
1033  return !expected_frame_size_.isEmpty() &&
1034  tree.frame_size() != expected_frame_size_;
1035  };
1036 
1037  task_runners_.GetRasterTaskRunner()->PostTask(
1038  [&waiting_for_first_frame = waiting_for_first_frame_,
1039  &waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
1040  rasterizer = rasterizer_->GetWeakPtr(), pipeline = std::move(pipeline),
1041  discard_callback = std::move(discard_callback)]() {
1042  if (rasterizer) {
1043  rasterizer->Draw(pipeline, std::move(discard_callback));
1044 
1045  if (waiting_for_first_frame.load()) {
1046  waiting_for_first_frame.store(false);
1047  waiting_for_first_frame_condition.notify_all();
1048  }
1049  }
1050  });
1051 }
1052 
1053 // |Animator::Delegate|
1054 void Shell::OnAnimatorDrawLastLayerTree() {
1055  FML_DCHECK(is_setup_);
1056 
1057  task_runners_.GetRasterTaskRunner()->PostTask(
1058  [rasterizer = rasterizer_->GetWeakPtr()]() {
1059  if (rasterizer) {
1060  rasterizer->DrawLastLayerTree();
1061  }
1062  });
1063 }
1064 
1065 // |Engine::Delegate|
1066 void Shell::OnEngineUpdateSemantics(SemanticsNodeUpdates update,
1068  FML_DCHECK(is_setup_);
1070 
1071  task_runners_.GetPlatformTaskRunner()->PostTask(
1072  [view = platform_view_->GetWeakPtr(), update = std::move(update),
1073  actions = std::move(actions)] {
1074  if (view) {
1075  view->UpdateSemantics(std::move(update), std::move(actions));
1076  }
1077  });
1078 }
1079 
1080 // |Engine::Delegate|
1081 void Shell::OnEngineHandlePlatformMessage(
1082  fml::RefPtr<PlatformMessage> message) {
1083  FML_DCHECK(is_setup_);
1085 
1086  if (message->channel() == kSkiaChannel) {
1087  HandleEngineSkiaMessage(std::move(message));
1088  return;
1089  }
1090 
1091  task_runners_.GetPlatformTaskRunner()->PostTask(
1092  [view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
1093  if (view) {
1094  view->HandlePlatformMessage(std::move(message));
1095  }
1096  });
1097 }
1098 
1099 void Shell::HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message) {
1100  const auto& data = message->data();
1101 
1102  rapidjson::Document document;
1103  document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
1104  if (document.HasParseError() || !document.IsObject())
1105  return;
1106  auto root = document.GetObject();
1107  auto method = root.FindMember("method");
1108  if (method->value != "Skia.setResourceCacheMaxBytes")
1109  return;
1110  auto args = root.FindMember("args");
1111  if (args == root.MemberEnd() || !args->value.IsInt())
1112  return;
1113 
1114  task_runners_.GetRasterTaskRunner()->PostTask(
1115  [rasterizer = rasterizer_->GetWeakPtr(), max_bytes = args->value.GetInt(),
1116  response = std::move(message->response())] {
1117  if (rasterizer) {
1118  rasterizer->SetResourceCacheMaxBytes(static_cast<size_t>(max_bytes),
1119  true);
1120  }
1121  if (response) {
1122  // The framework side expects this to be valid json encoded as a list.
1123  // Return `[true]` to signal success.
1124  std::vector<uint8_t> data = {'[', 't', 'r', 'u', 'e', ']'};
1125  response->Complete(
1126  std::make_unique<fml::DataMapping>(std::move(data)));
1127  }
1128  });
1129 }
1130 
1131 // |Engine::Delegate|
1132 void Shell::OnPreEngineRestart() {
1133  FML_DCHECK(is_setup_);
1135 
1138  task_runners_.GetPlatformTaskRunner(),
1139  [view = platform_view_->GetWeakPtr(), &latch]() {
1140  if (view) {
1141  view->OnPreEngineRestart();
1142  }
1143  latch.Signal();
1144  });
1145  // This is blocking as any embedded platform views has to be flushed before
1146  // we re-run the Dart code.
1147  latch.Wait();
1148 }
1149 
1150 // |Engine::Delegate|
1151 void Shell::OnRootIsolateCreated() {
1152  if (is_added_to_service_protocol_) {
1153  return;
1154  }
1155  auto description = GetServiceProtocolDescription();
1157  task_runners_.GetPlatformTaskRunner(),
1158  [self = weak_factory_.GetWeakPtr(),
1159  description = std::move(description)]() {
1160  if (self) {
1161  self->vm_->GetServiceProtocol()->AddHandler(self.get(), description);
1162  }
1163  });
1164  is_added_to_service_protocol_ = true;
1165 }
1166 
1167 // |Engine::Delegate|
1168 void Shell::UpdateIsolateDescription(const std::string isolate_name,
1169  int64_t isolate_port) {
1170  Handler::Description description(isolate_port, isolate_name);
1171  vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
1172 }
1173 
1174 void Shell::SetNeedsReportTimings(bool value) {
1175  needs_report_timings_ = value;
1176 }
1177 
1178 // |Engine::Delegate|
1179 std::unique_ptr<std::vector<std::string>> Shell::ComputePlatformResolvedLocale(
1180  const std::vector<std::string>& supported_locale_data) {
1181  return ComputePlatformViewResolvedLocale(supported_locale_data);
1182 }
1183 
1184 // |PlatformView::Delegate|
1185 std::unique_ptr<std::vector<std::string>>
1186 Shell::ComputePlatformViewResolvedLocale(
1187  const std::vector<std::string>& supported_locale_data) {
1188  return platform_view_->ComputePlatformResolvedLocales(supported_locale_data);
1189 }
1190 
1191 void Shell::ReportTimings() {
1192  FML_DCHECK(is_setup_);
1194 
1195  auto timings = std::move(unreported_timings_);
1196  unreported_timings_ = {};
1197  task_runners_.GetUITaskRunner()->PostTask([timings, engine = weak_engine_] {
1198  if (engine) {
1199  engine->ReportTimings(std::move(timings));
1200  }
1201  });
1202 }
1203 
1204 size_t Shell::UnreportedFramesCount() const {
1205  // Check that this is running on the raster thread to avoid race conditions.
1207  FML_DCHECK(unreported_timings_.size() % FrameTiming::kCount == 0);
1208  return unreported_timings_.size() / FrameTiming::kCount;
1209 }
1210 
1211 void Shell::OnFrameRasterized(const FrameTiming& timing) {
1212  FML_DCHECK(is_setup_);
1214 
1215  // The C++ callback defined in settings.h and set by Flutter runner. This is
1216  // independent of the timings report to the Dart side.
1217  if (settings_.frame_rasterized_callback) {
1218  settings_.frame_rasterized_callback(timing);
1219  }
1220 
1221  if (!needs_report_timings_) {
1222  return;
1223  }
1224 
1225  for (auto phase : FrameTiming::kPhases) {
1226  unreported_timings_.push_back(
1227  timing.Get(phase).ToEpochDelta().ToMicroseconds());
1228  }
1229 
1230  // In tests using iPhone 6S with profile mode, sending a batch of 1 frame or a
1231  // batch of 100 frames have roughly the same cost of less than 0.1ms. Sending
1232  // a batch of 500 frames costs about 0.2ms. The 1 second threshold usually
1233  // kicks in before we reaching the following 100 frames threshold. The 100
1234  // threshold here is mainly for unit tests (so we don't have to write a
1235  // 1-second unit test), and make sure that our vector won't grow too big with
1236  // future 120fps, 240fps, or 1000fps displays.
1237  //
1238  // In the profile/debug mode, the timings are used by development tools which
1239  // require a latency of no more than 100ms. Hence we lower that 1-second
1240  // threshold to 100ms because performance overhead isn't that critical in
1241  // those cases.
1242  if (!first_frame_rasterized_ || UnreportedFramesCount() >= 100) {
1243  first_frame_rasterized_ = true;
1244  ReportTimings();
1245  } else if (!frame_timings_report_scheduled_) {
1246 #if FLUTTER_RELEASE
1247  constexpr int kBatchTimeInMilliseconds = 1000;
1248 #else
1249  constexpr int kBatchTimeInMilliseconds = 100;
1250 #endif
1251 
1252  // Also make sure that frame times get reported with a max latency of 1
1253  // second. Otherwise, the timings of last few frames of an animation may
1254  // never be reported until the next animation starts.
1255  frame_timings_report_scheduled_ = true;
1256  task_runners_.GetRasterTaskRunner()->PostDelayedTask(
1257  [self = weak_factory_gpu_->GetWeakPtr()]() {
1258  if (!self) {
1259  return;
1260  }
1261  self->frame_timings_report_scheduled_ = false;
1262  if (self->UnreportedFramesCount() > 0) {
1263  self->ReportTimings();
1264  }
1265  },
1266  fml::TimeDelta::FromMilliseconds(kBatchTimeInMilliseconds));
1267  }
1268 }
1269 
1270 fml::Milliseconds Shell::GetFrameBudget() {
1271  double display_refresh_rate = display_manager_->GetMainDisplayRefreshRate();
1272  if (display_refresh_rate > 0) {
1273  return fml::RefreshRateToFrameBudget(display_refresh_rate);
1274  } else {
1275  return fml::kDefaultFrameBudget;
1276  }
1277 }
1278 
1279 fml::TimePoint Shell::GetLatestFrameTargetTime() const {
1280  std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1281  FML_CHECK(latest_frame_target_time_.has_value())
1282  << "GetLatestFrameTargetTime called before OnAnimatorBeginFrame";
1283  return latest_frame_target_time_.value();
1284 }
1285 
1286 // |ServiceProtocol::Handler|
1287 fml::RefPtr<fml::TaskRunner> Shell::GetServiceProtocolHandlerTaskRunner(
1288  std::string_view method) const {
1289  FML_DCHECK(is_setup_);
1290  auto found = service_protocol_handlers_.find(method);
1291  if (found != service_protocol_handlers_.end()) {
1292  return found->second.first;
1293  }
1294  return task_runners_.GetUITaskRunner();
1295 }
1296 
1297 // |ServiceProtocol::Handler|
1298 bool Shell::HandleServiceProtocolMessage(
1299  std::string_view method, // one if the extension names specified above.
1300  const ServiceProtocolMap& params,
1301  rapidjson::Document* response) {
1302  auto found = service_protocol_handlers_.find(method);
1303  if (found != service_protocol_handlers_.end()) {
1304  return found->second.second(params, response);
1305  }
1306  return false;
1307 }
1308 
1309 // |ServiceProtocol::Handler|
1310 ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
1311  const {
1313 
1314  if (!weak_engine_) {
1316  }
1317 
1318  return {
1319  weak_engine_->GetUIIsolateMainPort(),
1320  weak_engine_->GetUIIsolateName(),
1321  };
1322 }
1323 
1324 static void ServiceProtocolParameterError(rapidjson::Document* response,
1325  std::string error_details) {
1326  auto& allocator = response->GetAllocator();
1327  response->SetObject();
1328  const int64_t kInvalidParams = -32602;
1329  response->AddMember("code", kInvalidParams, allocator);
1330  response->AddMember("message", "Invalid params", allocator);
1331  {
1332  rapidjson::Value details(rapidjson::kObjectType);
1333  details.AddMember("details", error_details, allocator);
1334  response->AddMember("data", details, allocator);
1335  }
1336 }
1337 
1338 static void ServiceProtocolFailureError(rapidjson::Document* response,
1339  std::string message) {
1340  auto& allocator = response->GetAllocator();
1341  response->SetObject();
1342  const int64_t kJsonServerError = -32000;
1343  response->AddMember("code", kJsonServerError, allocator);
1344  response->AddMember("message", message, allocator);
1345 }
1346 
1347 // Service protocol handler
1348 bool Shell::OnServiceProtocolScreenshot(
1350  rapidjson::Document* response) {
1352  auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1354  if (screenshot.data) {
1355  response->SetObject();
1356  auto& allocator = response->GetAllocator();
1357  response->AddMember("type", "Screenshot", allocator);
1358  rapidjson::Value image;
1359  image.SetString(static_cast<const char*>(screenshot.data->data()),
1360  screenshot.data->size(), allocator);
1361  response->AddMember("screenshot", image, allocator);
1362  return true;
1363  }
1364  ServiceProtocolFailureError(response, "Could not capture image screenshot.");
1365  return false;
1366 }
1367 
1368 // Service protocol handler
1369 bool Shell::OnServiceProtocolScreenshotSKP(
1371  rapidjson::Document* response) {
1373  auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1375  if (screenshot.data) {
1376  response->SetObject();
1377  auto& allocator = response->GetAllocator();
1378  response->AddMember("type", "ScreenshotSkp", allocator);
1379  rapidjson::Value skp;
1380  skp.SetString(static_cast<const char*>(screenshot.data->data()),
1381  screenshot.data->size(), allocator);
1382  response->AddMember("skp", skp, allocator);
1383  return true;
1384  }
1385  ServiceProtocolFailureError(response, "Could not capture SKP screenshot.");
1386  return false;
1387 }
1388 
1389 // Service protocol handler
1390 bool Shell::OnServiceProtocolRunInView(
1392  rapidjson::Document* response) {
1394 
1395  if (params.count("mainScript") == 0) {
1397  "'mainScript' parameter is missing.");
1398  return false;
1399  }
1400 
1401  if (params.count("assetDirectory") == 0) {
1403  "'assetDirectory' parameter is missing.");
1404  return false;
1405  }
1406 
1407  std::string main_script_path =
1408  fml::paths::FromURI(params.at("mainScript").data());
1409  std::string asset_directory_path =
1410  fml::paths::FromURI(params.at("assetDirectory").data());
1411 
1412  auto main_script_file_mapping =
1413  std::make_unique<fml::FileMapping>(fml::OpenFile(
1414  main_script_path.c_str(), false, fml::FilePermission::kRead));
1415 
1416  auto isolate_configuration = IsolateConfiguration::CreateForKernel(
1417  std::move(main_script_file_mapping));
1418 
1419  RunConfiguration configuration(std::move(isolate_configuration));
1420 
1421  configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
1422  engine_->GetLastEntrypointLibrary());
1423 
1424  configuration.AddAssetResolver(std::make_unique<DirectoryAssetBundle>(
1425  fml::OpenDirectory(asset_directory_path.c_str(), false,
1427  false));
1428 
1429  // Preserve any original asset resolvers to avoid syncing unchanged assets
1430  // over the DevFS connection.
1431  auto old_asset_manager = engine_->GetAssetManager();
1432  if (old_asset_manager != nullptr) {
1433  for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
1434  if (old_resolver->IsValidAfterAssetManagerChange()) {
1435  configuration.AddAssetResolver(std::move(old_resolver));
1436  }
1437  }
1438  }
1439 
1440  auto& allocator = response->GetAllocator();
1441  response->SetObject();
1442  if (engine_->Restart(std::move(configuration))) {
1443  response->AddMember("type", "Success", allocator);
1444  auto new_description = GetServiceProtocolDescription();
1445  rapidjson::Value view(rapidjson::kObjectType);
1446  new_description.Write(this, view, allocator);
1447  response->AddMember("view", view, allocator);
1448  return true;
1449  } else {
1450  FML_DLOG(ERROR) << "Could not run configuration in engine.";
1451  ServiceProtocolFailureError(response,
1452  "Could not run configuration in engine.");
1453  return false;
1454  }
1455 
1456  FML_DCHECK(false);
1457  return false;
1458 }
1459 
1460 // Service protocol handler
1461 bool Shell::OnServiceProtocolFlushUIThreadTasks(
1463  rapidjson::Document* response) {
1465  // This API should not be invoked by production code.
1466  // It can potentially starve the service isolate if the main isolate pauses
1467  // at a breakpoint or is in an infinite loop.
1468  //
1469  // It should be invoked from the VM Service and and blocks it until UI thread
1470  // tasks are processed.
1471  response->SetObject();
1472  response->AddMember("type", "Success", response->GetAllocator());
1473  return true;
1474 }
1475 
1476 bool Shell::OnServiceProtocolGetDisplayRefreshRate(
1478  rapidjson::Document* response) {
1480  response->SetObject();
1481  response->AddMember("type", "DisplayRefreshRate", response->GetAllocator());
1482  response->AddMember("fps", display_manager_->GetMainDisplayRefreshRate(),
1483  response->GetAllocator());
1484  return true;
1485 }
1486 
1488  return display_manager_->GetMainDisplayRefreshRate();
1489 }
1490 
1491 bool Shell::OnServiceProtocolGetSkSLs(
1493  rapidjson::Document* response) {
1495  response->SetObject();
1496  response->AddMember("type", "GetSkSLs", response->GetAllocator());
1497 
1498  rapidjson::Value shaders_json(rapidjson::kObjectType);
1500  std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
1501  for (const auto& sksl : sksls) {
1502  size_t b64_size =
1503  SkBase64::Encode(sksl.second->data(), sksl.second->size(), nullptr);
1504  sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
1505  char* b64_char = static_cast<char*>(b64_data->writable_data());
1506  SkBase64::Encode(sksl.second->data(), sksl.second->size(), b64_char);
1507  b64_char[b64_size] = 0; // make it null terminated for printing
1508  rapidjson::Value shader_value(b64_char, response->GetAllocator());
1509  rapidjson::Value shader_key(PersistentCache::SkKeyToFilePath(*sksl.first),
1510  response->GetAllocator());
1511  shaders_json.AddMember(shader_key, shader_value, response->GetAllocator());
1512  }
1513  response->AddMember("SkSLs", shaders_json, response->GetAllocator());
1514  return true;
1515 }
1516 
1517 bool Shell::OnServiceProtocolEstimateRasterCacheMemory(
1519  rapidjson::Document* response) {
1521  const auto& raster_cache = rasterizer_->compositor_context()->raster_cache();
1522  response->SetObject();
1523  response->AddMember("type", "EstimateRasterCacheMemory",
1524  response->GetAllocator());
1525  response->AddMember<uint64_t>("layerBytes",
1526  raster_cache.EstimateLayerCacheByteSize(),
1527  response->GetAllocator());
1528  response->AddMember<uint64_t>("pictureBytes",
1529  raster_cache.EstimatePictureCacheByteSize(),
1530  response->GetAllocator());
1531  return true;
1532 }
1533 
1534 // Service protocol handler
1535 bool Shell::OnServiceProtocolSetAssetBundlePath(
1537  rapidjson::Document* response) {
1539 
1540  if (params.count("assetDirectory") == 0) {
1542  "'assetDirectory' parameter is missing.");
1543  return false;
1544  }
1545 
1546  auto& allocator = response->GetAllocator();
1547  response->SetObject();
1548 
1549  auto asset_manager = std::make_shared<AssetManager>();
1550 
1551  asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
1552  fml::OpenDirectory(params.at("assetDirectory").data(), false,
1554  false));
1555 
1556  // Preserve any original asset resolvers to avoid syncing unchanged assets
1557  // over the DevFS connection.
1558  auto old_asset_manager = engine_->GetAssetManager();
1559  if (old_asset_manager != nullptr) {
1560  for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
1561  if (old_resolver->IsValidAfterAssetManagerChange()) {
1562  asset_manager->PushBack(std::move(old_resolver));
1563  }
1564  }
1565  }
1566 
1567  if (engine_->UpdateAssetManager(std::move(asset_manager))) {
1568  response->AddMember("type", "Success", allocator);
1569  auto new_description = GetServiceProtocolDescription();
1570  rapidjson::Value view(rapidjson::kObjectType);
1571  new_description.Write(this, view, allocator);
1572  response->AddMember("view", view, allocator);
1573  return true;
1574  } else {
1575  FML_DLOG(ERROR) << "Could not update asset directory.";
1576  ServiceProtocolFailureError(response, "Could not update asset directory.");
1577  return false;
1578  }
1579 
1580  FML_DCHECK(false);
1581  return false;
1582 }
1583 
1585  Rasterizer::ScreenshotType screenshot_type,
1586  bool base64_encode) {
1587  TRACE_EVENT0("flutter", "Shell::Screenshot");
1589  Rasterizer::Screenshot screenshot;
1591  task_runners_.GetRasterTaskRunner(), [&latch, //
1592  rasterizer = GetRasterizer(), //
1593  &screenshot, //
1594  screenshot_type, //
1595  base64_encode //
1596  ]() {
1597  if (rasterizer) {
1598  screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type,
1599  base64_encode);
1600  }
1601  latch.Signal();
1602  });
1603  latch.Wait();
1604  return screenshot;
1605 }
1606 
1608  FML_DCHECK(is_setup_);
1609  if (task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread() ||
1610  task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()) {
1612  "WaitForFirstFrame called from thread that can't wait "
1613  "because it is responsible for generating the frame.");
1614  }
1615 
1616  std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
1617  bool success = waiting_for_first_frame_condition_.wait_for(
1618  lock, std::chrono::milliseconds(timeout.ToMilliseconds()),
1619  [&waiting_for_first_frame = waiting_for_first_frame_] {
1620  return !waiting_for_first_frame.load();
1621  });
1622  if (success) {
1623  return fml::Status();
1624  } else {
1626  }
1627 }
1628 
1630  FML_DCHECK(is_setup_);
1632 
1633  if (!engine_) {
1634  return false;
1635  }
1636  engine_->GetFontCollection().GetFontCollection()->SetupDefaultFontManager();
1637  engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
1638  // After system fonts are reloaded, we send a system channel message
1639  // to notify flutter framework.
1640  rapidjson::Document document;
1641  document.SetObject();
1642  auto& allocator = document.GetAllocator();
1643  rapidjson::Value message_value;
1644  message_value.SetString(kFontChange, allocator);
1645  document.AddMember(kTypeKey, message_value, allocator);
1646 
1647  rapidjson::StringBuffer buffer;
1648  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
1649  document.Accept(writer);
1650  std::string message = buffer.GetString();
1651  fml::RefPtr<PlatformMessage> fontsChangeMessage =
1652  fml::MakeRefCounted<flutter::PlatformMessage>(
1653  kSystemChannel, std::vector<uint8_t>(message.begin(), message.end()),
1654  nullptr);
1655 
1656  OnPlatformViewDispatchPlatformMessage(fontsChangeMessage);
1657  return true;
1658 }
1659 
1660 std::shared_ptr<fml::SyncSwitch> Shell::GetIsGpuDisabledSyncSwitch() const {
1661  return is_gpu_disabled_sync_switch_;
1662 }
1663 
1665  std::vector<Display> displays) {
1666  display_manager_->HandleDisplayUpdates(update_type, displays);
1667 }
1668 
1669 } // namespace flutter
static const std::string_view kGetDisplayRefreshRateExtensionName
static void Tokenize(const std::string &input, std::vector< std::string > *results, char delimiter)
Definition: shell.cc:177
bool IsValid() const
Definition: task_runners.cc:46
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition: shell.h:99
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75
std::map< std::string_view, std::string_view > ServiceProtocolMap
std::shared_ptr< ServiceProtocol > GetServiceProtocol() const
The service protocol instance associated with this running Dart VM instance. This object manages nati...
Definition: dart_vm.cc:493
static const std::string_view kRunInViewExtensionName
#define FML_DCHECK(condition)
Definition: logging.h:86
bool skia_deterministic_rendering_on_cpu
Definition: settings.h:202
constexpr int64_t ToMilliseconds() const
Definition: time_delta.h:63
std::string trace_allowlist
Definition: settings.h:104
void SetLogSettings(const LogSettings &settings)
Definition: log_settings.cc:23
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
Definition: shell.cc:583
fml::WeakPtr< Engine > GetEngine()
Engines may only be accessed on the UI thread. This method is deprecated, and implementers should ins...
Definition: shell.cc:592
static void RunNowOrPostTask(fml::RefPtr< fml::TaskRunner > runner, const fml::closure &task)
Definition: task_runner.cc:55
void InitializeICU(const std::string &icu_data_path)
Definition: icu_util.cc:103
The Dart error code for an API error.
void InitializeICUFromMapping(std::unique_ptr< Mapping > mapping)
Definition: icu_util.cc:114
Dart_NativeFunction function
Definition: fuchsia.cc:51
bool EngineHasLivePorts() const
Used by embedders to check if the Engine is running and has any live ports remaining. For example, the Flutter tester uses this method to check whether it should continue to wait for a running test or not.
Definition: shell.cc:518
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
virtual void PostTask(const fml::closure &task)
Definition: task_runner.cc:24
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
TimeDelta ToEpochDelta() const
Definition: time_point.h:40
#define FML_LOG(severity)
Definition: logging.h:65
static void SetCacheSkSL(bool value)
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...
#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id)
Definition: trace_event.h:89
static void PerformInitializationTasks(Settings &settings)
Definition: shell.cc:193
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
static DartVMRef Create(Settings settings, fml::RefPtr< DartSnapshot > vm_snapshot=nullptr, fml::RefPtr< DartSnapshot > isolate_snapshot=nullptr)
void SetLogHandler(std::function< void(const char *)> handler)
Definition: log.cc:46
void AddWorkerTaskRunner(fml::RefPtr< fml::TaskRunner > task_runner)
constexpr char kSkiaChannel[]
Definition: shell.cc:37
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
Definition: file_posix.cc:94
static const std::string_view kScreenshotExtensionName
The Dart error code for an unkonwn error.
bool verbose_logging
Definition: settings.h:203
static const std::string_view kFlushUIThreadTasksExtensionName
static constexpr Phase kPhases[kCount]
Definition: settings.h:35
std::string FromURI(const std::string &uri)
Definition: paths_posix.cc:53
std::function< void()> closure
Definition: closure.h:14
void RunEngine(RunConfiguration run_configuration)
Starts an isolate for the given RunConfiguration.
Definition: shell.cc:461
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition: make_copyable.h:57
fml::WeakPtr< ShellIOManager > GetIOManager()
The IO Manager may only be accessed on the IO task runner.
Definition: shell.cc:602
#define TRACE_FLOW_BEGIN(category, name, id)
Definition: trace_event.h:115
std::chrono::microseconds engine_start_timestamp
Definition: settings.h:241
A POD type used to return the screenshot data along with the size of the frame.
Definition: rasterizer.h:279
uint8_t value
void OnDisplayUpdates(DisplayUpdateType update_type, std::vector< Display > displays)
Notifies the display manager of the updates.
Definition: shell.cc:1664
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition: rasterizer.h:249
constexpr int64_t ToMicroseconds() const
Definition: time_delta.h:62
void RemoveWorkerTaskRunner(fml::RefPtr< fml::TaskRunner > task_runner)
std::shared_ptr< fml::SyncSwitch > GetIsGpuDisabledSyncSwitch() const override
Accessor for the disable GPU SyncSwitch.
Definition: shell.cc:1660
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetRasterizer() const
Rasterizers may only be accessed on the GPU task runner.
Definition: shell.cc:587
Specifies all the configuration required by the runtime library to launch the root isolate...
std::vector< SkSLCache > LoadSkSLs()
Load all the SkSL shader caches in the right directory.
FlutterPointerPhase phase
Definition: fl_view.cc:78
Milliseconds RefreshRateToFrameBudget(T refresh_rate)
Definition: time_delta.h:24
double GetMainDisplayRefreshRate()
Queries the DisplayManager for the main display refresh rate.
Definition: shell.cc:1487
constexpr char kSystemChannel[]
Definition: shell.cc:38
SemanticsAction action
void NotifyLowMemoryWarning() const
Used by embedders to notify that there is a low memory warning. The shell will attempt to purge cache...
Definition: shell.cc:439
constexpr char kFontChange[]
Definition: shell.cc:40
void SetEntrypointAndLibrary(std::string entrypoint, std::string library)
Specifies the main Dart entrypoint and the library to find that entrypoint in. By default...
void TraceSetAllowlist(const std::vector< std::string > &allowlist)
Definition: trace_event.cc:289
void InitSkiaEventTracer(bool enabled)
static std::string SkKeyToFilePath(const SkData &data)
bool dump_skp_on_shader_compilation
Definition: settings.h:107
fml::Status WaitForFirstFrame(fml::TimeDelta timeout)
Pauses the calling thread until the first frame is presented.
Definition: shell.cc:1607
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
Definition: task_runners.cc:38
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
Definition: task_runners.cc:34
fml::WeakPtr< PlatformView > GetPlatformView()
Platform views may only be accessed on the platform task runner.
Definition: shell.cc:597
std::string icu_data_path
Definition: settings.h:211
#define TRACE_EVENT_ASYNC_END0(category_group, name, id)
Definition: trace_event.h:92
bool AddAssetResolver(std::unique_ptr< AssetResolver > resolver)
Asset managers maintain a list of resolvers that are checked in order when attempting to locate an as...
constexpr LogSeverity LOG_ERROR
Definition: log_level.h:15
static void ServiceProtocolFailureError(rapidjson::Document *response, std::string message)
Definition: shell.cc:1338
void SetIsDumpingSkp(bool value)
Describes a running instance of the Dart VM. There may only be one running instance of the Dart VM in...
Definition: dart_vm.h:61
static PersistentCache * GetCacheForProcess()
#define FML_CHECK(condition)
Definition: logging.h:68
static void ServiceProtocolParameterError(rapidjson::Document *response, std::string error_details)
Definition: shell.cc:1324
LogSeverity min_log_level
Definition: log_settings.h:25
constexpr LogSeverity LOG_INFO
Definition: log_level.h:13
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
DartVM * GetDartVM()
Get a pointer to the Dart VM used by this running shell instance.
Definition: shell.cc:607
constexpr Milliseconds kDefaultFrameBudget
Definition: time_delta.h:21
fml::UniqueFD OpenFile(const char *path, bool create_if_necessary, FilePermission permission)
This can open a directory on POSIX, but not on Windows.
Definition: file_posix.cc:64
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
fml::TimePoint Get(Phase phase) const
Definition: settings.h:38
bool IsSetup() const
Used by embedders to check if all shell subcomponents are initialized. It is the embedder&#39;s responsib...
Definition: shell.cc:529
int32_t id
#define FML_DLOG(severity)
Definition: logging.h:85
RunStatus
Indicates the result of the call to Engine::Run.
Definition: engine.h:80
bool icu_initialization_required
Definition: settings.h:210
size_t TraceNonce()
Definition: trace_event.cc:291
MappingCallback icu_mapper
Definition: settings.h:212
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
const Settings & GetSettings() const
Definition: shell.cc:579
The Dart error code for a compilation error.
static const std::string_view kScreenshotSkpExtensionName
static std::unique_ptr< Shell > Create(TaskRunners task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
Definition: shell.cc:239
bool ReloadSystemFonts()
Used by embedders to reload the system fonts in FontCollection. It also clears the cached font famili...
Definition: shell.cc:1629
std::chrono::duration< double, std::milli > Milliseconds
Definition: time_delta.h:18
virtual void PostDelayedTask(const fml::closure &task, fml::TimeDelta delay)
Definition: task_runner.cc:33
~Shell()
Destroys the shell. This is a synchronous operation and synchronous barrier blocks are introduced on ...
Definition: shell.cc:386
constexpr char kTypeKey[]
Definition: shell.cc:39
bool purge_persistent_cache
Definition: settings.h:109
static const std::string_view kSetAssetBundlePathExtensionName
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66
FrameRasterizedCallback frame_rasterized_callback
Definition: settings.h:221
std::optional< DartErrorCode > GetUIIsolateLastError() const
Used by embedders to get the last error from the Dart UI Isolate, if one exists.
Definition: shell.cc:498
Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, bool base64_encode)
Captures a screenshot and optionally Base64 encodes the data of the last layer tree rendered by the r...
Definition: shell.cc:1584
static const std::string_view kGetSkSLsExtensionName
No error has occurred.
static const std::string_view kEstimateRasterCacheMemoryExtensionName
Represents the 2 code paths available when calling |SyncSwitch::Execute|.
Definition: sync_switch.h:24