diff --git a/detekt_custom_unsafe_calls.yml b/detekt_custom_unsafe_calls.yml index d9903bbcf4..4ad6f0f34b 100644 --- a/detekt_custom_unsafe_calls.yml +++ b/detekt_custom_unsafe_calls.yml @@ -112,6 +112,7 @@ datadog: - "java.util.concurrent.BlockingQueue.drainTo(kotlin.collections.MutableCollection):java.lang.UnsupportedOperationException,java.lang.ClassCastException,java.lang.NullPointerException,java.lang.IllegalArgumentException" - "java.util.concurrent.BlockingQueue.drainTo(kotlin.collections.MutableCollection?):java.lang.UnsupportedOperationException,java.lang.ClassCastException,java.lang.NullPointerException,java.lang.IllegalArgumentException" - "java.util.concurrent.Callable.call():java.lang.Exception" + - "java.util.concurrent.ConcurrentHashMap.computeIfAbsent(kotlin.String, java.util.function.Function):java.lang.NullPointerException,java.lang.IllegalStateException,java.lang.RuntimeException" - "java.util.concurrent.ConcurrentHashMap.contains(kotlin.Any?):java.lang.NullPointerException" - "java.util.concurrent.ConcurrentHashMap.remove(com.datadog.android.api.feature.FeatureContextUpdateReceiver):java.lang.NullPointerException" - "java.util.concurrent.ConcurrentHashMap.remove(kotlin.String?):java.lang.NullPointerException" diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/metric/slowframes/SlowFramesListener.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/metric/slowframes/SlowFramesListener.kt index 7591cec564..19d1627cb5 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/metric/slowframes/SlowFramesListener.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/metric/slowframes/SlowFramesListener.kt @@ -5,6 +5,7 @@ */ package com.datadog.android.rum.internal.metric.slowframes +import android.os.Build import androidx.metrics.performance.FrameData import com.datadog.android.internal.time.TimeProvider import com.datadog.android.rum.configuration.SlowFramesConfiguration @@ -65,6 +66,8 @@ internal class DefaultSlowFramesListener( // Called from the background thread override fun onFrame(volatileFrameData: FrameData) { val viewId = currentViewId + // currentViewStartedTimestampNs can be set by RUM thread in onViewCreated after we read currentViewId, + // there is no consistency guarantee here if (viewId == null || volatileFrameData.frameStartNanos < currentViewStartedTimestampNs) { if (viewId != null) { metricDispatcher.incrementMissedFrameCount(viewId) @@ -139,11 +142,20 @@ internal class DefaultSlowFramesListener( // do nothing } - private fun getViewPerformanceReport(viewId: String) = slowFramesRecords.getOrPut(viewId) { - ViewUIPerformanceReport( - currentViewStartedTimestampNs, - configuration.maxSlowFramesAmount, - minimumViewLifetimeThresholdNs = configuration.minViewLifetimeThresholdNs - ) + private fun getViewPerformanceReport(viewId: String): ViewUIPerformanceReport { + val createLambda = { + ViewUIPerformanceReport( + currentViewStartedTimestampNs, + configuration.maxSlowFramesAmount, + minimumViewLifetimeThresholdNs = configuration.minViewLifetimeThresholdNs + ) + } + + return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + @Suppress("UnsafeThirdPartyFunctionCall") // all args are safe + slowFramesRecords.computeIfAbsent(viewId) { createLambda.invoke() } + } else { + slowFramesRecords.getOrPut(viewId, createLambda) + } } } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/AggregatingVitalMonitor.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/AggregatingVitalMonitor.kt index 44bc5b548c..1c848cc077 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/AggregatingVitalMonitor.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/AggregatingVitalMonitor.kt @@ -6,14 +6,16 @@ package com.datadog.android.rum.internal.vitals +import java.util.concurrent.ConcurrentHashMap import kotlin.math.max import kotlin.math.min internal class AggregatingVitalMonitor : VitalMonitor { + @Volatile private var lastKnownSample: Double = Double.NaN - private val listeners: MutableMap = mutableMapOf() + private val listeners: MutableMap = ConcurrentHashMap() // region VitalObserver