…tReporter
The standalone app-start feature was spread across ActivityLifecycleIntegration,
AppStartMetrics, and PerformanceAndroidEventProcessor: ALI held the transaction
field, creation branches, and the headless listener callback; AppStartMetrics
acted as a trace-id mailbox; and the event processor re-derived "is this a
headless standalone app start" by sniffing the presence of a span-data key. No
single place owned the feature.
Introduce StandaloneAppStartReporter, which owns the feature end-to-end on the
post-init side of the SDK (it holds an IScopes and can start transactions):
emitting the activity-launch sibling and the headless transaction, keeping the
shared trace id, and classifying transactions for the event processor via
isStandaloneAppStart/isHeadlessAppStart. AppStartMetrics stays a pre-init,
scope-less recorder that only emits the headless signal; ALI delegates to the
reporter instead of carrying the logic; the event processor asks the reporter
how to classify a transaction rather than poking at its data map. Only data
crosses the pre-/post-init seam, not logic.
No behavior change. Net -76 lines and two fewer public methods on AppStartMetrics.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ref(android): Consolidate headless app start scheduling to one site
Scheduling of the main-thread idle check lived in two places: registerLifecycleCallbacks
(gated on appStartType == UNKNOWN || listener != null) and setHeadlessAppStartListener
(a side-effect gated on isCallbackRegistered && no activities yet && first draw not done).
The setter's side-effect was load-bearing because the listener is installed during SDK
init, after the early SentryPerformanceProvider registration, so on API 35+ with a known
start type registerLifecycleCallbacks would skip scheduling and the setter had to cover it.
Schedule the idle check unconditionally from the single registration site and make the
setter a plain assignment. The idle handler already no-ops once an Activity exists and reads
the listener when it fires (after init has installed it), so it can serve both consumers —
the pre-API-35 cold/warm heuristic and standalone headless emission — without the setter
needing to know about timing.
The only behavior change: on API 35+ with a known type and standalone disabled, the idle
check is now scheduled (previously skipped). It no-ops for foreground launches and, for a
truly headless launch, correctly marks the start as background and stops app-start profilers.
ref(android): Add AppStartIntegration for standalone app start
Move headless standalone app-start emission out of AppStartMetrics into
StandaloneAppStartReporter behind a new AppStartIntegration. Metrics keeps
idle scheduling and shared boot bookkeeping; ActivityLifecycleIntegration
coordinates via StandaloneAppStartCoordinator only when the feature is enabled.
Refs #5342
Co-Authored-By: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ref(android): Decouple app start from ActivityLifecycleIntegration
ActivityLifecycleIntegration dispatches AppStartLifecycle callbacks instead
of taking a StandaloneAppStartCoordinator. AppStartIntegration registers
StandaloneAppStartReporter as the listener at init time.
Refs #5342
Co-Authored-By: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ref(android): Plan first ui.load via standalone app start listener
Use UiLoadStartPlan so ActivityLifecycleIntegration starts ui.load without
headless branching while StandaloneAppStartReporter owns trace reuse and
sibling App Start emission.
Co-Authored-By: Cursor <cursoragent@cursor.com>
ref(android): Use single ui.load startTransaction path for standalone
planFirstUiLoad now takes isFirstProcessStart so ActivityLifecycleIntegration
always builds one TransactionContext while headless reuse stays in the reporter.
Co-Authored-By: Cursor <cursoragent@cursor.com>
ref(android): Rename FirstUiLoad types and narrow standalone API
Rename AppStartLifecycle and AppStartLifecycleListener to FirstUiLoad and
FirstUiLoadListener. Make standalone app start wiring package-private and
drop those types from the public api dump.
Co-Authored-By: Cursor <cursoragent@cursor.com>
ref(android): Replace static FirstUiLoad with init-scoped coordinator
Wire the standalone app-start listener through a FirstUiLoadCoordinator
created in AndroidOptionsInitializer and shared by AppStartIntegration
and ActivityLifecycleIntegration instead of a static global holder.
Co-Authored-By: Auto <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>