Skip to content

SentryFrameMetricsCollector blocks the main thread in HandlerThread.getLooper() when the first activity transaction starts #6443

Open

Description

@ikerfah

Integration

sentry-android

Build System

Gradle

AGP Version

9.2.1

Proguard

Enabled

Other Error Monitoring Solution

No

Version

8.60.0

Steps to Reproduce

  1. Use sentry-android 8.60.0 (same code in 8.61.0) with enablePerformanceV2 and enableFramesTracking on (the defaults) and activity tracing on.
  2. Cold start the app on a busy device, for example shortly after boot.
  3. Record a Perfetto trace of the cold start.
  4. Look at the main thread during the launcher activity's onCreate: it sits in HandlerThread.getLooper() under SentryFrameMetricsCollector.startCollection, called from SpanFrameMetricsCollector.onSpanStarted when ActivityLifecycleIntegration starts the activity transaction.

Expected Result

Starting frame collection for the first activity transaction doesn't block the main thread.

Actual Result

SentryFrameMetricsCollector.ensureHandlerThreadStarted() starts the HandlerThread and then calls getLooper(), which blocks the main thread until the new thread is running. In our trace this took 308 ms during the launcher activity's onCreate. Since #5641 (8.47.0) this wait happens at the first startCollection() call instead of during SentryAndroid.init, so it moved to Activity.onCreate rather than going away.

Image

Activity

  1. linear-code commented on Nov 2, 2026

    @linear-code
  2. ikerfah commented on Nov 3, 2026

    @ikerfah
    Author

    Probably the main cause is that ensureHandlerThreadStarted() calls handlerThread.start() and then getLooper(), which waits until the new thread has run.

    One potential solution is to keep starting the thread lazily, but stop calling getLooper() on the calling thread, then create the Handler in HandlerThread.onLooperPrepared(). It runs on the new thread once its looper exists, so nothing waits.
    The only trad-off I can think off is that the listener is only attached before the activity's first frame if the thread is ready by the time that frame is scheduled, it means that if the thread is slower, we might miss some transactions.

    I that frame drops are critical, this proposal may require further consideration

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions