Pause dart microtasks while UI thread is processing frame workloads (#25789)

diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc
index e763696..00c12f0 100644
--- a/shell/common/shell_test.cc
+++ b/shell/common/shell_test.cc
@@ -325,7 +325,7 @@
           std::make_unique<ShellTestVsyncWaiter>(task_runners, vsync_clock));
     } else {
       return static_cast<std::unique_ptr<VsyncWaiter>>(
-          std::make_unique<VsyncWaiterFallback>(task_runners));
+          std::make_unique<VsyncWaiterFallback>(task_runners, true));
     }
   };
 
diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc
index 5a21085..d31c138 100644
--- a/shell/common/shell_unittests.cc
+++ b/shell/common/shell_unittests.cc
@@ -1335,6 +1335,7 @@
   };
   AddNativeCallback("NativeReportTimingsCallback",
                     CREATE_NATIVE_ENTRY(nativeTimingCallback));
+  ASSERT_TRUE(configuration.IsValid());
   RunEngine(shell.get(), std::move(configuration));
 
   for (int i = 0; i < 10; i += 1) {
diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc
index 886f672..40ced72 100644
--- a/shell/common/vsync_waiter.cc
+++ b/shell/common/vsync_waiter.cc
@@ -91,7 +91,8 @@
 }
 
 void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
-                               fml::TimePoint frame_target_time) {
+                               fml::TimePoint frame_target_time,
+                               bool pause_secondary_tasks) {
   Callback callback;
   std::vector<fml::closure> secondary_callbacks;
 
@@ -114,6 +115,9 @@
 
   if (callback) {
     auto flow_identifier = fml::tracing::TraceNonce();
+    if (pause_secondary_tasks) {
+      PauseDartMicroTasks();
+    }
 
     // The base trace ensures that flows have a root to begin from if one does
     // not exist. The trace viewer will ignore traces that have no base event
@@ -124,11 +128,15 @@
     TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier);
 
     task_runners_.GetUITaskRunner()->PostTaskForTime(
-        [callback, flow_identifier, frame_start_time, frame_target_time]() {
+        [this, callback, flow_identifier, frame_start_time, frame_target_time,
+         pause_secondary_tasks]() {
           FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime",
                           frame_start_time, "TargetTime", frame_target_time);
           callback(frame_start_time, frame_target_time);
           TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier);
+          if (pause_secondary_tasks) {
+            ResumeDartMicroTasks();
+          }
         },
         frame_start_time);
   }
@@ -139,4 +147,16 @@
   }
 }
 
+void VsyncWaiter::PauseDartMicroTasks() {
+  auto ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId();
+  auto task_queues = fml::MessageLoopTaskQueues::GetInstance();
+  task_queues->PauseSecondarySource(ui_task_queue_id);
+}
+
+void VsyncWaiter::ResumeDartMicroTasks() {
+  auto ui_task_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId();
+  auto task_queues = fml::MessageLoopTaskQueues::GetInstance();
+  task_queues->ResumeSecondarySource(ui_task_queue_id);
+}
+
 }  // namespace flutter
diff --git a/shell/common/vsync_waiter.h b/shell/common/vsync_waiter.h
index 0843990..d593c70 100644
--- a/shell/common/vsync_waiter.h
+++ b/shell/common/vsync_waiter.h
@@ -49,13 +49,17 @@
   virtual void AwaitVSync() = 0;
 
   void FireCallback(fml::TimePoint frame_start_time,
-                    fml::TimePoint frame_target_time);
+                    fml::TimePoint frame_target_time,
+                    bool pause_secondary_tasks = true);
 
  private:
   std::mutex callback_mutex_;
   Callback callback_;
   std::unordered_map<uintptr_t, fml::closure> secondary_callbacks_;
 
+  void PauseDartMicroTasks();
+  void ResumeDartMicroTasks();
+
   FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter);
 };
 
diff --git a/shell/common/vsync_waiter_fallback.cc b/shell/common/vsync_waiter_fallback.cc
index 514dc02..8bf51c5 100644
--- a/shell/common/vsync_waiter_fallback.cc
+++ b/shell/common/vsync_waiter_fallback.cc
@@ -21,8 +21,11 @@
 
 }  // namespace
 
-VsyncWaiterFallback::VsyncWaiterFallback(TaskRunners task_runners)
-    : VsyncWaiter(std::move(task_runners)), phase_(fml::TimePoint::Now()) {}
+VsyncWaiterFallback::VsyncWaiterFallback(TaskRunners task_runners,
+                                         bool for_testing)
+    : VsyncWaiter(std::move(task_runners)),
+      phase_(fml::TimePoint::Now()),
+      for_testing_(for_testing) {}
 
 VsyncWaiterFallback::~VsyncWaiterFallback() = default;
 
@@ -36,7 +39,7 @@
   auto next =
       SnapToNextTick(fml::TimePoint::Now(), phase_, kSingleFrameInterval);
 
-  FireCallback(next, next + kSingleFrameInterval);
+  FireCallback(next, next + kSingleFrameInterval, !for_testing_);
 }
 
 }  // namespace flutter
diff --git a/shell/common/vsync_waiter_fallback.h b/shell/common/vsync_waiter_fallback.h
index 5226dda..b2ae63f 100644
--- a/shell/common/vsync_waiter_fallback.h
+++ b/shell/common/vsync_waiter_fallback.h
@@ -15,12 +15,14 @@
 /// A |VsyncWaiter| that will fire at 60 fps irrespective of the vsync.
 class VsyncWaiterFallback final : public VsyncWaiter {
  public:
-  VsyncWaiterFallback(TaskRunners task_runners);
+  explicit VsyncWaiterFallback(TaskRunners task_runners,
+                               bool for_testing = false);
 
   ~VsyncWaiterFallback() override;
 
  private:
   fml::TimePoint phase_;
+  const bool for_testing_;
 
   // |VsyncWaiter|
   void AwaitVSync() override;
diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm
index d71ecd7d7..37d9b23 100644
--- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm
+++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm
@@ -23,7 +23,8 @@
                                              callback:std::bind(&VsyncWaiterIOS::FireCallback,
                                                                 this,
                                                                 std::placeholders::_1,
-                                                                std::placeholders::_2)]) {}
+                                                                std::placeholders::_2,
+                                                                true)]) {}
 
 VsyncWaiterIOS::~VsyncWaiterIOS() {
   // This way, we will get no more callbacks from the display link that holds a weak (non-nilling)
diff --git a/shell/platform/fuchsia/flutter/vsync_waiter.cc b/shell/platform/fuchsia/flutter/vsync_waiter.cc
index 5a8fe59..fd8f601 100644
--- a/shell/platform/fuchsia/flutter/vsync_waiter.cc
+++ b/shell/platform/fuchsia/flutter/vsync_waiter.cc
@@ -197,7 +197,7 @@
   }
   fml::TimePoint previous_vsync = next_vsync - vsync_info.presentation_interval;
 
-  FireCallback(previous_vsync, next_vsync);
+  FireCallback(previous_vsync, next_vsync, false);
 }
 
 }  // namespace flutter_runner