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

Commit 0ca8e1a

Browse files
author
Emmanuel Garcia
authored
Conditionally call FlutterViewDestroyOverlaySurfaces (#31464)
1 parent 70c1173 commit 0ca8e1a

File tree

6 files changed

+64
-10
lines changed

6 files changed

+64
-10
lines changed

shell/common/shell.cc

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -869,10 +869,13 @@ void Shell::OnPlatformViewDestroyed() {
869869
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetRasterTaskRunner(),
870870
raster_task);
871871
latch.Wait();
872-
// On Android, the external view embedder posts a task to the platform thread,
873-
// and waits until it completes.
874-
// As a result, the platform thread must not be blocked prior to calling
875-
// this method.
872+
// On Android, the external view embedder may post a task to the platform
873+
// thread, and wait until it completes if overlay surfaces must be released.
874+
// However, the platform thread might be blocked when Dart is initializing.
875+
// In this situation, calling TeardownExternalViewEmbedder is safe because no
876+
// platform views have been created before Flutter renders the first frame.
877+
// Overall, the longer term plan is to remove this implementation once
878+
// https://github.com/flutter/flutter/issues/96679 is fixed.
876879
rasterizer_->TeardownExternalViewEmbedder();
877880
}
878881

shell/platform/android/external_view_embedder/external_view_embedder.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ void AndroidExternalViewEmbedder::Teardown() {
309309

310310
// |ExternalViewEmbedder|
311311
void AndroidExternalViewEmbedder::DestroySurfaces() {
312+
if (!surface_pool_->HasLayers()) {
313+
return;
314+
}
312315
fml::AutoResetWaitableEvent latch;
313316
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetPlatformTaskRunner(),
314317
[&]() {

shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,5 +970,16 @@ TEST(AndroidExternalViewEmbedder, Teardown) {
970970
embedder->Teardown();
971971
}
972972

973+
TEST(AndroidExternalViewEmbedder, TeardownDoesNotCallJNIMethod) {
974+
auto jni_mock = std::make_shared<JNIMock>();
975+
auto android_context =
976+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
977+
auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
978+
*android_context, jni_mock, nullptr, GetTaskRunnersForFixture());
979+
980+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
981+
embedder->Teardown();
982+
}
983+
973984
} // namespace testing
974985
} // namespace flutter

shell/platform/android/external_view_embedder/surface_pool.cc

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ std::shared_ptr<OverlayLayer> SurfacePool::GetLayer(
2424
const AndroidContext& android_context,
2525
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
2626
std::shared_ptr<AndroidSurfaceFactory> surface_factory) {
27+
std::lock_guard lock(mutex_);
2728
// Destroy current layers in the pool if the frame size has changed.
2829
if (requested_frame_size_ != current_frame_size_) {
29-
DestroyLayers(jni_facade);
30+
DestroyLayersLocked(jni_facade);
3031
}
31-
3232
intptr_t gr_context_key = reinterpret_cast<intptr_t>(gr_context);
3333
// Allocate a new surface if there isn't one available.
3434
if (available_layer_index_ >= layers_.size()) {
@@ -56,6 +56,7 @@ std::shared_ptr<OverlayLayer> SurfacePool::GetLayer(
5656
layer->gr_context_key = gr_context_key;
5757
layers_.push_back(layer);
5858
}
59+
5960
std::shared_ptr<OverlayLayer> layer = layers_[available_layer_index_];
6061
// Since the surfaces are recycled, it's possible that the GrContext is
6162
// different.
@@ -73,19 +74,33 @@ std::shared_ptr<OverlayLayer> SurfacePool::GetLayer(
7374
}
7475

7576
void SurfacePool::RecycleLayers() {
77+
std::lock_guard lock(mutex_);
7678
available_layer_index_ = 0;
7779
}
7880

81+
bool SurfacePool::HasLayers() {
82+
std::lock_guard lock(mutex_);
83+
return layers_.size() > 0;
84+
}
85+
7986
void SurfacePool::DestroyLayers(
8087
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
81-
if (layers_.size() > 0) {
82-
jni_facade->FlutterViewDestroyOverlaySurfaces();
88+
std::lock_guard lock(mutex_);
89+
DestroyLayersLocked(jni_facade);
90+
}
91+
92+
void SurfacePool::DestroyLayersLocked(
93+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
94+
if (layers_.size() == 0) {
95+
return;
8396
}
97+
jni_facade->FlutterViewDestroyOverlaySurfaces();
8498
layers_.clear();
8599
available_layer_index_ = 0;
86100
}
87101

88102
std::vector<std::shared_ptr<OverlayLayer>> SurfacePool::GetUnusedLayers() {
103+
std::lock_guard lock(mutex_);
89104
std::vector<std::shared_ptr<OverlayLayer>> results;
90105
for (size_t i = available_layer_index_; i < layers_.size(); i++) {
91106
results.push_back(layers_[i]);
@@ -94,6 +109,7 @@ std::vector<std::shared_ptr<OverlayLayer>> SurfacePool::GetUnusedLayers() {
94109
}
95110

96111
void SurfacePool::SetFrameSize(SkISize frame_size) {
112+
std::lock_guard lock(mutex_);
97113
requested_frame_size_ = frame_size;
98114
}
99115

shell/platform/android/external_view_embedder/surface_pool.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_SURFACE_POOL_H_
66
#define FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_SURFACE_POOL_H_
77

8+
#include <mutex>
9+
810
#include "flutter/flow/surface.h"
911
#include "flutter/shell/platform/android/context/android_context.h"
1012
#include "flutter/shell/platform/android/surface/android_surface.h"
@@ -41,7 +43,6 @@ struct OverlayLayer {
4143
intptr_t gr_context_key;
4244
};
4345

44-
// This class isn't thread safe.
4546
class SurfacePool {
4647
public:
4748
SurfacePool();
@@ -72,6 +73,9 @@ class SurfacePool {
7273
// then they are deallocated as soon as |GetLayer| is called.
7374
void SetFrameSize(SkISize frame_size);
7475

76+
// Returns true if the current pool has layers in use.
77+
bool HasLayers();
78+
7579
private:
7680
// The index of the entry in the layers_ vector that determines the beginning
7781
// of the unused layers. For example, consider the following vector:
@@ -95,6 +99,11 @@ class SurfacePool {
9599

96100
// The frame size to be used by future layers.
97101
SkISize requested_frame_size_;
102+
103+
// Used to guard public methods.
104+
std::mutex mutex_;
105+
106+
void DestroyLayersLocked(std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
98107
};
99108

100109
} // namespace flutter

shell/platform/android/external_view_embedder/surface_pool_unittests.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ TEST(SurfacePool, GetLayerAllocateOneLayer) {
6262
auto layer = pool->GetLayer(gr_context.get(), *android_context, jni_mock,
6363
surface_factory);
6464

65+
ASSERT_TRUE(pool->HasLayers());
6566
ASSERT_NE(nullptr, layer);
6667
ASSERT_EQ(reinterpret_cast<intptr_t>(gr_context.get()),
6768
layer->gr_context_key);
@@ -96,6 +97,7 @@ TEST(SurfacePool, GetUnusedLayers) {
9697

9798
pool->RecycleLayers();
9899

100+
ASSERT_TRUE(pool->HasLayers());
99101
ASSERT_EQ(1UL, pool->GetUnusedLayers().size());
100102
ASSERT_EQ(layer, pool->GetUnusedLayers()[0]);
101103
}
@@ -137,6 +139,7 @@ TEST(SurfacePool, GetLayerRecycle) {
137139
auto layer_2 = pool->GetLayer(gr_context_2.get(), *android_context, jni_mock,
138140
surface_factory);
139141

142+
ASSERT_TRUE(pool->HasLayers());
140143
ASSERT_NE(nullptr, layer_1);
141144
ASSERT_EQ(layer_1, layer_2);
142145
ASSERT_EQ(reinterpret_cast<intptr_t>(gr_context_2.get()),
@@ -176,6 +179,8 @@ TEST(SurfacePool, GetLayerAllocateTwoLayers) {
176179
surface_factory);
177180
auto layer_2 = pool->GetLayer(gr_context.get(), *android_context, jni_mock,
178181
surface_factory);
182+
183+
ASSERT_TRUE(pool->HasLayers());
179184
ASSERT_NE(nullptr, layer_1);
180185
ASSERT_NE(nullptr, layer_2);
181186
ASSERT_NE(layer_1, layer_2);
@@ -213,9 +218,11 @@ TEST(SurfacePool, DestroyLayers) {
213218
pool->GetLayer(gr_context.get(), *android_context, jni_mock, surface_factory);
214219

215220
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces());
221+
222+
ASSERT_TRUE(pool->HasLayers());
216223
pool->DestroyLayers(jni_mock);
217224

218-
pool->RecycleLayers();
225+
ASSERT_FALSE(pool->HasLayers());
219226
ASSERT_TRUE(pool->GetUnusedLayers().empty());
220227
}
221228

@@ -246,8 +253,12 @@ TEST(SurfacePool, DestroyLayersFrameSizeChanged) {
246253
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
247254
0, window))));
248255

256+
ASSERT_FALSE(pool->HasLayers());
257+
249258
pool->GetLayer(gr_context.get(), *android_context, jni_mock, surface_factory);
250259

260+
ASSERT_TRUE(pool->HasLayers());
261+
251262
pool->SetFrameSize(SkISize::Make(20, 20));
252263
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(1);
253264
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
@@ -258,6 +269,7 @@ TEST(SurfacePool, DestroyLayersFrameSizeChanged) {
258269
pool->GetLayer(gr_context.get(), *android_context, jni_mock, surface_factory);
259270

260271
ASSERT_TRUE(pool->GetUnusedLayers().empty());
272+
ASSERT_TRUE(pool->HasLayers());
261273
}
262274

263275
} // namespace testing

0 commit comments

Comments
 (0)