Skip to content

fix(android): Defer frame metrics reflection during init - #5886

Open
0xadam-brown wants to merge 1 commit into
mainfrom
fix/no-reflection-on-main-thread
Open

fix(android): Defer frame metrics reflection during init#5886
0xadam-brown wants to merge 1 commit into
mainfrom
fix/no-reflection-on-main-thread

Conversation

@0xadam-brown

@0xadam-brown 0xadam-brown commented Aug 4, 2026

Copy link
Copy Markdown
Member

📜 Description

Moves Choreographer private field lookup out of the frame metrics collector constructor synchronously framework reflection on the calling (i.e., main) thread during Sentry.init(). Helps us reduce the likelihood of another common class of init ANRs (see here).

💡 Motivation and Context

We've seen 583k ANR events involving the SentryFrameMetricsCollector across 257 affected users since November 2024 (link), making it the highest-volume SDK-caused ANR we track.

Those numbers got lots better thanks to @runningcode's fix in #5641: events peaked at ~12k per 3-day window in June 2026, then dropped sharply to (a fairly consistent) ~4k/3d. But the reflection this PR addresses continues to contribute to those remaining ANRs across all SDK versions, including the newest ones.

Any behavior changes?

Behavior change from the user's perspective should be nonexistant in most cases, and minor in the worst case.

The choreographer and choreographerLastFrameTimeField properties are still initialized by a main-thread Handler post made during collector construction, before later startCollection() calls post frame-listener registration work to the same main looper. Since those main looper tasks run in order, the Choreographer fallback should be populated before any collected frame or pending-frame interpolation normally needs it. If it's not ready yet, the failure mode is a missed/less precise first pending-frame calculation rather than a crash.

💚 How did you test it?

Unit tests + manual smoke tests on Android sample app.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

@0xadam-brown
0xadam-brown force-pushed the fix/no-reflection-on-main-thread branch from e23fd78 to 1420ac9 Compare August 4, 2026 11:48
@sentry

sentry Bot commented Aug 4, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.51.0 (1) release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 324.23 ms 374.78 ms 50.55 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
d15471f 369.38 ms 459.08 ms 89.70 ms
bbc35bb 324.88 ms 425.73 ms 100.85 ms
b193867 319.59 ms 403.09 ms 83.50 ms
62b579c 299.75 ms 364.84 ms 65.09 ms
382d6c1 306.85 ms 368.70 ms 61.85 ms
48277cd 320.38 ms 379.90 ms 59.52 ms
5b1a06b 315.40 ms 353.33 ms 37.94 ms
ee747ae 415.92 ms 470.15 ms 54.23 ms
37ec571 366.04 ms 424.28 ms 58.23 ms
462dea2 277.68 ms 359.83 ms 82.15 ms

App size

Revision Plain With Sentry Diff
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
bbc35bb 1.58 MiB 2.12 MiB 553.01 KiB
b193867 1.58 MiB 2.19 MiB 620.00 KiB
62b579c 0 B 0 B 0 B
382d6c1 1.58 MiB 2.29 MiB 719.85 KiB
48277cd 0 B 0 B 0 B
5b1a06b 0 B 0 B 0 B
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
37ec571 0 B 0 B 0 B
462dea2 0 B 0 B 0 B

Moves Choreographer private field lookup out of the frame metrics collector constructor so SDK init does not synchronously perform framework reflection on the calling thread. Helps us reduce the likelihood of another common class of Sentry.init() ANRs (see [here](https://sentry.sentry.io/issues/6138715212/?project=4506812075540480&referrer=seer.agent.in-chat-link)).

Behavior change from the user's perspective should usually be non-existant, and minor in the worst case. The choreographer and choreographerLastFrameTimeField properties are still initialized by a main-thread Handler post made during collector construction, before later startCollection() calls post frame-listener registration work to the same main looper. Since those main-looper tasks run in order, the Choreographer fallback should be populated before any collected frame or pending-frame interpolation normally needs it. If it's not ready yet, the failure mode is a missed/less precise first pending-frame calculation rather than a crash.

Co-Authored-By: OpenCode <noreply@opencode.ai>
@0xadam-brown
0xadam-brown force-pushed the fix/no-reflection-on-main-thread branch from 1420ac9 to ec477f3 Compare August 4, 2026 12:02
@0xadam-brown
0xadam-brown marked this pull request as ready for review August 4, 2026 12:06
@0xadam-brown 0xadam-brown added the sanity-check PR needs a lightweight review for obvious issues label Aug 4, 2026

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good with one nit! Thanks for taking this further!

private @Nullable Window.OnFrameMetricsAvailableListener frameMetricsAvailableListener;
private @Nullable Choreographer choreographer;
private @Nullable Field choreographerLastFrameTimeField;
private volatile @Nullable Choreographer choreographer;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only ever access these from the main thread why do we need to add volatile here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sanity-check PR needs a lightweight review for obvious issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants