Skip to content

[camera_android] Use WeakReference to prevent startImageStream OOM error when main thread hangs (flutter#166533) #9571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 14, 2025

Conversation

kwikwag
Copy link
Contributor

@kwikwag kwikwag commented Jul 7, 2025

This is an alternative solution to the pull request #8998

When streaming images using CameraController.startImageStream(), images are being post()-ed to the main looper in the Android implementation, even if it's hanging or paused. This will happen, for instance, when the Flutter debugger is paused or when the main thread is very busy. This can quickly result in an OOM (out-of-memory) error due to many images pending in queue, and the Android OS will kill the app abruptly.

This version of the fix is done by keep the frames (except for the latest one) as WeakReferences. When memory pressur is on, the runtime can free weak references, therefore dropping frames. A log message is emitted for each dropped frame. As opposed to the back-pressure solution, there is no hard limit to how many frames are kept in queue - this means that if the main thread is delayed in processing frames for some reason, they will pile up as long as the memory can sustain them.

Fixes flutter/flutter#166533 That issue also provides a demo program for testing the behavior.

Some more data and considerations are listed in the original pull request.

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

kwikwag added 11 commits April 4, 2025 02:10
…read paused (flutter#166533)

When streaming images using CameraController.startImageStream(), images are being post()-ed to the main looper even if it's halted. This is common when debugging. This quickly results in an OOM and the app crashes abruptly.

The fix is done by counting the number of images that have been posted to the main thread but have not yet arrived. If too many images are in transit (I arbitrarily chose 3 as the maximum allowable amount) subsequent frames are dropped, until the main thread receives the pending images.

A log message is emitted for each dropped frame.

Fixes flutter/flutter#166533

That issue also provides a demo program.
…read paused (flutter#166533)

When streaming images using CameraController.startImageStream(), images are being `post()`-ed to the main looper even if it's hanging or paused. This will happen, for instance, if the debugger is paused or the main thread is busy. This can quickly result in the OS killing the app abruptly with an OOM (out-of-memory) error.

This fixes it by using a `WeakReference` rather than a hard reference to the image data. If too much memory is used up, the runtime may release image frames that have not yet been processed.

A log message is emitted for each frame that was evicted before it was processed.
Copy link
Contributor

@reidbaker reidbaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@camsim99 can you spend extra time validating that you are happy with the test coverage of this new behavior. Async testing is tricky and we dont want to regress this feature.

import java.nio.ByteBuffer;

public class ImageStreamReaderTestUtils {
public static Image getImage(int imageWidth, int imageHeight, int padding, int imageFormat) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add java doc for this method

boolean postResult =
handler.post(
new Runnable() {
// a public field is required in order to test this code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This comment can be removed it does not add anything over the @visibleForTesing annotation.

@Override
public void run() {
final Map<String, Object> imageBuffer = weakImageBuffer.get();
if (imageBuffer == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is correct but can you add a comment here about why garbage collected image buffer is neither and error or success?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope the comment I added is sufficient?

@kwikwag
Copy link
Contributor Author

kwikwag commented Jul 8, 2025

Hey @reidbaker thanks for the review. I've addressed the comments, hopefully correctly. I also merged main. Let me know if there's anything else.

Copy link
Contributor

@camsim99 camsim99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, the test covers the cases well. LGTM!

@camsim99 camsim99 added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 14, 2025
@auto-submit auto-submit bot merged commit a86b6c9 into flutter:main Jul 14, 2025
78 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 17, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 17, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 17, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 17, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 17, 2025
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request Jul 17, 2025
flutter/packages@4a231ae...cb8fef6

2025-07-17 49699333+dependabot[bot]@users.noreply.github.com
[dependabot]: Bump androidx.activity:activity from 1.9.3 to 1.10.1 in
/packages/image_picker/image_picker_android/android
(flutter/packages#8725)
2025-07-17 stuartmorgan@google.com [webview_flutter] Update
androidx.webkit to 1.14.0 (flutter/packages#9638)
2025-07-17 engine-flutter-autoroll@skia.org Roll Flutter from
c2739f0 to 9c626d9 (18 revisions) (flutter/packages#9641)
2025-07-17 engine-flutter-autoroll@skia.org Roll Flutter (stable) from
077b4a4 to d7b523b (3 revisions) (flutter/packages#9640)
2025-07-17 stuartmorgan@google.com Fix Gemini note wrapping
(flutter/packages#9639)
2025-07-17 49699333+dependabot[bot]@users.noreply.github.com
[dependabot]: Bump com.google.android.gms:play-services-maps from 18.2.0
to 19.2.0 in
/packages/google_maps_flutter/google_maps_flutter_android/android
(flutter/packages#9120)
2025-07-17 49699333+dependabot[bot]@users.noreply.github.com
[dependabot]: Bump androidx.fragment:fragment from 1.6.2 to 1.8.8 in
/packages/local_auth/local_auth_android/android (flutter/packages#9406)
2025-07-16 stuartmorgan@google.com [ci] Add Gemini Code Assist review
config (flutter/packages#9632)
2025-07-16 engine-flutter-autoroll@skia.org Roll Flutter from
cc3110c to c2739f0 (15 revisions) (flutter/packages#9633)
2025-07-16 105786499+syedaniq@users.noreply.github.com [image_picker]
redesign example app (flutter/packages#9625)
2025-07-16 robert.odrowaz@leancode.pl [camera_avfoundation]
Implementation swift migration - part 7 (flutter/packages#9595)
2025-07-15 10687576+bparrishMines@users.noreply.github.com
[webview_flutter_wkwebview] Replace Flutter method failure assertion
with nslog (flutter/packages#9587)
2025-07-15 engine-flutter-autoroll@skia.org Roll Flutter from
a930ec1 to cc3110c (24 revisions) (flutter/packages#9631)
2025-07-15 stuartmorgan@google.com [webview_flutter] Add
setMixedContentMode for Android (flutter/packages#9586)
2025-07-15 stuartmorgan@google.com [google_sign_in] Add exception info
to migration guide (flutter/packages#9574)
2025-07-14 392199+kwikwag@users.noreply.github.com [camera_android] Use
WeakReference to prevent startImageStream OOM error when main thread
hangs (#166533) (flutter/packages#9571)
2025-07-14 jason-simmons@users.noreply.github.com [quick_actions]
Restore the appShortcutLaunchActivityAfterStarting test in
quick_actions_android (flutter/packages#9508)
2025-07-14 engine-flutter-autoroll@skia.org Roll Flutter from
35f197f to a930ec1 (3 revisions) (flutter/packages#9624)
2025-07-14 49699333+dependabot[bot]@users.noreply.github.com
[dependabot]: Bump com.android.tools.build:gradle from 8.9.1 to 8.11.1
in /packages/pigeon/platform_tests/test_plugin/android
(flutter/packages#9618)
2025-07-12 engine-flutter-autoroll@skia.org Roll Flutter from
43657f3 to 35f197f (39 revisions) (flutter/packages#9602)
2025-07-11 stuartmorgan@google.com Replace popularity badges
(flutter/packages#9594)
2025-07-11 1961493+harryterkelsen@users.noreply.github.com [rfw] Update
test to not depend on toString() (flutter/packages#9590)
2025-07-11 robert.odrowaz@leancode.pl [camera_avfoundation]
Implementation swift migration - part 6 (flutter/packages#9588)
2025-07-10 52160996+FMorschel@users.noreply.github.com [url_launcher]
Fixes new unnecessary boolean operations warnings
(flutter/packages#9409)
2025-07-10 stuartmorgan@google.com [google_sign_in] Add troubleshooting
to Android README (flutter/packages#9581)
2025-07-10 engine-flutter-autoroll@skia.org Roll Flutter from
ac12f66 to 43657f3 (25 revisions) (flutter/packages#9589)
2025-07-10 32538273+ValentinVignal@users.noreply.github.com
[go_router_builder] Update case sensitive test to `go_router` 16.0.0
(flutter/packages#9482)
2025-07-09 737941+loic-sharma@users.noreply.github.com [rfw] Remove the
RFW WASM example (flutter/packages#9551)
2025-07-09 engine-flutter-autoroll@skia.org Roll Flutter (stable) from
fcf2c11 to 077b4a4 (5 revisions) (flutter/packages#9585)
2025-07-09 engine-flutter-autoroll@skia.org Roll Flutter from
adffe24 to ac12f66 (28 revisions) (flutter/packages#9584)
2025-07-09 malo.allee@gmail.com [video_player] Add html 5 video poster
support (thumbnail) as a VideoPlayerWebOptions (flutter/packages#8940)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App p: camera platform-android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[camera_android][0.10.10+2] Pausing the debugger (reaching a breakpoint) after startImageStream() causes memory leak, then OOM crash
3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy