Skip to content

[Impeller][GLES] ImageDecoderImpeller SIGABRT persists on Flutter 3.44.8 across Android 10 Mali devices #190640

Closed

Description

@dfdgsdfg

Related closed issue

This is a follow-up to #188472, which I originally reported. That issue was closed while waiting for confirmation on a newer stable Flutter release. I later added a production confirmation for Flutter 3.44.6, but the issue remains closed. The closing bot explicitly requested a new issue when additional evidence became available.

There are no currently open issues matching ImageDecoderImpeller + BlitPassGLES + Android 10.

Steps to reproduce

We still do not have a deterministic local reproduction. This is an intermittent production engine crash.

  1. Run a release-mode Flutter app with Android Impeller enabled.
  2. Use a Samsung Android 10 device with a Mali GPU.
  3. Navigate through screens that decode and upload images.
  4. The process intermittently aborts on the Impeller IO thread while uploading a decoded image through the GLES blit path.

The crash disappears for the affected cohort when the app starts Flutter with Skia instead of Impeller. We now apply that mitigation by Android API level and Build.DEVICE codename.

Latest production environment

The latest base release is built through Shorebird with:

  • Flutter: 3.44.8 stable
  • Shorebird: 1.6.115
  • Shorebird Flutter revision: c15ef6379403a0a55531a058bdb2c8e55bc05c98
  • Shorebird engine revision: 69f9831c360d9152862ec3897c67fb09ae843f3b
  • App build: 3.35.2 (113261)
  • Patch: base release / patch 0
  • Renderer: Impeller enabled by default
  • ABI: ARM64

A new event occurred on 2026-08-05 on Flutter 3.44.8:

  • Samsung Galaxy A31 SM-A315N
  • Build.DEVICE=a31
  • Android 10 / API 29
  • MediaTek MT6768 / Helio P65
  • Mali-G52 MC2
  • Crash type: SIGABRT
  • Blamed library: libflutter.so

This is important because the original report was concentrated on Samsung Exynos/Mali devices. The A31 uses a MediaTek SoC but still uses a Mali GPU, so the observed boundary is broader than Exynos 9810.

Exact symbolized stack

The current 3.35.2 Crashlytics export omits native frames, but it is grouped into the same Crashlytics issue and variant as earlier Build-ID-matched events. The exact stack below was symbolized from the production 3.34.0 (113182) build using the matching ARM64 Shorebird engine symbols:

  • Flutter: 3.44.6 stable
  • Engine revision: 401254d5890cba1abe1ea364004f4d6bf8e58c24
  • libflutter.so Build ID: 730039c16a8d226e3597c77d059f4f0c863b15ba
fml::LogMessage::~LogMessage()                                 logging.cc:186
impeller::BlitPassGLES::EncodeCommands() const::$_0            blit_pass_gles.cc:88
impeller::ReactorGLES::React()                                 reactor_gles.cc:261
flutter::ImageDecoderImpeller::UnsafeUploadTextureToPrivate()  image_decoder_impeller.cc:527

The complete native stack is:

#00 libc.so (abort)
#01 libflutter.so (fml::KillProcess)
#02 libflutter.so (fml::LogMessage::~LogMessage)
#03 libflutter.so (impeller::BlitPassGLES::EncodeCommands() const::$_0)
#04 libflutter.so (impeller::ReactorGLES::React)
#05 libflutter.so (impeller::ReactorGLES::AddOperation)
#06 libflutter.so (impeller::BlitPassGLES::EncodeCommands)
#07 libflutter.so (flutter::ImageDecoderImpeller::UnsafeUploadTextureToPrivate)
#08 libflutter.so (flutter::ImageDecoderImpeller::UploadTextureToPrivate::$_0)
#09 libflutter.so (fml::SyncSwitch::Execute)
#10 libflutter.so (flutter::ImageDecoderImpeller::UploadTextureToPrivate)
#11 libflutter.so (flutter::ImageDecoderImpeller::Decode::$_1)
#12 libflutter.so (fml::MessageLoopImpl::RunExpiredTasksNow)
#13 libflutter.so (fml::MessageLoopAndroid callback)
#14 libutils.so (android::Looper::pollInner)
#15 libutils.so (android::Looper::pollOnce)
#16 libandroid.so (ALooper_pollOnce)
#17 libflutter.so (fml::MessageLoopAndroid::Run)

No Dart frame or app-owned Android plugin frame appears in this crash stack.

Production impact after the previous issue was closed

From 2026-07-15 through 2026-08-06, the same Crashlytics variant produced 572 events across 113 installations on Android 10. Counts are deduplicated by event ID and installation ID.

Device Build.DEVICE family SoC / GPU Events Installations
Galaxy Note9 SM-N960N crownlte* Exynos 9810 / Mali-G72 401 78
Galaxy S9+ SM-G965N star2lte* Exynos 9810 / Mali-G72 58 16
Galaxy A31 SM-A315N a31* MediaTek MT6768 / Mali-G52 44 2
Galaxy S9 SM-G960N starlte* Exynos 9810 / Mali-G72 36 8
Galaxy S10+ SM-G975N beyond2* Exynos 9820 / Mali-G76 15 3
Galaxy S10 5G SM-G977N beyondx* Exynos 9820 / Mali-G76 8 1
Galaxy Tab S6 Lite SM-P610 gta4xlwifi* Exynos 9611 / Mali-G72 5 3
Galaxy S9+ SM-G965F star2lte* Exynos 9810 / Mali-G72 4 1
Galaxy Note10+ 5G SM-N976N d2x* Exynos 9825 / Mali-G76 1 1

All rows above are Android 10. The issue is still heavily concentrated on Exynos 9810/Mali-G72, but it also occurs on other Mali generations and now on a MediaTek/Mali device.

Expected results

Impeller should decode and upload images without aborting the process on Android 10 Mali/GLES devices.

If the underlying driver behavior cannot be handled safely, Flutter should consider a renderer denylist/fallback for the affected Android 10 Mali driver families instead of requiring each application to maintain a device-codename list.

Actual results

The engine calls fml::KillProcess from BlitPassGLES::EncodeCommands during ImageDecoderImpeller::UnsafeUploadTextureToPrivate, terminating the app without an app-owned frame.

App-side mitigation

We now force Skia only when both conditions match:

  • Android API 29
  • An observed Build.DEVICE prefix such as crownlte, starlte, star2lte, beyond, d2x, gta4xlwifi, m20, a7y18lte, a50, or a31

This requires a native release because renderer selection happens during Flutter process bootstrap. We will monitor whether the crash disappears after rollout, but this per-app device list is fragile and cannot protect other Flutter apps.

Flutter doctor

flutter doctor -v
[✓] Flutter (Channel stable, 3.44.8, on macOS 26.6 darwin-arm64, locale ko-KR)
    • Flutter version 3.44.8 on channel stable
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 058e0af2c2 (2026-07-23)
    • Engine revision 0cd610717b
    • Dart version 3.12.2
    • 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, enable-swift-package-manager,
      omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration

[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
    • Platform android-36.1, build-tools 36.1.0
    • Java version OpenJDK Runtime Environment 25.0.2
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.6)
    • Build 17F113
    • CocoaPods version 1.17.0

[✓] Chrome - develop for the web
[✓] Network resources

• No issues found!

Request

Could the Impeller/engine team investigate why BlitPassGLES::EncodeCommands treats this Android 10 Mali failure as fatal, and whether Flutter should apply a built-in GLES/Impeller denylist or safe fallback for this driver cohort?

This report intentionally excludes private production session IDs, user identifiers, and application logs. I can provide additional Build-ID-matched native evidence if the engine team identifies a specific artifact or diagnostic needed.

Activity

  1. suryaKommana2662 commented on Aug 6, 2026

    @suryaKommana2662
    Contributor

    @dfdgsdfg Thanks for the detailed follow-up report and for confirming that the issue persists on Flutter 3.44.8 with updated production evidence. The report contains a symbolicated native stack, updated engine revision information, affected device/GPU details, and production data demonstrating that the crash continues to occur in the Impeller GLES image upload path. Routing this to the team-engine for further investigation.

  2. added
    platform-androidAndroid applications specifically
    e: impellerImpeller rendering backend issues and features requests
    and removed
    in triagePresently being triaged by the triage team
    on Aug 6, 2026
  3. FelixMittermeier commented on Aug 7, 2026

    @FelixMittermeier
    Contributor

    @dfdgsdfg Not sure if you saw it, but I created a PR with a likely fix for this issue yesterday. Could you please test if the issue no longer happens if you build the engine from my PR's branch? Thanks

  4. gaaclarke commented on Aug 10, 2026

    @gaaclarke
    Member

    The stacktrace unfortunately isn't helpful. Without a reproduction this is going to be difficult to address. @FelixMittermeier posted a draft PR that attempts to fix this. It would be an interesting datapoint to test. Unfortunately if we don't have a reproduction, we can't really know if it fixes it though.

  5. added
    needs repro infoAutomated crash report whose cause isn't yet known
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    P2Important issues not at the top of the work list
    on Aug 10, 2026
  6. FelixMittermeier commented on Aug 27, 2026

    @FelixMittermeier
    Contributor

    @dfdgsdfg Is there any update on this topic? Do you have exact stacktrace or did you test if the change from the linked PR fixes the issue?

  7. dfdgsdfg commented on Aug 27, 2026

    @dfdgsdfg
    ContributorAuthor

    Thanks for following up. I'm currently working on a reproducible demo. Since I don't have access to any of the affected physical devices, my plan is to first reproduce the issue with our actual app on a target device using Firebase Test Lab, and then reduce it to a minimal reproducible sample app.

    This is taking longer than I expected, so I haven't yet been able to reliably test whether the linked PR fixes the issue. The exact symbolicated stack trace currently available is the one included in the issue description. I'll share an update as soon as I have either a reproducible case or test results from the PR.

  8. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Aug 27, 2026
  9. dfdgsdfg commented on Sep 2, 2026

    @dfdgsdfg
    ContributorAuthor

    Update: I now have a deterministic physical-device reproduction and a candidate engine workaround. The evidence below is self-contained and does not require access to the Test Lab project. The full sanitized evidence is public in docs/evidence.md.

    @FelixMittermeier

    Reproduction

    The public reproducer is https://github.com/dfdgsdfg/mali-crash-app. Scenario 9 fixes the app source and arguments, device, renderer, and duration:

    • Physical Samsung Galaxy S9 (starlte), Android 10 / API 29, Mali-G72
    • Impeller with OpenGLES
    • 606-second game-loop test

    Only the embedded Flutter engine variant changes. The stock and diagnostic variants abort within about ten seconds in BlitPassGLES; the force-rebind variant completes.

    Confirmed failure signature

    The deterministic run ends in the same engine-side FML_CHECK/SIGABRT signature:

    signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
    Abort message: '[FATAL:flutter/impeller/renderer/backend/gles/blit_pass_gles.cc(88)] Check failed: result. Must be able to encode GL commands without error.
    Break on 'ImpellerValidationBreak' to inspect point of failure: Could not create a complete framebuffer: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
    Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE)
    

    The previously Build-ID-matched production symbolization confirms the major native path:

    fml::LogMessage::~LogMessage()
    impeller::BlitPassGLES::EncodeCommands() const::$_0
    impeller::ReactorGLES::React()
    flutter::ImageDecoderImpeller::UnsafeUploadTextureToPrivate()
    

    No Dart or app-owned plugin frame appears in that stack.

    Confirmed GL chronology

    This concise sanitized excerpt follows the failing GL name 7; context and thread identities are redacted:

    TextureTrace stage=initialize.bind logical_handle=209 gl_name=7 target=3553 thread=<redacted> raw_error_group=operation raw_error=GL_NO_ERROR(0) is_texture=true raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=initialize.tex_image_2d logical_handle=209 gl_name=7 target=3553 thread=<redacted> raw_error_group=operation raw_error=GL_NO_ERROR(0) is_texture=true raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=attachment.framebuffer_texture_2d.after logical_handle=209 gl_name=7 target=36009 textarget=3553 thread=<redacted> raw_error_group=operation raw_error=GL_NO_ERROR(0) is_texture=true raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=texture.delete.after logical_handle=209 gl_name=7 thread=<redacted> raw_error_group=delete raw_error=GL_NO_ERROR(0) is_texture=false raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=texture.generated logical_handle=unassigned gl_name=7 thread=<redacted> note=glIsTexture_may_be_false_before_first_bind
    TextureTrace stage=upload.tex_sub_image_2d logical_handle=215 gl_name=7 target=3553 thread=<redacted> raw_error_group=operation raw_error=GL_NO_ERROR(0) is_texture=false raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=attachment.framebuffer_texture_2d.after logical_handle=215 gl_name=7 target=36008 textarget=3553 thread=<redacted> raw_error_group=operation raw_error=GL_INVALID_OPERATION(1282) is_texture=false raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    ConfigureFBO role=read/source fbo=1 status=GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
    

    Confirmed sequence:

    1. The resource/offscreen context successfully binds, materializes, and attaches logical_handle=209, GL name 7.
    2. The shared renderer context sees name 7 as a valid texture and deletes that logical texture.
    3. glGenTextures returns numeric name 7 again for logical_handle=215. A false glIsTexture result immediately after generation can be normal before the first successful bind.
    4. Its upload reports GL_NO_ERROR, but glIsTexture(7) remains false.
    5. The first isolated GL error is GL_INVALID_OPERATION from FramebufferTexture2D; the read FBO then has GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, leading to the abort.

    The resource-context eglMakeCurrent succeeded, expected and actual EGL state matched, and the offscreen-created texture was visible from the renderer context.

    Inferred mechanism

    This is an inference from the trace and A/B, not a confirmed driver-internal fact: the deleted object may remain bound in the resource context after its numeric name becomes reusable. If Mali treats BindTexture(target, 7) as no state transition because that context still reports binding name 7, the newly generated name may never become a new texture object.

    The candidate workaround forces an explicit transition:

    BindTexture(target, 0);
    BindTexture(target, name);

    The passing trace repeatedly exercises numeric-name recycling. One representative successful reuse of name 7 records:

    TextureTrace stage=texture.delete.after logical_handle=175 gl_name=7 thread=<redacted> raw_error_group=delete raw_error=GL_NO_ERROR(0) is_texture=false raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=texture.generated logical_handle=unassigned gl_name=7 thread=<redacted> note=glIsTexture_may_be_false_before_first_bind
    TextureTrace stage=upload.tex_sub_image_2d logical_handle=213 gl_name=7 target=3553 thread=<redacted> raw_error_group=operation raw_error=GL_NO_ERROR(0) is_texture=true raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    TextureTrace stage=attachment.framebuffer_texture_2d.after logical_handle=213 gl_name=7 target=36008 textarget=3553 thread=<redacted> raw_error_group=operation raw_error=GL_NO_ERROR(0) is_texture=true raw_error_group=is_texture_query raw_error=GL_NO_ERROR(0)
    

    A/B result

    The Flutter 3.44.8-based force-rebind diagnostic engine passed 4/4 physical runs, each for 606 seconds:

    Run Iterations Resize probes
    1 33,860 2,148 / 2,148
    2 33,397 2,148 / 2,148
    3 33,338 2,149 / 2,149
    4 33,436 2,148 / 2,148

    Across all four logs there were no observed GL_INVALID_OPERATION, ConfigureFBO failure, upload/attachment is_texture=false, or fatal/SIGABRT events.

    The minimal current-master patch is #192158. The physical A/B used the equivalent workaround on a Flutter 3.44.8-based diagnostic engine. PR #192158 ports it to current master; the current-master patch has host unit-test validation but has not itself been packaged for this physical run.

    This does not supersede #190655. That PR addresses a different failed-eglMakeCurrent lifecycle path. eglMakeCurrent succeeds in this reproduction, so this run does not exercise that condition. I have not directly tested #190655 and am not claiming that it fails to address other cases.

    Limitations: the deterministic A/B currently covers one device/driver combination, and the workaround adds one GL bind to each direct buffer-to-texture upload. Broader driver coverage and feedback on the performance/scope trade-off would be useful.

    I can provide raw logcats, result JSON files, exact engine/APK hashes, or additional sanitized excerpts if helpful.

  10. FelixMittermeier commented on Sep 3, 2026

    @FelixMittermeier
    Contributor

    Great that you found a way to reproduce and fix it. I closed my initial PR because it really did not solve this specific issue.

    I am just wondering if this new extra call is needed all the time or just in special cases. Maybe there are performance impacts if there is now an additional call?

    However I think it makes more sense to tag @gaaclarke instead of me at this point. I am not part of the flutter team so I can't review your PR.

  11. marcuschanws commented on Sep 16, 2026

    @marcuschanws

    Another data point for this, from a different vendor and a much newer Flutter. I do not have a symbolized stack, so I am adding it here rather than opening a separate issue — if maintainers read it as distinct I am happy to move it.

    Still present on Flutter 3.47.0 stable

    The newest report above is 3.44.8. We hit the same abort on:

    • Flutter 3.47.0 stable, framework 4cf2416426, engine 5f77625673, Dart 3.13.0
    • Renderer: Impeller default, on the GLES backend (Vulkan is not viable on this device)
    F/libc: Fatal signal 6 (SIGABRT), pid <app>
    Abort message: [FATAL:flutter/impeller/renderer/backend/gles/blit_pass_gles.cc(88)]
    Check failed: result. Must be able to encode GL commands without error.
    

    One abort signature across ~103k lines of logcat, so the check itself is unambiguous — but the native frames were not symbolized, so I can confirm blit_pass_gles.cc(88) and not the frame above it. I have no reduced reproduction to hand over either; it is intermittent.

    Widens the device boundary again — Huawei / Kirin

    The report above notes the cohort had already grown past Exynos to MediaTek, both Samsung. This one is neither:

    • Huawei Mate 10 Pro, BLA-L29
    • Android 10 / API 29
    • HiSilicon Kirin 970
    • Mali-G72
    • OpenGL ES 3.2

    So the common factor across all three reports is Mali + Android 10 + the GLES backend, rather than any one SoC vendor.

    What the app was doing

    It aborted in two places, and both are this app's busiest moments for the GPU:

    1. A camera preview with video recording running beside it (package:camera, CameraX).
    2. A screen that plays two clips side by side — one video_player, and one "flipbook": a few hundred JPEG frames read from disk, decoded through ui.instantiateImageCodec / Codec.getNextFrame(), and painted as RawImage at ~30 fps.

    The second one is worth flagging. It drives ImageDecoderImpeller::UploadTextureToPrivate hard and on a clock — a freshly decoded ui.Image uploaded every frame or two, for hundreds of frames in a row. If the upload path in the stack above is the right one, that shape of workload may provoke it far more readily than waiting for a production crash, because it is a texture upload per frame rather than one per screen.

    The app uses no FragmentProgram and no BackdropFilter, so #186186 is not what this is.

    The mitigation, and the reason for writing

    The same as yours: EnableImpeller=false in the manifest ends it — same build, same phone. That is what we have shipped.

    The reason for adding to this issue rather than quietly taking the workaround is that the workaround now prints a deprecation notice:

    [Action Required]: Impeller opt-out deprecated. These options are going to go
    away in an upcoming Flutter release. Remove the explicit opt-out. If you need
    to opt-out, please report a bug describing the issue.
    

    This is that bug report. The escape hatch that several of us are relying on for Android 10 Mali devices is scheduled to disappear, and as far as I can tell the underlying abort has not moved since #188472. Knowing whether the opt-out will outlive this issue — or what is meant to replace it for GLES-only devices — would be worth a great deal to anyone in this thread. It decides whether those devices stay supported at all.

  12. dfdgsdfg commented on Sep 16, 2026

    @dfdgsdfg
    ContributorAuthor

    For reference, Arm has identified the driver erratum matching the API sequence in our deterministic reproduction:

    Arm errata EN_ID 1,792,661 — affects Bifrost and Valhall GPU drivers r17p0 through r23p0, and was fixed in r24p0.

    Arm's confirmation and affected driver range.

    Arm confirmed that binding texture zero before rebinding the desired texture name reliably avoids this issue. They also noted that some OEMs may have backported the fix to earlier driver releases; applications cannot detect those backports. This historical erratum will not be added to the current public errata document, which only covers r36p0 and later, so the forum reply provides the reference and tracking ID.

    This is Arm's corrected diagnosis: their earlier reply about general FBO-attachment synchronization concerned a different issue.

    The workaround is under review in #192158. The current patch targets native GLES Mali-G / Immortalis-G drivers in the r17–r23 range, with a conservative fallback when the driver version cannot be parsed.

    The affected range above is a driver-version boundary, not a Samsung/Exynos or Android-version boundary. However, the shared blit_pass_gles.cc abort signature alone does not establish that every report here has this cause. For additional devices, including the Huawei/Kirin report, the full runtime GL_VENDOR, GL_RENDERER, and GL_VERSION strings would help establish whether they fall within Arm's confirmed range.

  13. github-actions commented on Oct 13, 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.

  14. locked as resolved and limited conversation to collaborators on Oct 13, 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

    P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requestsneeds repro infoAutomated crash report whose cause isn't yet knownplatform-androidAndroid applications specificallyteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions