Repository navigation
Description
Steps to reproduce
We can't reproduce this on demand and don't have an affected device. It is a production regression that appeared when we upgraded from Flutter 3.44.9 to 3.47.2. We did not change any Impeller or renderer settings between the two builds (Impeller enabled, EnableHcpp=false, default FlutterSurfaceView).
The conditions it shows up under:
- A MediaTek phone with a Mali GPU whose vendor partition reports
ro.vendor.build.version.sdk< 32. Since Bumped required mediatek vender sdk version. #186405 these phones no longer get Vulkan, so Impeller runs on OpenGLES. On 3.44 the same phones ran Vulkan. - The app calls
ui.Image.toByteData(format: ui.ImageByteFormat.rawRgba)on decoded network images, for example to sample a dominant colour (the same thingPaletteGenerator.fromImageProviderdoes). For images that are not owned by the raster context, the engine does this readback on theiothread:EncodeImageposts to the IO runner, thenImageEncodingImpeller::ConvertImageToRaster→BlitCopyTextureToBufferCommandGLES::Encode→gl.ReadPixels. - Normal app use. We could not tie it to a specific screen or user action.
Expected results
The app keeps rendering and responding to input, as it did on 3.44.9 on the same devices.
Actual results
The UI freezes on the last frame and input is ignored. Android then reports an ANR.
How the ANR counts changed from our 3.44.9 build to our 3.47.2 build (Crashlytics). By now both builds have had similar exposure: unrelated ANRs are at about the same level on both.
| ANR | 3.47.2 build vs 3.44.9 build |
|---|---|
[libGLES_mali.so] osup_sync_object_wait (blamed thread: HWUI RenderThread; includes a second grouping first seen on 3.47.2) |
~85x more |
FlutterJNI.nativeSurfaceDestroyed (main thread) |
~60x more |
Unrelated baseline ANRs (MessageQueue.nativePollOnce, root cause unknown) |
about the same (0.8x–1.2x) |
For example, on OPPO CPH2371 neither of these ANRs occurred at all on the 3.44.9 build.
Affected devices. These are the 15 devices that hit the osup_sync_object_wait ANR most often, most frequent first. All are MediaTek SoCs with Mali GPUs:
| Device (as Crashlytics reports it) | Model | SoC / GPU |
|---|---|---|
| samsung SM-A226B | Galaxy A22 5G | Dimensity 700 (MT6833) / Mali-G57 |
| samsung SM-A326U | Galaxy A32 5G | Dimensity 720 (MT6853) / Mali-G57 |
| samsung SM-A326B | Galaxy A32 5G | Dimensity 720 (MT6853) / Mali-G57 |
| samsung SM-A136U | Galaxy A13 5G | Dimensity 700 (MT6833) / Mali-G57 |
| OPPO CPH2211 | A94 5G / Reno5 Z | Dimensity 800U / Mali-G57 |
| Xiaomi 2201117SY | Redmi Note 11S | Helio G96 (MT6781) / Mali-G57 |
| OPPO CPH2371 | Reno7 5G | Dimensity 900 (MT6877) / Mali-G68 |
| Xiaomi M2103K19G | Redmi Note 10 5G | Dimensity 700 (MT6833) / Mali-G57 |
| Xiaomi 2201117PG | POCO M4 Pro | Helio G96 (MT6781) / Mali-G57 |
| Amazon KFSNWI | Fire Max 11 | MT8188J / Mali-G57 |
| Xiaomi 2201116TG | Redmi Note 11 Pro | Helio G96 (MT6781) / Mali-G57 |
| samsung SM-A226BR | Galaxy A22 5G | Dimensity 700 (MT6833) / Mali-G57 |
| OnePlus DN2103 | Nord 2 5G | Dimensity 1200 (MT6893) / Mali-G77 |
| motorola edge 20 lite | Edge 20 Lite | Dimensity 720 (MT6853) / Mali-G57 |
| motorola moto g 5G (2022) | moto g 5G (2022) | Dimensity 700 (MT6833) / Mali-G57 |
Model names and SoCs come from public spec sheets, not from Crashlytics. As far as we can tell, these phones all launched on Android 11 or 12, so their vendor partition should report SDK ≤ 31 and hit the new check. We have no device to confirm this with getprop. They are mostly Dimensity (Mali-G57/G68/G77), which is a wider set than the Helio / Mali-G52 phones in #193148.
What the full thread dump shows. This dump is from a motorola edge 20 lite on Android 13. The driver frames are not symbolised, so this reading is inferred:
1.iois insideglReadPixels, waiting on a Mali sync object (osup_sync_object_wait).- Mali's own backend thread (
mali-cmar-backe) and Flutter's1.rasterare both blocked on a mutex insidelibGLES_mali.so. - The sync object therefore never signals.
1.rasternever servicesShell::OnPlatformViewDestroyed, so the main thread blocks innativeSurfaceDestroyed→ ANR. - The libflutter frame
0x8456a4appears in both the1.rasterand1.iostacks. - When the freeze happens in the foreground, HWUI's
RenderThreadgets stuck in the same driver (eglQuerySurface→osup_sync_object_wait). That is theosup_sync_object_waitcluster we see in Play Console.
What changed in the engine (shell/platform/android/android_context_dynamic_impeller.cc, 3.44.9 → 3.47.x; unchanged in 3.47.5). On 3.44.9 these phones (Android 13, API 33) passed the check and ran Vulkan. On 3.47 their vendor SDK (≤ 31) fails it, and they run OpenGLES.
Engine diff, 3.44.9 → 3.47.x
- constexpr int kMinimumAndroidApiLevelForMediaTekVulkan = 31;
+ constexpr int kMinimumAndroidApiLevelForMediaTekVulkan = 32;
...
- if (api_level < kMinimumAndroidApiLevelForMediaTekVulkan &&
+ int vendor_api_level = api_level;
+ if (__system_property_get("ro.vendor.build.version.sdk", property) > 0) {
+ vendor_api_level = std::atoi(property);
+ }
+
+ if (vendor_api_level < kMinimumAndroidApiLevelForMediaTekVulkan &&
__system_property_find("ro.vendor.mediatek.platform") != nullptr) {Suggestions
- Narrow the MediaTek check so phones that ran Vulkan fine on 3.44 keep Vulkan. For example, key it on the SoC or driver from [Impeller][Vulkan] gralloc4 rejects format 0x38 on MediaTek MT8788 (Mali-G57) buffer allocation fails at engine init #186067 (MT8788), as proposed in [Impeller][Android] Vendor-SDK Vulkan gate from #186405 also blocks Mali-G52 (MT6768/MT6769, vendor SDK 31) where Vulkan worked on 3.44; the GLES fallback costs +40–90 MB of graphics memory — Flutter 3.47.1 #193148. That alone would take these phones off the OpenGLES path.
- Separately, look at the OpenGLES path: a
glReadPixelson theiothread's context while the raster thread is rendering appears able to deadlock the Mali OpenGLES driver process-wide.
Related issues
- [Impeller][Android] Vendor-SDK Vulkan gate from #186405 also blocks Mali-G52 (MT6768/MT6769, vendor SDK 31) where Vulkan worked on 3.44; the GLES fallback costs +40–90 MB of graphics memory — Flutter 3.47.1 #193148: same MediaTek Vulkan check, but reports only extra graphics memory on Mali-G52. This issue adds freezes/ANRs on Mali-G57/G68/G77.
- Bumped required mediatek vender sdk version. #186405: the PR that introduced the vendor-SDK check (a fix for [Impeller][Vulkan] gralloc4 rejects format 0x38 on MediaTek MT8788 (Mali-G57) buffer allocation fails at engine init #186067 on MT8788).
- ANR on Android 16: main thread blocks in Shell::OnPlatformViewDestroyed while raster thread hangs in Surface::dequeueBuffer during backgrounding (Impeller GLES) #190599: same main-thread shape (
OnPlatformViewDestroyedwaiting on the raster thread), on Adreno with Impeller OpenGLES. Closed for lack of a repro. [Impeller][Vulkan] HostBuffer destructor calls vkDeviceWaitIdle without timeout, deadlocking raster thread → ANR#186573: Maliosup_sync_object_timedwaitblocking the raster thread, on the Vulkan backend.- [flutter 3.29.3] Crashlytics report of ANR io.flutter.embedding.engine.FlutterJNI.nativeSurfaceDestroyed #169585: generic
nativeSurfaceDestroyedANR.
Code sample
We have no minimal repro. This is the pattern that triggers the IO-thread readback:
Code sample
final ImageStream stream = NetworkImage(url).resolve(ImageConfiguration.empty);
stream.addListener(ImageStreamListener((ImageInfo info, bool _) async {
// Readback of an IO-owned image; on Impeller GLES this runs glReadPixels on the io thread.
final ByteData? bytes = await info.image.toByteData(format: ui.ImageByteFormat.rawRgba);
// ... average the pixels to get a dominant colour ...
}));Screenshots or Video
None. We are not able to reproduce this issue ourselves and have no affected device. All data comes from production Crashlytics and Play Console reports.
Logs
libflutter.so below (shown as split_config.arm64_v8a.apk in the raw dump) is the stock 3.47.2 android-arm64-release engine (engine a804b261645ef8c13eb3d5c44a5c2fb0340c5539, BuildId fdf0a0a6f673cdcfc6c0e5f8dc7c8828d63fb3b6), so the frames can be symbolised with the published symbols.zip.
Full ANR dump: motorola edge 20 lite, Android 13 (trimmed to the relevant threads)
"main" tid=1 native
#00 pc 0x4f85c libc.so (syscall+28)
#01 pc 0x54140 libc.so (__futex_wait_ex+144)
#02 pc 0xc0b08 libc.so (pthread_cond_wait+72)
#03 pc 0x4f9c2c libflutter.so (std::__fl::condition_variable::wait) <- symbolised by Play Console
#04 pc 0x50e628 libflutter.so (fml::AutoResetWaitableEvent::Wait)
#05 pc 0x888f64 libflutter.so (flutter::Shell::OnPlatformViewDestroyed)
#06 pc 0x4eca04 libflutter.so (flutter::PlatformViewAndroid::NotifyDestroyed)
#07 pc 0x4f0210 libflutter.so (flutter::SurfaceDestroyed)
at io.flutter.embedding.engine.FlutterJNI.nativeSurfaceDestroyed(FlutterJNI.java)
at io.flutter.embedding.engine.FlutterJNI.onSurfaceDestroyed(FlutterJNI.java:669)
at io.flutter.embedding.engine.renderer.FlutterRenderer.stopRenderingToSurface(FlutterRenderer.java:1196)
at io.flutter.embedding.android.FlutterSurfaceView.disconnectSurfaceFromRenderer(FlutterSurfaceView.java:295)
at io.flutter.embedding.android.FlutterSurfaceView$1.surfaceDestroyed(FlutterSurfaceView.java:81)
at android.view.SurfaceView.notifySurfaceDestroyed(SurfaceView.java:1812)
at android.view.SurfaceView.setWindowStopped(SurfaceView.java:281)
at android.view.ViewRootImpl.setWindowStopped(ViewRootImpl.java:2322)
at android.app.Activity.performStop(Activity.java:8803)
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5366)
"1.raster" tid=95 native
#00 pc 0x4f85c libc.so (syscall+28)
#01 pc 0x54140 libc.so (__futex_wait_ex+144)
#02 pc 0xc2cc8 libc.so (NonPI::MutexLockWithTimeout+328)
#03 pc 0xc29fc libc.so (pthread_mutex_lock+188)
#04 pc 0x7144d8 libGLES_mali.so (BuildId: 885d4d3064df5a2e)
#05 pc 0x752a48 libGLES_mali.so
#06 pc 0x74fdb0 libGLES_mali.so
#07 pc 0x849960 libflutter.so
#08 pc 0x83cd0c libflutter.so
#09 pc 0x846b8c libflutter.so
#10 pc 0x8456a4 libflutter.so
#11 pc 0x80a3e4 libflutter.so
#12 pc 0x80fafc libflutter.so
#13 pc 0x894320 libflutter.so
#14 pc 0x89420c libflutter.so
#15 pc 0x894150 libflutter.so
#16 pc 0x50e5e0 libflutter.so
#17 pc 0x8940d4 libflutter.so
#18 pc 0x87eafc libflutter.so
#19 pc 0x8b0824 libflutter.so
#20 pc 0x50d25c libflutter.so
#21 pc 0x511168 libflutter.so
#22 pc 0x18224 libutils.so (android::Looper::pollInner+1060)
#24 pc 0x18604 libandroid.so (ALooper_pollOnce+100)
"1.io" tid=20417
#00 pc 0x4f85c libc.so (syscall+28)
#01 pc 0x54140 libc.so (__futex_wait_ex+144)
#02 pc 0xc0b08 libc.so (pthread_cond_wait+72)
#03 pc 0x17aa740 libGLES_mali.so (osup_sync_object_wait+56)
#04 pc 0x16f6f18 libGLES_mali.so
#05 pc 0x7dfd2c libGLES_mali.so
#06 pc 0x7ddf08 libGLES_mali.so
#07 pc 0x7dde4c libGLES_mali.so
#08 pc 0x746d5c libGLES_mali.so
#09 pc 0x75c720 libGLES_mali.so
#10 pc 0x711364 libGLES_mali.so
#11 pc 0x711a58 libGLES_mali.so
#12 pc 0x70c870 libGLES_mali.so
#13 pc 0x7069d0 libGLES_mali.so (glReadPixels+152)
#14 pc 0x83bab0 libflutter.so
#15 pc 0x83c3a0 libflutter.so
#16 pc 0x8456a4 libflutter.so
#17 pc 0x844f90 libflutter.so
#18 pc 0x83bfe4 libflutter.so
#19 pc 0x8b95f4 libflutter.so
#20 pc 0x50e5e0 libflutter.so
#21 pc 0x8b8f54 libflutter.so
#22 pc 0x8b8b98 libflutter.so
#23 pc 0x8aab38 libflutter.so
#24 pc 0x50d25c libflutter.so
#25 pc 0x511168 libflutter.so
#26 pc 0x18224 libutils.so (android::Looper::pollInner+1060)
#28 pc 0x18604 libandroid.so (ALooper_pollOnce+100)
"mali-cmar-backe" tid=20432
#00 pc 0x4f85c libc.so (syscall+28)
#01 pc 0x54140 libc.so (__futex_wait_ex+144)
#02 pc 0xc2cc8 libc.so (NonPI::MutexLockWithTimeout+328)
#03 pc 0xc29fc libc.so (pthread_mutex_lock+188)
#04 pc 0x714a84 libGLES_mali.so
#05 pc 0x75b038 libGLES_mali.so
#06 pc 0x779748 libGLES_mali.so
#07 pc 0x777574 libGLES_mali.so
#08 pc 0x16e4dc0 libGLES_mali.so
#09 pc 0x16f6648 libGLES_mali.so
#10 pc 0x16f92fc libGLES_mali.so
"RenderThread" tid=45 native (idle in this dump)
#00 pc 0xacb68 libc.so (__epoll_pwait+8)
#03 pc 0x2756dc libhwui.so (android::uirenderer::ThreadBase::waitForWork+156)
Foreground variant, Crashlytics (OPPO CPH2371, Android 13, 3.47.2): HWUI RenderThread stuck in the Mali driver
Thread: RenderThread
syscall
__futex_wait_ex
pthread_cond_wait
osup_sync_object_wait (libGLES_mali.so)
<libGLES_mali.so>
<libGLES_mali.so>
eglQuerySurface
android::eglQuerySurfaceImpl
eglQuerySurface
android::uirenderer::renderthread::EglManager::beginFrame
android::uirenderer::renderthread::CanvasContext::draw
android::uirenderer::renderthread::DrawFrameTask::postAndWait::$_0
android::uirenderer::WorkQueue::process
android::uirenderer::renderthread::RenderThread::threadLoop
Foreground variant, Play Console: main thread waiting on that RenderThread
"main" tid=1 Native
#00 pc 0x4f55c libc.so (syscall+28)
#01 pc 0x53e40 libc.so (__futex_wait_ex+144)
#02 pc 0xc0838 libc.so (pthread_cond_wait+72)
#03 pc 0x286864 libhwui.so (android::uirenderer::renderthread::DrawFrameTask::drawFrame+356)
at android.graphics.HardwareRenderer.nSyncAndDrawFrame (Native method)
at android.graphics.HardwareRenderer.syncAndDrawFrame (HardwareRenderer.java:457)
at android.view.ThreadedRenderer.draw (ThreadedRenderer.java:817)
at android.view.ViewRootImpl.draw (ViewRootImpl.java:4903)
at android.view.ViewRootImpl.performDraw (ViewRootImpl.java:4604)
at android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:3805)
at android.view.Choreographer.doFrame (Choreographer.java:880)
Flutter Doctor output
This is the toolchain we build with today (Flutter 3.47.5). The ANR dumps above come from our 3.47.2 build. The MediaTek check is identical in both versions.
flutter doctor -v
[✓] Flutter (Channel stable, 3.47.5, on macOS 26.5 25F71 darwin-arm64, locale en-IN) [274ms]
• Flutter version 3.47.5 on channel stable at ~/fvm/versions/3.47.5
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 6a19cca564 (10 days ago), 2026-09-17 14:13:22 -0400
• Engine revision af7e796e16
• Dart version 3.13.4
• DevTools version 2.60.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, no-cli-animations, enable-native-assets, enable-record-use, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [374ms]
• Android SDK at ~/Library/Android/sdk
• Emulator version 37.1.11.0 (build_id 15917651) (CL:N/A)
• Platform android-37.0, build-tools 36.0.0
• Java binary at: /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/bin/java
This JDK is specified in your Flutter configuration.
To change the current JDK, run: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment Temurin-17.0.16+8 (build 17.0.16+8)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 26.2) [592ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17C52
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [5ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Connected device (3 available) [5.9s]
• <personal iOS device redacted>
• macOS (desktop) • macos • darwin-arm64 • macOS 26.5 25F71 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 153.0.8010.53
[✓] Network resources [448ms]
• All expected network resources are available.
• No issues found!
Activity
suryaKommana2662 commentedon Sep 28, 2026
@vishnunew Thanks for the detailed report and for providing the ANR traces, affected device information, and analysis of the MediaTek Vulkan-to-OpenGLES fallback.
Related to #193148. While #193148 tracks the increased graphics memory usage associated with the MediaTek Vulkan fallback on Mali-G52 devices, this issue tracks the reported OpenGLES/Mali driver deadlocks and ANRs associated with IO-thread
glReadPixelsreadbacks on Mali-G57/G68/G77 devices.Based on the information provided, I’ll route this issue to
team-enginefor further investigation.gaaclarke commentedon Sep 28, 2026
@suryaKommana2662 this is going be hard to make progress on without some sort of reproduction. An app can have plugins which cause hangs like this. Can you please send some time trying to identify a reproduction? Thanks.
15 remaining items
preethi0228-git commentedon Oct 5, 2026
Hi,
The reporter was able to reproduce the issue on SDK 32. However, the available testing device is currently running SDK 33. I have verified the reported behavior on SDK 33, but I was unable to reproduce the issue in my testing environment.
Device tested : moto g 2025 + Mediatek + ro.vendor.build.version.sdk 33.
impellerfreeze.mov
Thanks
vishnunew commentedon Oct 8, 2026
Thanks for testing! That phone isn't affected. Your screenshot shows "Not the affected configuration" and "Impeller backend in use: Vulkan", because its vendor SDK is 33.
The freeze needs
ro.vendor.build.version.sdkbelow 32 (31 or lower). That's what makes 3.47 pick OpenGLES on MediaTek. It's the vendor partition level, not the Android version. For example,austinruns Android 13 (API 33) but its vendor SDK is 31.Check with:
adb shell getprop ro.vendor.build.version.sdkAffected phones are usually MediaTek phones that launched on Android 12 or earlier and were upgraded later. The moto g 5G (2022) is available on Firebase Test Lab as
austin(version 33). The repro's first screen says "Affected configuration" and shows "OpenGLES" on a phone that qualifies.WessimBetclic commentedon Oct 26, 2026
Production data from another app, same 3.47 OpenGL ES fallback, but the readback crashes rather than freezing. Filed separately as #195319 since the stacks and the signal differ.
Our app reads 16 columns of the status bar area back after a
Picture.toImage(Image.toByteData,rawRgba) on route changes and on return to the foreground. On Impeller GLES this dies in two ways, both inside the deferredBlitCopyTextureToBufferCommandGLESencode thatImageEncodingImpeller::ConvertDlImageToSkImagequeues:ConfigureFBO→SetAsFramebufferAttachment(blit_command_gles.cc:49), throughglFramebufferTexture2DMultisampleEXT.FML_CHECK(result) << "Must be able to encode GL commands without error."(blit_pass_gles.cc:88) when that encode returns false.Flutter 3.47.3 stable, engine
06a2e2a1. Over 7 days on that build: about 960 users across our 6 Android apps, about 70% of all crashed users on our largest one.Device overlap with this issue: TECNO KM7, KM6, KM7k, CL6k, CM6, KJ7, KJ5, CK6, CLA5, Infinix X6880, itel A669W (MediaTek, Mali,
libGLES_mali.soin 102 of 136 decoded stacks). Not only MediaTek though: Honor ABR-NX1 and FNE-NX9 and Samsung SM-G973U crash the same way withlibGLESv2_adreno.soin the stack (17 of 136), so the GLES readback path is affected wherever the engine lands on OpenGL ES.Symbolicated stacks, counts and the sequence we run are in #195319. We will report back from production once a fix ships in a release we can take.
walley892 commentedon Nov 4, 2026
I don't think the affected configuration is correctly nailed down. I've failed to repro on a Redmi Note 9 and a fire HD 10, both of which advertise "Affected configuration" using https://github.com/vishnunew/flutter-mali-gles-freeze-repro. Both of these devices fall back to OpenGL
b-luk commentedon Nov 4, 2026
@vishnunew I have a potential fix for this at #195927, but we've been unable to repro the issue with the devices we have on hand. Are you able to try patching this PR and seeing if it fixes the issue on your device?
b-luk commentedon Nov 7, 2026
I was able to get a moto g 5g (2022) to test with. I was able to repro the issue, and confirmed that it no longer repros with the fix.
Read back images on the raster thread on OpenGLES (flutter#195927)
b-luk commentedon Nov 10, 2026
Fixed by #195927
dfdgsdfg commentedon Nov 13, 2026
Adding a standalone native reproducer as a reference for this investigation and #195927:
The native comparison keeps producer
glFinish, immutable source lifetimes, software UI, and IO attachment/read A fixed. Only Raster's source changes: A in AA, B in AB.In both AA captures, progress remains unchanged for over 30 seconds. The selected stacks show IO inside
glReadPixels, Raster inside that generation's firstglBindTexture, and a Mali backend waiting on a mutex. Diagnostic SIGABRT is intentional after the stall. AB also retains overlapping first-use host-call intervals and completes without a reported GL error.