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

Metadata

Metadata

Assignees

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions