From c57169835a4e8596b9debbb07867ffc0dd983cd4 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 1 Aug 2023 11:38:40 -0700 Subject: [PATCH] Avoid concurrent modification of persistent frame callbacks (#131677) Fixes https://github.com/flutter/flutter/issues/131415 We should do an audit of all such cases though, filed https://github.com/flutter/flutter/issues/131678 --- packages/flutter/lib/src/scheduler/binding.dart | 2 +- .../flutter/test/scheduler/binding_test.dart | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 0ff4b85c7f7..73b0971eb96 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -1227,7 +1227,7 @@ mixin SchedulerBinding on BindingBase { try { // PERSISTENT FRAME CALLBACKS _schedulerPhase = SchedulerPhase.persistentCallbacks; - for (final FrameCallback callback in _persistentCallbacks) { + for (final FrameCallback callback in List.of(_persistentCallbacks)) { _invokeFrameCallback(callback, _currentFrameTimeStamp!); } diff --git a/packages/flutter/test/scheduler/binding_test.dart b/packages/flutter/test/scheduler/binding_test.dart index 233e12c94af..5079db9266f 100644 --- a/packages/flutter/test/scheduler/binding_test.dart +++ b/packages/flutter/test/scheduler/binding_test.dart @@ -28,4 +28,21 @@ void main() { ); timeDilation = 1.0; }); + + test('Adding a persistent frame callback during a persistent frame callback', () { + bool calledBack = false; + SchedulerBinding.instance.addPersistentFrameCallback((Duration timeStamp) { + if (!calledBack) { + SchedulerBinding.instance.addPersistentFrameCallback((Duration timeStamp) { + calledBack = true; + }); + } + }); + SchedulerBinding.instance.handleBeginFrame(null); + SchedulerBinding.instance.handleDrawFrame(); + expect(calledBack, false); + SchedulerBinding.instance.handleBeginFrame(null); + SchedulerBinding.instance.handleDrawFrame(); + expect(calledBack, true); + }); }