Skip to content

Commit

Permalink
[QA] Make replay lazy and faster (#3799)
Browse files Browse the repository at this point in the history
* Make replay lazy and faster

* Changelog
  • Loading branch information
romtsn authored Oct 16, 2024
1 parent bd82483 commit ee6ab95
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Fix potential ANRs due to NDK System.loadLibrary calls ([#3670](https://github.com/getsentry/sentry-java/pull/3670))
- Fix slow `Log` calls on app startup ([#3793](https://github.com/getsentry/sentry-java/pull/3793))
- Fix slow Integration name parsing ([#3794](https://github.com/getsentry/sentry-java/pull/3794))
- Session Replay: Reduce startup and capture overhead ([#3799](https://github.com/getsentry/sentry-java/pull/3799))

## 7.15.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import kotlin.LazyThreadSafetyMode.NONE
public open class DefaultReplayBreadcrumbConverter : ReplayBreadcrumbConverter {
internal companion object {
private val snakecasePattern by lazy(NONE) { "_[a-z]".toRegex() }
private val supportedNetworkData = setOf(
"status_code",
"method",
"response_content_length",
"request_content_length",
"http.response_content_length",
"http.request_content_length"
)
private val supportedNetworkData by lazy(NONE) {
setOf(
"status_code",
"method",
"response_content_length",
"request_content_length",
"http.response_content_length",
"http.request_content_length"
)
}
}

private var lastConnectivityState: String? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import java.util.concurrent.Executors
import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import kotlin.LazyThreadSafetyMode.NONE
import kotlin.math.roundToInt

@TargetApi(26)
Expand All @@ -51,15 +52,19 @@ internal class ScreenshotRecorder(
}
private var rootView: WeakReference<View>? = null
private val pendingViewHierarchy = AtomicReference<ViewHierarchyNode>()
private val maskingPaint = Paint()
private val singlePixelBitmap: Bitmap = Bitmap.createBitmap(
1,
1,
Bitmap.Config.ARGB_8888
)
private val singlePixelBitmapCanvas: Canvas = Canvas(singlePixelBitmap)
private val prescaledMatrix = Matrix().apply {
preScale(config.scaleFactorX, config.scaleFactorY)
private val maskingPaint by lazy(NONE) { Paint() }
private val singlePixelBitmap: Bitmap by lazy(NONE) {
Bitmap.createBitmap(
1,
1,
Bitmap.Config.ARGB_8888
)
}
private val singlePixelBitmapCanvas: Canvas by lazy(NONE) { Canvas(singlePixelBitmap) }
private val prescaledMatrix by lazy(NONE) {
Matrix().apply {
preScale(config.scaleFactorX, config.scaleFactorY)
}
}
private val contentChanged = AtomicBoolean(false)
private val isCapturing = AtomicBoolean(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,6 @@ internal abstract class BaseCaptureStrategy(
}
}

init {
runInBackground { onChange(propertyName, initialValue, initialValue) }
}

override fun getValue(thisRef: Any?, property: KProperty<*>): T? = value.get()

override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import androidx.compose.ui.graphics.isUnspecified
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.findRootCoordinates
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.node.Owner
import androidx.compose.ui.semantics.SemanticsActions
Expand Down Expand Up @@ -87,12 +86,13 @@ internal object ComposeViewHierarchyNode {
(semantics == null || !semantics.contains(SemanticsProperties.InvisibleToUser)) &&
visibleRect.height() > 0 && visibleRect.width() > 0
val isEditable = semantics?.contains(SemanticsActions.SetText) == true
val positionInWindow = node.coordinates.positionInWindow()
return when {
semantics?.contains(SemanticsProperties.Text) == true || isEditable -> {
val shouldMask = isVisible && node.shouldMask(isImage = false, options)

parent?.setImportantForCaptureToAncestors(true)
// TODO: if we get reports that it's slow, we can drop this, and just mask
// TODO: the whole view instead of per-line
val textLayoutResults = mutableListOf<TextLayoutResult>()
semantics?.getOrNull(SemanticsActions.GetTextLayoutResult)
?.action
Expand All @@ -108,8 +108,8 @@ internal object ComposeViewHierarchyNode {
TextViewHierarchyNode(
layout = if (textLayoutResults.isNotEmpty() && !isEditable) ComposeTextLayout(textLayoutResults.first(), hasFillModifier) else null,
dominantColor = textColor?.toArgb()?.toOpaque(),
x = positionInWindow.x,
y = positionInWindow.y,
x = visibleRect.left.toFloat(),
y = visibleRect.top.toFloat(),
width = node.width,
height = node.height,
elevation = (parent?.elevation ?: 0f),
Expand All @@ -128,8 +128,8 @@ internal object ComposeViewHierarchyNode {

parent?.setImportantForCaptureToAncestors(true)
ImageViewHierarchyNode(
x = positionInWindow.x,
y = positionInWindow.y,
x = visibleRect.left.toFloat(),
y = visibleRect.top.toFloat(),
width = node.width,
height = node.height,
elevation = (parent?.elevation ?: 0f),
Expand All @@ -147,8 +147,8 @@ internal object ComposeViewHierarchyNode {
// TODO: traverse the ViewHierarchyNode here again. For now we can recommend
// TODO: using custom modifiers to obscure the entire node if it's sensitive
GenericViewHierarchyNode(
x = positionInWindow.x,
y = positionInWindow.y,
x = visibleRect.left.toFloat(),
y = visibleRect.top.toFloat(),
width = node.width,
height = node.height,
elevation = (parent?.elevation ?: 0f),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ sealed class ViewHierarchyNode(
private fun Class<*>.isAssignableFrom(set: Set<String>): Boolean {
var cls: Class<*>? = this
while (cls != null) {
val canonicalName = cls.canonicalName
if (canonicalName != null && set.contains(canonicalName)) {
val canonicalName = cls.name
if (set.contains(canonicalName)) {
return true
}
cls = cls.superclass
Expand Down

0 comments on commit ee6ab95

Please sign in to comment.