Repository navigation
Description
Steps to reproduce
- Run a Flutter application on an Android device with Adreno GPU (Impeller/Vulkan backend)
- While the Flutter app is in the foreground, trigger GPU pressure through one of:
- Launch a GPU-intensive game (e.g., cold start of a game that performs heavy shader compilation and texture uploads)
- Allow DMA-BUF memory leak to accumulate (observed 1.9GB~3.1GB in production)
- While GPU is under pressure, switch away from the Flutter app (press Home or switch to another app), triggering
Activity.onStop()→onSurfaceDestroyed() - The app ANRs within 5-10 seconds
Expected results
The Flutter engine should gracefully handle GPU pressure during surface teardown. When the GPU cannot complete rendering within a reasonable time, the engine should:
- Time out the fence wait
- Abandon the current frame (dropping one frame is acceptable)
- Free the raster thread to process the teardown task
- Allow the platform thread to complete the Activity lifecycle without blocking indefinitely
Actual results
The platform (main) thread is blocked indefinitely, causing an ANR (Application Not Responding). The blocking chain:
Platform thread:
Shell::OnPlatformViewDestroyed() [shell.cc:1189]
→ latch.Wait() // no timeout, waits forever
→ waiting for raster thread to complete teardown
Raster thread (blocked, cannot process teardown):
KHRSwapchainImplVK::AcquireNextDrawable()
→ KHRFrameSynchronizerVK::WaitForFence() [khr_swapchain_impl_vk.cc:54]
→ vkWaitForFences(timeout=UINT64_MAX) // infinite wait on GPU fence
The raster thread is stuck in vkWaitForFences with UINT64_MAX timeout because the GPU cannot signal the fence (due to contention or memory pressure). Since the raster thread never completes the current draw, it never picks up the teardown task from its queue, so the latch is never signaled, and the platform thread blocks forever.
Code sample
Code sample
The issue is in the engine internals, not application code. The problematic code locations:
1. impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc:47-58
bool WaitForFence(const vk::Device& device) {
if (!acquire_fence_pending) {
return true;
}
if (auto result = device.waitForFences(
*acquire, // fence
true, // wait all
std::numeric_limits<uint64_t>::max() // timeout (ns) ← INFINITE
);
result != vk::Result::eSuccess) {
VALIDATION_LOG << "Fence wait failed: " << vk::to_string(result);
return false;
}
// ...
}2. impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc:382-387
// @bug Non-infinite timeouts are not supported on some older Android
// devices and the only indication we get is log spam which serves to
// add confusion. Just use an infinite timeout instead of being
// defensive.
auto [acq_result, index] = context.GetDevice().acquireNextImageKHR(
*swapchain_, // swapchain
std::numeric_limits<uint64_t>::max(), // timeout (ns) ← INFINITE
*sync->render_ready, // signal semaphore
nullptr // fence
);3. shell/common/shell.cc:1189
// Shell::OnPlatformViewDestroyed()
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetRasterTaskRunner(),
raster_task);
latch.Wait(); // ← no timeout, blocks platform thread foreverScreenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
We observed this ANR pattern across 3 different production logs on Android devices with Adreno GPUs:
| Scenario | GPU Memory | Fence Delay | Root Cause |
|---|---|---|---|
| Game cold start (P11U) | Normal (~456MB) | ~7s | GPU command queue saturated by game's shader compilation and texture uploads |
| Frequent app switching (O8) | Elevated (1.9GB) | ~68s | GPU memory pressure from high DMA-BUF usage |
| DMA-BUF leak (O8) | Leaked (2.2~3.1GB) | ~3min | GPU memory exhaustion, fence cannot signal |
All three cases share the identical blocking chain: vkWaitForFences(UINT64_MAX) on raster thread → platform thread latch.Wait() → ANR.
Note about the existing @bug comment in the code (line 378-381):
The comment states "Non-infinite timeouts are not supported on some older Android devices." This may have been true historically, but the consequence of using infinite timeout is that any GPU issue becomes an unrecoverable ANR. A timeout with graceful frame-drop would be strictly better than an infinite hang.
Flutter Doctor output
Doctor output
Flutter 3.38
Android devices: Qualcomm Adreno GPU (Snapdragon platforms)
Affected devices observed: Xiaomi Mix Filp2 REDMI K90
Activity
puneetkukreja98 commentedon Apr 10, 2026
@XyTechWorks Thanks for reporting it.
Could you please verify if this persists on the latest stable version (3.41.6)?
XyTechWorks commentedon Apr 13, 2026
I cannot use the latest stable, but I see that on the latest master branch, the waitforfenc waiting time in ahb_soapchain_impl_vk.cc is still max, so this problem should still exist, Why is it designed as max here.
gaaclarke commentedon Apr 13, 2026
The root cause of this may have been addressed by @jason-simmons in #183288
XyTechWorks commentedon Apr 14, 2026
I see that khr_swapchain_impl_vk.cc is in this change, so does ahb_swapchain_impl_vk.cc not need to be changed?