Skip to content

PANA-8412: Support cross-platform embedded content in Session Replay - #3690

Open
jonathanmos wants to merge 6 commits into
feature/flutter-supportfrom
jmoskovich/02-flutter-support
Open

PANA-8412: Support cross-platform embedded content in Session Replay#3690
jonathanmos wants to merge 6 commits into
feature/flutter-supportfrom
jmoskovich/02-flutter-support

Conversation

@jonathanmos

Copy link
Copy Markdown
Member

What does this PR do?

Adds generic support for embedded cross-platform content in Android Session Replay.
• Exposes internal APIs to mark an Android View with a slot ID and submit embedded records and resources.
• Records marked views as embedded_content wireframes without traversing their native subtree.
• Tracks slot visibility and removal without retaining views.
• Supports marked views in both native and Jetpack Compose interop capture.
• Enriches embedded records with native RUM context and includes them in replay counts.

Motivation

Brings Android in line with the generic iOS implementation without introducing Flutter-specific dependencies.

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@codecov-commenter

codecov-commenter commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.59557% with 52 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.67%. Comparing base (3376f37) to head (c591883).
⚠️ Report is 21 commits behind head on feature/flutter-support.

Files with missing lines Patch % Lines
...droid/sessionreplay/_SessionReplayInternalProxy.kt 60.00% 2 Missing and 14 partials ⚠️
...eplay/internal/embedded/EmbeddedContentReceiver.kt 78.57% 5 Missing and 4 partials ⚠️
...ernal/recorder/mapper/EmbeddedContentViewMapper.kt 89.87% 4 Missing and 4 partials ⚠️
...y/internal/embedded/EmbeddedContentSlotRegistry.kt 83.87% 0 Missing and 5 partials ⚠️
...oid/sessionreplay/internal/SessionReplayFeature.kt 92.68% 2 Missing and 1 partial ⚠️
...sessionreplay/internal/processor/WireframeUtils.kt 62.50% 0 Missing and 3 partials ⚠️
...essionreplay/internal/recorder/SnapshotProducer.kt 50.00% 0 Missing and 2 partials ⚠️
...ssionreplay/internal/recorder/TreeViewTraversal.kt 81.82% 1 Missing and 1 partial ⚠️
...com/datadog/android/sessionreplay/SessionReplay.kt 66.67% 0 Missing and 1 partial ⚠️
...onreplay/internal/embedded/EmbeddedContentEvent.kt 94.44% 0 Missing and 1 partial ⚠️
... and 2 more
Additional details and impacted files
@@                     Coverage Diff                     @@
##           feature/flutter-support    #3690      +/-   ##
===========================================================
+ Coverage                    73.39%   73.67%   +0.27%     
===========================================================
  Files                          997     1002       +5     
  Lines                        36479    36802     +323     
  Branches                      6190     6270      +80     
===========================================================
+ Hits                         26773    27111     +338     
+ Misses                        7982     7954      -28     
- Partials                      1724     1737      +13     
Files with missing lines Coverage Δ
.../sessionreplay/internal/DefaultRecorderProvider.kt 93.75% <100.00%> (+0.04%) ⬆️
...sionreplay/internal/SessionReplayRecordCallback.kt 100.00% <100.00%> (ø)
...replay/internal/SessionReplayRumContextProvider.kt 94.12% <100.00%> (+1.81%) ⬆️
...ssionreplay/internal/processor/MutationResolver.kt 89.71% <ø> (+0.46%) ⬆️
...replay/internal/processor/RecordedDataProcessor.kt 97.50% <100.00%> (-0.23%) ⬇️
...sionreplay/internal/processor/ResourceProcessor.kt 100.00% <100.00%> (ø)
...nreplay/internal/recorder/SessionReplayRecorder.kt 94.55% <100.00%> (+3.76%) ⬆️
...nreplay/internal/recorder/ViewOnDrawInterceptor.kt 88.89% <100.00%> (+0.65%) ⬆️
...lay/internal/resources/ResourceDataStoreManager.kt 94.03% <100.00%> (+1.05%) ⬆️
...onreplay/internal/utils/SessionReplayRumContext.kt 100.00% <100.00%> (+10.00%) ⬆️
... and 12 more

... and 33 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds embedded cross-platform content support to Android Session Replay by introducing slot tagging + embedded record/resource ingestion, mapping tagged views as embedded_content wireframes (without traversing native subtrees), and ensuring embedded batches/resources are accounted for and deduplicated.

Changes:

  • Exposed internal APIs to tag a View with an embedded slot ID and to submit embedded record batches/resources.
  • Added embedded-content capture/mapping pipeline (slot registry, wireframe mapper + snapshot lifecycle hooks, receiver + writers, RUM-context enrichment).
  • Reworked resource deduplication to be “mark-once” (incl. concurrency handling) and updated processors/tests accordingly.

Reviewed changes

Copilot reviewed 49 out of 49 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/SessionReplayRecorderTest.kt Adds coverage for avoiding decor invalidation and for requestCapture() behavior.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/SessionReplayInternalProxyTest.kt Tests new internal proxy APIs for slot tagging and embedded event submission.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/PrivacyOverrideExtensionsTest.kt Ensures privacy tag changes don’t force view invalidation.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/utils/SessionReplayRumContextTest.kt Adds tests for new “application+session validity” helper.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/storage/SessionReplayRecordWriterTest.kt Verifies embedded raw writes and embedded record counting callback behavior.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/SessionReplayRumContextProviderTest.kt Tests new RUM view-change notification and key constants usage.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/SessionReplayRecordCallbackTest.kt Adds coverage for aggregating native + embedded record counts.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/SessionReplayFeatureTest.kt Tests embedded event routing and capture requests on RUM view transitions.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/resources/ResourceDataStoreManagerTest.kt Updates tests for new “mark once” resource dedup + concurrency/pending persistence.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/resources/ResourceDataStoreManagerMigrationTest.kt Updates migration test to use new resource marking API.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewOnDrawInterceptorTest.kt Adds tests around request-triggered capture behavior.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/TreeViewTraversalTest.kt Ensures embedded mapper is chosen for tagged views (incl. Compose interop paths).
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/SnapshotProducerTest.kt Verifies snapshot lifecycle delegates to embedded mapper.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/EmbeddedContentViewMapperTest.kt New tests for embedded wireframe mapping + cache/hidden-node behavior.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/listener/WindowsOnDrawListenerTest.kt Validates hidden embedded node is prepended when embedded views disappear.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/processor/WireframeUtilsTest.kt Adds embedded hidden-wireframe rules for coverage/validity.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/processor/ResourceProcessorTest.kt New unit tests for resource dedup + write behavior.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/processor/RecordedDataProcessorTest.kt Updates resource processing expectations to use new marking API.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/processor/MutationResolverTest.kt Updates mutation expectations for embedded removals.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/embedded/EmbeddedContentSlotRegistryTest.kt New unit tests for weak-registration slot tracking semantics.
features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/embedded/EmbeddedContentReceiverTest.kt New unit tests for embedded event enrichment + routing.
features/dd-sdk-android-session-replay/src/main/res/values/ids.xml Adds internal view tag IDs for embedded slot + registration tracking.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/utils/SessionReplayRumContext.kt Adds hasValidApplicationAndSession() and refactors validity logic.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/storage/SessionReplayRecordWriter.kt Implements embedded raw record writing and embedded record-count callback.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/storage/EmbeddedContentRecordWriter.kt New internal writer interface for embedded raw batches.
features/dd-sdk-android-sessionreplay/src/main/kotlin/com/datadog/android/sessionreplay/internal/SessionReplayRumContextProvider.kt Adds view-change callback and centralizes RUM context key constants.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/SessionReplayRecordCallback.kt Adds embedded-record counting path into feature context.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/SessionReplayFeature.kt Integrates embedded receiver, resource processor, and capture triggers on RUM view changes.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/resources/ResourceDataStoreManager.kt Replaces cache API with atomic “mark-once” + pending persistence logic.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/ViewOnDrawInterceptor.kt Adds requestCapture() to trigger an immediate snapshot pass.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/TreeViewTraversal.kt Adds embedded-mapper selection and visibility/hidden handling adjustments.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/SnapshotProducer.kt Adds snapshot lifecycle hooks for embedded mapping cache.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/SessionReplayRecorder.kt Wires embedded mapper into traversal/producer and exposes requestCapture().
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/Recorder.kt Adds requestCapture() to recorder interface.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/mapper/EmbeddedContentViewMapper.kt New mapper to emit EmbeddedContentWireframe and manage hidden wireframes via cache.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/listener/WindowsOnDrawListener.kt Calls snapshot begin/finish and prepends hidden embedded node when needed.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/processor/WireframeUtils.kt Treats hidden embedded wireframes as valid and not “covered”.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/processor/ResourceProcessor.kt New processor to dedup and write resources consistently.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/processor/RecordedDataProcessor.kt Delegates resource processing to ResourceProcessor.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/processor/MutationResolver.kt Removes embedded-specific “hide on remove” path (now handled via hidden wireframes).
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/embedded/EmbeddedContentSlotRegistry.kt New weak-registration slot registry to track marked embedded slots without retaining views.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/embedded/EmbeddedContentReceiver.kt New receiver to enrich embedded records with native RUM context and route resources.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/embedded/EmbeddedContentEvent.kt New internal event types for embedded record batches/resources.
features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/_SessionReplayInternalProxy.kt Adds internal APIs to tag slots and submit embedded records/resources.
features/dd-sdk-android-session-replay/src/androidTest/kotlin/com/datadog/android/sessionreplay/internal/embedded/EmbeddedContentSlotRegistryInstrumentedTest.kt Instrumented test validating slot retention across view removal/restore.
features/dd-sdk-android-session-replay/build.gradle.kts Enables instrumentation tests for the module and adds integration test deps.
features/dd-sdk-android-session-replay/api/dd-sdk-android-session-replay.api Updates public API dump for newly exposed internal proxy methods.
features/dd-sdk-android-session-replay/api/apiSurface Updates API surface listing for new internal proxy companion methods.
features/dd-sdk-android-session-replay-compose/src/test/kotlin/com/datadog/android/sessionreplay/compose/internal/mappers/semantics/RootSemanticsNodeMapperTest.kt Adjusts Compose interop test to preserve embedded wireframe output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jonathanmos
jonathanmos force-pushed the jmoskovich/02-flutter-support branch from 24d8cc5 to 5c09527 Compare August 3, 2026 09:28
@jonathanmos
jonathanmos marked this pull request as ready for review August 3, 2026 11:20
@jonathanmos
jonathanmos requested review from a team as code owners August 3, 2026 11:20
ambushwork
ambushwork previously approved these changes Aug 3, 2026
@ambushwork

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 5c09527ad1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Suppress("UNCHECKED_CAST")
fun onEmbeddedRecordsForViewSent(viewId: String, recordsCount: Int) {
if (recordsCount > 0) {
featureSdkCore.updateFeatureContext(Feature.SESSION_REPLAY_FEATURE_NAME, useContextThread = false) {

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.

what is the reasoning behind useContextThread = false?

@jonathanmos jonathanmos Aug 5, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Using the context thread would queue the update and leave a window where the count is stale. I’ve moved the native and embedded paths into the same helper and added a comment explaining why we update synchronously.

@jonathanmos
jonathanmos force-pushed the jmoskovich/02-flutter-support branch from c2251c6 to c591883 Compare August 5, 2026 09:53
@jonathanmos
jonathanmos requested a review from 0xnm August 5, 2026 11:45
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.

5 participants