Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions runtime/runtime_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,19 @@ bool RuntimeController::NotifyIdle(fml::TimePoint deadline) {
return true;
}

bool RuntimeController::NotifyDestroyed() {
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
if (!root_isolate) {
return false;
}

tonic::DartState::Scope scope(root_isolate);

Dart_NotifyDestroyed();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this call block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No.


return true;
}

bool RuntimeController::DispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
Expand Down
11 changes: 11 additions & 0 deletions runtime/runtime_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,17 @@ class RuntimeController : public PlatformConfigurationClient {
///
virtual bool NotifyIdle(fml::TimePoint deadline);

//----------------------------------------------------------------------------
/// @brief Notify the Dart VM that the attached flutter view has been
/// destroyed. This gives the Dart VM to perform some cleanup
/// activities e.g: perform garbage collection to free up any
/// unused memory.
///
/// NotifyDestroyed is advisory. The VM may or may not perform any clean up
/// activities.
///
virtual bool NotifyDestroyed();

//----------------------------------------------------------------------------
/// @brief Returns if the root isolate is running. The isolate must be
/// transitioned to the running phase manually. The isolate can
Expand Down
5 changes: 5 additions & 0 deletions shell/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ void Engine::NotifyIdle(fml::TimePoint deadline) {
runtime_controller_->NotifyIdle(deadline);
}

void Engine::NotifyDestroyed() {
TRACE_EVENT0("flutter", "Engine::NotifyDestroyed");
runtime_controller_->NotifyDestroyed();
}

std::optional<uint32_t> Engine::GetUIIsolateReturnCode() {
return runtime_controller_->GetRootIsolateReturnCode();
}
Expand Down
7 changes: 7 additions & 0 deletions shell/common/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,13 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
///
void NotifyIdle(fml::TimePoint deadline);

//----------------------------------------------------------------------------
/// @brief Notifies the engine that the attached flutter view has been
/// destroyed.
/// This enables the engine to notify the Dart VM so it can do
/// some cleanp activities.
void NotifyDestroyed();

//----------------------------------------------------------------------------
/// @brief Dart code cannot fully measure the time it takes for a
/// specific frame to be rendered. This is because Dart code only
Expand Down
7 changes: 7 additions & 0 deletions shell/common/fixtures/shell_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ void performanceModeImpactsNotifyIdle() {
PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.balanced);
}

@pragma('vm:entry-point')
void callNotifyDestroyed() {
notifyDestroyed();
}

@pragma('vm:external-name', 'NotifyMessage')
external void notifyMessage(String string);

Expand Down Expand Up @@ -424,6 +429,8 @@ Future<void> runCallback(IsolateParam param) async {
@pragma('vm:entry-point')
@pragma('vm:external-name', 'NotifyNativeBool')
external void notifyNativeBool(bool value);
@pragma('vm:external-name', 'NotifyDestroyed')
external void notifyDestroyed();

@pragma('vm:entry-point')
Future<void> testPluginUtilitiesCallbackHandle() async {
Expand Down
8 changes: 8 additions & 0 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,14 @@ void Shell::OnPlatformViewDestroyed() {
// This incorrect assumption can lead to deadlock.
rasterizer_->DisableThreadMergerIfNeeded();

// Notify the Dart VM that the PlatformView has been destroyed and some
// cleanup activity can be done (e.g: garbage collect the Dart heap).
task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() {
if (engine) {
engine->NotifyDestroyed();
}
});

// Note:
// This is a synchronous operation because certain platforms depend on
// setup/suspension of all activities that may be interacting with the GPU in
Expand Down
34 changes: 34 additions & 0 deletions shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3932,6 +3932,40 @@ TEST_F(ShellTest, NotifyIdleNotCalledInLatencyMode) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}

TEST_F(ShellTest, NotifyDestroyed) {
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()));

fml::CountDownLatch latch(1);
AddNativeCallback("NotifyDestroyed", CREATE_NATIVE_ENTRY([&](auto args) {
auto runtime_controller = const_cast<RuntimeController*>(
shell->GetEngine()->GetRuntimeController());
bool success = runtime_controller->NotifyDestroyed();
EXPECT_TRUE(success);
latch.CountDown();
}));

auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("callNotifyDestroyed");
RunEngine(shell.get(), std::move(configuration));

latch.Wait();

DestroyShell(std::move(shell), task_runners);
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}

} // namespace testing
} // namespace flutter

Expand Down