diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index 9441c8dc9470c..c85ad66f8dc75 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -64,4 +64,6 @@ bool ExternalViewEmbedder::SupportsDynamicThreadMerging() { return false; } +void ExternalViewEmbedder::Teardown() {} + } // namespace flutter diff --git a/flow/embedded_views.h b/flow/embedded_views.h index c94d671752e0c..b5ff328eb0956 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -337,6 +337,11 @@ class ExternalViewEmbedder { // |RasterThreadMerger| instance. virtual bool SupportsDynamicThreadMerging(); + // Called when the rasterizer is being torn down. + // This method provides a way to release resources associated with the current + // embedder. + virtual void Teardown(); + FML_DISALLOW_COPY_AND_ASSIGN(ExternalViewEmbedder); }; // ExternalViewEmbedder diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index cc17ce762339c..9462fd6d78163 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -97,6 +97,10 @@ void Rasterizer::Teardown() { raster_thread_merger_->UnMergeNowIfLastOne(); raster_thread_merger_->SetMergeUnmergeCallback(nullptr); } + + if (external_view_embedder_) { + external_view_embedder_->Teardown(); + } } void Rasterizer::EnableThreadMergerIfNeeded() { diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index 08596ba8ad925..0c326eb950b03 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -298,4 +298,9 @@ bool AndroidExternalViewEmbedder::SupportsDynamicThreadMerging() { return true; } +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder::Teardown() { + surface_pool_->DestroyLayers(jni_facade_); +} + } // namespace flutter diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index a0386167418d1..278d7693e7661 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -73,6 +73,8 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { bool SupportsDynamicThreadMerging() override; + void Teardown() override; + // Gets the rect based on the device pixel ratio of a platform view displayed // on the screen. SkRect GetViewRect(int view_id) const; diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index 4e1014ac9ad3f..aa72b6b13f73f 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -883,5 +883,70 @@ TEST(AndroidExternalViewEmbedder, DisableThreadMerger) { ASSERT_FALSE(raster_thread_merger->IsMerged()); } +TEST(AndroidExternalViewEmbedder, Teardown) { + auto jni_mock = std::make_shared(); + auto android_context = + std::make_shared(AndroidRenderingAPI::kSoftware); + auto window = fml::MakeRefCounted(nullptr); + auto gr_context = GrDirectContext::MakeMock(nullptr); + auto frame_size = SkISize::Make(1000, 1000); + auto surface_factory = std::make_shared( + [&android_context, gr_context, window, frame_size]() { + auto surface_frame_1 = std::make_unique( + SkSurface::MakeNull(1000, 1000), false, + [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { + return true; + }); + + auto surface_mock = std::make_unique(); + EXPECT_CALL(*surface_mock, AcquireFrame(frame_size)) + .WillOnce(Return(ByMove(std::move(surface_frame_1)))); + + auto android_surface_mock = + std::make_unique(android_context); + EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true)); + EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get())) + .WillOnce(Return(ByMove(std::move(surface_mock)))); + + return android_surface_mock; + }); + + auto embedder = std::make_unique( + *android_context, jni_mock, surface_factory); + fml::Thread rasterizer_thread("rasterizer"); + auto raster_thread_merger = + GetThreadMergerFromPlatformThread(&rasterizer_thread); + + embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger); + + // Add an Android view. + MutatorsStack stack; + auto view_params = std::make_unique( + SkMatrix(), SkSize::Make(200, 200), stack); + + embedder->PrerollCompositeEmbeddedView(0, std::move(view_params)); + + // This simulates Flutter UI that intersects with the Android view. + embedder->CompositeEmbeddedView(0)->drawRect( + SkRect::MakeXYWH(50, 50, 200, 200), SkPaint()); + + // Create a new overlay surface. + EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface()) + .WillOnce(Return( + ByMove(std::make_unique( + 0, window)))); + + auto surface_frame = std::make_unique( + SkSurface::MakeNull(1000, 1000), false, + [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; }); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); + + embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger); + + EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()); + // Teardown. + embedder->Teardown(); +} + } // namespace testing } // namespace flutter