Skip to content

Conversation

@markushi
Copy link
Member

@markushi markushi commented Dec 29, 2025

📜 Description

Improves app start type detection by introducing a new timing mechanism that captures when the first Handler.post executes on the main thread. This helps distinguish between cold and warm starts more accurately when activity creation is delayed.

Fixes #4920

The changes add:

  • A new firstPostUptimeMillis field to track when the main thread becomes ready
  • Enhanced logic in onActivityCreated() to detect warm starts when activity creation happens after the first main thread post
  • Comprehensive unit tests covering the new timing logic and edge cases

💡 Motivation and Context

The existing app start type detection could incorrectly classify some warm starts as cold starts, particularly when there was a delay between process initialization and activity creation. This change adds an additional timing check to improve accuracy.

💚 How did you test it?

  • Added 8 new unit tests covering:
    • Field initialization and cleanup
    • Timing capture behavior
    • WARM/COLD detection logic
    • Condition precedence ordering
    • Edge cases (race conditions, timing equality)
  • All existing tests pass
  • Code formatted with spotlessApply

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

Update CHANGELOG.md after PR creation

@github-actions
Copy link
Contributor

github-actions bot commented Dec 29, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 337.15 ms 398.88 ms 61.73 ms
Size 1.58 MiB 2.20 MiB 635.38 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
f634d01 375.06 ms 420.04 ms 44.98 ms
d5a29b6 298.62 ms 391.78 ms 93.16 ms
fcec2f2 314.96 ms 373.66 ms 58.70 ms
bbc35bb 324.88 ms 425.73 ms 100.85 ms
ee747ae 405.43 ms 485.70 ms 80.28 ms
d15471f 369.38 ms 459.08 ms 89.70 ms
ee747ae 396.82 ms 441.67 ms 44.86 ms
fc5ccaf 276.52 ms 370.46 ms 93.93 ms
bbc35bb 298.53 ms 372.17 ms 73.64 ms
d15471f 310.66 ms 368.19 ms 57.53 ms

App size

Revision Plain With Sentry Diff
f634d01 1.58 MiB 2.10 MiB 533.40 KiB
d5a29b6 1.58 MiB 2.12 MiB 549.37 KiB
fcec2f2 1.58 MiB 2.12 MiB 551.50 KiB
bbc35bb 1.58 MiB 2.12 MiB 553.01 KiB
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
fc5ccaf 1.58 MiB 2.13 MiB 557.54 KiB
bbc35bb 1.58 MiB 2.12 MiB 553.01 KiB
d15471f 1.58 MiB 2.13 MiB 559.54 KiB

Previous results on branch: fix/app-start-warm-detection

Startup times

Revision Plain With Sentry Diff
a0d0a05 303.68 ms 339.38 ms 35.70 ms

App size

Revision Plain With Sentry Diff
a0d0a05 1.58 MiB 2.13 MiB 559.63 KiB

@markushi
Copy link
Member Author

@sentry review

Comment on lines 358 to 364
if (activeActivitiesCounter.incrementAndGet() == 1 && !firstDrawDone.get()) {
final long nowUptimeMs = SystemClock.uptimeMillis();

// If the app (process) was launched more than 1 minute ago, it's likely wrong
// If the app (process) was launched more than 1 minute ago, consider it a warm start
final long durationSinceAppStartMillis = nowUptimeMs - appStartSpan.getStartUptimeMs();
if (!appLaunchedInForeground || durationSinceAppStartMillis > TimeUnit.MINUTES.toMillis(1)) {
appStartType = AppStartType.WARM;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The appStartSpan is used before it is started in onActivityCreated(), causing cold starts to be incorrectly classified as warm starts.
Severity: HIGH | Confidence: High

🔍 Detailed Analysis

In the onActivityCreated method, the duration since app start is calculated using appStartSpan.getStartUptimeMs(). However, the appStartSpan is only started later within the same method. Because appStartSpan is not yet started, getStartUptimeMs() returns its default value of 0. This causes the durationSinceAppStartMillis to be incorrectly calculated as nowUptimeMs - 0, a large value that will almost always exceed one minute. As a result, the logic incorrectly classifies cold app starts as warm starts, skewing performance metrics.

💡 Suggested Fix

The logic should be changed to ensure appStartSpan is started before its start time is read for the duration calculation. Alternatively, add a check to see if the span has been started before using its value.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java#L358-L364

Potential issue: In the `onActivityCreated` method, the duration since app start is
calculated using `appStartSpan.getStartUptimeMs()`. However, the `appStartSpan` is only
started later within the same method. Because `appStartSpan` is not yet started,
`getStartUptimeMs()` returns its default value of 0. This causes the
`durationSinceAppStartMillis` to be incorrectly calculated as `nowUptimeMs - 0`, a large
value that will almost always exceed one minute. As a result, the logic incorrectly
classifies cold app starts as warm starts, skewing performance metrics.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 7993492

use `options.isCollectExternalStorageContext = true` or `<meta-data android:name="io.sentry.external-storage-context" android:value="true" />`
- Fix `NullPointerException` when reading ANR marker ([#4979](https://github.com/getsentry/sentry-java/pull/4979))
- Report discarded log in batch processor as `log_byte` ([#4971](https://github.com/getsentry/sentry-java/pull/4971))
- Fix warm app start type detection for edge cases ([#4999](https://github.com/getsentry/sentry-java/pull/4999))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 🚫 The changelog entry seems to be part of an already released section ## 8.30.0.
    Consider moving the entry to the ## Unreleased section, please.

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.

Warm starts potentially reported as cold starts for activities in singleTask launch mode

2 participants