Skip to content

[file_selector] Selecting very large files on Android causes OOM crash #141002

Open

Description

@CatKevin

Steps to reproduce

I opened a 300 MB file on the Android side using a component, and the application crashed. This happened multiple times.

Expected results

App crashes

Actual results

Throwing OutOfMemoryError "Failed to allocate a 346750536 byte allocation with 100663296 free bytes and 178MB until OOM, target footprint 450734840, growth limit 536870912" (VmSize 12973952 kB)

E/AndroidRuntime(20784): java.lang.OutOfMemoryError: Failed to allocate a 346750536 byte allocation with 100663296 free bytes and 178MB until OOM, target footprint 450734840, growth limit 536870912
E/AndroidRuntime(20784): 	at java.util.Arrays.copyOf(Arrays.java:3670)
E/AndroidRuntime(20784): 	at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:120)
E/AndroidRuntime(20784): 	at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:95)
E/AndroidRuntime(20784): 	at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:156)

Code sample

Code sample
final List<XFile> files = await openFiles();

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Details

[✓] Flutter (Channel stable, 3.16.5, on macOS 13.5.2 22G91 darwin-arm64, locale zh-Hans-CN)
    • Flutter version 3.16.5 on channel stable at /Users/kevin/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 78666c8dc5 (2 weeks ago), 2023-12-19 16:14:14 -0800
    • Engine revision 3f3e560236
    • Dart version 3.2.3
    • DevTools version 2.28.4

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /Users/kevin/Library/Android/sdk
    • Platform android-34, build-tools 33.0.1
    • ANDROID_HOME = /Users/kevin/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14E300c
    • CocoaPods version 1.14.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.80.0

[!] Proxy Configuration
    • HTTP_PROXY is set
    ! NO_PROXY is not set

[✓] Connected device (3 available)
    • 2304FPN6DC (mobile) • a2329c3d • android-arm64  • Android 13 (API 33)
    • macOS (desktop)     • macos    • darwin-arm64   • macOS 13.5.2 22G91 darwin-arm64
    • Chrome (web)        • chrome   • web-javascript • Google Chrome 120.0.6099.199

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.

Activity

  1. CatKevin commented on Jan 5, 2024

    @CatKevin
    Author

    We think the error occurred here, causing a memory overflow:
    image
    image

  2. changed the title [-][file_selector] Error code that crashes the app[/-] [+][file_selector] [serious] Error code that crashes the app[/+] on Jan 5, 2024
  3. added
    in triagePresently being triaged by the triage team
    on Jan 5, 2024
  4. dam-ease commented on Jan 5, 2024

    @dam-ease

    Thanks for filing this @CatKevin
    From the logs, this seems to be an OutOfMemory issue that occurs in android and might not be an issue with flutter itself
    Can you please see if this helps in your case https://stackoverflow.com/a/32245018?
    Also to further investigate this issue, could you help with a minimal complete reproducible code sample that doesn’t include 3rd party plugins or complex production code and possibly a file we could upload to reproduce this issue on our end?

  5. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Jan 5, 2024
  6. added
    packageflutter/packages repository. See also p: labels.
    team-androidOwned by Android platform team
    triaged-androidTriaged by Android platform team
    fyi-ecosystemFor the attention of Ecosystem team
    and removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    in triagePresently being triaged by the triage team
    on Jan 5, 2024
  7. stuartmorgan-g commented on Jan 5, 2024

    @stuartmorgan-g
    Contributor

    Currently we read and return the entire file contents, since Dart has no direct way to access a content resolver. That's not well suited to very large files, as in this case.

    #91869 has some discussion about making cross_file more feature-rich in ways that would allow things like having an implementation that would let file_selector return a content resolver reference instead, and then interact with it in other ways (e.g., streaming the content incrementally).

  8. changed the title [-][file_selector] [serious] Error code that crashes the app[/-] [+][file_selector] Selecting very large files causes OOM crash[/+] on Jan 5, 2024
  9. 15 remaining items

  10. ekuleshov commented on May 6, 2025

    @ekuleshov

    Yes, and a streaming API implemented via method channels would do that with a fixed overhead that we control (the chunk size), rather than an overhead equivalent to the size of the file.

    @stuartmorgan-g please correct me if I'm wrong. In my understanding the method channels currently don't support streaming and you are suggesting to build that support for all platforms? Is that right?

  11. stuartmorgan-g commented on May 6, 2025

    @stuartmorgan-g
    Contributor

    I'm not sure I understand the question. What do you mean by "method channels currently don't support streaming"? What would prevent sending a series of fixed-size chunks of data via method channels?

  12. ChristianEdwardPadilla commented on May 21, 2025

    @ChristianEdwardPadilla

    I agree that a stream-based change would be most robust, but I'd like to check again on the rationale for the byte[] in the first place and propose an improvement.

    The Java implementation packs the bytes and sends them to the Dart platform interface implementation which uses XFile.fromData:
    https://github.com/flutter/packages/blob/83d5dc91a08ea55579ec6c47b062040cefcb7636/packages/file_selector/file_selector_android/lib/src/file_selector_android.dart#L63

    But, the Java implementation actually also creates a duplicate file in the app's cache directory via a call to getPathFromCopyOfFileFromUri:
    https://github.com/flutter/packages/blob/83d5dc91a08ea55579ec6c47b062040cefcb7636/packages/file_selector/file_selector_android/android/src/main/java/dev/flutter/packages/file_selector_android/FileSelectorApiImpl.java#L357

    The resulting (potentially null) path is sent along with the byte[] to Dart but, I think, it's effectively unused by XFile.fromData.

    We could change the Java implementation to only pack the byte[] if the path generation above fails. Then, on the Dart side fall back to the byte[] if the path is null. In other words, change the Dart platform interface impl to something like this:

      XFile _xFileFromFileResponse(FileResponse file) {
        if (file.fileSelectorNativeException != null) {
          _resolveErrorCodeAndMaybeThrow(file.fileSelectorNativeException!);
        }
        if (file.path.isNotEmpty && file.path != 'FILE_SELECTOR_EXCEPTION') {
          return XFile(file.path, name: file.name, mimeType: file.mimeType);
        }
        return XFile.fromData(
          file.bytes,
          // Note: The name parameter is not used by XFile. The XFile.name returns
          // the extracted file name from XFile.path.
          name: file.name,
          length: file.size,
          mimeType: file.mimeType,
          path: file.path,
        );
      }
  13. stuartmorgan-g commented on May 22, 2025

    @stuartmorgan-g
    Contributor

    But, the Java implementation actually also creates a duplicate file in the app's cache directory via a call to getPathFromCopyOfFileFromUri

    I didn't realize this had been added (flutter/packages#6438); the original implementation didn't do this, it just read the bytes from the content provider and then sent them back.

    @camsim99 is there any reason to still send the bytes after your change, in the short term? (Long term we still need an abstraction that is not so filesystem-focused, to better handle Android.)

  14. ekuleshov commented on May 22, 2025

    @ekuleshov

    @stuartmorgan-g I'm still looking at the stream/chunk-based handling, but for the short term wouldn't it make more sense to use path to an existing files instead of copying bytes through channel and then accumulating then in the XFile.bytes? Essentially bloating memory with the large file content...

  15. camsim99 commented on May 22, 2025

    @camsim99
    Contributor

    #141002 (comment) seems like a reasonable solution to me. Of course, not copying when possible would be ideal, but IIRC we added the copy in flutter/packages#6438 to get the data from the URI to return a path instead of a URI and I'm not sure what the workaround is for that since accessing the files directly is discouraged by Android and unreliable.

  16. architjee commented on Oct 30, 2025

    @architjee
  17. stuartmorgan-g commented on Oct 30, 2025

    @stuartmorgan-g
  18. Laurie-Lin commented on May 13, 2026

    @Laurie-Lin
    Contributor

    I also encountered the same problem. Is there any update?

  19. CatKevin commented on May 13, 2026

    @CatKevin
    Author

    Please use file_picker instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: crashStack traces logged to the consolec: fatal crashCrashes that terminate the processcustomer: flask (g3)p: file_selectorThe file_selector pluginpackageflutter/packages repository. See also p: labels.team-androidOwned by Android platform teamtriaged-androidTriaged by Android platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions