From 6e159a39ac1e5c27ca3e5860d9f3a0274fe74310 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 2 Jul 2026 16:42:28 +0200 Subject: [PATCH 1/3] fix(sdk-crash-detection): Allow ART memory/GC context through event stripper Android SDK (getsentry/sentry-java#5428) added ArtContext (context key "art") to ANR events containing GC and heap memory stats parsed from ANR thread dumps. The sdk-crashes event_stripper was dropping the entire "art" context because it wasn't in the allowlist. Add all 11 ArtContext fields (gc.* and memory.*) under contexts.art so they survive stripping. --- src/sentry/utils/sdk_crashes/event_stripper.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sentry/utils/sdk_crashes/event_stripper.py b/src/sentry/utils/sdk_crashes/event_stripper.py index c227a4ad6d2c..0e95b67e62d9 100644 --- a/src/sentry/utils/sdk_crashes/event_stripper.py +++ b/src/sentry/utils/sdk_crashes/event_stripper.py @@ -102,6 +102,19 @@ def with_explanation(self, explanation: str) -> "Allow": "version": Allow.SIMPLE_TYPE, "build": Allow.SIMPLE_TYPE, }, + "art": { + "gc.total_count": Allow.SIMPLE_TYPE, + "gc.total_time": Allow.SIMPLE_TYPE, + "gc.blocking_count": Allow.SIMPLE_TYPE, + "gc.blocking_time": Allow.SIMPLE_TYPE, + "gc.pre_oome_count": Allow.SIMPLE_TYPE, + "gc.waiting_time": Allow.SIMPLE_TYPE, + "memory.free": Allow.SIMPLE_TYPE, + "memory.free_until_gc": Allow.SIMPLE_TYPE, + "memory.free_until_oome": Allow.SIMPLE_TYPE, + "memory.total": Allow.SIMPLE_TYPE, + "memory.max": Allow.SIMPLE_TYPE, + }, }, } From d05e00d7ca03c7b9eed2c1081e9c8bfb32cffb91 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 2 Jul 2026 16:42:33 +0200 Subject: [PATCH 2/3] test(sdk-crash-detection): Assert ART context is preserved by event stripper --- .../utils/sdk_crashes/test_event_stripper.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/sentry/utils/sdk_crashes/test_event_stripper.py b/tests/sentry/utils/sdk_crashes/test_event_stripper.py index 295c9cb6c3d7..3452b979924b 100644 --- a/tests/sentry/utils/sdk_crashes/test_event_stripper.py +++ b/tests/sentry/utils/sdk_crashes/test_event_stripper.py @@ -94,6 +94,43 @@ def test_strip_event_data_strips_context(store_and_strip_event) -> None: } +@django_db_all +@pytest.mark.snuba +def test_strip_event_data_keeps_art_context(store_and_strip_event) -> None: + """ART (Android Runtime) memory and GC context from ANR thread dumps must survive stripping.""" + event_data = get_crash_event() + event_data["contexts"]["art"] = { + "gc.total_count": 42, + "gc.total_time": 123.4, + "gc.blocking_count": 5, + "gc.blocking_time": 50.1, + "gc.pre_oome_count": 1, + "gc.waiting_time": 10.0, + "memory.free": 1024, + "memory.free_until_gc": 2048, + "memory.free_until_oome": 512, + "memory.total": 4096, + "memory.max": 8192, + "some_private_field": "should_be_stripped", + } + + stripped_event_data = store_and_strip_event(data=event_data) + + assert stripped_event_data["contexts"]["art"] == { + "gc.total_count": 42, + "gc.total_time": 123.4, + "gc.blocking_count": 5, + "gc.blocking_time": 50.1, + "gc.pre_oome_count": 1, + "gc.waiting_time": 10.0, + "memory.free": 1024, + "memory.free_until_gc": 2048, + "memory.free_until_oome": 512, + "memory.total": 4096, + "memory.max": 8192, + } + + @django_db_all @pytest.mark.snuba def test_strip_event_data_strips_sdk(store_and_strip_event) -> None: From 9616ad792f9819c85078ae829a511b64a18da340 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 2 Jul 2026 16:50:28 +0200 Subject: [PATCH 3/3] fix(sdk-crash-detection): Use set_path to avoid mypy indexed assignment error event_data["contexts"] is typed as object so direct indexed assignment fails mypy. Use the already-imported set_path() instead. --- .../utils/sdk_crashes/test_event_stripper.py | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/sentry/utils/sdk_crashes/test_event_stripper.py b/tests/sentry/utils/sdk_crashes/test_event_stripper.py index 3452b979924b..eea65bd07dfc 100644 --- a/tests/sentry/utils/sdk_crashes/test_event_stripper.py +++ b/tests/sentry/utils/sdk_crashes/test_event_stripper.py @@ -99,20 +99,25 @@ def test_strip_event_data_strips_context(store_and_strip_event) -> None: def test_strip_event_data_keeps_art_context(store_and_strip_event) -> None: """ART (Android Runtime) memory and GC context from ANR thread dumps must survive stripping.""" event_data = get_crash_event() - event_data["contexts"]["art"] = { - "gc.total_count": 42, - "gc.total_time": 123.4, - "gc.blocking_count": 5, - "gc.blocking_time": 50.1, - "gc.pre_oome_count": 1, - "gc.waiting_time": 10.0, - "memory.free": 1024, - "memory.free_until_gc": 2048, - "memory.free_until_oome": 512, - "memory.total": 4096, - "memory.max": 8192, - "some_private_field": "should_be_stripped", - } + set_path( + event_data, + "contexts", + "art", + value={ + "gc.total_count": 42, + "gc.total_time": 123.4, + "gc.blocking_count": 5, + "gc.blocking_time": 50.1, + "gc.pre_oome_count": 1, + "gc.waiting_time": 10.0, + "memory.free": 1024, + "memory.free_until_gc": 2048, + "memory.free_until_oome": 512, + "memory.total": 4096, + "memory.max": 8192, + "some_private_field": "should_be_stripped", + }, + ) stripped_event_data = store_and_strip_event(data=event_data)