Skip to content

fix(android): clear static event mapper on engine detach - #1112

Draft
c-tshibas wants to merge 2 commits into
DataDog:developfrom
c-tshibas:corneille/rums-6227-fix-android-event-mapper-detach
Draft

fix(android): clear static event mapper on engine detach#1112
c-tshibas wants to merge 2 commits into
DataDog:developfrom
c-tshibas:corneille/rums-6227-fix-android-event-mapper-detach

Conversation

@c-tshibas

Copy link
Copy Markdown

What & why

Fixes a native crash reported in RUMS-6227: Android SIGSEGV inside JNI
CallObjectMethod, at a consistent/deterministic offset.

The RUM/Logs event mapper (DatadogRumEventMapper/DatadogLogEventMapper)
is held in a static, process-wide singleton in DatadogRumPlugin /
DatadogLogsPlugin. It's only ever overwritten when a mapper is
attached — never cleared. When a Flutter engine detaches (app
backgrounded and killed, hot restart, or Activity recreation on a
config change), that static field keeps pointing at a jnigen-generated
JNI proxy tied to the now-destroyed engine's Dart isolate.

dd-sdk-android's RUM/Logs core is itself a process-wide singleton with
background writer/upload threads that outlive any single Flutter
engine. When one of those threads serializes a queued event and calls
into the stale mapper, it crashes inside CallObjectMethod — a
use-after-detach JNI reference, invoked from a background thread. The
deterministic crash offset is the fingerprint of this exact failure
mode (a fixed-layout call into freed memory), rather than random heap
corruption.

Change

  • detachFromEngine() in both DatadogRumPlugin and DatadogLogsPlugin
    now clears the static mapper's eventMapper field.
  • DatadogRumEventMapper.eventMapper / DatadogLogEventMapper.eventMapper
    marked @Volatile, so the clear is guaranteed visible to whatever
    background thread might be racing to read it.
  • Added a regression test (DatadogRumPluginTest) asserting the mapper
    is null after detachFromEngine().
  • CHANGELOG entry under Unreleased.

Testing

⚠️ I wasn't able to run the existing/new unit tests in my environment
due to a Flutter/Gradle toolchain version mismatch unrelated to this
change (fails identically on unmodified develop). Needs a real CI run
before merge.

Refs: RUMS-6227

🤖 Generated with Claude Code

The RUM/Logs event mapper is stored in a static, process-wide singleton
that is only ever overwritten, never cleared. When a Flutter engine is
detached (app backgrounded and killed, hot restart, or Activity
recreation on a config change), the mapper field still holds a JNI
reference tied to that now-destroyed engine's Dart isolate.

dd-sdk-android's RUM/Logs core keeps writing/uploading queued events on
a background thread independent of any Flutter engine's lifecycle. When
it invokes the stale mapper to serialize an event, it crashes with a
SIGSEGV inside CallObjectMethod at a deterministic offset -- the
fingerprint of a JNI call into a freed/torn-down reference.

Clears the mapper in detachFromEngine() for both DatadogRumPlugin and
DatadogLogsPlugin, and marks both mapper fields @volatile so a clear
from the main thread is guaranteed visible to the background writer
thread reading it.

Refs: RUMS-6227
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.

1 participant