Skip to content

[DNM] Thought experiment: Encapsulate standalone app start logic in AppStartIntegration#5488

Draft
0xadam-brown wants to merge 2 commits into
mainfrom
arb/2-standalone-thought-experiment
Draft

[DNM] Thought experiment: Encapsulate standalone app start logic in AppStartIntegration#5488
0xadam-brown wants to merge 2 commits into
mainfrom
arb/2-standalone-thought-experiment

Conversation

@0xadam-brown
Copy link
Copy Markdown
Member

@0xadam-brown 0xadam-brown commented Jun 1, 2026

📜 Description

PR's latest commit represents a halfway house between the current standalone app implementation from #5342 (== the PR's first commit) and our possible ideal of using AppStartMetrics as a relay point for transaction-related info that must be shared between ActivityLifecycleIntegration and (the newly-proposed) AppStartIntegration (trace ID, start timestamp, end timestamp).

See related Excalidraw: link for a comparison between #5342, this branch, and the proposed ideal. (Don't interpret its proposals as being fully baked – they're just initial sketches we'll want to fill in.)


"Draft" status is meant in earnest: I asked Codex for an implementation that treated AppStartMetrics as an inert data holder + sequestered standalone app start logic into a new AppStartIntegration, and I got one; I haven't reviewed the details.

🔮 Next steps

Decide whether we want to merge #5432 as-is, go for the halfway house, or implement the ideal.

buenaflor and others added 2 commits May 29, 2026 20:16
Squashed representation of PR #5342. Adds standalone Android app-start
transaction support behind the opt-in enableStandaloneAppStartTracing option
and the io.sentry.standalone-app-start-tracing.enable manifest key, including
the non-activity (headless) startup path. Legacy flag-off behavior is preserved:
activity app-start data remains nested under the ui.load transaction.

Refs #5342
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants