Skip to content

Defer SentryFrameMetricsCollector thread startup #5483

Description

@linear-code

SentryFrameMetricsCollector created and started its HandlerThread in the constructor and then called new Handler(handlerThread.getLooper()). getLooper() blocks the caller until the new thread's looper is ready — and the collector is constructed on the main thread during SentryAndroid.init (loadDefaultAndMetadataOptions).

The customer-provided Perfetto trace (sentryinvest) showed the main thread blocking ~5.75 ms on HandlerThread.getLooper() during init via SentryFrameMetricsCollector.<init>.

Fix

The handler is only used by trackCurrentWindow(), which no-ops until a listener is registered via startCollection(). Start the HandlerThread lazily on the first startCollection() (profiling / SpanFrameMetricsCollector). The constructor still registers the activity-lifecycle callback (current-window tracking unchanged) but no longer blocks. Apps that never collect frame metrics never start the thread at all.

Reusing the SDK's shared executor isn't viable: addOnFrameMetricsAvailableListener requires a dedicated non-main-thread Handler (Looper), which the shared ScheduledExecutorService doesn't provide.

Pixel 3 benchmark (Android 12, ART method trace → Perfetto trace_processor)

Constructor HandlerThread.getLooper() / blocking Object.wait() slices: old = 1 / 1 → new = 0 / 0. The synchronous main-thread wait is removed from construction.

PR

#5641

Activity

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

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions