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