Skip to content

RUM-15483: Fix clock mismatch in DefaultAppStartTimeProvider app start time computation#3587

Merged
hamorillo merged 1 commit into
developfrom
hector.morilloprieto/RUM-15483
Jun 30, 2026
Merged

RUM-15483: Fix clock mismatch in DefaultAppStartTimeProvider app start time computation#3587
hamorillo merged 1 commit into
developfrom
hector.morilloprieto/RUM-15483

Conversation

@hamorillo

@hamorillo hamorillo commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes a clock-domain mismatch in DefaultAppStartTimeProvider where the app start time computation mixed CLOCK_BOOTTIME (elapsedRealtime / Process.getStartElapsedRealtime()) with CLOCK_MONOTONIC (System.nanoTime()). The fix replaces the CLOCK_BOOTTIME pair with a fully CLOCK_MONOTONIC computation using SystemClock.uptimeMillis() / Process.getStartUptimeMillis().

To support this, getDeviceUptimeMillis() is added to the TimeProvider interface and implemented in BaseTimeProvider as SystemClock.uptimeMillis().

Motivation

On devices that sleep between process start and the first lazy access of appStartTimeNs (background launches, OEM battery optimization), the old formula produced a value that was too small by exactly the sleep duration. This silently inflated TTID, app startup duration, timeSinceAppStartNs on fatal/ANR errors, and NDK crash timestamps. The bug was identified while investigating the CI flake fixed in RUM-15269 (PR #3339).

Additional Notes

  • Process.getStartUptimeMillis() is available from API 24+ (confirmed from AOSP source) — no API level branching is required. It is already pre-approved in detekt_custom_safe_calls_android.yml.

Related to: #3339

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)

@hamorillo

Copy link
Copy Markdown
Contributor Author

@codex review

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

Copy link
Copy Markdown

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: f2483ebd1e

ℹ️ 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".

buildSdkVersionProvider.isAtLeastN -> {
val timeProvider = timeProviderFactory()
val diffMs = timeProvider.getDeviceElapsedRealtimeMillis() - Process.getStartElapsedRealtime()
val diffMs = timeProvider.getDeviceUptimeMillis() - Process.getStartUptimeMillis()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve a wall-clock start time for startup events

In the sleep-after-process-start case this now stores a sleep-excluding uptime/nanoTime value, but RUM still converts sdkCore.appStartTimeNs to a Time via asTimeNs() and uses scenario.initialTime.timestamp for TTID/TTFD startup events in RumSessionScopeStartupManager. Since wall time advances during device sleep while uptimeMillis()/nanoTime() do not, those startup events are timestamped late by exactly the sleep duration; keeping only this uptime-domain value fixes durations but corrupts event timing, so the timestamp path needs a separate boottime/wall-clock process start value.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think this PR is making it worse or better, but I could use a second opinion here if anyone thinks otherwise.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 72.53%. Comparing base (c6e8fe9) to head (f2483eb).
⚠️ Report is 6 commits behind head on develop.

Files with missing lines Patch % Lines
.../com/datadog/android/internal/time/TimeProvider.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #3587   +/-   ##
========================================
  Coverage    72.52%   72.53%           
========================================
  Files          978      978           
  Lines        36052    36046    -6     
  Branches      6038     6040    +2     
========================================
- Hits         26146    26143    -3     
+ Misses        8234     8228    -6     
- Partials      1672     1675    +3     
Files with missing lines Coverage Δ
.../core/internal/time/DefaultAppStartTimeProvider.kt 100.00% <100.00%> (ø)
.../com/datadog/android/internal/time/TimeProvider.kt 0.00% <0.00%> (ø)

... and 33 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
hamorillo marked this pull request as ready for review June 29, 2026 13:32
@hamorillo
hamorillo requested review from a team as code owners June 29, 2026 13:32
@hamorillo
hamorillo merged commit 478f4af into develop Jun 30, 2026
27 checks passed
@hamorillo
hamorillo deleted the hector.morilloprieto/RUM-15483 branch June 30, 2026 06:52
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.

5 participants