Skip to content

[camera_android_camerax] takePicture creates a single-thread executor per capture that is never shut down #190523

Closed
flutter/packages
#12361

Description

@toyaji

What package does this bug report belong to?

camera

What target platforms are you seeing this bug on?

Android

Have you already upgraded your packages?

Yes

Dependency versions

The example depends on the plugin by path, so the version below is the working tree rather than a published one. The code this report is about is unchanged in 0.7.4+3 on pub.dev and on main.

pubspec.lock
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
  async:
    dependency: transitive
    description:
      name: async
      sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
      url: "https://pub.dev"
    source: hosted
    version: "2.13.1"
  boolean_selector:
    dependency: transitive
    description:
      name: boolean_selector
      sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.2"
  camera_android_camerax:
    dependency: "direct main"
    description:
      path: ".."
      relative: true
    source: path
    version: "0.7.4+4"
  camera_platform_interface:
    dependency: "direct main"
    description:
      name: camera_platform_interface
      sha256: "4524ca6eb4176b066864036ad4fe02c3e4863e63b77eadc21a5bf56824f43498"
      url: "https://pub.dev"
    source: hosted
    version: "2.13.1"
  characters:
    dependency: transitive
    description:
      name: characters
      sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
      url: "https://pub.dev"
    source: hosted
    version: "1.4.1"
  clock:
    dependency: transitive
    description:
      name: clock
      sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
      url: "https://pub.dev"
    source: hosted
    version: "1.1.2"
  collection:
    dependency: transitive
    description:
      name: collection
      sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
      url: "https://pub.dev"
    source: hosted
    version: "1.19.1"
  cross_file:
    dependency: transitive
    description:
      name: cross_file
      sha256: "92c9c43c383bfa1c32079d3bc492d55d6d4318044b7b47edaff8971cbb555c51"
      url: "https://pub.dev"
    source: hosted
    version: "0.3.5+4"
  csslib:
    dependency: transitive
    description:
      name: csslib
      sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
      url: "https://pub.dev"
    source: hosted
    version: "1.0.2"
  espresso:
    dependency: "direct dev"
    description:
      name: espresso
      sha256: "67e4c4ecb57612c85ad7d7617f6c1414ced1afa41f217fd6399a917be4f4a4cd"
      url: "https://pub.dev"
    source: hosted
    version: "0.4.0+25"
  fake_async:
    dependency: transitive
    description:
      name: fake_async
      sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
      url: "https://pub.dev"
    source: hosted
    version: "1.3.3"
  file:
    dependency: transitive
    description:
      name: file
      sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
      url: "https://pub.dev"
    source: hosted
    version: "7.0.1"
  flutter:
    dependency: "direct main"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_driver:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_test:
    dependency: "direct dev"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_web_plugins:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  fuchsia_remote_debug_protocol:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  html:
    dependency: transitive
    description:
      name: html
      sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602"
      url: "https://pub.dev"
    source: hosted
    version: "0.15.6"
  integration_test:
    dependency: "direct dev"
    description: flutter
    source: sdk
    version: "0.0.0"
  leak_tracker:
    dependency: transitive
    description:
      name: leak_tracker
      sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
      url: "https://pub.dev"
    source: hosted
    version: "11.0.2"
  leak_tracker_flutter_testing:
    dependency: transitive
    description:
      name: leak_tracker_flutter_testing
      sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.10"
  leak_tracker_testing:
    dependency: transitive
    description:
      name: leak_tracker_testing
      sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
      url: "https://pub.dev"
    source: hosted
    version: "3.0.2"
  matcher:
    dependency: transitive
    description:
      name: matcher
      sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
      url: "https://pub.dev"
    source: hosted
    version: "0.12.19"
  material_color_utilities:
    dependency: transitive
    description:
      name: material_color_utilities
      sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
      url: "https://pub.dev"
    source: hosted
    version: "0.13.0"
  meta:
    dependency: transitive
    description:
      name: meta
      sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
      url: "https://pub.dev"
    source: hosted
    version: "1.18.0"
  path:
    dependency: transitive
    description:
      name: path
      sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
      url: "https://pub.dev"
    source: hosted
    version: "1.9.1"
  platform:
    dependency: transitive
    description:
      name: platform
      sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
      url: "https://pub.dev"
    source: hosted
    version: "3.1.6"
  plugin_platform_interface:
    dependency: transitive
    description:
      name: plugin_platform_interface
      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.8"
  process:
    dependency: transitive
    description:
      name: process
      sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744
      url: "https://pub.dev"
    source: hosted
    version: "5.0.5"
  sky_engine:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  source_span:
    dependency: transitive
    description:
      name: source_span
      sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
      url: "https://pub.dev"
    source: hosted
    version: "1.10.2"
  stack_trace:
    dependency: transitive
    description:
      name: stack_trace
      sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
      url: "https://pub.dev"
    source: hosted
    version: "1.12.1"
  stream_channel:
    dependency: transitive
    description:
      name: stream_channel
      sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.4"
  stream_transform:
    dependency: transitive
    description:
      name: stream_transform
      sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
      url: "https://pub.dev"
    source: hosted
    version: "2.1.1"
  string_scanner:
    dependency: transitive
    description:
      name: string_scanner
      sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
      url: "https://pub.dev"
    source: hosted
    version: "1.4.1"
  sync_http:
    dependency: transitive
    description:
      name: sync_http
      sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
      url: "https://pub.dev"
    source: hosted
    version: "0.3.1"
  term_glyph:
    dependency: transitive
    description:
      name: term_glyph
      sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
      url: "https://pub.dev"
    source: hosted
    version: "1.2.2"
  test_api:
    dependency: transitive
    description:
      name: test_api
      sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
      url: "https://pub.dev"
    source: hosted
    version: "0.7.11"
  vector_math:
    dependency: transitive
    description:
      name: vector_math
      sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
      url: "https://pub.dev"
    source: hosted
    version: "2.2.0"
  video_player:
    dependency: "direct main"
    description:
      name: video_player
      sha256: "20ef311160e2ced020a62f38e4cc399a1bf289e722fc5fe37c9d7b18e44c9e8d"
      url: "https://pub.dev"
    source: hosted
    version: "2.13.0"
  video_player_android:
    dependency: transitive
    description:
      name: video_player_android
      sha256: e229676f8fade3e0124482495aaa2b548872cc4018b6268adfca4868be16aa74
      url: "https://pub.dev"
    source: hosted
    version: "2.12.0"
  video_player_avfoundation:
    dependency: transitive
    description:
      name: video_player_avfoundation
      sha256: c238f5f0a26845cd0bcc2956049b63065a4d3c40ddfc22c3414cd170bef7fff9
      url: "https://pub.dev"
    source: hosted
    version: "2.11.0"
  video_player_platform_interface:
    dependency: transitive
    description:
      name: video_player_platform_interface
      sha256: "92c0fbabe20c788e71fd10d26cea998d0d253282e65d145aed0818731cf593ce"
      url: "https://pub.dev"
    source: hosted
    version: "6.9.0"
  video_player_web:
    dependency: transitive
    description:
      name: video_player_web
      sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb"
      url: "https://pub.dev"
    source: hosted
    version: "2.4.0"
  vm_service:
    dependency: transitive
    description:
      name: vm_service
      sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
      url: "https://pub.dev"
    source: hosted
    version: "15.2.0"
  web:
    dependency: transitive
    description:
      name: web
      sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
      url: "https://pub.dev"
    source: hosted
    version: "1.1.1"
  webdriver:
    dependency: transitive
    description:
      name: webdriver
      sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade"
      url: "https://pub.dev"
    source: hosted
    version: "3.1.0"
sdks:
  dart: ">=3.12.0 <4.0.0"
  flutter: ">=3.44.0"

Steps to reproduce

  1. Run the camera_android_camerax example on an Android device.
  2. Take a photo.
  3. Inspect the app's threads, e.g. in the Android Studio profiler or with adb shell ps -T -p $(adb shell pidof io.flutter.plugins.cameraxexample), and look for a pool-*-thread-* entry that outlives the capture.

Expected results

Taking a photo does not create a thread that the plugin never shuts down.

Actual results

Every capture creates one, by allocating its own executor:

https://github.com/flutter/packages/blob/3498b9d7b67143a68dc43b90951acb577e92f64e/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureProxyApi.java#L108-L109

Executors.newSingleThreadExecutor() returns a ThreadPoolExecutor whose core thread does not time out, wrapped in a FinalizableDelegatedExecutorService whose finalize() is the only thing that shuts it down. Since the plugin never calls shutdown(), that thread is reclaimed at a time the plugin does not control.

The executor is not doing the capture work. In camera-core 1.6.1, ProcessingNode.saveJpegToDisk runs on mBlockingExecutor, which comes from ImageCaptureConfig.getIoExecutor(CameraXExecutors.ioExecutor()) — the plugin never calls setIoExecutor, so encoding and file I/O happen on CameraX's own IO executor. TakePictureRequest.onResult then does nothing but getAppExecutor().execute(...). The executor passed to takePicture therefore only delivers an already finished result, and the plugin's callback body only forwards the file path to Dart.

Every other CameraX callback in this plugin is dispatched with ContextCompat.getMainExecutor(...) — CameraControlProxyApi, Camera2CameraControlProxyApi, ImageAnalysisProxyApi, ProcessCameraProviderProxyApi and PendingRecordingProxyApi, nine call sites in total. ImageCaptureProxyApi is the exception, and I could not find a reason for it in the code.

PreviewProxyApi.createSurfaceProvider uses the same pattern when calling SurfaceRequest.provideSurface, once per surface request rather than once per capture. That one seems worth a separate look, since its callback releases a Surface.

I can open a PR for the ImageCaptureProxyApi case.

Code sample

Reproducible with the camera_android_camerax example; a single takePicture() is enough.
await controller.initialize();
await controller.takePicture();

Screenshots or Videos

Logs

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.44.1, on macOS 26.5.1 25F80 darwin-arm64, locale ko-KR) [460ms]
    • Flutter version 3.44.1 on channel stable at /Users/paul/projects/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 924134a44c (10 weeks ago), 2026-05-29 12:13:22 -0400
    • Engine revision c416acfeb8
    • Dart version 3.12.1
    • DevTools version 2.57.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, no-enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration

[✓] Android toolchain - develop for Android devices (Android SDK version 37.0.0) [2.6s]
    • Android SDK at /Users/paul/Library/Android/sdk
    • Emulator version 35.3.11.0 (build_id 12836668) (CL:N/A)
    • Platform android-37.0, build-tools 37.0.0
    • ANDROID_HOME = /Users/paul/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
      This is the JDK bundled with the latest Android Studio installation on this machine.
      To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment (build 21.0.7+-13880790-b1038.58)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.2) [1,568ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17C52
    • CocoaPods version 1.16.2

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

[✓] Connected device (3 available) [7.2s]
    • 신바울의 iPhone (mobile) • 00008110-0018254A3686401E • ios            • iOS 26.5.2 23F84
    • macOS (desktop)      • macos                     • darwin-arm64   • macOS 26.5.1 25F80 darwin-arm64
    • Chrome (web)         • chrome                    • web-javascript • Google Chrome 150.0.7871.187

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

• No issues found!

Activity

  1. added
    packageflutter/packages repository. See also p: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    fyi-ecosystemFor the attention of Ecosystem team
    team-androidOwned by Android platform team
    and removed
    fyi-ecosystemFor the attention of Ecosystem team
    on Aug 4, 2026
  2. mbcorona commented on Aug 4, 2026

    @mbcorona
    Member

    Hi @toyaji , thanks for the report and for raising a PR.
    Routing to the Android team with fyi-ecosystem for evaluation.

  3. added
    P1High-priority issues at the top of the work list
    triaged-androidTriaged by Android platform team
    on Aug 4, 2026
  4. added a commit that references this issue on Aug 12, 2026
    c85072a
  5. added a commit that references this issue on Aug 12, 2026
    456f992
  6. github-actions commented on Aug 26, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  7. locked as resolved and limited conversation to collaborators on Aug 26, 2026
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

    P1High-priority issues at the top of the work listfound in release: 3.44Found to occur in 3.44has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: cameraThe camera 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