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

Commit 8636f6e

Browse files
committed
Workaround HardwareRenderer breakage in Android 14
- Destroy ImageReaders on memory trim. - Unset the VirtualDisplay's surface on memory trim. - On resume, recreate ImageReaders. - On resume, do a dumb little dance and then set the VirtualDisplay's surface Fixes: flutter/flutter#146499 Fixes: flutter/flutter#144219 Internal bug: b/335646931 Android Fix: https://googleplex-android-review.git.corp.google.com/c/platform/frameworks/base/+/27015418 Unclear when the Android fix will be available in phones.
1 parent c093562 commit 8636f6e

File tree

4 files changed

+69
-4
lines changed

4 files changed

+69
-4
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,6 @@ public boolean onPreDraw() {
560560
* lifecycle.
561561
*/
562562
void onResume() {
563-
Log.v(TAG, "onResume()");
564563
ensureAlive();
565564
if (host.shouldDispatchAppLifecycleState() && flutterEngine != null) {
566565
flutterEngine.getLifecycleChannel().appIsResumed();
@@ -579,10 +578,10 @@ void onResume() {
579578
// TODO(mattcarroll): determine why this can't be in onResume(). Comment reason, or move if
580579
// possible.
581580
void onPostResume() {
582-
Log.v(TAG, "onPostResume()");
583581
ensureAlive();
584582
if (flutterEngine != null) {
585583
updateSystemUiOverlays();
584+
flutterEngine.getPlatformViewsController().onResume();
586585
} else {
587586
Log.w(TAG, "onPostResume() invoked before FlutterFragment was attached to an Activity.");
588587
}
@@ -1020,6 +1019,7 @@ void onTrimMemory(int level) {
10201019
flutterEngine.getSystemChannel().sendMemoryPressureWarning();
10211020
}
10221021
flutterEngine.getRenderer().onTrimMemory(level);
1022+
flutterEngine.getPlatformViewsController().onTrimMemory(level);
10231023
}
10241024
}
10251025

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import static io.flutter.Build.API_LEVELS;
88

99
import android.annotation.TargetApi;
10+
import android.content.ComponentCallbacks2;
1011
import android.graphics.Bitmap;
1112
import android.graphics.ImageFormat;
1213
import android.graphics.Rect;
@@ -421,14 +422,16 @@ final class ImageReaderSurfaceProducer
421422
// If we cleanup the ImageReaders on memory pressure it breaks VirtualDisplay
422423
// backed platform views. Disable for now as this is only necessary to work
423424
// around a Samsung-specific Android 14 bug.
424-
private static final boolean CLEANUP_ON_MEMORY_PRESSURE = false;
425+
private static final boolean CLEANUP_ON_MEMORY_PRESSURE = true;
425426

426427
private final long id;
427428

428429
private boolean released;
429430
// Will be true in tests and on Android API < 33.
430431
private boolean ignoringFence = false;
431432

433+
private boolean trimOnMemoryPressure = CLEANUP_ON_MEMORY_PRESSURE;
434+
432435
// The requested width and height are updated by setSize.
433436
private int requestedWidth = 1;
434437
private int requestedHeight = 1;
@@ -659,7 +662,10 @@ PerImage dequeueImage() {
659662

660663
@Override
661664
public void onTrimMemory(int level) {
662-
if (!CLEANUP_ON_MEMORY_PRESSURE) {
665+
if (!trimOnMemoryPressure) {
666+
return;
667+
}
668+
if (level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
663669
return;
664670
}
665671
cleanup();

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static io.flutter.Build.API_LEVELS;
1010

1111
import android.annotation.TargetApi;
12+
import android.content.ComponentCallbacks2;
1213
import android.content.Context;
1314
import android.content.MutableContextWrapper;
1415
import android.os.Build;
@@ -1053,6 +1054,21 @@ private void diposeAllViews() {
10531054
}
10541055
}
10551056

1057+
public void onTrimMemory(int level) {
1058+
if (level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
1059+
return;
1060+
}
1061+
for (VirtualDisplayController vdc : vdControllers.values()) {
1062+
vdc.clearSurface();
1063+
}
1064+
}
1065+
1066+
public void onResume() {
1067+
for (VirtualDisplayController vdc : vdControllers.values()) {
1068+
vdc.resetSurface();
1069+
}
1070+
}
1071+
10561072
/**
10571073
* Disposes a single
10581074
*

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,49 @@ public void dispatchTouchEvent(MotionEvent event) {
284284
presentation.dispatchTouchEvent(event);
285285
}
286286

287+
public void clearSurface() {
288+
virtualDisplay.setSurface(null);
289+
}
290+
291+
public void resetSurface() {
292+
final int width = getRenderTargetWidth();
293+
final int height = getRenderTargetHeight();
294+
final boolean isFocused = getView().isFocused();
295+
final SingleViewPresentation.PresentationState presentationState = presentation.detachState();
296+
297+
// We detach the surface to prevent it being destroyed when releasing the vd.
298+
virtualDisplay.setSurface(null);
299+
virtualDisplay.release();
300+
final DisplayManager displayManager =
301+
(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
302+
int flags = 0;
303+
virtualDisplay =
304+
displayManager.createVirtualDisplay(
305+
"flutter-vd#" + viewId,
306+
width,
307+
height,
308+
densityDpi,
309+
renderTarget.getSurface(),
310+
flags,
311+
callback,
312+
null /* handler */);
313+
// Create a new SingleViewPresentation and show() it before we cancel() the existing
314+
// presentation. Calling show() and cancel() in this order fixes
315+
// https://github.com/flutter/flutter/issues/26345 and maintains seamless transition
316+
// of the contents of the presentation.
317+
SingleViewPresentation newPresentation =
318+
new SingleViewPresentation(
319+
context,
320+
virtualDisplay.getDisplay(),
321+
accessibilityEventsDelegate,
322+
presentationState,
323+
focusChangeListener,
324+
isFocused);
325+
newPresentation.show();
326+
presentation.cancel();
327+
presentation = newPresentation;
328+
}
329+
287330
static class OneTimeOnDrawListener implements ViewTreeObserver.OnDrawListener {
288331
static void schedule(View view, Runnable runnable) {
289332
OneTimeOnDrawListener listener = new OneTimeOnDrawListener(view, runnable);

0 commit comments

Comments
 (0)