Skip to content

fix(replay): Do not recycle the canvas screenshot during a pixel copy - #6342

Merged
romtsn merged 2 commits into
mainfrom
fix/replay-canvas-close-crash
Oct 21, 2026
Merged

romtsn merged 2 commits into
mainfrom
fix/replay-canvas-close-crash

Conversation

@romtsn

@romtsn romtsn commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

📜 Description

Stopping Session Replay with the canvas screenshot strategy no longer crashes the app when a frame copy is still in progress.

CanvasStrategy.close() posted a cleanup to the background handler that recycled the screenshot bitmap and released the surface. A PixelCopy.request started just before close() keeps writing into that bitmap on the RenderThread until its callback runs, so the cleanup could recycle the bitmap mid-copy. libhwui then aborts the process:

F libc  : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid … (RenderThread)
F DEBUG : Abort message: 'Error, cannot access an invalid/free'd bitmap here!'

The render task, the PixelCopy callback and the cleanup all run on the same background handler, so a plain flag tracks the in-flight copy without extra synchronization. close() skips the cleanup while a copy is in flight, and the copy callback releases the bitmap and surface once it sees the strategy is closed. This mirrors the in-flight gate PixelCopyStrategy got in #5808; PixelCopyStrategy needs a CAS there because its frame work spans several threads.

On SDK shutdown, WindowRecorder.close() still drops pending background work and quits that thread, so the resources may not be released then. That leak behavior is unchanged and cannot crash.

💡 Motivation and Context

Found while verifying #6340 on an emulator: stopping a buffering replay with the canvas strategy aborted the RenderThread.

💚 How did you test it?

CanvasStrategyTest holds back the PixelCopy result and checks that close() keeps the screenshot alive until the copy finishes, and that it still recycles right away when no copy is in flight. The first test fails without the fix.

On an API 34 emulator with the sample app (canvas strategy), a stress loop ran 100 cycles of startBuffering(), a 60–160 ms wait, then stop():

Runs crashed
main 3 of 4 (2 of 2 with the focused 60–160 ms sweep)
This PR 0 of 4 — the copy was still in flight at close() 50 times and the callback did the cleanup

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

🤖 Generated with Claude Code

romtsn and others added 2 commits October 21, 2026 13:04
CanvasStrategy.close() recycled the screenshot bitmap and released the surface on the background
handler even when a PixelCopy request was still writing into that bitmap on the RenderThread.
libhwui then aborted the process with "cannot access an invalid/free'd bitmap".

Track the in-flight copy on the background handler, which runs the render task, the copy
callback and the cleanup. close() skips the cleanup while a copy is in flight, and the copy
callback releases the resources once it sees the strategy is closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sentry

sentry Bot commented Oct 21, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.61.0 (1) release

⚙️ sentry-android Build Distribution Settings

@romtsn
romtsn marked this pull request as ready for review October 21, 2026 11:12

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice!

@markushi markushi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@romtsn
romtsn merged commit 28c6417 into main Oct 21, 2026
71 checks passed
@romtsn
romtsn deleted the fix/replay-canvas-close-crash branch October 21, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants