Add call to Dart_NotifyDestroyed when the flutter view is destroyed. (flutter/engine#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.
This commit is contained in:
Siva 2022-11-17 13:11:21 -08:00 committed by GitHub
parent 62002a345b
commit 7296b2b66d
7 changed files with 85 additions and 0 deletions

View File

@ -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();
return true;
}
bool RuntimeController::DispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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);
@ -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 {

View File

@ -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

View File

@ -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