Skip to content

RUM-14471: Auto-forward TTID to next activity for interstitial pattern#3199

Merged
hamorillo merged 4 commits intodevelopfrom
hector.morilloprieto/RUM-14471-auto-subscribe
Mar 4, 2026
Merged

RUM-14471: Auto-forward TTID to next activity for interstitial pattern#3199
hamorillo merged 4 commits intodevelopfrom
hector.morilloprieto/RUM-14471-auto-subscribe

Conversation

@hamorillo
Copy link
Copy Markdown
Contributor

@hamorillo hamorillo commented Feb 24, 2026

What does this PR do?

Note: This PR is targeting hector.morilloprieto/RUM-14471, as it is an iteration of it. It's motivated by this comment.

Automatically detects and forwards TTID (Time To Initial Display) measurement to the next qualifying activity when an interstitial activity (e.g. a splash screen) calls startActivity() + finish() without ever calling setContentView(). In this pattern the OnDrawListener never fires on the interstitial, so TTID is silently dropped. This PR makes the SDK detect that case and subscribe to the next activity's first frame draw instead — with no customer configuration required.

Motivation

Customers using a splash/auth screen pattern were losing TTID data entirely because the SDK had no way to recover when the first tracked activity never drew a frame.

How to test

Apply the attached patch to the branch:

The patch modifies the sample app to add a SplashActivity as the launcher activity. This activity immediately calls startActivity(NavActivity) + finish() without setting a content view, simulating an interstitial splash screen. It also sets telemetry sampling to 100% and reduces session inactivity timeout to 15 seconds for easier testing.

Run the sample app and check the RUM dashboard — you should see TTID reported for NavActivity with was_forwarded: true in the startup telemetry metric.

Additional Notes

  • No time-based heuristics — forwarding is triggered purely by activity lifecycle events (onBeforeActivityCreated while a pending startup scenario exists).
  • First-draw-wins — if multiple activities are created concurrently, whichever draws first reports TTID; subsequent callbacks are discarded via an identity check on pendingScenario.
  • wasForwarded telemetry flag added to RumTTIDInfo and reported via the telemetry metric so we can measure how often this path is taken.
  • New integration tests cover synchronous interstitial, chained (A→B→C), and async/deferred navigation scenarios.

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

When an interstitial activity (e.g. splash screen) starts the next
activity and finishes without ever calling setContentView(), the
OnDrawListener never fires and TTID is never reported. This change
detects that pattern automatically and forwards the TTID subscription
to the next qualifying activity — no customer configuration required.
@datadog-datadog-prod-us1-2
Copy link
Copy Markdown

datadog-datadog-prod-us1-2 Bot commented Feb 24, 2026

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 66.60%

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 095fa1e | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback!

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 93.33333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.47%. Comparing base (faf2b5e) to head (095fa1e).
⚠️ Report is 199 commits behind head on develop.

Files with missing lines Patch % Lines
...lin/com/datadog/android/rum/internal/RumFeature.kt 77.78% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3199      +/-   ##
===========================================
+ Coverage    71.26%   71.47%   +0.22%     
===========================================
  Files          929      929              
  Lines        34457    34489      +32     
  Branches      5813     5825      +12     
===========================================
+ Hits         24553    24651      +98     
+ Misses        8263     8210      -53     
+ Partials      1641     1628      -13     
Files with missing lines Coverage Δ
...roid/rum/internal/startup/RumAppStartupDetector.kt 100.00% <ø> (ø)
.../rum/internal/startup/RumAppStartupDetectorImpl.kt 97.01% <100.00%> (+3.01%) ⬆️
...rnal/startup/RumAppStartupTelemetryReporterImpl.kt 100.00% <100.00%> (ø)
...atadog/android/rum/internal/startup/RumTTIDInfo.kt 100.00% <100.00%> (ø)
...lin/com/datadog/android/rum/internal/RumFeature.kt 92.66% <77.78%> (+3.38%) ⬆️

... and 35 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@hamorillo
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5b94701d6b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +87 to +91
val isFirstTrackedActivityWithNoPendingStartup =
trackedActivities.size == 1 &&
!isChangingConfigurations &&
shouldTrackStartup &&
pendingScenario == null
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reset stale pending startup before suppressing new scenarios

The new pendingScenario == null gate means a startup scenario can block all future startup detection indefinitely if the original interstitial never draws and no follow-up activity is created immediately (for example, user leaves the app after a splash finish(), then returns later in the same process). In that case, the next launch path skips creating a fresh scenario and keeps forwarding the old one, which can suppress the new app-start event and report an inflated TTID based on the stale initialTime.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

@hamorillo hamorillo Feb 25, 2026

Choose a reason for hiding this comment

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

Not sure how common this case would be.

I see two options here:

  • Prevent stale pendingScenario from blocking future startups by clearing it in RumAppStartupDetectorImpl.onBeforeActivityCreated() when it’s older than rumSessionScopeStartupManagerImpl.MAX_TTID_DURATION_NS (let's say 1 minute), so a later “re-launch” in the same process creates a fresh startup scenario instead of forwarding a stale one?

  • Accept this case and create some documentation.

Any other ideas?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thought about it for a bit. Your option 1 seems like a right thing to do. We already have this 1 minute threshold

for TTID.

@hamorillo hamorillo marked this pull request as ready for review February 25, 2026 14:51
@hamorillo hamorillo requested review from a team as code owners February 25, 2026 14:51
Comment on lines +87 to +91
val isFirstTrackedActivityWithNoPendingStartup =
trackedActivities.size == 1 &&
!isChangingConfigurations &&
shouldTrackStartup &&
pendingScenario == null
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thought about it for a bit. Your option 1 seems like a right thing to do. We already have this 1 minute threshold

for TTID.

Copy link
Copy Markdown
Contributor

@aleksandr-gringauz aleksandr-gringauz left a comment

Choose a reason for hiding this comment

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

LGTM!

Base automatically changed from hector.morilloprieto/RUM-14471 to develop March 4, 2026 08:49
@hamorillo hamorillo dismissed aleksandr-gringauz’s stale review March 4, 2026 08:49

The base branch was changed.

@hamorillo hamorillo merged commit 091844a into develop Mar 4, 2026
25 checks passed
@hamorillo hamorillo deleted the hector.morilloprieto/RUM-14471-auto-subscribe branch March 4, 2026 08:59
@ncreated ncreated restored the hector.morilloprieto/RUM-14471-auto-subscribe branch April 9, 2026 09:51
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.

3 participants