Repository navigation
Description
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.
- Run a release-mode Flutter app with Android Impeller enabled.
- Use a Samsung Android 10 device with a Mali GPU.
- Navigate through screens that decode and upload images.
- 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.8stable - 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.6stable - Engine revision:
401254d5890cba1abe1ea364004f4d6bf8e58c24 libflutter.soBuild 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:527The 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.DEVICEprefix such ascrownlte,starlte,star2lte,beyond,d2x,gta4xlwifi,m20,a7y18lte,a50, ora31
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
suryaKommana2662 commentedon Aug 6, 2026
@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.
FelixMittermeier commentedon Aug 7, 2026
@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
gaaclarke commentedon Aug 10, 2026
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.
FelixMittermeier commentedon Aug 27, 2026
@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?
dfdgsdfg commentedon Aug 27, 2026
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.
dfdgsdfg commentedon Sep 2, 2026
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:
starlte), Android 10 / API 29, Mali-G72Only 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:The previously Build-ID-matched production symbolization confirms the major native path:
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:Confirmed sequence:
logical_handle=209, GL name7.7as a valid texture and deletes that logical texture.glGenTexturesreturns numeric name7again forlogical_handle=215. A falseglIsTextureresult immediately after generation can be normal before the first successful bind.GL_NO_ERROR, butglIsTexture(7)remains false.GL_INVALID_OPERATIONfromFramebufferTexture2D; the read FBO then hasGL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, leading to the abort.The resource-context
eglMakeCurrentsucceeded, 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 name7, the newly generated name may never become a new texture object.The candidate workaround forces an explicit transition:
The passing trace repeatedly exercises numeric-name recycling. One representative successful reuse of name
7records:A/B result
The Flutter 3.44.8-based force-rebind diagnostic engine passed 4/4 physical runs, each for 606 seconds:
Across all four logs there were no observed
GL_INVALID_OPERATION,ConfigureFBO failure, upload/attachmentis_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-
eglMakeCurrentlifecycle path.eglMakeCurrentsucceeds 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.
FelixMittermeier commentedon Sep 3, 2026
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.
marcuschanws commentedon Sep 16, 2026
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:
3.47.0stable, framework4cf2416426, engine5f77625673, Dart 3.13.0One 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:
BLA-L29So 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:
package:camera, CameraX).video_player, and one "flipbook": a few hundred JPEG frames read from disk, decoded throughui.instantiateImageCodec/Codec.getNextFrame(), and painted asRawImageat ~30 fps.The second one is worth flagging. It drives
ImageDecoderImpeller::UploadTextureToPrivatehard and on a clock — a freshly decodedui.Imageuploaded 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
FragmentProgramand noBackdropFilter, so #186186 is not what this is.The mitigation, and the reason for writing
The same as yours:
EnableImpeller=falsein 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:
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.
dfdgsdfg commentedon Sep 16, 2026
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.ccabort signature alone does not establish that every report here has this cause. For additional devices, including the Huawei/Kirin report, the full runtimeGL_VENDOR,GL_RENDERER, andGL_VERSIONstrings would help establish whether they fall within Arm's confirmed range.[Impeller][GLES] Rebind textures before buffer uploads (flutter#192158)
github-actions commentedon Oct 13, 2026
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 -vand a minimal reproduction of the issue.