diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 1d008de30f52f..d3d56c13f1029 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -371,9 +371,17 @@ void PlatformConfigurationNativeApi::SetIsolateDebugName( UIDartState::Current()->SetDebugName(name); } +Dart_PerformanceMode PlatformConfigurationNativeApi::current_performace_mode_ = + Dart_PerformanceMode_Default; + +Dart_PerformanceMode PlatformConfigurationNativeApi::GetDartPerformanceMode() { + return current_performace_mode_; +} + int PlatformConfigurationNativeApi::RequestDartPerformanceMode(int mode) { UIDartState::ThrowIfUIOperationsProhibited(); - return Dart_SetPerformanceMode(static_cast(mode)); + current_performace_mode_ = static_cast(mode); + return Dart_SetPerformanceMode(current_performace_mode_); } Dart_Handle PlatformConfigurationNativeApi::GetPersistentIsolateData() { diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 268bbdc4a017b..c5019962867cc 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -515,9 +515,18 @@ class PlatformConfigurationNativeApi { /// static int RequestDartPerformanceMode(int mode); + //-------------------------------------------------------------------------- + /// @brief Returns the current performance mode of the Dart VM. Defaults + /// to `Dart_PerformanceMode_Default` if no prior requests to change the + /// performance mode have been made. + static Dart_PerformanceMode GetDartPerformanceMode(); + static int64_t GetRootIsolateToken(); static void RegisterBackgroundIsolate(int64_t root_isolate_token); + + private: + static Dart_PerformanceMode current_performace_mode_; }; } // namespace flutter diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 933b5abe84671..553c8f5c5e092 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -219,6 +219,12 @@ bool RuntimeController::NotifyIdle(fml::TimePoint deadline) { tonic::DartState::Scope scope(root_isolate); + Dart_PerformanceMode performance_mode = + PlatformConfigurationNativeApi::GetDartPerformanceMode(); + if (performance_mode == Dart_PerformanceMode::Dart_PerformanceMode_Latency) { + return false; + } + Dart_NotifyIdle(deadline.ToEpochDelta().ToMicroseconds()); // Idle notifications being in isolate scope are part of the contract. diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart index d722eefb8d12b..9a7c02179fd6b 100644 --- a/shell/common/fixtures/shell_test.dart +++ b/shell/common/fixtures/shell_test.dart @@ -204,6 +204,14 @@ void canAccessIsolateLaunchData() { ); } +@pragma('vm:entry-point') +void performanceModeImpactsNotifyIdle() { + notifyNativeBool(false); + PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.latency); + notifyNativeBool(true); + PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.balanced); +} + @pragma('vm:external-name', 'NotifyMessage') external void notifyMessage(String string); diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index fe89e63ae5678..91f2a24864902 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -3891,6 +3891,47 @@ TEST_F(ShellTest, PluginUtilitiesCallbackHandleErrorHandling) { DestroyShell(std::move(shell)); } +TEST_F(ShellTest, NotifyIdleNotCalledInLatencyMode) { + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); + Settings settings = CreateSettingsForFixture(); + ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", + ThreadHost::Type::Platform | ThreadHost::UI | + ThreadHost::IO | ThreadHost::RASTER); + auto platform_task_runner = thread_host.platform_thread->GetTaskRunner(); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + auto shell = CreateShell(settings, task_runners); + ASSERT_TRUE(DartVMRef::IsInstanceRunning()); + ASSERT_TRUE(ValidateShell(shell.get())); + + // we start off in balanced mode, where we expect idle notifications to + // succeed. After the first `NotifyNativeBool` we expect to be in latency + // mode, where we expect idle notifications to fail. + fml::CountDownLatch latch(2); + AddNativeCallback( + "NotifyNativeBool", CREATE_NATIVE_ENTRY([&](auto args) { + Dart_Handle exception = nullptr; + bool is_in_latency_mode = + tonic::DartConverter::FromArguments(args, 0, exception); + auto runtime_controller = const_cast( + shell->GetEngine()->GetRuntimeController()); + bool success = runtime_controller->NotifyIdle(fml::TimePoint::Now()); + EXPECT_EQ(success, !is_in_latency_mode); + latch.CountDown(); + })); + + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("performanceModeImpactsNotifyIdle"); + RunEngine(shell.get(), std::move(configuration)); + + latch.Wait(); + + DestroyShell(std::move(shell), task_runners); + ASSERT_FALSE(DartVMRef::IsInstanceRunning()); +} + } // namespace testing } // namespace flutter