Skip to content

Commit fd6e633

Browse files
committed
Fix redacting out of sync
1 parent 0f4e718 commit fd6e633

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

sentry-android-replay/src/main/java/io/sentry/android/replay/ScreenshotRecorder.kt

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import io.sentry.SentryLevel.WARNING
2121
import io.sentry.SentryOptions
2222
import io.sentry.android.replay.viewhierarchy.ViewHierarchyNode
2323
import java.lang.ref.WeakReference
24-
import java.util.WeakHashMap
2524
import java.util.concurrent.atomic.AtomicBoolean
25+
import java.util.concurrent.atomic.AtomicReference
2626
import kotlin.system.measureTimeMillis
2727

2828
@TargetApi(26)
@@ -35,7 +35,7 @@ internal class ScreenshotRecorder(
3535
private var rootView: WeakReference<View>? = null
3636
private val thread = HandlerThread("SentryReplayRecorder").also { it.start() }
3737
private val handler = Handler(thread.looper)
38-
private val bitmapToVH = WeakHashMap<Bitmap, ViewHierarchyNode>()
38+
private val pendingViewHierarchy = AtomicReference<ViewHierarchyNode>()
3939
private val maskingPaint = Paint()
4040
private val singlePixelBitmap: Bitmap = Bitmap.createBitmap(
4141
1,
@@ -51,6 +51,8 @@ internal class ScreenshotRecorder(
5151
private var lastScreenshot: Bitmap? = null
5252

5353
fun capture() {
54+
val viewHierarchy = pendingViewHierarchy.get()
55+
5456
if (!isCapturing.get()) {
5557
options.logger.log(DEBUG, "ScreenshotRecorder is paused, not capturing screenshot")
5658
return
@@ -87,13 +89,6 @@ internal class ScreenshotRecorder(
8789

8890
// postAtFrontOfQueue to ensure the view hierarchy and bitmap are ase close in-sync as possible
8991
Handler(Looper.getMainLooper()).postAtFrontOfQueue {
90-
val time = measureTimeMillis {
91-
val rootNode = ViewHierarchyNode.fromView(root)
92-
root.traverse(rootNode)
93-
bitmapToVH[bitmap] = rootNode
94-
}
95-
options.logger.log(DEBUG, "Took %d ms to capture view hierarchy", time)
96-
9792
try {
9893
PixelCopy.request(
9994
window,
@@ -102,17 +97,14 @@ internal class ScreenshotRecorder(
10297
if (copyResult != PixelCopy.SUCCESS) {
10398
options.logger.log(INFO, "Failed to capture replay recording: %d", copyResult)
10499
bitmap.recycle()
105-
bitmapToVH.remove(bitmap)
106100
return@request
107101
}
108102

109-
val viewHierarchy = bitmapToVH[bitmap]
110103
val scaledBitmap: Bitmap
111104

112105
if (viewHierarchy == null) {
113106
options.logger.log(INFO, "Failed to determine view hierarchy, not capturing")
114107
bitmap.recycle()
115-
bitmapToVH.remove(bitmap)
116108
return@request
117109
} else {
118110
scaledBitmap = Bitmap.createScaledBitmap(
@@ -149,19 +141,30 @@ internal class ScreenshotRecorder(
149141

150142
scaledBitmap.recycle()
151143
bitmap.recycle()
152-
bitmapToVH.remove(bitmap)
153144
},
154145
handler
155146
)
156147
} catch (e: Throwable) {
157148
options.logger.log(WARNING, "Failed to capture replay recording", e)
158149
bitmap.recycle()
159-
bitmapToVH.remove(bitmap)
160150
}
161151
}
162152
}
163153

164154
override fun onDraw() {
155+
val root = rootView?.get()
156+
if (root == null || root.width <= 0 || root.height <= 0 || !root.isShown) {
157+
options.logger.log(DEBUG, "Root view is invalid, not capturing screenshot")
158+
return
159+
}
160+
161+
val time = measureTimeMillis {
162+
val rootNode = ViewHierarchyNode.fromView(root)
163+
root.traverse(rootNode)
164+
pendingViewHierarchy.set(rootNode)
165+
}
166+
options.logger.log(DEBUG, "Took %d ms to capture view hierarchy", time)
167+
165168
contentChanged.set(true)
166169
}
167170

@@ -194,7 +197,7 @@ internal class ScreenshotRecorder(
194197
unbind(rootView?.get())
195198
rootView?.clear()
196199
lastScreenshot?.recycle()
197-
bitmapToVH.clear()
200+
pendingViewHierarchy.set(null)
198201
isCapturing.set(false)
199202
thread.quitSafely()
200203
}

0 commit comments

Comments
 (0)