Add an API to the Sentry Android SDK to extend the app start measurement past its default end point and instrument the extended region with child spans.
// Simple: extend the app start window, then finish
Sentry.extendAppStart()
initializeRemoteConfig()
Sentry.finishExtendedAppStart()
// With child spans: instrument the extended region
Sentry.extendAppStart()
val span = Sentry.getExtendedAppStartSpan()
val configSpan = span.startChild("app.init", "fetch remote config")
fetchRemoteConfig()
configSpan.finish()
Sentry.finishExtendedAppStart()
Reference: getsentry/sentry-cocoa#6886 (Done, SentryExtendedAppLaunchManager). Siblings: getsentry/sentry-dart#3767, getsentry/sentry-react-native#6303 — shared contract, per-platform deltas below.
API
extendAppStart(): void — creates the extended app start span (op app.start.extended, description "Extended App Start").
finishExtendedAppStart — finishes it (returns void); triggers finalization.
getExtendedAppStartSpan(): ISpan — returns the span for attaching children; a no-op span when there's no active extension.
finishExtendedAppStart is equivalent to calling .finish() on the returned span.
Lifecycle
extendAppStart: creates the span (start = call time). No-ops if app start already finished, if none is in progress, or on repeat calls (first wins).
getExtendedAppStartSpan: returns the extended span, else a no-op span.
finishExtendedAppStart: no-ops if not extended or called twice. Doesn't finalize directly — the parent (auto-generated, waitForChildren) finalizes when its last child finishes and trims its end to that child. Open children of the extended span are finished cancelled at the finish-call time.
Duration & measurement
- Parent duration = end of the last child to finish (trim-to-last-child), floored at the default app start end — i.e.
end = max(last child end, default app start end). Extending can only push the end later; finishing before the default end keeps the default (never shorter than a non-extended app start). The extended span is just one participant.
- App start measurement = that final duration (process start → last child), set at finalization. The normal completion-time measurement must be suppressed in extended mode so the early (non-extended) value doesn't win.
Timeout
- Parent's auto-finish deadline is 30s. If
finishExtendedAppStart is never called, the transaction auto-finishes on the deadline (unfinished children → deadlineExceeded, snapped to transaction end), is still captured, but the app.vitals.start measurement is suppressed — never emit a ~30s app start. Same for standalone and ui.load.
Standalone & non-standalone
- Both supported, same mechanism: standalone uses the app-start tracer, non-standalone the
ui.load transaction (also waitForChildren + deadline). In non-standalone the duration is bounded by anything keeping ui.load open (TTID, other children), so it can include spans unrelated to the extension.
Android delta
Acceptance criteria
Add an API to the Sentry Android SDK to extend the app start measurement past its default end point and instrument the extended region with child spans.
Reference: getsentry/sentry-cocoa#6886 (Done,
SentryExtendedAppLaunchManager). Siblings: getsentry/sentry-dart#3767, getsentry/sentry-react-native#6303 — shared contract, per-platform deltas below.API
extendAppStart(): void— creates the extended app start span (opapp.start.extended, description"Extended App Start").finishExtendedAppStart— finishes it (returns void); triggers finalization.getExtendedAppStartSpan(): ISpan— returns the span for attaching children; a no-op span when there's no active extension.Lifecycle
extendAppStart: creates the span (start = call time). No-ops if app start already finished, if none is in progress, or on repeat calls (first wins).getExtendedAppStartSpan: returns the extended span, else a no-op span.finishExtendedAppStart: no-ops if not extended or called twice. Doesn't finalize directly — the parent (auto-generated,waitForChildren) finalizes when its last child finishes and trims its end to that child. Open children of the extended span are finishedcancelledat the finish-call time.Duration & measurement
end = max(last child end, default app start end). Extending can only push the end later; finishing before the default end keeps the default (never shorter than a non-extended app start). The extended span is just one participant.Timeout
finishExtendedAppStartis never called, the transaction auto-finishes on the deadline (unfinished children →deadlineExceeded, snapped to transaction end), is still captured, but theapp.vitals.startmeasurement is suppressed — never emit a ~30s app start. Same for standalone andui.load.Standalone & non-standalone
ui.loadtransaction (alsowaitForChildren+ deadline). In non-standalone the duration is bounded by anything keepingui.loadopen (TTID, other children), so it can include spans unrelated to the extension.Android delta
ActivityLifecycleIntegration/AppStartMetrics); extended launches must inherit the existingapp_start_typetagging (Android: Tag all spans withapp_start_type#3989).Acceptance criteria
extendAppStart()creates the span before finish; no-ops when too late, not started, or called repeatedly.getExtendedAppStartSpan()returns the span, else a no-op span (including after finish).Extended App Start.finishExtendedAppStartno-ops if not extended or called twice; finalizes viawaitForChildrenwith transaction end = last child.cancelled; on deadline →deadlineExceeded, snapped to end.app.vitals.startsuppressed.app_start_typemetadata.