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

Commit 96e6410

Browse files
committed
Modify according to review comments.
1 parent edeb1dc commit 96e6410

File tree

7 files changed

+75
-90
lines changed

7 files changed

+75
-90
lines changed

shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
package io.flutter.embedding.android;
66

7-
import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
87
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
98
import static io.flutter.embedding.android.FlutterActivityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
109

@@ -849,22 +848,6 @@ void onTrimMemory(int level) {
849848
}
850849
}
851850

852-
/**
853-
* Invoke this from {@link android.app.Activity#onLowMemory()}.
854-
*
855-
* <p>A {@code Fragment} host must have its containing {@code Activity} forward this call so that
856-
* the {@code Fragment} can then invoke this method.
857-
*
858-
* <p>This method sends a "memory pressure warning" message to Flutter over the "system channel".
859-
*/
860-
void onLowMemory() {
861-
Log.v(TAG, "Forwarding onLowMemory() to FlutterEngine.");
862-
ensureAlive();
863-
flutterEngine.getDartExecutor().notifyLowMemoryWarning();
864-
flutterEngine.getSystemChannel().sendMemoryPressureWarning();
865-
flutterEngine.getRenderer().onTrimMemory(TRIM_MEMORY_COMPLETE);
866-
}
867-
868851
/**
869852
* Ensures that this delegate has not been {@link #release()}'ed.
870853
*

shell/platform/android/io/flutter/embedding/android/FlutterFragment.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -980,19 +980,6 @@ public void onTrimMemory(int level) {
980980
}
981981
}
982982

983-
/**
984-
* Callback invoked when memory is low.
985-
*
986-
* <p>This implementation forwards a memory pressure warning to the running Flutter app.
987-
*/
988-
@Override
989-
public void onLowMemory() {
990-
super.onLowMemory();
991-
if (stillAttachedForEvent("onLowMemory")) {
992-
delegate.onLowMemory();
993-
}
994-
}
995-
996983
/**
997984
* {@link FlutterActivityAndFragmentDelegate.Host} method that is used by {@link
998985
* FlutterActivityAndFragmentDelegate} to obtain Flutter shell arguments when initializing

shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@
1313
import android.view.Surface;
1414
import androidx.annotation.NonNull;
1515
import androidx.annotation.Nullable;
16+
import androidx.annotation.VisibleForTesting;
1617
import io.flutter.Log;
1718
import io.flutter.embedding.engine.FlutterJNI;
1819
import io.flutter.view.TextureRegistry;
20+
import java.lang.ref.WeakReference;
1921
import java.nio.ByteBuffer;
2022
import java.util.ArrayList;
23+
import java.util.HashSet;
24+
import java.util.Iterator;
2125
import java.util.List;
2226
import java.util.Set;
23-
import java.util.concurrent.CopyOnWriteArraySet;
2427
import java.util.concurrent.atomic.AtomicLong;
2528

2629
/**
@@ -47,8 +50,8 @@ public class FlutterRenderer implements TextureRegistry {
4750
private Handler handler = new Handler();
4851

4952
@NonNull
50-
private final Set<TextureRegistry.OnLowMemoryListener> onLowMemoryListeners =
51-
new CopyOnWriteArraySet<>();
53+
private final Set<WeakReference<TextureRegistry.OnTrimMemoryListener>> onTrimMemoryListeners =
54+
new HashSet<>();
5255

5356
@NonNull
5457
private final FlutterUiDisplayListener flutterUiDisplayListener =
@@ -98,16 +101,25 @@ public void removeIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListene
98101
}
99102

100103
/** Adds a listener that is invoked when a memory pressure warning was forward. */
101-
public void addOnLowMemoryListener(@NonNull OnLowMemoryListener listener) {
102-
onLowMemoryListeners.add(listener);
104+
@VisibleForTesting
105+
/* package */ void addOnTrimMemoryListener(@NonNull OnTrimMemoryListener listener) {
106+
onTrimMemoryListeners.add(new WeakReference<>(listener));
103107
}
104108

105109
/**
106-
* Removes a {@link OnLowMemoryListener} that was added with {@link
107-
* #addOnLowMemoryListener(OnLowMemoryListener)}.
110+
* Removes a {@link OnTrimMemoryListener} that was added with {@link
111+
* #addOnTrimMemoryListener(OnTrimMemoryListener)}.
108112
*/
109-
public void removeOnLowMemoryListener(@NonNull OnLowMemoryListener listener) {
110-
onLowMemoryListeners.remove(listener);
113+
@VisibleForTesting
114+
/* package */ void removeOnTrimMemoryListener(@NonNull OnTrimMemoryListener listener) {
115+
final Iterator<WeakReference<OnTrimMemoryListener>> iterator = onTrimMemoryListeners.iterator();
116+
while (iterator.hasNext()) {
117+
final WeakReference<OnTrimMemoryListener> listenerRef = iterator.next();
118+
if (listenerRef.get() == listener) {
119+
iterator.remove();
120+
break;
121+
}
122+
}
111123
}
112124

113125
// ------ START TextureRegistry IMPLEMENTATION -----
@@ -133,23 +145,34 @@ public SurfaceTextureEntry registerSurfaceTexture(@NonNull SurfaceTexture surfac
133145
new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
134146
Log.v(TAG, "New SurfaceTexture ID: " + entry.id());
135147
registerTexture(entry.id(), entry.textureWrapper());
136-
addOnLowMemoryListener(entry);
148+
addOnTrimMemoryListener(entry);
137149
return entry;
138150
}
139151

140152
@Override
141153
public void onTrimMemory(int level) {
142-
for (TextureRegistry.OnLowMemoryListener listener : onLowMemoryListeners) {
143-
listener.onLowMemory(level);
154+
Set<WeakReference<OnTrimMemoryListener>> listenerToBeDeleted = new HashSet<>();
155+
for (WeakReference<OnTrimMemoryListener> listenerRef : onTrimMemoryListeners) {
156+
final OnTrimMemoryListener listener = listenerRef.get();
157+
if (listener != null) {
158+
listener.onTrimMemory(level);
159+
} else {
160+
listenerToBeDeleted.add(listenerRef);
161+
}
162+
}
163+
164+
// Purge cleared refs lazily to avoid accumulating a lot of dead listener.
165+
for (WeakReference<OnTrimMemoryListener> listenerRef : listenerToBeDeleted) {
166+
onTrimMemoryListeners.remove(listenerRef);
144167
}
145168
}
146169

147170
final class SurfaceTextureRegistryEntry
148-
implements TextureRegistry.SurfaceTextureEntry, TextureRegistry.OnLowMemoryListener {
171+
implements TextureRegistry.SurfaceTextureEntry, TextureRegistry.OnTrimMemoryListener {
149172
private final long id;
150173
@NonNull private final SurfaceTextureWrapper textureWrapper;
151174
private boolean released;
152-
@Nullable private OnLowMemoryListener lowMemoryListener;
175+
@Nullable private OnTrimMemoryListener trimMemoryListener;
153176
@Nullable private OnFrameConsumedListener frameConsumedListener;
154177
private final Runnable onFrameConsumed =
155178
new Runnable() {
@@ -181,9 +204,9 @@ public void run() {
181204
}
182205

183206
@Override
184-
public void onLowMemory(int level) {
185-
if (lowMemoryListener != null) {
186-
lowMemoryListener.onLowMemory(level);
207+
public void onTrimMemory(int level) {
208+
if (trimMemoryListener != null) {
209+
trimMemoryListener.onTrimMemory(level);
187210
}
188211
}
189212

@@ -203,7 +226,7 @@ public void onFrameAvailable(@NonNull SurfaceTexture texture) {
203226
};
204227

205228
private void removeListener() {
206-
removeOnLowMemoryListener(this);
229+
removeOnTrimMemoryListener(this);
207230
}
208231

209232
@NonNull
@@ -241,17 +264,7 @@ protected void finalize() throws Throwable {
241264
return;
242265
}
243266

244-
handler.post(
245-
new Runnable() {
246-
@Override
247-
public void run() {
248-
if (!flutterJNI.isAttached()) {
249-
return;
250-
}
251-
unregisterTexture(id);
252-
removeListener();
253-
}
254-
});
267+
handler.post(new SurfaceTextureFinalizerRunnable(id, flutterJNI));
255268
} finally {
256269
super.finalize();
257270
}
@@ -263,8 +276,27 @@ public void setOnFrameConsumedListener(@Nullable OnFrameConsumedListener listene
263276
}
264277

265278
@Override
266-
public void setOnLowMemoryListener(@Nullable OnLowMemoryListener listener) {
267-
lowMemoryListener = listener;
279+
public void setOnTrimMemoryListener(@Nullable OnTrimMemoryListener listener) {
280+
trimMemoryListener = listener;
281+
}
282+
}
283+
284+
static final class SurfaceTextureFinalizerRunnable implements Runnable {
285+
private final long id;
286+
private final FlutterJNI flutterJNI;
287+
288+
SurfaceTextureFinalizerRunnable(long id, @NonNull FlutterJNI flutterJNI) {
289+
this.id = id;
290+
this.flutterJNI = flutterJNI;
291+
}
292+
293+
@Override
294+
public void run() {
295+
if (!flutterJNI.isAttached()) {
296+
return;
297+
}
298+
Log.v(TAG, "Releasing a SurfaceTexture (" + id + ").");
299+
flutterJNI.unregisterTexture(id);
268300
}
269301
}
270302
// ------ END TextureRegistry IMPLEMENTATION ----

shell/platform/android/io/flutter/plugin/platform/PlatformViewWrapper.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,15 @@ public void onFrameConsumed() {
6969
};
7070

7171
private boolean shouldRecreateSurfaceForLowMemory = false;
72-
private final TextureRegistry.OnLowMemoryListener lowMemoryListener =
73-
new TextureRegistry.OnLowMemoryListener() {
72+
private final TextureRegistry.OnTrimMemoryListener trimMemoryListener =
73+
new TextureRegistry.OnTrimMemoryListener() {
7474
@Override
75-
public void onLowMemory(int level) {
75+
public void onTrimMemory(int level) {
7676
// When a memory pressure warning is received and the level equal {@code
7777
// ComponentCallbacks2.TRIM_MEMORY_COMPLETE}, the Android system release the underlying
7878
// surface. If we continue to use the surface (e.g., call lockHardwareCanvas), a crash
7979
// occurs, and we found that this crash appeared on Android10 and above.
80+
// See https://github.com/flutter/flutter/issues/103870 for more details.
8081
//
8182
// Here our workaround is to recreate the surface before using it.
8283
if (level == TRIM_MEMORY_COMPLETE && Build.VERSION.SDK_INT >= 29) {
@@ -117,7 +118,7 @@ public PlatformViewWrapper(
117118
@NonNull Context context, @NonNull TextureRegistry.SurfaceTextureEntry textureEntry) {
118119
this(context);
119120
textureEntry.setOnFrameConsumedListener(frameConsumedListener);
120-
textureEntry.setOnLowMemoryListener(lowMemoryListener);
121+
textureEntry.setOnTrimMemoryListener(trimMemoryListener);
121122
setTexture(textureEntry.surfaceTexture());
122123
}
123124

shell/platform/android/io/flutter/view/TextureRegistry.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ interface SurfaceTextureEntry {
5454
default void setOnFrameConsumedListener(@Nullable OnFrameConsumedListener listener) {}
5555

5656
/** Set a listener that will be notified when a memory pressure warning was forward. */
57-
default void setOnLowMemoryListener(@Nullable OnLowMemoryListener listener) {}
57+
default void setOnTrimMemoryListener(@Nullable OnTrimMemoryListener listener) {}
5858
}
5959

6060
/** Listener invoked when the most recent image has been consumed. */
@@ -67,8 +67,8 @@ interface OnFrameConsumedListener {
6767
}
6868

6969
/** Listener invoked when a memory pressure warning was forward. */
70-
interface OnLowMemoryListener {
70+
interface OnTrimMemoryListener {
7171
/** This method will be invoked when a memory pressure warning was forward. */
72-
void onLowMemory(int level);
72+
void onTrimMemory(int level);
7373
}
7474
}

shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -863,23 +863,6 @@ public void itNotifiesDartExecutorAndSendsMessageOverSystemChannelWhenToldToTrim
863863
verify(mockFlutterEngine.getSystemChannel(), times(6)).sendMemoryPressureWarning();
864864
}
865865

866-
@Test
867-
public void itNotifiesDartExecutorAndSendsMessageOverSystemChannelWhenInformedOfLowMemory() {
868-
// Create the real object that we're testing.
869-
FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost);
870-
871-
// --- Execute the behavior under test ---
872-
// The FlutterEngine is set up in onAttach().
873-
delegate.onAttach(ctx);
874-
875-
// Emulate the host and call the method that we expect to be forwarded.
876-
delegate.onLowMemory();
877-
878-
// Verify that the call was forwarded to the engine.
879-
verify(mockFlutterEngine.getDartExecutor(), times(1)).notifyLowMemoryWarning();
880-
verify(mockFlutterEngine.getSystemChannel(), times(1)).sendMemoryPressureWarning();
881-
}
882-
883866
@Test
884867
public void itDestroysItsOwnEngineIfHostRequestsIt() {
885868
// ---- Test setup ----

shell/platform/android/test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,18 +347,17 @@ public void itNotifySurfaceTextureEntryWhenMemoryPressureWarning() {
347347
FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI);
348348

349349
AtomicInteger invocationCount = new AtomicInteger(0);
350-
final TextureRegistry.OnLowMemoryListener listener =
351-
new TextureRegistry.OnLowMemoryListener() {
350+
final TextureRegistry.OnTrimMemoryListener listener =
351+
new TextureRegistry.OnTrimMemoryListener() {
352352
@Override
353-
public void onLowMemory(int level) {
353+
public void onTrimMemory(int level) {
354354
invocationCount.incrementAndGet();
355355
}
356356
};
357357

358358
FlutterRenderer.SurfaceTextureRegistryEntry entry =
359359
(FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture();
360-
entry.setOnLowMemoryListener(listener);
361-
flutterRenderer.addOnLowMemoryListener(entry);
360+
entry.setOnTrimMemoryListener(listener);
362361

363362
// Execute the behavior under test.
364363
flutterRenderer.onTrimMemory(TRIM_MEMORY_COMPLETE);

0 commit comments

Comments
 (0)