Skip to content

Commit c7ab9b6

Browse files
authored
Merge pull request #2732 from DataDog/yl/sr/avoid-copying-hardware-bitmap
RUM-10346: Avoid copying hardware bitmap in Session Replay
2 parents ade2b0b + 821b386 commit c7ab9b6

File tree

1 file changed

+34
-1
lines changed
  • features/dd-sdk-android-session-replay-compose/src/main/kotlin/com/datadog/android/sessionreplay/compose/internal/utils

1 file changed

+34
-1
lines changed

features/dd-sdk-android-session-replay-compose/src/main/kotlin/com/datadog/android/sessionreplay/compose/internal/utils/SemanticsUtils.kt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package com.datadog.android.sessionreplay.compose.internal.utils
88

99
import android.graphics.Bitmap
10+
import android.os.Build
1011
import android.view.View
1112
import androidx.compose.foundation.shape.RoundedCornerShape
1213
import androidx.compose.ui.Modifier
@@ -28,6 +29,7 @@ import androidx.compose.ui.unit.Density
2829
import com.datadog.android.Datadog
2930
import com.datadog.android.api.InternalLogger
3031
import com.datadog.android.api.feature.FeatureSdkCore
32+
import com.datadog.android.core.sampling.RateBasedSampler
3133
import com.datadog.android.sessionreplay.ImagePrivacy
3234
import com.datadog.android.sessionreplay.TextAndInputPrivacy
3335
import com.datadog.android.sessionreplay.TouchPrivacy
@@ -42,7 +44,10 @@ import com.datadog.android.sessionreplay.compose.internal.mappers.semantics.Text
4244
import com.datadog.android.sessionreplay.utils.GlobalBounds
4345

4446
@Suppress("TooManyFunctions")
45-
internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = ReflectionUtils()) {
47+
internal class SemanticsUtils(
48+
private val reflectionUtils: ReflectionUtils = ReflectionUtils(),
49+
private val sampler: RateBasedSampler<Unit> = RateBasedSampler(BITMAP_TELEMETRY_SAMPLE_RATE)
50+
) {
4651

4752
internal fun findRootSemanticsNode(view: View): SemanticsNode? {
4853
reflectionUtils.apply {
@@ -273,6 +278,15 @@ internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = Ref
273278
}
274279
}
275280

281+
// Send telemetry about the original bitmap before copying it.
282+
bitmap?.let {
283+
sendBitmapInfoTelemetry(it, isContextualImage)
284+
}
285+
286+
// Avoid copying hardware bitmap because it is slow and may violate [StrictMode#noteSlowCall]
287+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && bitmap?.config == Bitmap.Config.HARDWARE) {
288+
return BitmapInfo(bitmap, isContextualImage)
289+
}
276290
val newBitmap = bitmap?.let {
277291
@Suppress("UnsafeThirdPartyFunctionCall") // isMutable is always false
278292
it.copy(Bitmap.Config.ARGB_8888, false)
@@ -282,6 +296,24 @@ internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = Ref
282296
}
283297
}
284298

299+
private fun sendBitmapInfoTelemetry(bitmap: Bitmap, isContextual: Boolean) {
300+
if (sampler.sample(Unit)) {
301+
(Datadog.getInstance() as? FeatureSdkCore)?.internalLogger?.log(
302+
level = InternalLogger.Level.INFO,
303+
target = InternalLogger.Target.TELEMETRY,
304+
messageBuilder = { "Resolved the bitmap from semantics node with id:${bitmap.generationId}" },
305+
additionalProperties = mapOf(
306+
"bitmap.id" to bitmap.generationId,
307+
"bitmap.byteCount" to bitmap.byteCount,
308+
"bitmap.width" to bitmap.width,
309+
"bitmap.height" to bitmap.height,
310+
"bitmap.config" to bitmap.config,
311+
"bitmap.isContextual" to isContextual
312+
)
313+
)
314+
}
315+
}
316+
285317
private fun logUnsupportedPainter(painter: Painter?) {
286318
val painterType = painter?.javaClass?.simpleName ?: "null"
287319
(Datadog.getInstance() as? FeatureSdkCore)?.internalLogger?.log(
@@ -390,6 +422,7 @@ internal class SemanticsUtils(private val reflectionUtils: ReflectionUtils = Ref
390422
}
391423
internal const val DEFAULT_COLOR_BLACK = "#000000FF"
392424
internal const val DEFAULT_COLOR_WHITE = "#FFFFFFFF"
425+
private const val BITMAP_TELEMETRY_SAMPLE_RATE = 1f
393426
}
394427

395428
internal fun getProgressBarRangeInfo(semanticsNode: SemanticsNode): ProgressBarRangeInfo? {

0 commit comments

Comments
 (0)