Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1e1a4ab

Browse files
authored
Add call to Dart_NotifyDestroyed when the flutter view is destroyed. (#37539)
* Add calls to Dart_NotifyDestroyed when the flutter view is destroyed. * Add unit test case. * Format. * Ensure the destroy task runs. * Address code review comments.
1 parent dd12a40 commit 1e1a4ab

File tree

7 files changed

+85
-0
lines changed

7 files changed

+85
-0
lines changed

runtime/runtime_controller.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ bool RuntimeController::NotifyIdle(fml::TimePoint deadline) {
235235
return true;
236236
}
237237

238+
bool RuntimeController::NotifyDestroyed() {
239+
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
240+
if (!root_isolate) {
241+
return false;
242+
}
243+
244+
tonic::DartState::Scope scope(root_isolate);
245+
246+
Dart_NotifyDestroyed();
247+
248+
return true;
249+
}
250+
238251
bool RuntimeController::DispatchPlatformMessage(
239252
std::unique_ptr<PlatformMessage> message) {
240253
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {

runtime/runtime_controller.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,17 @@ class RuntimeController : public PlatformConfigurationClient {
360360
///
361361
virtual bool NotifyIdle(fml::TimePoint deadline);
362362

363+
//----------------------------------------------------------------------------
364+
/// @brief Notify the Dart VM that the attached flutter view has been
365+
/// destroyed. This gives the Dart VM to perform some cleanup
366+
/// activities e.g: perform garbage collection to free up any
367+
/// unused memory.
368+
///
369+
/// NotifyDestroyed is advisory. The VM may or may not perform any clean up
370+
/// activities.
371+
///
372+
virtual bool NotifyDestroyed();
373+
363374
//----------------------------------------------------------------------------
364375
/// @brief Returns if the root isolate is running. The isolate must be
365376
/// transitioned to the running phase manually. The isolate can

shell/common/engine.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ void Engine::NotifyIdle(fml::TimePoint deadline) {
266266
runtime_controller_->NotifyIdle(deadline);
267267
}
268268

269+
void Engine::NotifyDestroyed() {
270+
TRACE_EVENT0("flutter", "Engine::NotifyDestroyed");
271+
runtime_controller_->NotifyDestroyed();
272+
}
273+
269274
std::optional<uint32_t> Engine::GetUIIsolateReturnCode() {
270275
return runtime_controller_->GetRootIsolateReturnCode();
271276
}

shell/common/engine.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,13 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
554554
///
555555
void NotifyIdle(fml::TimePoint deadline);
556556

557+
//----------------------------------------------------------------------------
558+
/// @brief Notifies the engine that the attached flutter view has been
559+
/// destroyed.
560+
/// This enables the engine to notify the Dart VM so it can do
561+
/// some cleanp activities.
562+
void NotifyDestroyed();
563+
557564
//----------------------------------------------------------------------------
558565
/// @brief Dart code cannot fully measure the time it takes for a
559566
/// specific frame to be rendered. This is because Dart code only

shell/common/fixtures/shell_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ void performanceModeImpactsNotifyIdle() {
212212
PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.balanced);
213213
}
214214

215+
@pragma('vm:entry-point')
216+
void callNotifyDestroyed() {
217+
notifyDestroyed();
218+
}
219+
215220
@pragma('vm:external-name', 'NotifyMessage')
216221
external void notifyMessage(String string);
217222

@@ -424,6 +429,8 @@ Future<void> runCallback(IsolateParam param) async {
424429
@pragma('vm:entry-point')
425430
@pragma('vm:external-name', 'NotifyNativeBool')
426431
external void notifyNativeBool(bool value);
432+
@pragma('vm:external-name', 'NotifyDestroyed')
433+
external void notifyDestroyed();
427434

428435
@pragma('vm:entry-point')
429436
Future<void> testPluginUtilitiesCallbackHandle() async {

shell/common/shell.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,14 @@ void Shell::OnPlatformViewDestroyed() {
851851
// This incorrect assumption can lead to deadlock.
852852
rasterizer_->DisableThreadMergerIfNeeded();
853853

854+
// Notify the Dart VM that the PlatformView has been destroyed and some
855+
// cleanup activity can be done (e.g: garbage collect the Dart heap).
856+
task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() {
857+
if (engine) {
858+
engine->NotifyDestroyed();
859+
}
860+
});
861+
854862
// Note:
855863
// This is a synchronous operation because certain platforms depend on
856864
// setup/suspension of all activities that may be interacting with the GPU in

shell/common/shell_unittests.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3932,6 +3932,40 @@ TEST_F(ShellTest, NotifyIdleNotCalledInLatencyMode) {
39323932
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
39333933
}
39343934

3935+
TEST_F(ShellTest, NotifyDestroyed) {
3936+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
3937+
Settings settings = CreateSettingsForFixture();
3938+
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
3939+
ThreadHost::Type::Platform | ThreadHost::UI |
3940+
ThreadHost::IO | ThreadHost::RASTER);
3941+
auto platform_task_runner = thread_host.platform_thread->GetTaskRunner();
3942+
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
3943+
thread_host.raster_thread->GetTaskRunner(),
3944+
thread_host.ui_thread->GetTaskRunner(),
3945+
thread_host.io_thread->GetTaskRunner());
3946+
auto shell = CreateShell(settings, task_runners);
3947+
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
3948+
ASSERT_TRUE(ValidateShell(shell.get()));
3949+
3950+
fml::CountDownLatch latch(1);
3951+
AddNativeCallback("NotifyDestroyed", CREATE_NATIVE_ENTRY([&](auto args) {
3952+
auto runtime_controller = const_cast<RuntimeController*>(
3953+
shell->GetEngine()->GetRuntimeController());
3954+
bool success = runtime_controller->NotifyDestroyed();
3955+
EXPECT_TRUE(success);
3956+
latch.CountDown();
3957+
}));
3958+
3959+
auto configuration = RunConfiguration::InferFromSettings(settings);
3960+
configuration.SetEntrypoint("callNotifyDestroyed");
3961+
RunEngine(shell.get(), std::move(configuration));
3962+
3963+
latch.Wait();
3964+
3965+
DestroyShell(std::move(shell), task_runners);
3966+
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
3967+
}
3968+
39353969
} // namespace testing
39363970
} // namespace flutter
39373971

0 commit comments

Comments
 (0)