Mobile Development 14 min read

Designing a Flutter Jank Monitoring System with Stack Trace Collection

The article outlines a Flutter jank monitoring system that detects frame stalls by measuring UI callback intervals and captures the offending Dart call stack, evaluating SDK modification, AOT native unwinding, and ultimately selecting a low‑overhead signal‑based stack‑collection method for production use.

Xianyu Technology
Xianyu Technology
Xianyu Technology
Designing a Flutter Jank Monitoring System with Stack Trace Collection

Flutter applications are known for high performance, but as they grow more complex occasional jank (frame drops) can occur. To diagnose these stalls, a monitoring system is needed that can both detect when jank happens and capture the call stack at that moment.

The problem is split into two parts: (1) determining that a jank event has occurred, and (2) obtaining the stack trace of the offending code during the stall.

Jank detection relies on understanding Flutter's rendering pipeline. The UI Task Runner executes Dart code and drives the pipeline via ui.window.scheduleFrame . When a VSync signal arrives, the engine calls ui.window.onBeginFrame and later ui.window.onDrawFrame . By measuring the time between these callbacks and comparing it to a configurable threshold (e.g., 100 ms), the system can decide that a jank has happened.

Three stack‑collection strategies were explored:

Modify the Dart SDK : Use StackTrace.current (an external native function) to retrieve the stack, but it cannot capture another isolate’s stack. By adding two new APIs, StackTrace.prepare (stores the root isolate’s thread) and StackTrace.root (retrieves the stored thread’s stack), the root isolate’s stack can be obtained from a helper isolate. The C++ implementations of these functions were examined (images omitted).

AOT native stack collection : In AOT builds the Dart code is compiled to native machine code. By pausing the UI thread, reading its PC and FP registers (using thread_get_state on iOS or ptrace on Android), and unwinding the native stack, the raw addresses can be symbolized against the app’s symbol table (generated with nm ) to reconstruct the Dart call stack.

Signal‑based collection (chosen solution) : Register a signal handler that, when triggered, captures the current thread’s stack without modifying the SDK. A helper thread periodically sends a signal to the UI Task Runner thread (identified by name, e.g., io.flutter.1.ui ). The handler pauses the thread, walks the stack, and then resumes execution. This method incurs the lowest performance overhead and avoids SDK changes.

A comparison of the three approaches shows that the signal‑based method offers minimal maintenance cost and the smallest runtime impact, so it was selected for production.

In summary, the article presents a comprehensive design for a Flutter jank monitoring system, covering detection logic, multiple stack‑capture techniques, and the final decision to use a lightweight signal‑based solution.

Dartflutterjank monitoringMobileNativeperformancestack trace
Xianyu Technology
Written by

Xianyu Technology

Official account of the Xianyu technology team

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.