Skip to content

Commit 0266a14

Browse files
Merge pull request #3055 from DataDog/aleksandr-gringauz/RUM-13082/fallback-to-DdRumContentProvider
RUM-13082: Fall back to DdRumContentProvider creation time
2 parents 10e070c + 872aab9 commit 0266a14

File tree

5 files changed

+53
-4
lines changed

5 files changed

+53
-4
lines changed

dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/time/DefaultAppStartTimeProvider.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import android.os.SystemClock
1313
import com.datadog.android.core.internal.system.BuildSdkVersionProvider
1414
import com.datadog.android.rum.DdRumContentProvider
1515
import java.util.concurrent.TimeUnit
16+
import kotlin.time.Duration.Companion.seconds
1617

1718
internal class DefaultAppStartTimeProvider(
1819
buildSdkVersionProvider: BuildSdkVersionProvider = BuildSdkVersionProvider.DEFAULT
@@ -23,12 +24,26 @@ internal class DefaultAppStartTimeProvider(
2324
when {
2425
buildSdkVersionProvider.version >= Build.VERSION_CODES.N -> {
2526
val diffMs = SystemClock.elapsedRealtime() - Process.getStartElapsedRealtime()
26-
System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(diffMs)
27+
val result = System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(diffMs)
28+
29+
/**
30+
* Occasionally [Process.getStartElapsedRealtime] returns buggy values. We filter them and fall back
31+
* to the time of creation of [DdRumContentProvider].
32+
*/
33+
if (DdRumContentProvider.createTimeNs - result > PROCESS_START_TO_CP_START_DIFF_THRESHOLD_NS) {
34+
DdRumContentProvider.createTimeNs
35+
} else {
36+
result
37+
}
2738
}
2839
else -> DdRumContentProvider.createTimeNs
2940
}
3041
}
3142

3243
override val appUptimeNs: Long
3344
get() = System.nanoTime() - appStartTimeNs
45+
46+
companion object {
47+
internal val PROCESS_START_TO_CP_START_DIFF_THRESHOLD_NS = 10.seconds.inWholeNanoseconds
48+
}
3449
}

dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/internal/time/DefaultAppStartTimeProviderTest.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import android.os.Process
1111
import android.os.SystemClock
1212
import com.datadog.android.core.internal.system.BuildSdkVersionProvider
1313
import com.datadog.android.rum.DdRumContentProvider
14+
import fr.xgouchet.elmyr.Forge
1415
import fr.xgouchet.elmyr.annotation.IntForgery
1516
import fr.xgouchet.elmyr.junit5.ForgeExtension
1617
import org.assertj.core.api.Assertions.assertThat
@@ -29,13 +30,19 @@ import java.util.concurrent.TimeUnit
2930
class DefaultAppStartTimeProviderTest {
3031
@Test
3132
fun `M return process start time W appStartTime { N+ }`(
32-
@IntForgery(min = Build.VERSION_CODES.N) apiVersion: Int
33+
@IntForgery(min = Build.VERSION_CODES.N) apiVersion: Int,
34+
forge: Forge
3335
) {
3436
// GIVEN
3537
val mockBuildSdkVersionProvider: BuildSdkVersionProvider = mock()
3638
whenever(mockBuildSdkVersionProvider.version) doReturn apiVersion
39+
3740
val diffMs = SystemClock.elapsedRealtime() - Process.getStartElapsedRealtime()
3841
val startTimeNs = System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(diffMs)
42+
43+
DdRumContentProvider.createTimeNs = startTimeNs +
44+
forge.aLong(min = 0, max = DefaultAppStartTimeProvider.PROCESS_START_TO_CP_START_DIFF_THRESHOLD_NS)
45+
3946
val testedProvider = DefaultAppStartTimeProvider(mockBuildSdkVersionProvider)
4047

4148
// WHEN
@@ -46,6 +53,31 @@ class DefaultAppStartTimeProviderTest {
4653
.isCloseTo(startTimeNs, Offset.offset(TimeUnit.MILLISECONDS.toNanos(100)))
4754
}
4855

56+
@Test
57+
fun `M fall back to DdRumContentProvider W appStartTime { N+ getStartElapsedRealtime returns buggy value }`(
58+
@IntForgery(min = Build.VERSION_CODES.N) apiVersion: Int,
59+
forge: Forge
60+
) {
61+
// GIVEN
62+
val mockBuildSdkVersionProvider: BuildSdkVersionProvider = mock()
63+
whenever(mockBuildSdkVersionProvider.version) doReturn apiVersion
64+
65+
val diffMs = SystemClock.elapsedRealtime() - Process.getStartElapsedRealtime()
66+
val startTimeNs = System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(diffMs)
67+
68+
DdRumContentProvider.createTimeNs = startTimeNs +
69+
forge.aLong(min = DefaultAppStartTimeProvider.PROCESS_START_TO_CP_START_DIFF_THRESHOLD_NS)
70+
71+
val testedProvider = DefaultAppStartTimeProvider(mockBuildSdkVersionProvider)
72+
73+
// WHEN
74+
val providedStartTime = testedProvider.appStartTimeNs
75+
76+
// THEN
77+
assertThat(providedStartTime)
78+
.isCloseTo(DdRumContentProvider.createTimeNs, Offset.offset(TimeUnit.MILLISECONDS.toNanos(100)))
79+
}
80+
4981
@Test
5082
fun `M return content provider load time W appStartTime { Legacy }`(
5183
@IntForgery(min = Build.VERSION_CODES.M, max = Build.VERSION_CODES.N) apiVersion: Int

dd-sdk-android-internal/api/apiSurface

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,6 @@ class com.datadog.android.rum.DdRumContentProvider : android.content.ContentProv
135135
override fun update(android.net.Uri, android.content.ContentValues?, String?, Array<String>?): Int
136136
companion object
137137
var processImportance: Int
138-
val createTimeNs: Long
138+
var createTimeNs: Long
139139
annotation com.datadog.tools.annotation.NoOpImplementation
140140
constructor(Boolean = false)

dd-sdk-android-internal/api/dd-sdk-android-internal.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ public final class com/datadog/android/rum/DdRumContentProvider : android/conten
349349
public final class com/datadog/android/rum/DdRumContentProvider$Companion {
350350
public final fun getCreateTimeNs ()J
351351
public final fun getProcessImportance ()I
352+
public final fun setCreateTimeNs (J)V
352353
public final fun setProcessImportance (I)V
353354
}
354355

dd-sdk-android-internal/src/main/java/com/datadog/android/rum/DdRumContentProvider.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ class DdRumContentProvider : ContentProvider() {
7676

7777
/**
7878
* fallback for APIs below Android N, see [DefaultAppStartTimeProvider].
79+
* Should be set from the outside only in tests.
7980
*/
80-
val createTimeNs: Long = System.nanoTime()
81+
var createTimeNs: Long = System.nanoTime()
8182
}
8283
}

0 commit comments

Comments
 (0)